]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Merge branches 'for-4.11/upstream-fixes', 'for-4.12/accutouch', 'for-4.12/cp2112...
authorJiri Kosina <jkosina@suse.cz>
Tue, 2 May 2017 09:01:10 +0000 (11:01 +0200)
committerJiri Kosina <jkosina@suse.cz>
Tue, 2 May 2017 09:01:10 +0000 (11:01 +0200)
2448 files changed:
Documentation/ABI/testing/sysfs-class-devfreq-event [new file with mode: 0644]
Documentation/ABI/testing/sysfs-class-led
Documentation/ABI/testing/sysfs-class-rc
Documentation/ABI/testing/sysfs-platform-hidma
Documentation/ABI/testing/sysfs-platform-hidma-mgmt
Documentation/acpi/acpi-lid.txt
Documentation/admin-guide/kernel-parameters.txt
Documentation/cdrom/cdrom-standard.tex
Documentation/cpu-freq/core.txt
Documentation/cpu-freq/cpu-drivers.txt
Documentation/cpu-freq/cpufreq-stats.txt
Documentation/cpu-freq/governors.txt
Documentation/cpu-freq/index.txt
Documentation/cpu-freq/intel-pstate.txt
Documentation/cpu-freq/user-guide.txt
Documentation/device-mapper/cache.txt
Documentation/device-mapper/dm-raid.txt
Documentation/devicetree/bindings/cpufreq/ti-cpufreq.txt [new file with mode: 0644]
Documentation/devicetree/bindings/devfreq/exynos-bus.txt
Documentation/devicetree/bindings/dma/stm32-dma.txt
Documentation/devicetree/bindings/input/hid-over-i2c.txt
Documentation/devicetree/bindings/leds/common.txt
Documentation/devicetree/bindings/leds/irled/spi-ir-led.txt [new file with mode: 0644]
Documentation/devicetree/bindings/media/fsl-vdoa.txt [new file with mode: 0644]
Documentation/devicetree/bindings/media/gpio-ir-receiver.txt
Documentation/devicetree/bindings/media/hix5hd2-ir.txt
Documentation/devicetree/bindings/media/i2c/toshiba,et8ek8.txt [new file with mode: 0644]
Documentation/devicetree/bindings/media/meson-ir.txt
Documentation/devicetree/bindings/media/mtk-cir.txt [new file with mode: 0644]
Documentation/devicetree/bindings/media/rc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/media/st,st-delta.txt [new file with mode: 0644]
Documentation/devicetree/bindings/media/sunxi-ir.txt
Documentation/devicetree/bindings/media/ti,da850-vpif.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mips/img/pistachio-marduk.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/amlogic,meson-gx.txt
Documentation/devicetree/bindings/mmc/mmc-pwrseq-sd8787.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/mmc.txt
Documentation/devicetree/bindings/mmc/sdhci-st.txt
Documentation/devicetree/bindings/mmc/sdhci.txt
Documentation/devicetree/bindings/mmc/sunxi-mmc.txt
Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt
Documentation/devicetree/bindings/mmc/tmio_mmc.txt
Documentation/devicetree/bindings/mmc/zx-dw-mshc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/wireless/marvell-8xxx.txt
Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/fsl,imx7d-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/marvell,armada-98dx3236-pinctrl.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/marvell,kirkwood-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/pinctrl-aspeed.txt
Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/ti,iodelay.txt [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/anatop-regulator.txt
Documentation/devicetree/bindings/regulator/cpcap-regulator.txt [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/gpio-regulator.txt
Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.txt
Documentation/devicetree/bindings/spi/spi-lantiq-ssc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/spi/spi-rockchip.txt
Documentation/gpio/driver.txt
Documentation/leds/leds-class.txt
Documentation/media/kapi/mc-core.rst
Documentation/media/uapi/gen-errors.rst
Documentation/media/uapi/rc/rc-sysfs-nodes.rst
Documentation/pinctrl.txt
Documentation/power/opp.txt
Documentation/power/states.txt
Documentation/security/LSM.txt
Documentation/spi/ep93xx_spi [deleted file]
MAINTAINERS
arch/alpha/kernel/traps.c
arch/alpha/mm/fault.c
arch/arc/mm/extable.c
arch/arm/boot/dts/imx6qdl.dtsi
arch/arm/boot/dts/stih407-family.dtsi
arch/arm/configs/exynos_defconfig
arch/arm/configs/multi_v5_defconfig
arch/arm/configs/multi_v7_defconfig
arch/arm/configs/mvebu_v5_defconfig
arch/arm/configs/pxa_defconfig
arch/arm/configs/shmobile_defconfig
arch/arm/mach-davinci/board-da850-evm.c
arch/arm/mach-davinci/board-dm644x-evm.c
arch/arm/mach-davinci/board-neuros-osd2.c
arch/arm/mach-davinci/board-omapl138-hawk.c
arch/arm/mach-ep93xx/edb93xx.c
arch/arm/mach-ep93xx/simone.c
arch/arm/mach-ep93xx/vision_ep9307.c
arch/arm/mach-exynos/suspend.c
arch/arm/mach-omap2/pdata-quirks.c
arch/arm/mach-omap2/pm.c
arch/arm/mach-pxa/balloon3.c
arch/arm/mach-pxa/colibri-pxa270-income.c
arch/arm/mach-pxa/corgi.c
arch/arm/mach-pxa/trizeps4.c
arch/arm/mach-pxa/vpac270.c
arch/arm/mach-pxa/zeus.c
arch/arm/mach-pxa/zylonite.c
arch/arm/mach-s5pv210/pm.c
arch/arm/mach-s5pv210/regs-clock.h
arch/arm/mm/extable.c
arch/arm/mm/fault.c
arch/arm/xen/enlighten.c
arch/arm/xen/hypercall.S
arch/arm64/xen/hypercall.S
arch/cris/arch-v32/kernel/traps.c
arch/frv/mm/extable.c
arch/hexagon/mm/vm_fault.c
arch/ia64/include/asm/exception.h [new file with mode: 0644]
arch/ia64/include/asm/uaccess.h
arch/ia64/kernel/acpi.c
arch/ia64/kernel/kprobes.c
arch/ia64/kernel/traps.c
arch/ia64/kernel/unaligned.c
arch/ia64/mm/fault.c
arch/m32r/mm/extable.c
arch/m32r/mm/fault.c
arch/metag/mm/extable.c
arch/microblaze/mm/fault.c
arch/mips/Kconfig
arch/mips/Makefile
arch/mips/Makefile.postlink [new file with mode: 0644]
arch/mips/alchemy/board-gpr.c
arch/mips/alchemy/common/dbdma.c
arch/mips/alchemy/common/dma.c
arch/mips/alchemy/common/gpiolib.c
arch/mips/alchemy/common/prom.c
arch/mips/alchemy/common/usb.c
arch/mips/alchemy/common/vss.c
arch/mips/alchemy/devboards/bcsr.c
arch/mips/alchemy/devboards/db1300.c
arch/mips/ar7/clock.c
arch/mips/ar7/gpio.c
arch/mips/ar7/memory.c
arch/mips/ar7/platform.c
arch/mips/ar7/prom.c
arch/mips/ath79/clock.c
arch/mips/ath79/common.c
arch/mips/bcm47xx/board.c
arch/mips/bcm47xx/buttons.c
arch/mips/bcm47xx/leds.c
arch/mips/bcm63xx/clk.c
arch/mips/bcm63xx/cpu.c
arch/mips/bcm63xx/cs.c
arch/mips/bcm63xx/gpio.c
arch/mips/bcm63xx/irq.c
arch/mips/bcm63xx/reset.c
arch/mips/bcm63xx/timer.c
arch/mips/boot/compressed/Makefile
arch/mips/boot/dts/Makefile
arch/mips/boot/dts/brcm/bcm7125.dtsi
arch/mips/boot/dts/brcm/bcm7346.dtsi
arch/mips/boot/dts/brcm/bcm7358.dtsi
arch/mips/boot/dts/brcm/bcm7360.dtsi
arch/mips/boot/dts/brcm/bcm7362.dtsi
arch/mips/boot/dts/brcm/bcm7420.dtsi
arch/mips/boot/dts/brcm/bcm7425.dtsi
arch/mips/boot/dts/brcm/bcm7435.dtsi
arch/mips/boot/dts/brcm/bcm97125cbmb.dts
arch/mips/boot/dts/brcm/bcm97346dbsmb.dts
arch/mips/boot/dts/brcm/bcm97358svmb.dts
arch/mips/boot/dts/brcm/bcm97360svmb.dts
arch/mips/boot/dts/brcm/bcm97362svmb.dts
arch/mips/boot/dts/brcm/bcm97420c.dts
arch/mips/boot/dts/brcm/bcm97425svmb.dts
arch/mips/boot/dts/brcm/bcm97435svmb.dts
arch/mips/boot/dts/img/Makefile [new file with mode: 0644]
arch/mips/boot/dts/img/pistachio.dtsi [new file with mode: 0644]
arch/mips/boot/dts/img/pistachio_marduk.dts [new file with mode: 0644]
arch/mips/boot/dts/xilfpga/nexys4ddr.dts
arch/mips/cavium-octeon/Makefile
arch/mips/cavium-octeon/crypto/octeon-crypto.c
arch/mips/cavium-octeon/dma-octeon.c
arch/mips/cavium-octeon/executive/cvmx-bootmem.c
arch/mips/cavium-octeon/executive/cvmx-helper-errata.c
arch/mips/cavium-octeon/executive/cvmx-helper-rgmii.c
arch/mips/cavium-octeon/executive/cvmx-helper-sgmii.c
arch/mips/cavium-octeon/executive/cvmx-helper-spi.c
arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c
arch/mips/cavium-octeon/executive/cvmx-helper.c
arch/mips/cavium-octeon/executive/cvmx-sysinfo.c
arch/mips/cavium-octeon/octeon-memcpy.S
arch/mips/cavium-octeon/octeon-platform.c
arch/mips/cavium-octeon/octeon-usb.c [new file with mode: 0644]
arch/mips/cavium-octeon/setup.c
arch/mips/cavium-octeon/smp.c
arch/mips/configs/bmips_stb_defconfig
arch/mips/configs/cavium_octeon_defconfig
arch/mips/configs/ip22_defconfig
arch/mips/configs/ip27_defconfig
arch/mips/configs/lemote2f_defconfig
arch/mips/configs/loongson1b_defconfig
arch/mips/configs/loongson1c_defconfig
arch/mips/configs/malta_defconfig
arch/mips/configs/malta_kvm_defconfig
arch/mips/configs/malta_kvm_guest_defconfig
arch/mips/configs/maltaup_xpa_defconfig
arch/mips/configs/nlm_xlp_defconfig
arch/mips/configs/nlm_xlr_defconfig
arch/mips/configs/xilfpga_defconfig
arch/mips/configs/xway_defconfig
arch/mips/dec/prom/identify.c
arch/mips/dec/setup.c
arch/mips/dec/wbflush.c
arch/mips/emma/markeins/setup.c
arch/mips/generic/Makefile
arch/mips/generic/init.c
arch/mips/generic/kexec.c [new file with mode: 0644]
arch/mips/include/asm/Kbuild
arch/mips/include/asm/asm-prototypes.h [new file with mode: 0644]
arch/mips/include/asm/asm.h
arch/mips/include/asm/bootinfo.h
arch/mips/include/asm/checksum.h
arch/mips/include/asm/elf.h
arch/mips/include/asm/highmem.h
arch/mips/include/asm/i8259.h
arch/mips/include/asm/irq.h
arch/mips/include/asm/mach-bcm47xx/bcm47xx_board.h
arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h
arch/mips/include/asm/mach-ip27/spaces.h
arch/mips/include/asm/mach-loongson32/loongson1.h
arch/mips/include/asm/mach-loongson32/platform.h
arch/mips/include/asm/mach-loongson32/regs-rtc.h [new file with mode: 0644]
arch/mips/include/asm/mach-ralink/mt7620.h
arch/mips/include/asm/mips-cm.h
arch/mips/include/asm/mipsregs.h
arch/mips/include/asm/octeon/cvmx-gpio-defs.h
arch/mips/include/asm/octeon/cvmx-helper-rgmii.h
arch/mips/include/asm/octeon/cvmx-helper-sgmii.h
arch/mips/include/asm/octeon/cvmx-helper-spi.h
arch/mips/include/asm/octeon/cvmx-helper-xaui.h
arch/mips/include/asm/octeon/cvmx-helper.h
arch/mips/include/asm/pgalloc.h
arch/mips/include/asm/r4kcache.h
arch/mips/include/asm/smp.h
arch/mips/include/asm/stackframe.h
arch/mips/include/asm/switch_to.h
arch/mips/include/asm/thread_info.h
arch/mips/include/asm/tlbex.h [new file with mode: 0644]
arch/mips/include/asm/uaccess.h
arch/mips/include/asm/uasm.h
arch/mips/include/asm/unaligned.h [deleted file]
arch/mips/jazz/jazzdma.c
arch/mips/jz4740/gpio.c
arch/mips/jz4740/prom.c
arch/mips/jz4740/timer.c
arch/mips/kernel/Makefile
arch/mips/kernel/asm-offsets.c
arch/mips/kernel/cacheinfo.c [new file with mode: 0644]
arch/mips/kernel/cpu-bugs64.c
arch/mips/kernel/crash.c
arch/mips/kernel/entry.S
arch/mips/kernel/genex.S
arch/mips/kernel/irq.c
arch/mips/kernel/linux32.c
arch/mips/kernel/machine_kexec.c
arch/mips/kernel/mcount.S
arch/mips/kernel/mips-mt-fpaff.c
arch/mips/kernel/mips-r2-to-r6-emul.c
arch/mips/kernel/mips_ksyms.c [deleted file]
arch/mips/kernel/perf_event_mipsxx.c
arch/mips/kernel/process.c
arch/mips/kernel/prom.c
arch/mips/kernel/ptrace.c
arch/mips/kernel/r2300_switch.S
arch/mips/kernel/r4k_switch.S
arch/mips/kernel/relocate.c
arch/mips/kernel/setup.c
arch/mips/kernel/smp-bmips.c
arch/mips/kernel/smp-cps.c
arch/mips/kernel/smp.c
arch/mips/kernel/sync-r4k.c
arch/mips/kernel/syscall.c
arch/mips/kernel/traps.c
arch/mips/kernel/uprobes.c
arch/mips/kernel/vmlinux.lds.S
arch/mips/lantiq/irq.c
arch/mips/lantiq/prom.c
arch/mips/lantiq/xway/dma.c
arch/mips/lantiq/xway/gptu.c
arch/mips/lantiq/xway/sysctrl.c
arch/mips/lasat/at93c.c
arch/mips/lasat/sysctl.c
arch/mips/lib/csum_partial.S
arch/mips/lib/memcpy.S
arch/mips/lib/memset.S
arch/mips/lib/strlen_user.S
arch/mips/lib/strncpy_user.S
arch/mips/lib/strnlen_user.S
arch/mips/loongson32/common/platform.c
arch/mips/loongson32/ls1b/board.c
arch/mips/loongson32/ls1c/board.c
arch/mips/loongson64/common/cs5536/cs5536_mfgpt.c
arch/mips/loongson64/common/dma-swiotlb.c
arch/mips/loongson64/common/env.c
arch/mips/loongson64/common/setup.c
arch/mips/loongson64/common/uart_base.c
arch/mips/loongson64/lemote-2f/ec_kb3310b.c
arch/mips/loongson64/lemote-2f/irq.c
arch/mips/loongson64/lemote-2f/pm.c
arch/mips/loongson64/loongson-3/irq.c
arch/mips/loongson64/loongson-3/numa.c
arch/mips/loongson64/loongson-3/smp.c
arch/mips/mm/Makefile
arch/mips/mm/c-r4k.c
arch/mips/mm/init.c
arch/mips/mm/mmap.c
arch/mips/mm/page-funcs.S
arch/mips/mm/page.c
arch/mips/mm/pgtable-64.c
arch/mips/mm/pgtable.c [new file with mode: 0644]
arch/mips/mm/sc-ip22.c
arch/mips/mm/sc-mips.c
arch/mips/mm/tlbex.c
arch/mips/mti-malta/malta-platform.c
arch/mips/netlogic/common/irq.c
arch/mips/netlogic/common/smpboot.S
arch/mips/netlogic/xlp/wakeup.c
arch/mips/oprofile/op_model_mipsxx.c
arch/mips/pci/pci-tx4927.c
arch/mips/pci/pci-tx4938.c
arch/mips/pci/pci-tx4939.c
arch/mips/pic32/pic32mzda/Makefile
arch/mips/pmcs-msp71xx/msp_prom.c
arch/mips/pmcs-msp71xx/msp_time.c
arch/mips/ralink/Kconfig
arch/mips/ralink/clk.c
arch/mips/ralink/irq.c
arch/mips/ralink/mt7620.c
arch/mips/ralink/mt7621.c
arch/mips/ralink/of.c
arch/mips/ralink/prom.c
arch/mips/ralink/rt288x.c
arch/mips/ralink/rt305x.c
arch/mips/ralink/rt3883.c
arch/mips/ralink/timer.c
arch/mips/rb532/irq.c
arch/mips/rb532/prom.c
arch/mips/sgi-ip22/Platform
arch/mips/sgi-ip22/ip22-hpc.c
arch/mips/sgi-ip22/ip22-mc.c
arch/mips/sgi-ip22/ip22-nvram.c
arch/mips/sgi-ip22/ip22-reset.c
arch/mips/sgi-ip22/ip22-setup.c
arch/mips/sgi-ip27/ip27-berr.c
arch/mips/sgi-ip27/ip27-init.c
arch/mips/sgi-ip27/ip27-klnuma.c
arch/mips/sgi-ip27/ip27-memory.c
arch/mips/sgi-ip32/crime.c
arch/mips/sgi-ip32/ip32-irq.c
arch/mips/sibyte/bcm1480/setup.c
arch/mips/sibyte/sb1250/setup.c
arch/mips/txx9/generic/7segled.c
arch/mips/txx9/generic/pci.c
arch/mips/txx9/generic/setup.c
arch/mips/txx9/generic/setup_tx3927.c
arch/mips/txx9/generic/setup_tx4927.c
arch/mips/txx9/generic/setup_tx4938.c
arch/mips/txx9/generic/setup_tx4939.c
arch/mips/txx9/generic/smsc_fdc37m81x.c
arch/mips/txx9/jmr3927/prom.c
arch/mips/txx9/jmr3927/setup.c
arch/mips/txx9/rbtx4938/setup.c
arch/mips/vdso/Makefile
arch/mips/vr41xx/common/bcu.c
arch/mips/vr41xx/common/cmu.c
arch/mips/vr41xx/common/icu.c
arch/mips/vr41xx/common/irq.c
arch/mips/xilfpga/intc.c
arch/mn10300/mm/extable.c
arch/mn10300/mm/misalignment.c
arch/nios2/mm/extable.c
arch/nios2/mm/fault.c
arch/openrisc/kernel/traps.c
arch/openrisc/mm/fault.c
arch/powerpc/configs/ppc6xx_defconfig
arch/score/kernel/traps.c
arch/score/mm/extable.c
arch/score/mm/fault.c
arch/sh/boot/romimage/mmcif-sh7724.c
arch/sh/configs/sh7785lcr_32bit_defconfig
arch/sh/include/asm/uaccess.h
arch/sh/kernel/kprobes.c
arch/sh/kernel/traps.c
arch/sh/mm/extable_32.c
arch/sh/mm/extable_64.c
arch/sparc/mm/extable.c
arch/unicore32/mm/extable.c
arch/unicore32/mm/fault.c
arch/x86/include/asm/xen/hypercall.h
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/acpi/cstate.c
arch/x86/xen/Kconfig
arch/x86/xen/Makefile
arch/x86/xen/apic.c
arch/x86/xen/enlighten.c
arch/x86/xen/mmu.c
arch/x86/xen/platform-pci-unplug.c
arch/x86/xen/setup.c
arch/x86/xen/smp.c
arch/x86/xen/smp.h
arch/x86/xen/xen-head.S
arch/x86/xen/xen-ops.h
arch/x86/xen/xen-pvh.S [new file with mode: 0644]
arch/xtensa/mm/fault.c
block/Kconfig
block/Kconfig.iosched
block/Makefile
block/bio.c
block/blk-cgroup.c
block/blk-core.c
block/blk-exec.c
block/blk-flush.c
block/blk-integrity.c
block/blk-ioc.c
block/blk-map.c
block/blk-merge.c
block/blk-mq-debugfs.c [new file with mode: 0644]
block/blk-mq-sched.c [new file with mode: 0644]
block/blk-mq-sched.h [new file with mode: 0644]
block/blk-mq-sysfs.c
block/blk-mq-tag.c
block/blk-mq-tag.h
block/blk-mq.c
block/blk-mq.h
block/blk-settings.c
block/blk-sysfs.c
block/blk-tag.c
block/blk-throttle.c
block/blk-wbt.c
block/blk.h
block/bsg-lib.c
block/bsg.c
block/cfq-iosched.c
block/compat_ioctl.c
block/deadline-iosched.c
block/elevator.c
block/genhd.c
block/ioctl.c
block/mq-deadline.c [new file with mode: 0644]
block/noop-iosched.c
block/opal_proto.h [new file with mode: 0644]
block/partitions/efi.c
block/scsi_ioctl.c
block/sed-opal.c [new file with mode: 0644]
drivers/acpi/acpi_processor.c
drivers/acpi/acpica/acapps.h
drivers/acpi/acpica/accommon.h
drivers/acpi/acpica/acdebug.h
drivers/acpi/acpica/acdispat.h
drivers/acpi/acpica/acevents.h
drivers/acpi/acpica/acglobal.h
drivers/acpi/acpica/achware.h
drivers/acpi/acpica/acinterp.h
drivers/acpi/acpica/aclocal.h
drivers/acpi/acpica/acmacros.h
drivers/acpi/acpica/acnamesp.h
drivers/acpi/acpica/acobject.h
drivers/acpi/acpica/acopcode.h
drivers/acpi/acpica/acparser.h
drivers/acpi/acpica/acpredef.h
drivers/acpi/acpica/acresrc.h
drivers/acpi/acpica/acstruct.h
drivers/acpi/acpica/actables.h
drivers/acpi/acpica/acutils.h
drivers/acpi/acpica/amlcode.h
drivers/acpi/acpica/amlresrc.h
drivers/acpi/acpica/dbcmds.c
drivers/acpi/acpica/dbconvert.c
drivers/acpi/acpica/dbdisply.c
drivers/acpi/acpica/dbexec.c
drivers/acpi/acpica/dbfileio.c
drivers/acpi/acpica/dbhistry.c
drivers/acpi/acpica/dbinput.c
drivers/acpi/acpica/dbmethod.c
drivers/acpi/acpica/dbnames.c
drivers/acpi/acpica/dbobject.c
drivers/acpi/acpica/dbstats.c
drivers/acpi/acpica/dbtest.c
drivers/acpi/acpica/dbutils.c
drivers/acpi/acpica/dbxface.c
drivers/acpi/acpica/dsargs.c
drivers/acpi/acpica/dscontrol.c
drivers/acpi/acpica/dsdebug.c
drivers/acpi/acpica/dsfield.c
drivers/acpi/acpica/dsinit.c
drivers/acpi/acpica/dsmethod.c
drivers/acpi/acpica/dsmthdat.c
drivers/acpi/acpica/dsobject.c
drivers/acpi/acpica/dsopcode.c
drivers/acpi/acpica/dsutils.c
drivers/acpi/acpica/dswexec.c
drivers/acpi/acpica/dswload.c
drivers/acpi/acpica/dswload2.c
drivers/acpi/acpica/dswscope.c
drivers/acpi/acpica/dswstate.c
drivers/acpi/acpica/evevent.c
drivers/acpi/acpica/evglock.c
drivers/acpi/acpica/evgpe.c
drivers/acpi/acpica/evgpeblk.c
drivers/acpi/acpica/evgpeinit.c
drivers/acpi/acpica/evgpeutil.c
drivers/acpi/acpica/evhandler.c
drivers/acpi/acpica/evmisc.c
drivers/acpi/acpica/evregion.c
drivers/acpi/acpica/evrgnini.c
drivers/acpi/acpica/evsci.c
drivers/acpi/acpica/evxface.c
drivers/acpi/acpica/evxfevnt.c
drivers/acpi/acpica/evxfgpe.c
drivers/acpi/acpica/evxfregn.c
drivers/acpi/acpica/exconcat.c
drivers/acpi/acpica/exconfig.c
drivers/acpi/acpica/exconvrt.c
drivers/acpi/acpica/excreate.c
drivers/acpi/acpica/exdebug.c
drivers/acpi/acpica/exdump.c
drivers/acpi/acpica/exfield.c
drivers/acpi/acpica/exfldio.c
drivers/acpi/acpica/exmisc.c
drivers/acpi/acpica/exmutex.c
drivers/acpi/acpica/exnames.c
drivers/acpi/acpica/exoparg1.c
drivers/acpi/acpica/exoparg2.c
drivers/acpi/acpica/exoparg3.c
drivers/acpi/acpica/exoparg6.c
drivers/acpi/acpica/exprep.c
drivers/acpi/acpica/exregion.c
drivers/acpi/acpica/exresnte.c
drivers/acpi/acpica/exresolv.c
drivers/acpi/acpica/exresop.c
drivers/acpi/acpica/exstore.c
drivers/acpi/acpica/exstoren.c
drivers/acpi/acpica/exstorob.c
drivers/acpi/acpica/exsystem.c
drivers/acpi/acpica/extrace.c
drivers/acpi/acpica/exutils.c
drivers/acpi/acpica/hwacpi.c
drivers/acpi/acpica/hwesleep.c
drivers/acpi/acpica/hwgpe.c
drivers/acpi/acpica/hwpci.c
drivers/acpi/acpica/hwregs.c
drivers/acpi/acpica/hwsleep.c
drivers/acpi/acpica/hwtimer.c
drivers/acpi/acpica/hwvalid.c
drivers/acpi/acpica/hwxface.c
drivers/acpi/acpica/hwxfsleep.c
drivers/acpi/acpica/nsaccess.c
drivers/acpi/acpica/nsalloc.c
drivers/acpi/acpica/nsarguments.c
drivers/acpi/acpica/nsconvert.c
drivers/acpi/acpica/nsdump.c
drivers/acpi/acpica/nsdumpdv.c
drivers/acpi/acpica/nseval.c
drivers/acpi/acpica/nsinit.c
drivers/acpi/acpica/nsload.c
drivers/acpi/acpica/nsnames.c
drivers/acpi/acpica/nsobject.c
drivers/acpi/acpica/nsparse.c
drivers/acpi/acpica/nspredef.c
drivers/acpi/acpica/nsprepkg.c
drivers/acpi/acpica/nsrepair.c
drivers/acpi/acpica/nsrepair2.c
drivers/acpi/acpica/nssearch.c
drivers/acpi/acpica/nsutils.c
drivers/acpi/acpica/nswalk.c
drivers/acpi/acpica/nsxfeval.c
drivers/acpi/acpica/nsxfname.c
drivers/acpi/acpica/nsxfobj.c
drivers/acpi/acpica/psargs.c
drivers/acpi/acpica/psloop.c
drivers/acpi/acpica/psobject.c
drivers/acpi/acpica/psopcode.c
drivers/acpi/acpica/psopinfo.c
drivers/acpi/acpica/psparse.c
drivers/acpi/acpica/psscope.c
drivers/acpi/acpica/pstree.c
drivers/acpi/acpica/psutils.c
drivers/acpi/acpica/pswalk.c
drivers/acpi/acpica/psxface.c
drivers/acpi/acpica/rsaddr.c
drivers/acpi/acpica/rscalc.c
drivers/acpi/acpica/rscreate.c
drivers/acpi/acpica/rsdump.c
drivers/acpi/acpica/rsdumpinfo.c
drivers/acpi/acpica/rsinfo.c
drivers/acpi/acpica/rsio.c
drivers/acpi/acpica/rsirq.c
drivers/acpi/acpica/rslist.c
drivers/acpi/acpica/rsmemory.c
drivers/acpi/acpica/rsmisc.c
drivers/acpi/acpica/rsserial.c
drivers/acpi/acpica/rsutils.c
drivers/acpi/acpica/rsxface.c
drivers/acpi/acpica/tbdata.c
drivers/acpi/acpica/tbfadt.c
drivers/acpi/acpica/tbfind.c
drivers/acpi/acpica/tbinstal.c
drivers/acpi/acpica/tbprint.c
drivers/acpi/acpica/tbutils.c
drivers/acpi/acpica/tbxface.c
drivers/acpi/acpica/tbxfload.c
drivers/acpi/acpica/tbxfroot.c
drivers/acpi/acpica/utaddress.c
drivers/acpi/acpica/utalloc.c
drivers/acpi/acpica/utascii.c
drivers/acpi/acpica/utbuffer.c
drivers/acpi/acpica/utcache.c
drivers/acpi/acpica/utcopy.c
drivers/acpi/acpica/utdebug.c
drivers/acpi/acpica/utdecode.c
drivers/acpi/acpica/utdelete.c
drivers/acpi/acpica/uterror.c
drivers/acpi/acpica/uteval.c
drivers/acpi/acpica/utexcep.c
drivers/acpi/acpica/utglobal.c
drivers/acpi/acpica/uthex.c
drivers/acpi/acpica/utids.c
drivers/acpi/acpica/utinit.c
drivers/acpi/acpica/utlock.c
drivers/acpi/acpica/utmath.c
drivers/acpi/acpica/utmisc.c
drivers/acpi/acpica/utmutex.c
drivers/acpi/acpica/utnonansi.c
drivers/acpi/acpica/utobject.c
drivers/acpi/acpica/utosi.c
drivers/acpi/acpica/utownerid.c
drivers/acpi/acpica/utpredef.c
drivers/acpi/acpica/utprint.c
drivers/acpi/acpica/utresrc.c
drivers/acpi/acpica/utstate.c
drivers/acpi/acpica/utstring.c
drivers/acpi/acpica/utstrtoul64.c
drivers/acpi/acpica/uttrack.c
drivers/acpi/acpica/utuuid.c
drivers/acpi/acpica/utxface.c
drivers/acpi/acpica/utxferror.c
drivers/acpi/acpica/utxfinit.c
drivers/acpi/acpica/utxfmutex.c
drivers/acpi/apei/einj.c
drivers/acpi/bus.c
drivers/acpi/button.c
drivers/acpi/ec.c
drivers/acpi/internal.h
drivers/acpi/osl.c
drivers/acpi/processor_perflib.c
drivers/acpi/sleep.c
drivers/ata/Kconfig
drivers/ata/Makefile
drivers/ata/ahci_imx.c
drivers/ata/ahci_qoriq.c
drivers/ata/ahci_xgene.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/libata-scsi.c
drivers/ata/libata-sff.c
drivers/ata/libata-transport.c
drivers/ata/libata.h
drivers/ata/pata_at91.c
drivers/ata/pata_atiixp.c
drivers/ata/pata_bf54x.c
drivers/ata/pata_ep93xx.c
drivers/ata/pata_falcon.c [new file with mode: 0644]
drivers/ata/pata_ixp4xx_cf.c
drivers/ata/pata_legacy.c
drivers/ata/pata_octeon_cf.c
drivers/ata/pata_of_platform.c
drivers/ata/pata_pcmcia.c
drivers/ata/pata_samsung_cf.c
drivers/ata/sata_mv.c
drivers/ata/sata_rcar.c
drivers/base/cpu.c
drivers/base/power/domain.c
drivers/base/power/opp/core.c
drivers/base/power/opp/cpu.c
drivers/base/power/opp/of.c
drivers/base/power/opp/opp.h
drivers/base/power/qos.c
drivers/base/power/wakeirq.c
drivers/base/property.c
drivers/base/regmap/regcache-rbtree.c
drivers/base/regmap/regcache.c
drivers/base/regmap/regmap-irq.c
drivers/base/regmap/regmap.c
drivers/block/Kconfig
drivers/block/aoe/aoeblk.c
drivers/block/cciss.c
drivers/block/cciss.h
drivers/block/drbd/drbd_main.c
drivers/block/drbd/drbd_nl.c
drivers/block/drbd/drbd_proc.c
drivers/block/drbd/drbd_req.c
drivers/block/floppy.c
drivers/block/hd.c
drivers/block/loop.c
drivers/block/mg_disk.c
drivers/block/nbd.c
drivers/block/null_blk.c
drivers/block/osdblk.c
drivers/block/paride/Kconfig
drivers/block/paride/pcd.c
drivers/block/paride/pd.c
drivers/block/pktcdvd.c
drivers/block/ps3disk.c
drivers/block/rbd.c
drivers/block/skd_main.c
drivers/block/sx8.c
drivers/block/virtio_blk.c
drivers/block/xen-blkback/xenbus.c
drivers/block/xen-blkfront.c
drivers/block/xsysace.c
drivers/block/zram/zram_drv.c
drivers/cdrom/cdrom.c
drivers/cdrom/gdrom.c
drivers/char/tpm/Kconfig
drivers/char/tpm/Makefile
drivers/char/tpm/st33zp24/st33zp24.c
drivers/char/tpm/tpm-chip.c
drivers/char/tpm/tpm-dev.c
drivers/char/tpm/tpm-interface.c
drivers/char/tpm/tpm-sysfs.c
drivers/char/tpm/tpm.h
drivers/char/tpm/tpm1_eventlog.c [new file with mode: 0644]
drivers/char/tpm/tpm2-cmd.c
drivers/char/tpm/tpm2_eventlog.c [new file with mode: 0644]
drivers/char/tpm/tpm_acpi.c
drivers/char/tpm/tpm_atmel.h
drivers/char/tpm/tpm_crb.c
drivers/char/tpm/tpm_eventlog.c [deleted file]
drivers/char/tpm/tpm_eventlog.h
drivers/char/tpm/tpm_ibmvtpm.c
drivers/char/tpm/tpm_nsc.c
drivers/char/tpm/tpm_of.c
drivers/char/tpm/tpm_tis.c
drivers/char/tpm/tpm_tis_core.c
drivers/char/tpm/tpm_tis_core.h
drivers/char/tpm/tpm_tis_spi.c
drivers/char/tpm/tpm_vtpm_proxy.c
drivers/char/tpm/xen-tpmfront.c
drivers/clk/tegra/clk-dfll.c
drivers/cpufreq/Kconfig
drivers/cpufreq/Kconfig.arm
drivers/cpufreq/Makefile
drivers/cpufreq/bmips-cpufreq.c [new file with mode: 0644]
drivers/cpufreq/brcmstb-avs-cpufreq.c
drivers/cpufreq/cpufreq-dt-platdev.c
drivers/cpufreq/cpufreq-dt.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_stats.c
drivers/cpufreq/exynos5440-cpufreq.c
drivers/cpufreq/imx6q-cpufreq.c
drivers/cpufreq/intel_pstate.c
drivers/cpufreq/mt8173-cpufreq.c
drivers/cpufreq/omap-cpufreq.c
drivers/cpufreq/powernv-cpufreq.c
drivers/cpufreq/ppc_cbe_cpufreq_pmi.c
drivers/cpufreq/qoriq-cpufreq.c
drivers/cpufreq/s3c2416-cpufreq.c
drivers/cpufreq/sti-cpufreq.c
drivers/cpufreq/ti-cpufreq.c [new file with mode: 0644]
drivers/cpuidle/governors/menu.c
drivers/devfreq/devfreq-event.c
drivers/devfreq/devfreq.c
drivers/devfreq/event/exynos-ppmu.c
drivers/devfreq/exynos-bus.c
drivers/devfreq/governor.h
drivers/devfreq/governor_passive.c
drivers/devfreq/governor_userspace.c
drivers/devfreq/rk3399_dmc.c
drivers/devfreq/tegra-devfreq.c
drivers/dma/Kconfig
drivers/dma/Makefile
drivers/dma/dmaengine.c
drivers/dma/dw/core.c
drivers/dma/dw/pci.c
drivers/dma/dw/platform.c
drivers/dma/dw/regs.h
drivers/dma/ipu/ipu_irq.c
drivers/dma/sh/rcar-dmac.c
drivers/dma/ste_dma40.c
drivers/dma/stm32-dma.c
drivers/dma/zx296702_dma.c [deleted file]
drivers/dma/zx_dma.c [new file with mode: 0644]
drivers/gpio/gpio-aspeed.c
drivers/gpio/gpio-bcm-kona.c
drivers/gpio/gpio-dln2.c
drivers/gpio/gpio-dwapb.c
drivers/gpio/gpio-ep93xx.c
drivers/gpio/gpio-f7188x.c
drivers/gpio/gpio-lp873x.c
drivers/gpio/gpio-max77620.c
drivers/gpio/gpio-menz127.c
drivers/gpio/gpio-merrifield.c
drivers/gpio/gpio-omap.c
drivers/gpio/gpio-tc3589x.c
drivers/gpio/gpio-tegra.c
drivers/gpio/gpio-tps65218.c
drivers/gpio/gpio-vx855.c
drivers/gpio/gpio-wcove.c
drivers/gpio/gpio-wm831x.c
drivers/gpio/gpio-wm8994.c
drivers/gpio/gpiolib.c
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-accutouch.c [new file with mode: 0644]
drivers/hid/hid-core.c
drivers/hid/hid-cp2112.c
drivers/hid/hid-debug.c
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/hid/hid-logitech-dj.c
drivers/hid/hid-logitech-hidpp.c
drivers/hid/hid-multitouch.c
drivers/hid/hid-nti.c [new file with mode: 0644]
drivers/hid/hid-picolcd_cir.c
drivers/hid/i2c-hid/i2c-hid.c
drivers/hid/usbhid/hid-core.c
drivers/hid/usbhid/hid-quirks.c
drivers/hid/usbhid/hiddev.c
drivers/hid/wacom.h
drivers/hid/wacom_sys.c
drivers/hid/wacom_wac.c
drivers/hid/wacom_wac.h
drivers/i2c/i2c-core.c
drivers/ide/Kconfig
drivers/ide/ide-atapi.c
drivers/ide/ide-cd.c
drivers/ide/ide-cd_ioctl.c
drivers/ide/ide-cd_verbose.c
drivers/ide/ide-devsets.c
drivers/ide/ide-disk.c
drivers/ide/ide-eh.c
drivers/ide/ide-floppy.c
drivers/ide/ide-io.c
drivers/ide/ide-ioctls.c
drivers/ide/ide-park.c
drivers/ide/ide-pm.c
drivers/ide/ide-probe.c
drivers/ide/ide-tape.c
drivers/ide/ide-taskfile.c
drivers/ide/sis5513.c
drivers/infiniband/ulp/iser/iscsi_iser.c
drivers/infiniband/ulp/srp/ib_srp.c
drivers/leds/Kconfig
drivers/leds/led-class.c
drivers/leds/leds-ktd2692.c
drivers/leds/trigger/ledtrig-heartbeat.c
drivers/lightnvm/Kconfig
drivers/lightnvm/Makefile
drivers/lightnvm/core.c
drivers/lightnvm/gennvm.c [deleted file]
drivers/lightnvm/gennvm.h [deleted file]
drivers/lightnvm/rrpc.c
drivers/lightnvm/rrpc.h
drivers/lightnvm/sysblk.c [deleted file]
drivers/md/bcache/request.c
drivers/md/bcache/super.c
drivers/md/dm-cache-metadata.c
drivers/md/dm-cache-metadata.h
drivers/md/dm-cache-target.c
drivers/md/dm-core.h
drivers/md/dm-era-target.c
drivers/md/dm-mpath.c
drivers/md/dm-raid.c
drivers/md/dm-round-robin.c
drivers/md/dm-rq.c
drivers/md/dm-rq.h
drivers/md/dm-stats.c
drivers/md/dm-table.c
drivers/md/dm-target.c
drivers/md/dm-thin.c
drivers/md/dm.c
drivers/md/dm.h
drivers/md/linear.c
drivers/md/md.c
drivers/md/multipath.c
drivers/md/persistent-data/dm-array.c
drivers/md/persistent-data/dm-array.h
drivers/md/persistent-data/dm-bitset.c
drivers/md/persistent-data/dm-bitset.h
drivers/md/persistent-data/dm-block-manager.c
drivers/md/persistent-data/dm-btree.c
drivers/md/persistent-data/dm-btree.h
drivers/md/persistent-data/dm-space-map-common.c
drivers/md/persistent-data/dm-space-map-metadata.c
drivers/md/raid0.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid5.c
drivers/media/cec/cec-core.c
drivers/media/common/b2c2/flexcop-fe-tuner.c
drivers/media/common/b2c2/flexcop.c
drivers/media/common/cx2341x.c
drivers/media/common/siano/sms-cards.c
drivers/media/common/siano/sms-cards.h
drivers/media/common/siano/smscoreapi.c
drivers/media/common/siano/smsir.c
drivers/media/common/tveeprom.c
drivers/media/dvb-core/demux.h
drivers/media/dvb-core/dmxdev.c
drivers/media/dvb-core/dmxdev.h
drivers/media/dvb-core/dvb-usb-ids.h
drivers/media/dvb-core/dvb_ca_en50221.c
drivers/media/dvb-core/dvb_demux.c
drivers/media/dvb-core/dvb_demux.h
drivers/media/dvb-core/dvb_frontend.c
drivers/media/dvb-core/dvb_math.c
drivers/media/dvb-core/dvb_math.h
drivers/media/dvb-core/dvb_net.c
drivers/media/dvb-core/dvb_net.h
drivers/media/dvb-core/dvb_ringbuffer.c
drivers/media/dvb-core/dvbdev.c
drivers/media/dvb-core/dvbdev.h
drivers/media/dvb-frontends/Kconfig
drivers/media/dvb-frontends/Makefile
drivers/media/dvb-frontends/af9013.c
drivers/media/dvb-frontends/af9013.h
drivers/media/dvb-frontends/af9013_priv.h
drivers/media/dvb-frontends/af9033.c
drivers/media/dvb-frontends/af9033.h
drivers/media/dvb-frontends/af9033_priv.h
drivers/media/dvb-frontends/atbm8830.c
drivers/media/dvb-frontends/atbm8830.h
drivers/media/dvb-frontends/atbm8830_priv.h
drivers/media/dvb-frontends/au8522_decoder.c
drivers/media/dvb-frontends/bcm3510.h
drivers/media/dvb-frontends/bcm3510_priv.h
drivers/media/dvb-frontends/bsbe1-d01a.h
drivers/media/dvb-frontends/bsbe1.h
drivers/media/dvb-frontends/bsru6.h
drivers/media/dvb-frontends/cx24113.c
drivers/media/dvb-frontends/cx24113.h
drivers/media/dvb-frontends/cx24123.c
drivers/media/dvb-frontends/cxd2820r_core.c
drivers/media/dvb-frontends/dib0070.c
drivers/media/dvb-frontends/dib0090.c
drivers/media/dvb-frontends/dib7000p.c
drivers/media/dvb-frontends/drx39xyj/drx39xxj.h
drivers/media/dvb-frontends/drxd.h
drivers/media/dvb-frontends/drxd_firm.c
drivers/media/dvb-frontends/drxd_firm.h
drivers/media/dvb-frontends/drxd_hard.c
drivers/media/dvb-frontends/drxd_map_firm.h
drivers/media/dvb-frontends/drxk_hard.c
drivers/media/dvb-frontends/dvb-pll.c
drivers/media/dvb-frontends/dvb_dummy_fe.c
drivers/media/dvb-frontends/dvb_dummy_fe.h
drivers/media/dvb-frontends/ec100.c
drivers/media/dvb-frontends/ec100.h
drivers/media/dvb-frontends/hd29l2.c [deleted file]
drivers/media/dvb-frontends/hd29l2.h [deleted file]
drivers/media/dvb-frontends/hd29l2_priv.h [deleted file]
drivers/media/dvb-frontends/isl6405.c
drivers/media/dvb-frontends/isl6405.h
drivers/media/dvb-frontends/isl6421.c
drivers/media/dvb-frontends/isl6421.h
drivers/media/dvb-frontends/itd1000.c
drivers/media/dvb-frontends/itd1000.h
drivers/media/dvb-frontends/itd1000_priv.h
drivers/media/dvb-frontends/ix2505v.c
drivers/media/dvb-frontends/ix2505v.h
drivers/media/dvb-frontends/lg2160.c
drivers/media/dvb-frontends/lg2160.h
drivers/media/dvb-frontends/lgdt3305.c
drivers/media/dvb-frontends/lgdt3305.h
drivers/media/dvb-frontends/lgdt3306a.c
drivers/media/dvb-frontends/lgdt3306a.h
drivers/media/dvb-frontends/lgdt330x.c
drivers/media/dvb-frontends/lgdt330x.h
drivers/media/dvb-frontends/lgdt330x_priv.h
drivers/media/dvb-frontends/lgs8gxx.c
drivers/media/dvb-frontends/lgs8gxx.h
drivers/media/dvb-frontends/lgs8gxx_priv.h
drivers/media/dvb-frontends/lnbh24.h
drivers/media/dvb-frontends/lnbp21.c
drivers/media/dvb-frontends/lnbp21.h
drivers/media/dvb-frontends/lnbp22.c
drivers/media/dvb-frontends/lnbp22.h
drivers/media/dvb-frontends/mn88473.c
drivers/media/dvb-frontends/mt352.c
drivers/media/dvb-frontends/mt352.h
drivers/media/dvb-frontends/mt352_priv.h
drivers/media/dvb-frontends/nxt200x.c
drivers/media/dvb-frontends/nxt200x.h
drivers/media/dvb-frontends/or51132.c
drivers/media/dvb-frontends/or51132.h
drivers/media/dvb-frontends/or51211.c
drivers/media/dvb-frontends/or51211.h
drivers/media/dvb-frontends/rtl2832_sdr.c
drivers/media/dvb-frontends/s5h1420.c
drivers/media/dvb-frontends/s5h1420.h
drivers/media/dvb-frontends/s5h1432.c
drivers/media/dvb-frontends/s5h1432.h
drivers/media/dvb-frontends/si2168.c
drivers/media/dvb-frontends/si2168_priv.h
drivers/media/dvb-frontends/stv0367.c
drivers/media/dvb-frontends/stv0367.h
drivers/media/dvb-frontends/stv0367_priv.h
drivers/media/dvb-frontends/stv0367_regs.h
drivers/media/dvb-frontends/stv0900.h
drivers/media/dvb-frontends/stv0900_core.c
drivers/media/dvb-frontends/stv0900_init.h
drivers/media/dvb-frontends/stv0900_priv.h
drivers/media/dvb-frontends/stv0900_reg.h
drivers/media/dvb-frontends/stv0900_sw.c
drivers/media/dvb-frontends/stv6110.c
drivers/media/dvb-frontends/stv6110.h
drivers/media/dvb-frontends/tda18271c2dd.c
drivers/media/dvb-frontends/tdhd1.h
drivers/media/dvb-frontends/tua6100.c
drivers/media/dvb-frontends/tua6100.h
drivers/media/dvb-frontends/zd1301_demod.c [new file with mode: 0644]
drivers/media/dvb-frontends/zd1301_demod.h [new file with mode: 0644]
drivers/media/dvb-frontends/zl10036.c
drivers/media/dvb-frontends/zl10036.h
drivers/media/dvb-frontends/zl10039.c
drivers/media/dvb-frontends/zl10353.c
drivers/media/dvb-frontends/zl10353.h
drivers/media/dvb-frontends/zl10353_priv.h
drivers/media/i2c/Kconfig
drivers/media/i2c/Makefile
drivers/media/i2c/adp1653.c
drivers/media/i2c/adv7170.c
drivers/media/i2c/adv7175.c
drivers/media/i2c/adv7180.c
drivers/media/i2c/adv7183.c
drivers/media/i2c/adv7183_regs.h
drivers/media/i2c/adv7604.c
drivers/media/i2c/ak881x.c
drivers/media/i2c/aptina-pll.c
drivers/media/i2c/aptina-pll.h
drivers/media/i2c/as3645a.c
drivers/media/i2c/bt819.c
drivers/media/i2c/bt856.c
drivers/media/i2c/cs5345.c
drivers/media/i2c/cs53l32a.c
drivers/media/i2c/cx25840/cx25840-audio.c
drivers/media/i2c/cx25840/cx25840-core.c
drivers/media/i2c/cx25840/cx25840-core.h
drivers/media/i2c/cx25840/cx25840-firmware.c
drivers/media/i2c/cx25840/cx25840-ir.c
drivers/media/i2c/cx25840/cx25840-vbi.c
drivers/media/i2c/et8ek8/Kconfig [new file with mode: 0644]
drivers/media/i2c/et8ek8/Makefile [new file with mode: 0644]
drivers/media/i2c/et8ek8/et8ek8_driver.c [new file with mode: 0644]
drivers/media/i2c/et8ek8/et8ek8_mode.c [new file with mode: 0644]
drivers/media/i2c/et8ek8/et8ek8_reg.h [new file with mode: 0644]
drivers/media/i2c/ir-kbd-i2c.c
drivers/media/i2c/ks0127.c
drivers/media/i2c/ks0127.h
drivers/media/i2c/m52790.c
drivers/media/i2c/m5mols/m5mols_core.c
drivers/media/i2c/ml86v7667.c
drivers/media/i2c/msp3400-driver.c
drivers/media/i2c/msp3400-kthreads.c
drivers/media/i2c/mt9m032.c
drivers/media/i2c/mt9p031.c
drivers/media/i2c/mt9v032.c
drivers/media/i2c/noon010pc30.c
drivers/media/i2c/ov2659.c
drivers/media/i2c/ov7640.c
drivers/media/i2c/ov9650.c
drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
drivers/media/i2c/s5k6a3.c
drivers/media/i2c/saa7110.c
drivers/media/i2c/saa7115.c
drivers/media/i2c/saa7127.c
drivers/media/i2c/saa717x.c
drivers/media/i2c/saa7185.c
drivers/media/i2c/soc_camera/ov9640.c
drivers/media/i2c/sony-btf-mpx.c
drivers/media/i2c/tc358743.c
drivers/media/i2c/tc358743_regs.h
drivers/media/i2c/tlv320aic23b.c
drivers/media/i2c/tvp514x.c
drivers/media/i2c/tvp514x_regs.h
drivers/media/i2c/tvp7002.c
drivers/media/i2c/tvp7002_reg.h
drivers/media/i2c/tw2804.c
drivers/media/i2c/tw9903.c
drivers/media/i2c/tw9906.c
drivers/media/i2c/uda1342.c
drivers/media/i2c/upd64031a.c
drivers/media/i2c/upd64083.c
drivers/media/i2c/vp27smpx.c
drivers/media/i2c/vpx3220.c
drivers/media/i2c/vs6624.c
drivers/media/i2c/vs6624_regs.h
drivers/media/i2c/wm8739.c
drivers/media/i2c/wm8775.c
drivers/media/media-device.c
drivers/media/media-devnode.c
drivers/media/media-entity.c
drivers/media/pci/b2c2/flexcop-pci.c
drivers/media/pci/bt8xx/bttv-input.c
drivers/media/pci/bt8xx/dst_ca.c
drivers/media/pci/bt8xx/dvb-bt8xx.c
drivers/media/pci/bt8xx/dvb-bt8xx.h
drivers/media/pci/cobalt/cobalt-cpld.c
drivers/media/pci/cx18/cx18-alsa-main.c
drivers/media/pci/cx18/cx18-alsa-mixer.c
drivers/media/pci/cx18/cx18-alsa-mixer.h
drivers/media/pci/cx18/cx18-alsa-pcm.c
drivers/media/pci/cx18/cx18-alsa-pcm.h
drivers/media/pci/cx18/cx18-alsa.h
drivers/media/pci/cx18/cx18-audio.c
drivers/media/pci/cx18/cx18-audio.h
drivers/media/pci/cx18/cx18-av-audio.c
drivers/media/pci/cx18/cx18-av-core.c
drivers/media/pci/cx18/cx18-av-core.h
drivers/media/pci/cx18/cx18-av-firmware.c
drivers/media/pci/cx18/cx18-av-vbi.c
drivers/media/pci/cx18/cx18-cards.c
drivers/media/pci/cx18/cx18-cards.h
drivers/media/pci/cx18/cx18-controls.c
drivers/media/pci/cx18/cx18-driver.c
drivers/media/pci/cx18/cx18-driver.h
drivers/media/pci/cx18/cx18-dvb.c
drivers/media/pci/cx18/cx18-dvb.h
drivers/media/pci/cx18/cx18-fileops.c
drivers/media/pci/cx18/cx18-fileops.h
drivers/media/pci/cx18/cx18-firmware.c
drivers/media/pci/cx18/cx18-firmware.h
drivers/media/pci/cx18/cx18-gpio.c
drivers/media/pci/cx18/cx18-gpio.h
drivers/media/pci/cx18/cx18-i2c.c
drivers/media/pci/cx18/cx18-i2c.h
drivers/media/pci/cx18/cx18-io.c
drivers/media/pci/cx18/cx18-io.h
drivers/media/pci/cx18/cx18-ioctl.c
drivers/media/pci/cx18/cx18-ioctl.h
drivers/media/pci/cx18/cx18-irq.c
drivers/media/pci/cx18/cx18-irq.h
drivers/media/pci/cx18/cx18-mailbox.c
drivers/media/pci/cx18/cx18-mailbox.h
drivers/media/pci/cx18/cx18-queue.c
drivers/media/pci/cx18/cx18-queue.h
drivers/media/pci/cx18/cx18-scb.c
drivers/media/pci/cx18/cx18-scb.h
drivers/media/pci/cx18/cx18-streams.c
drivers/media/pci/cx18/cx18-streams.h
drivers/media/pci/cx18/cx18-vbi.c
drivers/media/pci/cx18/cx18-vbi.h
drivers/media/pci/cx18/cx18-version.h
drivers/media/pci/cx18/cx18-video.c
drivers/media/pci/cx18/cx18-video.h
drivers/media/pci/cx18/cx23418.h
drivers/media/pci/cx23885/cx23885-dvb.c
drivers/media/pci/cx23885/cx23885-input.c
drivers/media/pci/cx25821/cx25821-alsa.c
drivers/media/pci/cx25821/cx25821-audio-upstream.c
drivers/media/pci/cx25821/cx25821-audio-upstream.h
drivers/media/pci/cx25821/cx25821-audio.h
drivers/media/pci/cx25821/cx25821-biffuncs.h
drivers/media/pci/cx25821/cx25821-cards.c
drivers/media/pci/cx25821/cx25821-core.c
drivers/media/pci/cx25821/cx25821-gpio.c
drivers/media/pci/cx25821/cx25821-i2c.c
drivers/media/pci/cx25821/cx25821-medusa-defines.h
drivers/media/pci/cx25821/cx25821-medusa-reg.h
drivers/media/pci/cx25821/cx25821-medusa-video.c
drivers/media/pci/cx25821/cx25821-medusa-video.h
drivers/media/pci/cx25821/cx25821-reg.h
drivers/media/pci/cx25821/cx25821-sram.h
drivers/media/pci/cx25821/cx25821-video-upstream.c
drivers/media/pci/cx25821/cx25821-video-upstream.h
drivers/media/pci/cx25821/cx25821-video.c
drivers/media/pci/cx25821/cx25821-video.h
drivers/media/pci/cx25821/cx25821.h
drivers/media/pci/cx88/cx88-input.c
drivers/media/pci/ddbridge/ddbridge-core.c
drivers/media/pci/ddbridge/ddbridge-regs.h
drivers/media/pci/ddbridge/ddbridge.h
drivers/media/pci/dm1105/Kconfig
drivers/media/pci/dm1105/dm1105.c
drivers/media/pci/ivtv/Kconfig
drivers/media/pci/ivtv/ivtv-alsa-main.c
drivers/media/pci/ivtv/ivtv-alsa-mixer.c
drivers/media/pci/ivtv/ivtv-alsa-mixer.h
drivers/media/pci/ivtv/ivtv-alsa-pcm.c
drivers/media/pci/ivtv/ivtv-alsa-pcm.h
drivers/media/pci/ivtv/ivtv-alsa.h
drivers/media/pci/ivtv/ivtv-driver.c
drivers/media/pci/ivtv/ivtv-driver.h
drivers/media/pci/ivtv/ivtv-ioctl.c
drivers/media/pci/ivtv/ivtv-mailbox.c
drivers/media/pci/ivtv/ivtvfb.c
drivers/media/pci/mantis/mantis_dvb.c
drivers/media/pci/mantis/mantis_input.c
drivers/media/pci/meye/meye.c
drivers/media/pci/meye/meye.h
drivers/media/pci/ngene/ngene-cards.c
drivers/media/pci/ngene/ngene-core.c
drivers/media/pci/ngene/ngene-dvb.c
drivers/media/pci/ngene/ngene-i2c.c
drivers/media/pci/ngene/ngene.h
drivers/media/pci/pluto2/pluto2.c
drivers/media/pci/pt1/pt1.c
drivers/media/pci/pt1/va1j5jf8007s.c
drivers/media/pci/pt1/va1j5jf8007s.h
drivers/media/pci/pt1/va1j5jf8007t.c
drivers/media/pci/pt1/va1j5jf8007t.h
drivers/media/pci/saa7134/saa7134-alsa.c
drivers/media/pci/saa7134/saa7134-cards.c
drivers/media/pci/saa7134/saa7134-core.c
drivers/media/pci/saa7134/saa7134-dvb.c
drivers/media/pci/saa7134/saa7134-empress.c
drivers/media/pci/saa7134/saa7134-i2c.c
drivers/media/pci/saa7134/saa7134-input.c
drivers/media/pci/saa7134/saa7134-ts.c
drivers/media/pci/saa7134/saa7134-tvaudio.c
drivers/media/pci/saa7134/saa7134-vbi.c
drivers/media/pci/saa7134/saa7134-video.c
drivers/media/pci/saa7134/saa7134.h
drivers/media/pci/saa7164/saa7164-api.c
drivers/media/pci/saa7164/saa7164-buffer.c
drivers/media/pci/saa7164/saa7164-bus.c
drivers/media/pci/saa7164/saa7164-cards.c
drivers/media/pci/saa7164/saa7164-cmd.c
drivers/media/pci/saa7164/saa7164-core.c
drivers/media/pci/saa7164/saa7164-dvb.c
drivers/media/pci/saa7164/saa7164-encoder.c
drivers/media/pci/saa7164/saa7164-fw.c
drivers/media/pci/saa7164/saa7164-i2c.c
drivers/media/pci/saa7164/saa7164-reg.h
drivers/media/pci/saa7164/saa7164-types.h
drivers/media/pci/saa7164/saa7164-vbi.c
drivers/media/pci/saa7164/saa7164.h
drivers/media/pci/smipcie/smipcie-ir.c
drivers/media/pci/solo6x10/solo6x10-g723.c
drivers/media/pci/sta2x11/sta2x11_vip.c
drivers/media/pci/sta2x11/sta2x11_vip.h
drivers/media/pci/ttpci/av7110.c
drivers/media/pci/ttpci/av7110_av.c
drivers/media/pci/ttpci/av7110_ca.c
drivers/media/pci/ttpci/av7110_hw.c
drivers/media/pci/ttpci/av7110_hw.h
drivers/media/pci/ttpci/av7110_ir.c
drivers/media/pci/ttpci/av7110_v4l.c
drivers/media/pci/ttpci/budget-av.c
drivers/media/pci/ttpci/budget-ci.c
drivers/media/pci/ttpci/budget-core.c
drivers/media/pci/ttpci/budget-patch.c
drivers/media/pci/ttpci/budget.c
drivers/media/pci/ttpci/dvb_filter.h
drivers/media/pci/tw686x/tw686x-core.c
drivers/media/pci/zoran/videocodec.c
drivers/media/pci/zoran/videocodec.h
drivers/media/pci/zoran/zoran.h
drivers/media/pci/zoran/zoran_card.c
drivers/media/pci/zoran/zoran_card.h
drivers/media/pci/zoran/zoran_device.c
drivers/media/pci/zoran/zoran_device.h
drivers/media/pci/zoran/zoran_driver.c
drivers/media/pci/zoran/zoran_procfs.c
drivers/media/pci/zoran/zoran_procfs.h
drivers/media/pci/zoran/zr36016.c
drivers/media/pci/zoran/zr36016.h
drivers/media/pci/zoran/zr36050.c
drivers/media/pci/zoran/zr36050.h
drivers/media/pci/zoran/zr36057.h
drivers/media/pci/zoran/zr36060.c
drivers/media/pci/zoran/zr36060.h
drivers/media/platform/Kconfig
drivers/media/platform/Makefile
drivers/media/platform/am437x/am437x-vpfe.c
drivers/media/platform/blackfin/bfin_capture.c
drivers/media/platform/blackfin/ppi.c
drivers/media/platform/coda/Makefile
drivers/media/platform/coda/coda-bit.c
drivers/media/platform/coda/coda-common.c
drivers/media/platform/coda/coda.h
drivers/media/platform/coda/imx-vdoa.c [new file with mode: 0644]
drivers/media/platform/coda/imx-vdoa.h [new file with mode: 0644]
drivers/media/platform/davinci/ccdc_hw_device.h
drivers/media/platform/davinci/dm355_ccdc.c
drivers/media/platform/davinci/dm355_ccdc_regs.h
drivers/media/platform/davinci/dm644x_ccdc.c
drivers/media/platform/davinci/dm644x_ccdc_regs.h
drivers/media/platform/davinci/isif.c
drivers/media/platform/davinci/isif_regs.h
drivers/media/platform/davinci/vpbe.c
drivers/media/platform/davinci/vpbe_osd.c
drivers/media/platform/davinci/vpbe_osd_regs.h
drivers/media/platform/davinci/vpbe_venc.c
drivers/media/platform/davinci/vpbe_venc_regs.h
drivers/media/platform/davinci/vpfe_capture.c
drivers/media/platform/davinci/vpif.c
drivers/media/platform/davinci/vpif_capture.c
drivers/media/platform/davinci/vpif_capture.h
drivers/media/platform/davinci/vpif_display.c
drivers/media/platform/davinci/vpss.c
drivers/media/platform/exynos-gsc/gsc-core.c
drivers/media/platform/exynos-gsc/gsc-m2m.c
drivers/media/platform/exynos4-is/fimc-capture.c
drivers/media/platform/exynos4-is/fimc-is-i2c.c
drivers/media/platform/exynos4-is/fimc-is.c
drivers/media/platform/exynos4-is/fimc-isp-video.c
drivers/media/platform/exynos4-is/fimc-lite.c
drivers/media/platform/exynos4-is/fimc-m2m.c
drivers/media/platform/exynos4-is/media-dev.c
drivers/media/platform/exynos4-is/media-dev.h
drivers/media/platform/exynos4-is/mipi-csis.c
drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
drivers/media/platform/mtk-vcodec/vdec_vpu_if.c
drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c
drivers/media/platform/mtk-vcodec/venc_vpu_if.c
drivers/media/platform/omap3isp/ispvideo.c
drivers/media/platform/rcar_fdp1.c
drivers/media/platform/s3c-camif/camif-capture.c
drivers/media/platform/soc_camera/soc_camera_platform.c
drivers/media/platform/sti/bdisp/bdisp-debug.c
drivers/media/platform/sti/delta/Makefile [new file with mode: 0644]
drivers/media/platform/sti/delta/delta-cfg.h [new file with mode: 0644]
drivers/media/platform/sti/delta/delta-debug.c [new file with mode: 0644]
drivers/media/platform/sti/delta/delta-debug.h [new file with mode: 0644]
drivers/media/platform/sti/delta/delta-ipc.c [new file with mode: 0644]
drivers/media/platform/sti/delta/delta-ipc.h [new file with mode: 0644]
drivers/media/platform/sti/delta/delta-mem.c [new file with mode: 0644]
drivers/media/platform/sti/delta/delta-mem.h [new file with mode: 0644]
drivers/media/platform/sti/delta/delta-mjpeg-dec.c [new file with mode: 0644]
drivers/media/platform/sti/delta/delta-mjpeg-fw.h [new file with mode: 0644]
drivers/media/platform/sti/delta/delta-mjpeg-hdr.c [new file with mode: 0644]
drivers/media/platform/sti/delta/delta-mjpeg.h [new file with mode: 0644]
drivers/media/platform/sti/delta/delta-v4l2.c [new file with mode: 0644]
drivers/media/platform/sti/delta/delta.h [new file with mode: 0644]
drivers/media/platform/sti/hva/Makefile
drivers/media/platform/sti/hva/hva-debugfs.c [new file with mode: 0644]
drivers/media/platform/sti/hva/hva-h264.c
drivers/media/platform/sti/hva/hva-hw.c
drivers/media/platform/sti/hva/hva-hw.h
drivers/media/platform/sti/hva/hva-mem.c
drivers/media/platform/sti/hva/hva-v4l2.c
drivers/media/platform/sti/hva/hva.h
drivers/media/platform/ti-vpe/vpdma.c
drivers/media/platform/vim2m.c
drivers/media/platform/vivid/vivid-vid-cap.c
drivers/media/platform/vsp1/vsp1_drm.c
drivers/media/platform/vsp1/vsp1_video.c
drivers/media/platform/xilinx/xilinx-dma.c
drivers/media/platform/xilinx/xilinx-tpg.c
drivers/media/radio/dsbr100.c
drivers/media/radio/radio-cadet.c
drivers/media/radio/radio-isa.c
drivers/media/radio/radio-isa.h
drivers/media/radio/radio-keene.c
drivers/media/radio/radio-ma901.c
drivers/media/radio/radio-mr800.c
drivers/media/radio/radio-shark.c
drivers/media/radio/radio-shark2.c
drivers/media/radio/radio-tea5764.c
drivers/media/radio/radio-tea5777.c
drivers/media/radio/radio-tea5777.h
drivers/media/radio/radio-timb.c
drivers/media/radio/radio-wl1273.c
drivers/media/radio/saa7706h.c
drivers/media/radio/si470x/radio-si470x-common.c
drivers/media/radio/si470x/radio-si470x-i2c.c
drivers/media/radio/si470x/radio-si470x-usb.c
drivers/media/radio/si470x/radio-si470x.h
drivers/media/radio/si4713/radio-platform-si4713.c
drivers/media/radio/si4713/si4713.c
drivers/media/radio/tef6862.c
drivers/media/radio/wl128x/fmdrv.h
drivers/media/radio/wl128x/fmdrv_common.c
drivers/media/radio/wl128x/fmdrv_common.h
drivers/media/radio/wl128x/fmdrv_rx.c
drivers/media/radio/wl128x/fmdrv_rx.h
drivers/media/radio/wl128x/fmdrv_tx.c
drivers/media/radio/wl128x/fmdrv_tx.h
drivers/media/radio/wl128x/fmdrv_v4l2.c
drivers/media/radio/wl128x/fmdrv_v4l2.h
drivers/media/rc/Kconfig
drivers/media/rc/Makefile
drivers/media/rc/ati_remote.c
drivers/media/rc/ene_ir.c
drivers/media/rc/ene_ir.h
drivers/media/rc/fintek-cir.c
drivers/media/rc/fintek-cir.h
drivers/media/rc/gpio-ir-recv.c
drivers/media/rc/igorplugusb.c
drivers/media/rc/iguanair.c
drivers/media/rc/img-ir/img-ir-hw.c
drivers/media/rc/img-ir/img-ir-nec.c
drivers/media/rc/img-ir/img-ir-raw.c
drivers/media/rc/img-ir/img-ir-sony.c
drivers/media/rc/imon.c
drivers/media/rc/ir-hix5hd2.c
drivers/media/rc/ir-jvc-decoder.c
drivers/media/rc/ir-lirc-codec.c
drivers/media/rc/ir-mce_kbd-decoder.c
drivers/media/rc/ir-nec-decoder.c
drivers/media/rc/ir-rc5-decoder.c
drivers/media/rc/ir-rc6-decoder.c
drivers/media/rc/ir-rx51.c
drivers/media/rc/ir-sanyo-decoder.c
drivers/media/rc/ir-sharp-decoder.c
drivers/media/rc/ir-sony-decoder.c
drivers/media/rc/ir-spi.c [new file with mode: 0644]
drivers/media/rc/ite-cir.c
drivers/media/rc/ite-cir.h
drivers/media/rc/keymaps/Makefile
drivers/media/rc/keymaps/rc-d680-dmb.c [new file with mode: 0644]
drivers/media/rc/keymaps/rc-dvico-mce.c [new file with mode: 0644]
drivers/media/rc/keymaps/rc-dvico-portable.c [new file with mode: 0644]
drivers/media/rc/keymaps/rc-geekbox.c [new file with mode: 0644]
drivers/media/rc/keymaps/rc-rc6-mce.c
drivers/media/rc/keymaps/rc-technisat-usb2.c
drivers/media/rc/keymaps/rc-tivo.c
drivers/media/rc/lirc_dev.c
drivers/media/rc/mceusb.c
drivers/media/rc/meson-ir.c
drivers/media/rc/mtk-cir.c [new file with mode: 0644]
drivers/media/rc/nuvoton-cir.c
drivers/media/rc/nuvoton-cir.h
drivers/media/rc/rc-core-priv.h
drivers/media/rc/rc-ir-raw.c
drivers/media/rc/rc-loopback.c
drivers/media/rc/rc-main.c
drivers/media/rc/redrat3.c
drivers/media/rc/serial_ir.c
drivers/media/rc/st_rc.c
drivers/media/rc/streamzap.c
drivers/media/rc/sunxi-cir.c
drivers/media/rc/ttusbir.c
drivers/media/rc/winbond-cir.c
drivers/media/tuners/fc0011.c
drivers/media/tuners/fc0012-priv.h
drivers/media/tuners/fc0012.c
drivers/media/tuners/fc0012.h
drivers/media/tuners/fc0013-priv.h
drivers/media/tuners/fc0013.c
drivers/media/tuners/fc0013.h
drivers/media/tuners/fc001x-common.h
drivers/media/tuners/it913x.c
drivers/media/tuners/it913x.h
drivers/media/tuners/max2165.c
drivers/media/tuners/max2165.h
drivers/media/tuners/max2165_priv.h
drivers/media/tuners/mc44s803.c
drivers/media/tuners/mc44s803.h
drivers/media/tuners/mc44s803_priv.h
drivers/media/tuners/mt2060.c
drivers/media/tuners/mt2060.h
drivers/media/tuners/mt2060_priv.h
drivers/media/tuners/mt2131.c
drivers/media/tuners/mt2131.h
drivers/media/tuners/mt2131_priv.h
drivers/media/tuners/mxl5007t.c
drivers/media/tuners/mxl5007t.h
drivers/media/tuners/qt1010.c
drivers/media/tuners/qt1010.h
drivers/media/tuners/qt1010_priv.h
drivers/media/tuners/tda18218.c
drivers/media/tuners/tda18218.h
drivers/media/tuners/tda18218_priv.h
drivers/media/tuners/tda827x.c
drivers/media/tuners/xc4000.c
drivers/media/tuners/xc4000.h
drivers/media/tuners/xc5000.c
drivers/media/tuners/xc5000.h
drivers/media/usb/au0828/au0828-cards.c
drivers/media/usb/au0828/au0828-cards.h
drivers/media/usb/au0828/au0828-core.c
drivers/media/usb/au0828/au0828-dvb.c
drivers/media/usb/au0828/au0828-i2c.c
drivers/media/usb/au0828/au0828-input.c
drivers/media/usb/au0828/au0828-reg.h
drivers/media/usb/au0828/au0828-video.c
drivers/media/usb/au0828/au0828.h
drivers/media/usb/cpia2/cpia2.h
drivers/media/usb/cpia2/cpia2_core.c
drivers/media/usb/cpia2/cpia2_registers.h
drivers/media/usb/cpia2/cpia2_usb.c
drivers/media/usb/cpia2/cpia2_v4l.c
drivers/media/usb/cx231xx/Kconfig
drivers/media/usb/cx231xx/cx231xx-417.c
drivers/media/usb/cx231xx/cx231xx-audio.c
drivers/media/usb/cx231xx/cx231xx-cards.c
drivers/media/usb/cx231xx/cx231xx-core.c
drivers/media/usb/cx231xx/cx231xx-dif.h
drivers/media/usb/cx231xx/cx231xx-dvb.c
drivers/media/usb/cx231xx/cx231xx-input.c
drivers/media/usb/cx231xx/cx231xx.h
drivers/media/usb/dvb-usb-v2/Kconfig
drivers/media/usb/dvb-usb-v2/Makefile
drivers/media/usb/dvb-usb-v2/af9015.c
drivers/media/usb/dvb-usb-v2/af9015.h
drivers/media/usb/dvb-usb-v2/af9035.c
drivers/media/usb/dvb-usb-v2/af9035.h
drivers/media/usb/dvb-usb-v2/anysee.c
drivers/media/usb/dvb-usb-v2/anysee.h
drivers/media/usb/dvb-usb-v2/au6610.c
drivers/media/usb/dvb-usb-v2/au6610.h
drivers/media/usb/dvb-usb-v2/ce6230.c
drivers/media/usb/dvb-usb-v2/ce6230.h
drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
drivers/media/usb/dvb-usb-v2/dvbsky.c
drivers/media/usb/dvb-usb-v2/ec168.c
drivers/media/usb/dvb-usb-v2/ec168.h
drivers/media/usb/dvb-usb-v2/lmedm04.c
drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c
drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h
drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c
drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h
drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c
drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h
drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c
drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h
drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h
drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c
drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h
drivers/media/usb/dvb-usb-v2/rtl28xxu.c
drivers/media/usb/dvb-usb-v2/zd1301.c [new file with mode: 0644]
drivers/media/usb/dvb-usb/af9005-fe.c
drivers/media/usb/dvb-usb/af9005-remote.c
drivers/media/usb/dvb-usb/af9005.c
drivers/media/usb/dvb-usb/af9005.h
drivers/media/usb/dvb-usb/cinergyT2-core.c
drivers/media/usb/dvb-usb/cinergyT2-fe.c
drivers/media/usb/dvb-usb/cinergyT2.h
drivers/media/usb/dvb-usb/cxusb.c
drivers/media/usb/dvb-usb/dib0700_devices.c
drivers/media/usb/dvb-usb/dtv5100.c
drivers/media/usb/dvb-usb/dtv5100.h
drivers/media/usb/dvb-usb/dvb-usb-firmware.c
drivers/media/usb/dvb-usb/dvb-usb-remote.c
drivers/media/usb/dvb-usb/gp8psk.c
drivers/media/usb/dvb-usb/technisat-usb2.c
drivers/media/usb/em28xx/em28xx-audio.c
drivers/media/usb/em28xx/em28xx-cards.c
drivers/media/usb/em28xx/em28xx-dvb.c
drivers/media/usb/em28xx/em28xx-input.c
drivers/media/usb/em28xx/em28xx.h
drivers/media/usb/gspca/autogain_functions.c
drivers/media/usb/gspca/benq.c
drivers/media/usb/gspca/conex.c
drivers/media/usb/gspca/cpia1.c
drivers/media/usb/gspca/etoms.c
drivers/media/usb/gspca/finepix.c
drivers/media/usb/gspca/gspca.c
drivers/media/usb/gspca/jeilinj.c
drivers/media/usb/gspca/jl2005bcd.c
drivers/media/usb/gspca/jpeg.h
drivers/media/usb/gspca/kinect.c
drivers/media/usb/gspca/konica.c
drivers/media/usb/gspca/mars.c
drivers/media/usb/gspca/mr97310a.c
drivers/media/usb/gspca/nw80x.c
drivers/media/usb/gspca/ov519.c
drivers/media/usb/gspca/ov534.c
drivers/media/usb/gspca/ov534_9.c
drivers/media/usb/gspca/pac207.c
drivers/media/usb/gspca/pac7302.c
drivers/media/usb/gspca/pac7311.c
drivers/media/usb/gspca/pac_common.h
drivers/media/usb/gspca/se401.c
drivers/media/usb/gspca/se401.h
drivers/media/usb/gspca/sn9c2028.c
drivers/media/usb/gspca/sn9c2028.h
drivers/media/usb/gspca/sn9c20x.c
drivers/media/usb/gspca/sonixb.c
drivers/media/usb/gspca/sonixj.c
drivers/media/usb/gspca/spca1528.c
drivers/media/usb/gspca/spca500.c
drivers/media/usb/gspca/spca501.c
drivers/media/usb/gspca/spca505.c
drivers/media/usb/gspca/spca506.c
drivers/media/usb/gspca/spca508.c
drivers/media/usb/gspca/spca561.c
drivers/media/usb/gspca/sq905.c
drivers/media/usb/gspca/sq905c.c
drivers/media/usb/gspca/sq930x.c
drivers/media/usb/gspca/stk014.c
drivers/media/usb/gspca/stk1135.c
drivers/media/usb/gspca/stk1135.h
drivers/media/usb/gspca/stv0680.c
drivers/media/usb/gspca/stv06xx/stv06xx.c
drivers/media/usb/gspca/stv06xx/stv06xx.h
drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.c
drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.h
drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c
drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.h
drivers/media/usb/gspca/stv06xx/stv06xx_sensor.h
drivers/media/usb/gspca/stv06xx/stv06xx_st6422.c
drivers/media/usb/gspca/stv06xx/stv06xx_st6422.h
drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c
drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.h
drivers/media/usb/gspca/sunplus.c
drivers/media/usb/gspca/t613.c
drivers/media/usb/gspca/tv8532.c
drivers/media/usb/gspca/vc032x.c
drivers/media/usb/gspca/vicam.c
drivers/media/usb/gspca/w996Xcf.c
drivers/media/usb/gspca/xirlink_cit.c
drivers/media/usb/gspca/zc3xx.c
drivers/media/usb/pvrusb2/pvrusb2-audio.c
drivers/media/usb/pvrusb2/pvrusb2-audio.h
drivers/media/usb/pvrusb2/pvrusb2-context.c
drivers/media/usb/pvrusb2/pvrusb2-context.h
drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c
drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.h
drivers/media/usb/pvrusb2/pvrusb2-ctrl.c
drivers/media/usb/pvrusb2/pvrusb2-ctrl.h
drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c
drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.h
drivers/media/usb/pvrusb2/pvrusb2-debug.h
drivers/media/usb/pvrusb2/pvrusb2-debugifc.c
drivers/media/usb/pvrusb2/pvrusb2-debugifc.h
drivers/media/usb/pvrusb2/pvrusb2-devattr.c
drivers/media/usb/pvrusb2/pvrusb2-devattr.h
drivers/media/usb/pvrusb2/pvrusb2-dvb.c
drivers/media/usb/pvrusb2/pvrusb2-eeprom.c
drivers/media/usb/pvrusb2/pvrusb2-eeprom.h
drivers/media/usb/pvrusb2/pvrusb2-encoder.c
drivers/media/usb/pvrusb2/pvrusb2-encoder.h
drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h
drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h
drivers/media/usb/pvrusb2/pvrusb2-hdw.c
drivers/media/usb/pvrusb2/pvrusb2-hdw.h
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c
drivers/media/usb/pvrusb2/pvrusb2-i2c-core.h
drivers/media/usb/pvrusb2/pvrusb2-io.c
drivers/media/usb/pvrusb2/pvrusb2-io.h
drivers/media/usb/pvrusb2/pvrusb2-ioread.c
drivers/media/usb/pvrusb2/pvrusb2-ioread.h
drivers/media/usb/pvrusb2/pvrusb2-main.c
drivers/media/usb/pvrusb2/pvrusb2-std.c
drivers/media/usb/pvrusb2/pvrusb2-std.h
drivers/media/usb/pvrusb2/pvrusb2-sysfs.c
drivers/media/usb/pvrusb2/pvrusb2-sysfs.h
drivers/media/usb/pvrusb2/pvrusb2-util.h
drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
drivers/media/usb/pvrusb2/pvrusb2-v4l2.h
drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c
drivers/media/usb/pvrusb2/pvrusb2-video-v4l.h
drivers/media/usb/pvrusb2/pvrusb2-wm8775.c
drivers/media/usb/pvrusb2/pvrusb2-wm8775.h
drivers/media/usb/pvrusb2/pvrusb2.h
drivers/media/usb/s2255/s2255drv.c
drivers/media/usb/stk1160/Kconfig
drivers/media/usb/stk1160/Makefile
drivers/media/usb/stk1160/stk1160-ac97.c
drivers/media/usb/stk1160/stk1160-core.c
drivers/media/usb/stk1160/stk1160-reg.h
drivers/media/usb/stk1160/stk1160.h
drivers/media/usb/stkwebcam/stk-sensor.c
drivers/media/usb/stkwebcam/stk-webcam.c
drivers/media/usb/stkwebcam/stk-webcam.h
drivers/media/usb/tm6000/tm6000-cards.c
drivers/media/usb/tm6000/tm6000-core.c
drivers/media/usb/tm6000/tm6000-dvb.c
drivers/media/usb/tm6000/tm6000-i2c.c
drivers/media/usb/tm6000/tm6000-input.c
drivers/media/usb/tm6000/tm6000-regs.h
drivers/media/usb/tm6000/tm6000-stds.c
drivers/media/usb/tm6000/tm6000-usb-isoc.h
drivers/media/usb/tm6000/tm6000-video.c
drivers/media/usb/tm6000/tm6000.h
drivers/media/usb/ttusb-dec/ttusb_dec.c
drivers/media/usb/ttusb-dec/ttusbdecfe.c
drivers/media/usb/ttusb-dec/ttusbdecfe.h
drivers/media/usb/usbtv/usbtv-video.c
drivers/media/usb/usbvision/usbvision-cards.c
drivers/media/usb/usbvision/usbvision-core.c
drivers/media/usb/usbvision/usbvision-i2c.c
drivers/media/usb/usbvision/usbvision-video.c
drivers/media/usb/usbvision/usbvision.h
drivers/media/usb/uvc/uvc_debugfs.c
drivers/media/usb/uvc/uvc_queue.c
drivers/media/usb/uvc/uvc_video.c
drivers/media/usb/uvc/uvcvideo.h
drivers/media/usb/zr364xx/zr364xx.c
drivers/media/v4l2-core/v4l2-async.c
drivers/media/v4l2-core/v4l2-ctrls.c
drivers/media/v4l2-core/v4l2-device.c
drivers/media/v4l2-core/v4l2-event.c
drivers/media/v4l2-core/v4l2-fh.c
drivers/media/v4l2-core/v4l2-mc.c
drivers/media/v4l2-core/v4l2-of.c
drivers/media/v4l2-core/v4l2-subdev.c
drivers/memstick/core/ms_block.c
drivers/memstick/core/mspro_block.c
drivers/message/fusion/mptfc.c
drivers/message/fusion/mptlan.h
drivers/message/fusion/mptsas.c
drivers/mmc/core/Kconfig
drivers/mmc/core/Makefile
drivers/mmc/core/block.c
drivers/mmc/core/block.h
drivers/mmc/core/bus.c
drivers/mmc/core/bus.h
drivers/mmc/core/card.h [new file with mode: 0644]
drivers/mmc/core/core.c
drivers/mmc/core/core.h
drivers/mmc/core/debugfs.c
drivers/mmc/core/host.c
drivers/mmc/core/host.h
drivers/mmc/core/mmc.c
drivers/mmc/core/mmc_ops.c
drivers/mmc/core/mmc_ops.h
drivers/mmc/core/mmc_test.c
drivers/mmc/core/pwrseq.h
drivers/mmc/core/pwrseq_sd8787.c [new file with mode: 0644]
drivers/mmc/core/queue.c
drivers/mmc/core/queue.h
drivers/mmc/core/quirks.c [deleted file]
drivers/mmc/core/quirks.h [new file with mode: 0644]
drivers/mmc/core/sd.c
drivers/mmc/core/sd.h
drivers/mmc/core/sd_ops.c
drivers/mmc/core/sd_ops.h
drivers/mmc/core/sdio.c
drivers/mmc/core/sdio_bus.c
drivers/mmc/core/sdio_bus.h
drivers/mmc/core/sdio_cis.h
drivers/mmc/core/sdio_io.c
drivers/mmc/core/sdio_irq.c
drivers/mmc/core/sdio_ops.c
drivers/mmc/core/sdio_ops.h
drivers/mmc/core/slot-gpio.c
drivers/mmc/core/slot-gpio.h
drivers/mmc/host/Kconfig
drivers/mmc/host/Makefile
drivers/mmc/host/davinci_mmc.c
drivers/mmc/host/dw_mmc-exynos.c
drivers/mmc/host/dw_mmc-k3.c
drivers/mmc/host/dw_mmc-pci.c
drivers/mmc/host/dw_mmc-pltfm.c
drivers/mmc/host/dw_mmc-rockchip.c
drivers/mmc/host/dw_mmc-zx.c [new file with mode: 0644]
drivers/mmc/host/dw_mmc-zx.h [new file with mode: 0644]
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/dw_mmc.h
drivers/mmc/host/meson-gx-mmc.c
drivers/mmc/host/mmci.c
drivers/mmc/host/mmci.h
drivers/mmc/host/mtk-sd.c
drivers/mmc/host/mxs-mmc.c
drivers/mmc/host/omap.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/rtsx_pci_sdmmc.c
drivers/mmc/host/rtsx_usb_sdmmc.c
drivers/mmc/host/s3cmci.c
drivers/mmc/host/sdhci-acpi.c
drivers/mmc/host/sdhci-cadence.c
drivers/mmc/host/sdhci-esdhc.h
drivers/mmc/host/sdhci-iproc.c
drivers/mmc/host/sdhci-msm.c
drivers/mmc/host/sdhci-of-esdhc.c
drivers/mmc/host/sdhci-pci-core.c
drivers/mmc/host/sdhci-pci.h
drivers/mmc/host/sdhci-s3c-regs.h [deleted file]
drivers/mmc/host/sdhci-s3c.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mmc/host/sh_mmcif.c
drivers/mmc/host/sh_mobile_sdhi.c
drivers/mmc/host/sunxi-mmc.c
drivers/mmc/host/tmio_mmc.h
drivers/mmc/host/tmio_mmc_pio.c
drivers/mmc/host/via-sdmmc.c
drivers/mmc/host/vub300.c
drivers/mmc/host/wbsd.c
drivers/mmc/host/wmt-sdmmc.c
drivers/mtd/mtd_blkdevs.c
drivers/mtd/ubi/block.c
drivers/net/xen-netback/netback.c
drivers/net/xen-netback/xenbus.c
drivers/net/xen-netfront.c
drivers/nvme/host/core.c
drivers/nvme/host/fc.c
drivers/nvme/host/lightnvm.c
drivers/nvme/host/nvme.h
drivers/nvme/host/pci.c
drivers/nvme/host/rdma.c
drivers/nvme/host/scsi.c
drivers/nvme/target/loop.c
drivers/of/base.c
drivers/of/fdt.c
drivers/pinctrl/Kconfig
drivers/pinctrl/Makefile
drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c
drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
drivers/pinctrl/aspeed/pinctrl-aspeed.c
drivers/pinctrl/aspeed/pinctrl-aspeed.h
drivers/pinctrl/bcm/pinctrl-bcm281xx.c
drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
drivers/pinctrl/bcm/pinctrl-ns2-mux.c
drivers/pinctrl/bcm/pinctrl-nsp-gpio.c
drivers/pinctrl/berlin/berlin-bg2.c
drivers/pinctrl/berlin/berlin-bg2cd.c
drivers/pinctrl/berlin/berlin-bg2q.c
drivers/pinctrl/berlin/berlin-bg4ct.c
drivers/pinctrl/core.c
drivers/pinctrl/core.h
drivers/pinctrl/devicetree.c
drivers/pinctrl/devicetree.h
drivers/pinctrl/freescale/Kconfig
drivers/pinctrl/freescale/pinctrl-imx.c
drivers/pinctrl/freescale/pinctrl-imx.h
drivers/pinctrl/intel/Kconfig
drivers/pinctrl/intel/Makefile
drivers/pinctrl/intel/pinctrl-baytrail.c
drivers/pinctrl/intel/pinctrl-broxton.c
drivers/pinctrl/intel/pinctrl-cherryview.c
drivers/pinctrl/intel/pinctrl-geminilake.c [new file with mode: 0644]
drivers/pinctrl/intel/pinctrl-intel.c
drivers/pinctrl/intel/pinctrl-intel.h
drivers/pinctrl/intel/pinctrl-sunrisepoint.c
drivers/pinctrl/mediatek/Kconfig
drivers/pinctrl/mediatek/pinctrl-mt7623.c
drivers/pinctrl/mediatek/pinctrl-mtk-common.c
drivers/pinctrl/mediatek/pinctrl-mtk-mt7623.h
drivers/pinctrl/meson/pinctrl-meson-gxbb.c
drivers/pinctrl/meson/pinctrl-meson-gxl.c
drivers/pinctrl/meson/pinctrl-meson.c
drivers/pinctrl/mvebu/pinctrl-armada-370.c
drivers/pinctrl/mvebu/pinctrl-armada-375.c
drivers/pinctrl/mvebu/pinctrl-armada-38x.c
drivers/pinctrl/mvebu/pinctrl-armada-39x.c
drivers/pinctrl/mvebu/pinctrl-armada-xp.c
drivers/pinctrl/mvebu/pinctrl-dove.c
drivers/pinctrl/mvebu/pinctrl-kirkwood.c
drivers/pinctrl/mvebu/pinctrl-mvebu.c
drivers/pinctrl/mvebu/pinctrl-mvebu.h
drivers/pinctrl/mvebu/pinctrl-orion.c
drivers/pinctrl/pinconf.c
drivers/pinctrl/pinconf.h
drivers/pinctrl/pinctrl-amd.c
drivers/pinctrl/pinctrl-amd.h
drivers/pinctrl/pinctrl-da850-pupd.c
drivers/pinctrl/pinctrl-falcon.c
drivers/pinctrl/pinctrl-lantiq.c
drivers/pinctrl/pinctrl-lantiq.h
drivers/pinctrl/pinctrl-lpc18xx.c
drivers/pinctrl/pinctrl-max77620.c
drivers/pinctrl/pinctrl-palmas.c
drivers/pinctrl/pinctrl-rockchip.c
drivers/pinctrl/pinctrl-single.c
drivers/pinctrl/pinctrl-sx150x.c
drivers/pinctrl/pinctrl-xway.c
drivers/pinctrl/pinmux.c
drivers/pinctrl/pinmux.h
drivers/pinctrl/qcom/pinctrl-msm.c
drivers/pinctrl/qcom/pinctrl-msm8660.c
drivers/pinctrl/samsung/pinctrl-exynos.c
drivers/pinctrl/samsung/pinctrl-s3c64xx.c
drivers/pinctrl/samsung/pinctrl-samsung.c
drivers/pinctrl/samsung/pinctrl-samsung.h
drivers/pinctrl/sh-pfc/pfc-r8a7791.c
drivers/pinctrl/sh-pfc/pfc-r8a7795.c
drivers/pinctrl/sh-pfc/pfc-r8a7796.c
drivers/pinctrl/sh-pfc/pinctrl.c
drivers/pinctrl/sirf/pinctrl-atlas7.c
drivers/pinctrl/spear/pinctrl-plgpio.c
drivers/pinctrl/spear/pinctrl-spear1310.c
drivers/pinctrl/spear/pinctrl-spear1340.c
drivers/pinctrl/spear/pinctrl-spear300.c
drivers/pinctrl/spear/pinctrl-spear310.c
drivers/pinctrl/spear/pinctrl-spear320.c
drivers/pinctrl/stm32/Kconfig
drivers/pinctrl/stm32/Makefile
drivers/pinctrl/stm32/pinctrl-stm32.c
drivers/pinctrl/stm32/pinctrl-stm32h743.c [new file with mode: 0644]
drivers/pinctrl/sunxi/Kconfig
drivers/pinctrl/sunxi/Makefile
drivers/pinctrl/sunxi/pinctrl-gr8.c [deleted file]
drivers/pinctrl/sunxi/pinctrl-sun50i-h5.c [new file with mode: 0644]
drivers/pinctrl/sunxi/pinctrl-sun5i-a10s.c [deleted file]
drivers/pinctrl/sunxi/pinctrl-sun5i-a13.c [deleted file]
drivers/pinctrl/sunxi/pinctrl-sun5i.c [new file with mode: 0644]
drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c
drivers/pinctrl/sunxi/pinctrl-sun6i-a31s.c [deleted file]
drivers/pinctrl/sunxi/pinctrl-sun8i-v3s.c [new file with mode: 0644]
drivers/pinctrl/sunxi/pinctrl-sunxi.c
drivers/pinctrl/sunxi/pinctrl-sunxi.h
drivers/pinctrl/ti/Kconfig [new file with mode: 0644]
drivers/pinctrl/ti/Makefile [new file with mode: 0644]
drivers/pinctrl/ti/pinctrl-ti-iodelay.c [new file with mode: 0644]
drivers/pinctrl/uniphier/pinctrl-uniphier-core.c
drivers/pinctrl/vt8500/pinctrl-wmt.c
drivers/regulator/88pm800.c
drivers/regulator/88pm8607.c
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/aat2870-regulator.c
drivers/regulator/act8945a-regulator.c
drivers/regulator/ad5398.c
drivers/regulator/anatop-regulator.c
drivers/regulator/arizona-ldo1.c
drivers/regulator/arizona-micsupp.c
drivers/regulator/as3711-regulator.c
drivers/regulator/axp20x-regulator.c
drivers/regulator/bcm590xx-regulator.c
drivers/regulator/core.c
drivers/regulator/cpcap-regulator.c [new file with mode: 0644]
drivers/regulator/devres.c
drivers/regulator/fan53555.c
drivers/regulator/hi655x-regulator.c
drivers/regulator/internal.h
drivers/regulator/lp8755.c
drivers/regulator/ltc3589.c
drivers/regulator/ltc3676.c
drivers/regulator/max14577-regulator.c
drivers/regulator/max77620-regulator.c
drivers/regulator/max77686-regulator.c
drivers/regulator/max77693-regulator.c
drivers/regulator/max77802-regulator.c
drivers/regulator/max8907-regulator.c
drivers/regulator/max8925-regulator.c
drivers/regulator/max8952.c
drivers/regulator/palmas-regulator.c
drivers/regulator/pbias-regulator.c
drivers/regulator/pcap-regulator.c
drivers/regulator/pcf50633-regulator.c
drivers/regulator/pfuze100-regulator.c
drivers/regulator/pv88060-regulator.c
drivers/regulator/pv88080-regulator.c
drivers/regulator/pv88090-regulator.c
drivers/regulator/qcom_smd-regulator.c
drivers/regulator/rc5t583-regulator.c
drivers/regulator/rn5t618-regulator.c
drivers/regulator/s2mpa01.c
drivers/regulator/tps65086-regulator.c
drivers/regulator/tps65217-regulator.c
drivers/rtc/rtc-omap.c
drivers/s390/block/scm_blk.c
drivers/s390/scsi/zfcp_scsi.c
drivers/scsi/Kconfig
drivers/scsi/NCR5380.c
drivers/scsi/NCR5380.h
drivers/scsi/aacraid/aachba.c
drivers/scsi/aacraid/aacraid.h
drivers/scsi/aacraid/commctrl.c
drivers/scsi/aacraid/comminit.c
drivers/scsi/aacraid/commsup.c
drivers/scsi/aacraid/dpcsup.c
drivers/scsi/aacraid/linit.c
drivers/scsi/aacraid/nark.c
drivers/scsi/aacraid/rkt.c
drivers/scsi/aacraid/rx.c
drivers/scsi/aacraid/sa.c
drivers/scsi/aacraid/src.c
drivers/scsi/atari_scsi.c
drivers/scsi/be2iscsi/be.h
drivers/scsi/be2iscsi/be_cmds.c
drivers/scsi/be2iscsi/be_cmds.h
drivers/scsi/be2iscsi/be_iscsi.c
drivers/scsi/be2iscsi/be_main.c
drivers/scsi/be2iscsi/be_main.h
drivers/scsi/be2iscsi/be_mgmt.c
drivers/scsi/be2iscsi/be_mgmt.h
drivers/scsi/bfa/bfa_fcs.c
drivers/scsi/bfa/bfa_fcs.h
drivers/scsi/bfa/bfad_im.c
drivers/scsi/bnx2fc/bnx2fc_fcoe.c
drivers/scsi/bnx2i/bnx2i_iscsi.c
drivers/scsi/csiostor/csio_scsi.c
drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
drivers/scsi/cxlflash/common.h
drivers/scsi/cxlflash/lunmgt.c
drivers/scsi/cxlflash/main.c
drivers/scsi/cxlflash/sislite.h
drivers/scsi/cxlflash/superpipe.c
drivers/scsi/cxlflash/vlun.c
drivers/scsi/device_handler/scsi_dh_emc.c
drivers/scsi/device_handler/scsi_dh_hp_sw.c
drivers/scsi/device_handler/scsi_dh_rdac.c
drivers/scsi/dpt_i2o.c
drivers/scsi/esas2r/esas2r_init.c
drivers/scsi/esas2r/esas2r_ioctl.c
drivers/scsi/esas2r/esas2r_log.h
drivers/scsi/esas2r/esas2r_main.c
drivers/scsi/fcoe/fcoe.c
drivers/scsi/fnic/fnic_main.c
drivers/scsi/g_NCR5380.c
drivers/scsi/g_NCR5380.h [deleted file]
drivers/scsi/hisi_sas/hisi_sas.h
drivers/scsi/hisi_sas/hisi_sas_main.c
drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
drivers/scsi/hosts.c
drivers/scsi/hpsa.c
drivers/scsi/hpsa.h
drivers/scsi/ibmvscsi/ibmvfc.c
drivers/scsi/ibmvscsi/ibmvscsi.c
drivers/scsi/iscsi_tcp.c
drivers/scsi/libfc/fc_lport.c
drivers/scsi/libiscsi.c
drivers/scsi/libsas/sas_expander.c
drivers/scsi/libsas/sas_host_smp.c
drivers/scsi/libsas/sas_init.c
drivers/scsi/libsas/sas_internal.h
drivers/scsi/libsas/sas_scsi_host.c
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_crtn.h
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hw.h
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/lpfc/lpfc_version.h
drivers/scsi/lpfc/lpfc_vport.c
drivers/scsi/mac_scsi.c
drivers/scsi/megaraid/megaraid_sas.h
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/megaraid/megaraid_sas_fp.c
drivers/scsi/megaraid/megaraid_sas_fusion.c
drivers/scsi/megaraid/megaraid_sas_fusion.h
drivers/scsi/mpt3sas/mpi/mpi2_ioc.h
drivers/scsi/mpt3sas/mpt3sas_base.c
drivers/scsi/mpt3sas/mpt3sas_base.h
drivers/scsi/mpt3sas/mpt3sas_ctl.c
drivers/scsi/mpt3sas/mpt3sas_scsih.c
drivers/scsi/mpt3sas/mpt3sas_transport.c
drivers/scsi/mvumi.c
drivers/scsi/osd/osd_initiator.c
drivers/scsi/osst.c
drivers/scsi/pm8001/pm8001_init.c
drivers/scsi/pm8001/pm8001_sas.h
drivers/scsi/pmcraid.c
drivers/scsi/pmcraid.h
drivers/scsi/qedi/qedi_dbg.c
drivers/scsi/qedi/qedi_iscsi.c
drivers/scsi/qla2xxx/qla_bsg.c
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_gs.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_mr.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla4xxx/ql4_def.h
drivers/scsi/qla4xxx/ql4_os.c
drivers/scsi/scsi.c
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_error.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_priv.h
drivers/scsi/scsi_transport_fc.c
drivers/scsi/scsi_transport_iscsi.c
drivers/scsi/scsi_transport_sas.c
drivers/scsi/scsi_transport_srp.c
drivers/scsi/sd.c
drivers/scsi/sg.c
drivers/scsi/smartpqi/smartpqi_init.c
drivers/scsi/snic/snic.h
drivers/scsi/snic/snic_isr.c
drivers/scsi/sr.c
drivers/scsi/st.c
drivers/scsi/storvsc_drv.c
drivers/scsi/sun3_scsi.c
drivers/scsi/sun3_scsi.h [deleted file]
drivers/scsi/ufs/ufs-qcom.c
drivers/scsi/ufs/ufs-qcom.h
drivers/scsi/ufs/ufs.h
drivers/scsi/ufs/ufs_quirks.h
drivers/scsi/ufs/ufshcd.c
drivers/scsi/ufs/ufshcd.h
drivers/scsi/ufs/ufshci.h
drivers/scsi/vmw_pvscsi.c
drivers/scsi/vmw_pvscsi.h
drivers/soc/samsung/exynos-pmu.c
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/spi-armada-3700.c
drivers/spi/spi-ath79.c
drivers/spi/spi-bcm-qspi.c
drivers/spi/spi-bcm53xx.c
drivers/spi/spi-dw.c
drivers/spi/spi-dw.h
drivers/spi/spi-ep93xx.c
drivers/spi/spi-fsl-lpspi.c
drivers/spi/spi-fsl-spi.c
drivers/spi/spi-imx.c
drivers/spi/spi-lantiq-ssc.c [new file with mode: 0644]
drivers/spi/spi-mpc52xx.c
drivers/spi/spi-mt65xx.c
drivers/spi/spi-ppc4xx.c
drivers/spi/spi-pxa2xx-pci.c
drivers/spi/spi-pxa2xx.c
drivers/spi/spi-rockchip.c
drivers/spi/spi-rspi.c
drivers/spi/spi-s3c64xx.c
drivers/spi/spi-sh-msiof.c
drivers/spi/spi-ti-qspi.c
drivers/spi/spi-topcliff-pch.c
drivers/spi/spi.c
drivers/staging/greybus/gpio.c
drivers/staging/media/davinci_vpfe/vpfe_video.c
drivers/staging/media/davinci_vpfe/vpfe_video.h
drivers/staging/media/lirc/Kconfig
drivers/staging/media/lirc/Makefile
drivers/staging/media/lirc/lirc_bt829.c [deleted file]
drivers/staging/media/lirc/lirc_imon.c [deleted file]
drivers/staging/media/lirc/lirc_parallel.c [deleted file]
drivers/staging/media/lirc/lirc_parallel.h [deleted file]
drivers/staging/media/lirc/lirc_sir.c
drivers/staging/media/omap4iss/iss_video.c
drivers/staging/media/s5p-cec/Kconfig
drivers/staging/media/s5p-cec/exynos_hdmi_cec.h
drivers/staging/media/s5p-cec/exynos_hdmi_cecctrl.c
drivers/target/Kconfig
drivers/target/target_core_pscsi.c
drivers/thermal/cpu_cooling.c
drivers/thermal/devfreq_cooling.c
drivers/usb/serial/cp210x.c
drivers/xen/cpu_hotplug.c
drivers/xen/events/events_base.c
drivers/xen/grant-table.c
drivers/xen/manage.c
drivers/xen/privcmd.c
drivers/xen/xen-balloon.c
drivers/xen/xen-pciback/xenbus.c
drivers/xen/xenbus/xenbus.h [new file with mode: 0644]
drivers/xen/xenbus/xenbus_client.c
drivers/xen/xenbus/xenbus_comms.c
drivers/xen/xenbus/xenbus_comms.h [deleted file]
drivers/xen/xenbus/xenbus_dev_backend.c
drivers/xen/xenbus/xenbus_dev_frontend.c
drivers/xen/xenbus/xenbus_probe.c
drivers/xen/xenbus/xenbus_probe.h [deleted file]
drivers/xen/xenbus/xenbus_probe_backend.c
drivers/xen/xenbus/xenbus_probe_frontend.c
drivers/xen/xenbus/xenbus_xs.c
drivers/xen/xenfs/super.c
drivers/xen/xenfs/xenstored.c
fs/block_dev.c
fs/btrfs/disk-io.c
fs/btrfs/volumes.c
fs/cifs/Kconfig
fs/cifs/cifsencrypt.c
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/file.c
fs/cifs/sess.c
fs/cifs/smb1ops.c
fs/cifs/smb2glob.h
fs/cifs/smb2maperror.c
fs/cifs/smb2misc.c
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c
fs/cifs/smb2pdu.h
fs/cifs/smb2proto.h
fs/cifs/smb2transport.c
fs/cifs/transport.c
fs/crypto/Kconfig
fs/crypto/Makefile
fs/crypto/bio.c [new file with mode: 0644]
fs/crypto/crypto.c
fs/crypto/fname.c
fs/crypto/fscrypt_private.h
fs/crypto/keyinfo.c
fs/crypto/policy.c
fs/dax.c
fs/debugfs/inode.c
fs/ext4/ext4.h
fs/ext4/ext4_jbd2.c
fs/ext4/extents.c
fs/ext4/file.c
fs/ext4/fsync.c
fs/ext4/hash.c
fs/ext4/ialloc.c
fs/ext4/inline.c
fs/ext4/inode.c
fs/ext4/ioctl.c
fs/ext4/mballoc.c
fs/ext4/namei.c
fs/ext4/page-io.c
fs/ext4/resize.c
fs/ext4/super.c
fs/ext4/xattr.c
fs/ext4/xattr.h
fs/f2fs/dir.c
fs/f2fs/f2fs.h
fs/f2fs/namei.c
fs/f2fs/super.c
fs/gfs2/aops.c
fs/gfs2/bmap.c
fs/gfs2/glock.c
fs/gfs2/incore.h
fs/gfs2/log.c
fs/gfs2/meta_io.c
fs/gfs2/ops_fstype.c
fs/gfs2/trans.c
fs/jbd2/journal.c
fs/jbd2/transaction.c
fs/nfsd/Kconfig
fs/nfsd/blocklayout.c
fs/nilfs2/super.c
fs/notify/fanotify/fanotify.c
fs/proc/base.c
fs/super.c
fs/ubifs/crypto.c
fs/ubifs/super.c
fs/ubifs/ubifs.h
fs/udf/ecma_167.h
fs/udf/file.c
fs/udf/inode.c
fs/udf/lowlevel.c
fs/udf/misc.c
fs/udf/namei.c
fs/udf/osta_udf.h
fs/udf/super.c
fs/udf/symlink.c
fs/udf/udfdecl.h
fs/xfs/xfs_buf.c
fs/xfs/xfs_buf.h
include/acpi/acbuffer.h
include/acpi/acconfig.h
include/acpi/acexcep.h
include/acpi/acnames.h
include/acpi/acoutput.h
include/acpi/acpi.h
include/acpi/acpi_bus.h
include/acpi/acpiosxf.h
include/acpi/acpixf.h
include/acpi/acrestyp.h
include/acpi/actbl.h
include/acpi/actbl1.h
include/acpi/actbl2.h
include/acpi/actbl3.h
include/acpi/actypes.h
include/acpi/acuuid.h
include/acpi/platform/acenv.h
include/acpi/platform/acenvex.h
include/acpi/platform/acgcc.h
include/acpi/platform/acgccex.h
include/acpi/platform/acintel.h [new file with mode: 0644]
include/acpi/platform/aclinux.h
include/acpi/platform/aclinuxex.h
include/dt-bindings/pinctrl/stm32h7-pinfunc.h [new file with mode: 0644]
include/linux/acpi.h
include/linux/async_tx.h
include/linux/audit.h
include/linux/backing-dev-defs.h
include/linux/backing-dev.h
include/linux/blk-mq.h
include/linux/blk_types.h
include/linux/blkdev.h
include/linux/blktrace_api.h
include/linux/bsg-lib.h
include/linux/cdrom.h
include/linux/cpufreq.h
include/linux/cryptohash.h
include/linux/debugfs.h
include/linux/devfreq.h
include/linux/device-mapper.h
include/linux/dma/dw.h
include/linux/dmaengine.h
include/linux/elevator.h
include/linux/fs.h
include/linux/fscrypt_common.h [new file with mode: 0644]
include/linux/fscrypt_notsupp.h [new file with mode: 0644]
include/linux/fscrypt_supp.h [new file with mode: 0644]
include/linux/fscrypto.h [deleted file]
include/linux/genhd.h
include/linux/gpio/driver.h
include/linux/hid.h
include/linux/hiddev.h
include/linux/i2c.h
include/linux/i2c/i2c-hid.h
include/linux/ide.h
include/linux/leds.h
include/linux/libata.h
include/linux/lightnvm.h
include/linux/lsm_hooks.h
include/linux/mfd/tmio.h
include/linux/mmc/boot.h [deleted file]
include/linux/mmc/card.h
include/linux/mmc/core.h
include/linux/mmc/dw_mmc.h [deleted file]
include/linux/mmc/host.h
include/linux/mmc/mmc.h
include/linux/mmc/sdio_ids.h
include/linux/mmc/sh_mmcif.h
include/linux/mmc/slot-gpio.h
include/linux/module.h
include/linux/nvme.h
include/linux/pinctrl/consumer.h
include/linux/pinctrl/pinconf-generic.h
include/linux/pinctrl/pinctrl.h
include/linux/platform_data/dma-dw.h
include/linux/platform_data/media/ir-rx51.h
include/linux/platform_data/mmc-mxcmmc.h
include/linux/platform_data/spi-ep93xx.h
include/linux/pm_domain.h
include/linux/pm_opp.h
include/linux/pm_qos.h
include/linux/property.h
include/linux/pxa2xx_ssp.h
include/linux/regmap.h
include/linux/sbitmap.h
include/linux/security.h
include/linux/sed-opal.h [new file with mode: 0644]
include/linux/soc/samsung/exynos-pmu.h
include/media/blackfin/ppi.h
include/media/davinci/ccdc_types.h
include/media/davinci/dm355_ccdc.h
include/media/davinci/dm644x_ccdc.h
include/media/davinci/isif.h
include/media/davinci/vpbe.h
include/media/davinci/vpbe_osd.h
include/media/davinci/vpbe_types.h
include/media/davinci/vpbe_venc.h
include/media/davinci/vpfe_capture.h
include/media/davinci/vpfe_types.h
include/media/davinci/vpif_types.h
include/media/davinci/vpss.h
include/media/drv-intf/tea575x.h
include/media/i2c/adp1653.h
include/media/i2c/adv7183.h
include/media/i2c/as3645a.h
include/media/i2c/lm3560.h
include/media/i2c/mt9m032.h
include/media/i2c/smiapp.h
include/media/i2c/ths7303.h
include/media/i2c/tvp514x.h
include/media/i2c/tvp7002.h
include/media/i2c/upd64031a.h
include/media/i2c/upd64083.h
include/media/media-device.h
include/media/media-devnode.h
include/media/media-entity.h
include/media/rc-core.h
include/media/rc-map.h
include/media/v4l2-event.h
include/media/v4l2-fh.h
include/media/v4l2-subdev.h
include/scsi/libiscsi.h
include/scsi/scsi.h
include/scsi/scsi_cmnd.h
include/scsi/scsi_host.h
include/scsi/scsi_request.h [new file with mode: 0644]
include/scsi/scsi_transport.h
include/scsi/scsi_transport_fc.h
include/scsi/scsi_transport_srp.h
include/trace/events/block.h
include/trace/events/ufs.h [new file with mode: 0644]
include/uapi/linux/audit.h
include/uapi/linux/input-event-codes.h
include/uapi/linux/lightnvm.h
include/uapi/linux/sed-opal.h [new file with mode: 0644]
include/uapi/scsi/cxlflash_ioctl.h
include/uapi/xen/privcmd.h
include/xen/arm/hypercall.h
include/xen/interface/elfnote.h
include/xen/interface/hvm/dm_op.h [new file with mode: 0644]
include/xen/interface/hvm/hvm_vcpu.h [new file with mode: 0644]
include/xen/interface/hvm/start_info.h [new file with mode: 0644]
include/xen/interface/xen.h
include/xen/xen.h
include/xen/xenbus.h
init/main.c
kernel/audit.c
kernel/audit.h
kernel/auditsc.c
kernel/exit.c
kernel/extable.c
kernel/module.c
kernel/power/suspend_test.c
kernel/power/swap.c
kernel/sched/core.c
kernel/seccomp.c
kernel/trace/blktrace.c
lib/Makefile
lib/halfmd4.c [deleted file]
lib/sbitmap.c
mm/backing-dev.c
mm/page-writeback.c
net/compat.c
samples/seccomp/bpf-helper.h
scripts/Kbuild.include
scripts/analyze_suspend.py
scripts/sign-file.c
security/apparmor/Kconfig
security/apparmor/Makefile
security/apparmor/apparmorfs.c
security/apparmor/audit.c
security/apparmor/capability.c
security/apparmor/context.c
security/apparmor/crypto.c
security/apparmor/domain.c
security/apparmor/file.c
security/apparmor/include/apparmor.h
security/apparmor/include/apparmorfs.h
security/apparmor/include/audit.h
security/apparmor/include/context.h
security/apparmor/include/crypto.h
security/apparmor/include/domain.h
security/apparmor/include/file.h
security/apparmor/include/lib.h [new file with mode: 0644]
security/apparmor/include/match.h
security/apparmor/include/path.h
security/apparmor/include/policy.h
security/apparmor/include/policy_ns.h [new file with mode: 0644]
security/apparmor/include/policy_unpack.h
security/apparmor/include/secid.h [new file with mode: 0644]
security/apparmor/include/sid.h [deleted file]
security/apparmor/ipc.c
security/apparmor/lib.c
security/apparmor/lsm.c
security/apparmor/match.c
security/apparmor/nulldfa.in [new file with mode: 0644]
security/apparmor/policy.c
security/apparmor/policy_ns.c [new file with mode: 0644]
security/apparmor/policy_unpack.c
security/apparmor/procattr.c
security/apparmor/resource.c
security/apparmor/secid.c [new file with mode: 0644]
security/apparmor/sid.c [deleted file]
security/commoncap.c
security/inode.c
security/integrity/ima/ima.h
security/integrity/ima/ima_api.c
security/integrity/ima/ima_main.c
security/keys/encrypted-keys/encrypted.c
security/loadpin/loadpin.c
security/security.c
security/selinux/hooks.c
security/selinux/include/classmap.h
security/selinux/include/objsec.h
security/selinux/include/security.h
security/selinux/selinuxfs.c
security/selinux/ss/services.c
security/smack/smack.h
security/smack/smack_lsm.c
security/smack/smackfs.c
security/tomoyo/tomoyo.c
security/yama/yama_lsm.c
tools/leds/Makefile
tools/leds/led_hw_brightness_mon.c [new file with mode: 0644]
tools/power/acpi/common/cmfsize.c
tools/power/acpi/common/getopt.c
tools/power/acpi/os_specific/service_layers/oslinuxtbl.c
tools/power/acpi/os_specific/service_layers/osunixdir.c
tools/power/acpi/os_specific/service_layers/osunixmap.c
tools/power/acpi/os_specific/service_layers/osunixxf.c
tools/power/acpi/tools/acpidump/acpidump.h
tools/power/acpi/tools/acpidump/apdump.c
tools/power/acpi/tools/acpidump/apfiles.c
tools/power/acpi/tools/acpidump/apmain.c
tools/power/x86/intel_pstate_tracer/intel_pstate_tracer.py [new file with mode: 0755]

diff --git a/Documentation/ABI/testing/sysfs-class-devfreq-event b/Documentation/ABI/testing/sysfs-class-devfreq-event
new file mode 100644 (file)
index 0000000..ceaf0f6
--- /dev/null
@@ -0,0 +1,25 @@
+What:          /sys/class/devfreq-event/event(x)/
+Date:          January 2017
+Contact:       Chanwoo Choi <cw00.choi@samsung.com>
+Description:
+               Provide a place in sysfs for the devfreq-event objects.
+               This allows accessing various devfreq-event specific variables.
+               The name of devfreq-event object denoted as 'event(x)' which
+               includes the unique number of 'x' for each devfreq-event object.
+
+What:          /sys/class/devfreq-event/event(x)/name
+Date:          January 2017
+Contact:       Chanwoo Choi <cw00.choi@samsung.com>
+Description:
+               The /sys/class/devfreq-event/event(x)/name attribute contains
+               the name of the devfreq-event object. This attribute is
+               read-only.
+
+What:          /sys/class/devfreq-event/event(x)/enable_count
+Date:          January 2017
+Contact:       Chanwoo Choi <cw00.choi@samsung.com>
+Description:
+               The /sys/class/devfreq-event/event(x)/enable_count attribute
+               contains the reference count to enable the devfreq-event
+               object. If the device is enabled, the value of attribute is
+               greater than zero.
index 491cdeedc195041a7f611f10490cc4ca569aeb9a..5f67f7ab277bc51af0bdb8ccb94ae03f6936ad6c 100644 (file)
@@ -23,6 +23,23 @@ Description:
                If the LED does not support different brightness levels, this
                should be 1.
 
+What:          /sys/class/leds/<led>/brightness_hw_changed
+Date:          January 2017
+KernelVersion: 4.11
+Description:
+               Last hardware set brightness level for this LED. Some LEDs
+               may be changed autonomously by hardware/firmware. Only LEDs
+               where this happens and the driver can detect this, will have
+               this file.
+
+               This file supports poll() to detect when the hardware changes
+               the brightness.
+
+               Reading this file will return the last brightness level set
+               by the hardware, this may be different from the current
+               brightness. Reading this file when no hw brightness change
+               event has happened will return an ENODATA error.
+
 What:          /sys/class/leds/<led>/trigger
 Date:          March 2006
 KernelVersion: 2.6.17
index b65674da43bb596b81dd4d29792774e0630bfe9d..8be1fd3760e038738d5a78cf04db330bc9b86b14 100644 (file)
@@ -62,18 +62,18 @@ Description:
                This value may be reset to 0 if the current protocol is altered.
 
 What:          /sys/class/rc/rcN/wakeup_protocols
-Date:          Feb 2014
-KernelVersion: 3.15
+Date:          Feb 2017
+KernelVersion: 4.11
 Contact:       Mauro Carvalho Chehab <m.chehab@samsung.com>
 Description:
                Reading this file returns a list of available protocols to use
                for the wakeup filter, something like:
-                   "rc5 rc6 nec jvc [sony]"
+                   "rc-5 nec nec-x rc-6-0 rc-6-6a-24 [rc-6-6a-32] rc-6-mce"
+               Note that protocol variants are listed, so "nec", "sony",
+               "rc-5", "rc-6" have their different bit length encodings
+               listed if available.
                The enabled wakeup protocol is shown in [] brackets.
-               Writing "+proto" will add a protocol to the list of enabled
-               wakeup protocols.
-               Writing "-proto" will remove a protocol from the list of enabled
-               wakeup protocols.
+               Only one protocol can be selected at a time.
                Writing "proto" will use "proto" for wakeup events.
                Writing "none" will disable wakeup.
                Write fails with EINVAL if an invalid protocol combination or
index d36441538660df72816841a3b966b878d9f0a838..fca40a54df5972a05957303cf8a3d4ef38d5b2a8 100644 (file)
@@ -2,7 +2,7 @@ What:           /sys/devices/platform/hidma-*/chid
                /sys/devices/platform/QCOM8061:*/chid
 Date:          Dec 2015
 KernelVersion: 4.4
-Contact:       "Sinan Kaya <okaya@cudeaurora.org>"
+Contact:       "Sinan Kaya <okaya@codeaurora.org>"
 Description:
                Contains the ID of the channel within the HIDMA instance.
                It is used to associate a given HIDMA channel with the
index c2fb5d033f0eb634276377693ce11846881d31c5..3b6c5c9eabdc6a72e544e56041d0c12689bd7b69 100644 (file)
@@ -2,7 +2,7 @@ What:           /sys/devices/platform/hidma-mgmt*/chanops/chan*/priority
                /sys/devices/platform/QCOM8060:*/chanops/chan*/priority
 Date:          Nov 2015
 KernelVersion: 4.4
-Contact:       "Sinan Kaya <okaya@cudeaurora.org>"
+Contact:       "Sinan Kaya <okaya@codeaurora.org>"
 Description:
                Contains either 0 or 1 and indicates if the DMA channel is a
                low priority (0) or high priority (1) channel.
@@ -11,7 +11,7 @@ What:         /sys/devices/platform/hidma-mgmt*/chanops/chan*/weight
                /sys/devices/platform/QCOM8060:*/chanops/chan*/weight
 Date:          Nov 2015
 KernelVersion: 4.4
-Contact:       "Sinan Kaya <okaya@cudeaurora.org>"
+Contact:       "Sinan Kaya <okaya@codeaurora.org>"
 Description:
                Contains 0..15 and indicates the weight of the channel among
                equal priority channels during round robin scheduling.
@@ -20,7 +20,7 @@ What:         /sys/devices/platform/hidma-mgmt*/chreset_timeout_cycles
                /sys/devices/platform/QCOM8060:*/chreset_timeout_cycles
 Date:          Nov 2015
 KernelVersion: 4.4
-Contact:       "Sinan Kaya <okaya@cudeaurora.org>"
+Contact:       "Sinan Kaya <okaya@codeaurora.org>"
 Description:
                Contains the platform specific cycle value to wait after a
                reset command is issued. If the value is chosen too short,
@@ -32,7 +32,7 @@ What:         /sys/devices/platform/hidma-mgmt*/dma_channels
                /sys/devices/platform/QCOM8060:*/dma_channels
 Date:          Nov 2015
 KernelVersion: 4.4
-Contact:       "Sinan Kaya <okaya@cudeaurora.org>"
+Contact:       "Sinan Kaya <okaya@codeaurora.org>"
 Description:
                Contains the number of dma channels supported by one instance
                of HIDMA hardware. The value may change from chip to chip.
@@ -41,7 +41,7 @@ What:         /sys/devices/platform/hidma-mgmt*/hw_version_major
                /sys/devices/platform/QCOM8060:*/hw_version_major
 Date:          Nov 2015
 KernelVersion: 4.4
-Contact:       "Sinan Kaya <okaya@cudeaurora.org>"
+Contact:       "Sinan Kaya <okaya@codeaurora.org>"
 Description:
                Version number major for the hardware.
 
@@ -49,7 +49,7 @@ What:         /sys/devices/platform/hidma-mgmt*/hw_version_minor
                /sys/devices/platform/QCOM8060:*/hw_version_minor
 Date:          Nov 2015
 KernelVersion: 4.4
-Contact:       "Sinan Kaya <okaya@cudeaurora.org>"
+Contact:       "Sinan Kaya <okaya@codeaurora.org>"
 Description:
                Version number minor for the hardware.
 
@@ -57,7 +57,7 @@ What:         /sys/devices/platform/hidma-mgmt*/max_rd_xactions
                /sys/devices/platform/QCOM8060:*/max_rd_xactions
 Date:          Nov 2015
 KernelVersion: 4.4
-Contact:       "Sinan Kaya <okaya@cudeaurora.org>"
+Contact:       "Sinan Kaya <okaya@codeaurora.org>"
 Description:
                Contains a value between 0 and 31. Maximum number of
                read transactions that can be issued back to back.
@@ -69,7 +69,7 @@ What:         /sys/devices/platform/hidma-mgmt*/max_read_request
                /sys/devices/platform/QCOM8060:*/max_read_request
 Date:          Nov 2015
 KernelVersion: 4.4
-Contact:       "Sinan Kaya <okaya@cudeaurora.org>"
+Contact:       "Sinan Kaya <okaya@codeaurora.org>"
 Description:
                Size of each read request. The value needs to be a power
                of two and can be between 128 and 1024.
@@ -78,7 +78,7 @@ What:         /sys/devices/platform/hidma-mgmt*/max_wr_xactions
                /sys/devices/platform/QCOM8060:*/max_wr_xactions
 Date:          Nov 2015
 KernelVersion: 4.4
-Contact:       "Sinan Kaya <okaya@cudeaurora.org>"
+Contact:       "Sinan Kaya <okaya@codeaurora.org>"
 Description:
                Contains a value between 0 and 31. Maximum number of
                write transactions that can be issued back to back.
@@ -91,7 +91,7 @@ What:         /sys/devices/platform/hidma-mgmt*/max_write_request
                /sys/devices/platform/QCOM8060:*/max_write_request
 Date:          Nov 2015
 KernelVersion: 4.4
-Contact:       "Sinan Kaya <okaya@cudeaurora.org>"
+Contact:       "Sinan Kaya <okaya@codeaurora.org>"
 Description:
                Size of each write request. The value needs to be a power
                of two and can be between 128 and 1024.
index effe7af3a5af95d25f86efadaa7dd2b127a0dea9..22cb3091f29776b2acfb0df339db150393a8ad83 100644 (file)
@@ -59,28 +59,20 @@ button driver uses the following 3 modes in order not to trigger issues.
 If the userspace hasn't been prepared to ignore the unreliable "opened"
 events and the unreliable initial state notification, Linux users can use
 the following kernel parameters to handle the possible issues:
-A. button.lid_init_state=method:
-   When this option is specified, the ACPI button driver reports the
-   initial lid state using the returning value of the _LID control method
-   and whether the "opened"/"closed" events are paired fully relies on the
-   firmware implementation.
-   This option can be used to fix some platforms where the returning value
-   of the _LID control method is reliable but the initial lid state
-   notification is missing.
-   This option is the default behavior during the period the userspace
-   isn't ready to handle the buggy AML tables.
-B. button.lid_init_state=open:
+A. button.lid_init_state=open:
    When this option is specified, the ACPI button driver always reports the
    initial lid state as "opened" and whether the "opened"/"closed" events
    are paired fully relies on the firmware implementation.
    This may fix some platforms where the returning value of the _LID
    control method is not reliable and the initial lid state notification is
    missing.
+   This option is the default behavior during the period the userspace
+   isn't ready to handle the buggy AML tables.
 
 If the userspace has been prepared to ignore the unreliable "opened" events
 and the unreliable initial state notification, Linux users should always
 use the following kernel parameter:
-C. button.lid_init_state=ignore:
+B. button.lid_init_state=ignore:
    When this option is specified, the ACPI button driver never reports the
    initial lid state and there is a compensation mechanism implemented to
    ensure that the reliable "closed" notifications can always be delievered
index 635d11135090cd7fc604c2c3496359a5b7a50f73..14ffef04113c096f9ce2840bf8c0485c81e3e86a 100644 (file)
        usbhid.mousepoll=
                        [USBHID] The interval which mice are to be polled at.
 
+       usbhid.jspoll=
+                       [USBHID] The interval which joysticks are to be polled at.
+
        usb-storage.delay_use=
                        [UMS] The delay in seconds before a new device is
                        scanned for Logical Units (default 1).
index c06233fe52ac2bea917e4e850551b2733f8d341f..8f85b0e41046231d5a0a6351bb06e377efb1a617 100644 (file)
@@ -249,7 +249,6 @@ struct& cdrom_device_ops\ \{ \hidewidth\cr
         unsigned\ long);\cr
 \noalign{\medskip}
   &const\ int& capability;& capability flags \cr
-  &int& n_minors;& number of active minor devices \cr
 \};\cr
 }
 $$
@@ -258,13 +257,7 @@ it should add a function pointer to this $struct$. When a particular
 function is not implemented, however, this $struct$ should contain a
 NULL instead. The $capability$ flags specify the capabilities of the
 \cdrom\ hardware and/or low-level \cdrom\ driver when a \cdrom\ drive
-is registered with the \UCD. The value $n_minors$ should be a positive
-value indicating the number of minor devices that are supported by
-the low-level device driver, normally~1. Although these two variables
-are `informative' rather than `operational,' they are included in
-$cdrom_device_ops$ because they describe the capability of the {\em
-driver\/} rather than the {\em drive}. Nomenclature has always been
-difficult in computer programming.
+is registered with the \UCD.
 
 Note that most functions have fewer parameters than their
 $blkdev_fops$ counterparts. This is because very little of the
index 4bc7287806de461823b2a3dedeb84322ad522a80..978463a7c81ea59ea24f2e967f9683321ef1188e 100644 (file)
@@ -8,6 +8,8 @@
 
                    Dominik Brodowski  <linux@brodo.de>
                     David Kimdon <dwhedon@debian.org>
+               Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+                  Viresh Kumar <viresh.kumar@linaro.org>
 
 
 
@@ -36,10 +38,11 @@ speed limits (like LCD drivers on ARM architecture). Additionally, the
 kernel "constant" loops_per_jiffy is updated on frequency changes
 here.
 
-Reference counting is done by cpufreq_get_cpu and cpufreq_put_cpu,
-which make sure that the cpufreq processor driver is correctly
-registered with the core, and will not be unloaded until
-cpufreq_put_cpu is called.
+Reference counting of the cpufreq policies is done by cpufreq_cpu_get
+and cpufreq_cpu_put, which make sure that the cpufreq driver is
+correctly registered with the core, and will not be unloaded until
+cpufreq_put_cpu is called. That also ensures that the respective cpufreq
+policy doesn't get freed while being used.
 
 2. CPUFreq notifiers
 ====================
@@ -69,18 +72,16 @@ CPUFreq policy notifier is called twice for a policy transition:
 The phase is specified in the second argument to the notifier.
 
 The third argument, a void *pointer, points to a struct cpufreq_policy
-consisting of five values: cpu, min, max, policy and max_cpu_freq. min 
-and max are the lower and upper frequencies (in kHz) of the new
-policy, policy the new policy, cpu the number of the affected CPU; and 
-max_cpu_freq the maximum supported CPU frequency. This value is given 
-for informational purposes only.
+consisting of several values, including min, max (the lower and upper
+frequencies (in kHz) of the new policy).
 
 
 2.2 CPUFreq transition notifiers
 --------------------------------
 
-These are notified twice when the CPUfreq driver switches the CPU core
-frequency and this change has any external implications.
+These are notified twice for each online CPU in the policy, when the
+CPUfreq driver switches the CPU core frequency and this change has no
+any external implications.
 
 The second argument specifies the phase - CPUFREQ_PRECHANGE or
 CPUFREQ_POSTCHANGE.
@@ -90,6 +91,7 @@ values:
 cpu    - number of the affected CPU
 old    - old frequency
 new    - new frequency
+flags  - flags of the cpufreq driver
 
 3. CPUFreq Table Generation with Operating Performance Point (OPP)
 ==================================================================
index 772b94fde2640a956db760fe8408af82d6ab1450..f71e6be26b83b48466353a58e5fc45ac75c239b8 100644 (file)
@@ -9,6 +9,8 @@
 
 
                    Dominik Brodowski  <linux@brodo.de>
+               Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+                  Viresh Kumar <viresh.kumar@linaro.org>
 
 
 
@@ -49,49 +51,65 @@ using cpufreq_register_driver()
 
 What shall this struct cpufreq_driver contain? 
 
-cpufreq_driver.name -          The name of this driver.
+ .name - The name of this driver.
 
-cpufreq_driver.init -          A pointer to the per-CPU initialization 
-                               function.
+ .init - A pointer to the per-policy initialization function.
 
-cpufreq_driver.verify -                A pointer to a "verification" function.
+ .verify - A pointer to a "verification" function.
 
-cpufreq_driver.setpolicy _or_ 
-cpufreq_driver.target/
-target_index           -       See below on the differences.
+ .setpolicy _or_ .fast_switch _or_ .target _or_ .target_index - See
+ below on the differences.
 
 And optionally
 
-cpufreq_driver.exit -          A pointer to a per-CPU cleanup
-                               function called during CPU_POST_DEAD
-                               phase of cpu hotplug process.
+ .flags - Hints for the cpufreq core.
 
-cpufreq_driver.stop_cpu -      A pointer to a per-CPU stop function
-                               called during CPU_DOWN_PREPARE phase of
-                               cpu hotplug process.
+ .driver_data - cpufreq driver specific data.
 
-cpufreq_driver.resume -                A pointer to a per-CPU resume function
-                               which is called with interrupts disabled
-                               and _before_ the pre-suspend frequency
-                               and/or policy is restored by a call to
-                               ->target/target_index or ->setpolicy.
+ .resolve_freq - Returns the most appropriate frequency for a target
+ frequency. Doesn't change the frequency though.
 
-cpufreq_driver.attr -          A pointer to a NULL-terminated list of
-                               "struct freq_attr" which allow to
-                               export values to sysfs.
+ .get_intermediate and target_intermediate - Used to switch to stable
+ frequency while changing CPU frequency.
 
-cpufreq_driver.get_intermediate
-and target_intermediate                Used to switch to stable frequency while
-                               changing CPU frequency.
+ .get - Returns current frequency of the CPU.
+
+ .bios_limit - Returns HW/BIOS max frequency limitations for the CPU.
+
+ .exit - A pointer to a per-policy cleanup function called during
+ CPU_POST_DEAD phase of cpu hotplug process.
+
+ .stop_cpu - A pointer to a per-policy stop function called during
+ CPU_DOWN_PREPARE phase of cpu hotplug process.
+
+ .suspend - A pointer to a per-policy suspend function which is called
+ with interrupts disabled and _after_ the governor is stopped for the
+ policy.
+
+ .resume - A pointer to a per-policy resume function which is called
+ with interrupts disabled and _before_ the governor is started again.
+
+ .ready - A pointer to a per-policy ready function which is called after
+ the policy is fully initialized.
+
+ .attr - A pointer to a NULL-terminated list of "struct freq_attr" which
+ allow to export values to sysfs.
+
+ .boost_enabled - If set, boost frequencies are enabled.
+
+ .set_boost - A pointer to a per-policy function to enable/disable boost
+ frequencies.
 
 
 1.2 Per-CPU Initialization
 --------------------------
 
 Whenever a new CPU is registered with the device model, or after the
-cpufreq driver registers itself, the per-CPU initialization function 
-cpufreq_driver.init is called. It takes a struct cpufreq_policy
-*policy as argument. What to do now?
+cpufreq driver registers itself, the per-policy initialization function
+cpufreq_driver.init is called if no cpufreq policy existed for the CPU.
+Note that the .init() and .exit() routines are called only once for the
+policy and not for each CPU managed by the policy. It takes a struct
+cpufreq_policy *policy as argument. What to do now?
 
 If necessary, activate the CPUfreq support on your CPU.
 
@@ -117,47 +135,45 @@ policy->governor          must contain the "default policy" for
                                cpufreq_driver.setpolicy or
                                cpufreq_driver.target/target_index is called
                                with these values.
+policy->cpus                   Update this with the masks of the
+                               (online + offline) CPUs that do DVFS
+                               along with this CPU (i.e.  that share
+                               clock/voltage rails with it).
 
 For setting some of these values (cpuinfo.min[max]_freq, policy->min[max]), the
 frequency table helpers might be helpful. See the section 2 for more information
 on them.
 
-SMP systems normally have same clock source for a group of cpus. For these the
-.init() would be called only once for the first online cpu. Here the .init()
-routine must initialize policy->cpus with mask of all possible cpus (Online +
-Offline) that share the clock. Then the core would copy this mask onto
-policy->related_cpus and will reset policy->cpus to carry only online cpus.
-
 
 1.3 verify
-------------
+----------
 
 When the user decides a new policy (consisting of
 "policy,governor,min,max") shall be set, this policy must be validated
 so that incompatible values can be corrected. For verifying these
-values, a frequency table helper and/or the
-cpufreq_verify_within_limits(struct cpufreq_policy *policy, unsigned
-int min_freq, unsigned int max_freq) function might be helpful. See
-section 2 for details on frequency table helpers.
+values cpufreq_verify_within_limits(struct cpufreq_policy *policy,
+unsigned int min_freq, unsigned int max_freq) function might be helpful.
+See section 2 for details on frequency table helpers.
 
 You need to make sure that at least one valid frequency (or operating
 range) is within policy->min and policy->max. If necessary, increase
 policy->max first, and only if this is no solution, decrease policy->min.
 
 
-1.4 target/target_index or setpolicy?
-----------------------------
+1.4 target or target_index or setpolicy or fast_switch?
+-------------------------------------------------------
 
 Most cpufreq drivers or even most cpu frequency scaling algorithms 
-only allow the CPU to be set to one frequency. For these, you use the
-->target/target_index call.
+only allow the CPU frequency to be set to predefined fixed values. For
+these, you use the ->target(), ->target_index() or ->fast_switch()
+callbacks.
 
-Some cpufreq-capable processors switch the frequency between certain
-limits on their own. These shall use the ->setpolicy call
+Some cpufreq capable processors switch the frequency between certain
+limits on their own. These shall use the ->setpolicy() callback.
 
 
 1.5. target/target_index
--------------
+------------------------
 
 The target_index call has two arguments: struct cpufreq_policy *policy,
 and unsigned int index (into the exposed frequency table).
@@ -186,9 +202,20 @@ actual frequency must be determined using the following rules:
 Here again the frequency table helper might assist you - see section 2
 for details.
 
+1.6. fast_switch
+----------------
 
-1.6 setpolicy
----------------
+This function is used for frequency switching from scheduler's context.
+Not all drivers are expected to implement it, as sleeping from within
+this callback isn't allowed. This callback must be highly optimized to
+do switching as fast as possible.
+
+This function has two arguments: struct cpufreq_policy *policy and
+unsigned int target_frequency.
+
+
+1.7 setpolicy
+-------------
 
 The setpolicy call only takes a struct cpufreq_policy *policy as
 argument. You need to set the lower limit of the in-processor or
@@ -198,7 +225,7 @@ setting when policy->policy is CPUFREQ_POLICY_PERFORMANCE, and a
 powersaving-oriented setting when CPUFREQ_POLICY_POWERSAVE. Also check
 the reference implementation in drivers/cpufreq/longrun.c
 
-1.7 get_intermediate and target_intermediate
+1.8 get_intermediate and target_intermediate
 --------------------------------------------
 
 Only for drivers with target_index() and CPUFREQ_ASYNC_NOTIFICATION unset.
@@ -222,42 +249,36 @@ failures as core would send notifications for that.
 
 As most cpufreq processors only allow for being set to a few specific
 frequencies, a "frequency table" with some functions might assist in
-some work of the processor driver. Such a "frequency table" consists
-of an array of struct cpufreq_frequency_table entries, with any value in
-"driver_data" you want to use, and the corresponding frequency in
-"frequency". At the end of the table, you need to add a
-cpufreq_frequency_table entry with frequency set to CPUFREQ_TABLE_END. And
-if you want to skip one entry in the table, set the frequency to 
-CPUFREQ_ENTRY_INVALID. The entries don't need to be in ascending
-order.
-
-By calling cpufreq_table_validate_and_show(struct cpufreq_policy *policy,
-                                       struct cpufreq_frequency_table *table);
-the cpuinfo.min_freq and cpuinfo.max_freq values are detected, and
-policy->min and policy->max are set to the same values. This is
-helpful for the per-CPU initialization stage.
-
-int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
-                                   struct cpufreq_frequency_table *table);
-assures that at least one valid frequency is within policy->min and
-policy->max, and all other criteria are met. This is helpful for the
-->verify call.
-
-int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
-                                   unsigned int target_freq,
-                                   unsigned int relation);
-
-is the corresponding frequency table helper for the ->target
-stage. Just pass the values to this function, and this function
-returns the number of the frequency table entry which contains
-the frequency the CPU shall be set to.
+some work of the processor driver. Such a "frequency table" consists of
+an array of struct cpufreq_frequency_table entries, with driver specific
+values in "driver_data", the corresponding frequency in "frequency" and
+flags set. At the end of the table, you need to add a
+cpufreq_frequency_table entry with frequency set to CPUFREQ_TABLE_END.
+And if you want to skip one entry in the table, set the frequency to
+CPUFREQ_ENTRY_INVALID. The entries don't need to be in sorted in any
+particular order, but if they are cpufreq core will do DVFS a bit
+quickly for them as search for best match is faster.
+
+By calling cpufreq_table_validate_and_show(), the cpuinfo.min_freq and
+cpuinfo.max_freq values are detected, and policy->min and policy->max
+are set to the same values. This is helpful for the per-CPU
+initialization stage.
+
+cpufreq_frequency_table_verify() assures that at least one valid
+frequency is within policy->min and policy->max, and all other criteria
+are met. This is helpful for the ->verify call.
+
+cpufreq_frequency_table_target() is the corresponding frequency table
+helper for the ->target stage. Just pass the values to this function,
+and this function returns the of the frequency table entry which
+contains the frequency the CPU shall be set to.
 
 The following macros can be used as iterators over cpufreq_frequency_table:
 
 cpufreq_for_each_entry(pos, table) - iterates over all entries of frequency
 table.
 
-cpufreq-for_each_valid_entry(pos, table) - iterates over all entries,
+cpufreq_for_each_valid_entry(pos, table) - iterates over all entries,
 excluding CPUFREQ_ENTRY_INVALID frequencies.
 Use arguments "pos" - a cpufreq_frequency_table * as a loop cursor and
 "table" - the cpufreq_frequency_table * you want to iterate over.
index 3c355f6ad83494e6de96a99f1a39ebf7e413a670..2bbe207354ed7c7e73ceb7f51ddb105c49827a1d 100644 (file)
@@ -34,10 +34,10 @@ cpufreq stats provides following statistics (explained in detail below).
 -  total_trans
 -  trans_table
 
-All the statistics will be from the time the stats driver has been inserted 
-to the time when a read of a particular statistic is done. Obviously, stats 
-driver will not have any information about the frequency transitions before
-the stats driver insertion.
+All the statistics will be from the time the stats driver has been inserted
+(or the time the stats were reset) to the time when a read of a particular
+statistic is done. Obviously, stats driver will not have any information
+about the frequency transitions before the stats driver insertion.
 
 --------------------------------------------------------------------------------
 <mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # ls -l
@@ -110,25 +110,13 @@ Config Main Menu
                CPU Frequency scaling  --->
                        [*] CPU Frequency scaling
                        [*]   CPU frequency translation statistics
-                       [*]     CPU frequency translation statistics details
 
 
 "CPU Frequency scaling" (CONFIG_CPU_FREQ) should be enabled to configure
 cpufreq-stats.
 
 "CPU frequency translation statistics" (CONFIG_CPU_FREQ_STAT) provides the
-basic statistics which includes time_in_state and total_trans.
+statistics which includes time_in_state, total_trans and trans_table.
 
-"CPU frequency translation statistics details" (CONFIG_CPU_FREQ_STAT_DETAILS)
-provides fine grained cpufreq stats by trans_table. The reason for having a
-separate config option for trans_table is:
-- trans_table goes against the traditional /sysfs rule of one value per
-  interface. It provides a whole bunch of value in a 2 dimensional matrix
-  form.
-
-Once these two options are enabled and your CPU supports cpufrequency, you
+Once this option is enabled and your CPU supports cpufrequency, you
 will be able to see the CPU frequency statistics in /sysfs.
-
-
-
-
index c15aa75f52275b703e3da46faff2a95e2ccfc6e9..61b3184b6c24e47c4a31c09763707e49a1d0de01 100644 (file)
@@ -10,6 +10,8 @@
 
                    Dominik Brodowski  <linux@brodo.de>
             some additions and corrections by Nico Golde <nico@ngolde.de>
+               Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+                  Viresh Kumar <viresh.kumar@linaro.org>
 
 
 
@@ -28,32 +30,27 @@ Contents:
 2.3  Userspace
 2.4  Ondemand
 2.5  Conservative
+2.6  Schedutil
 
 3.   The Governor Interface in the CPUfreq Core
 
+4.   References
 
 
 1. What Is A CPUFreq Governor?
 ==============================
 
 Most cpufreq drivers (except the intel_pstate and longrun) or even most
-cpu frequency scaling algorithms only offer the CPU to be set to one
-frequency. In order to offer dynamic frequency scaling, the cpufreq
-core must be able to tell these drivers of a "target frequency". So
-these specific drivers will be transformed to offer a "->target/target_index"
-call instead of the existing "->setpolicy" call. For "longrun", all
-stays the same, though.
+cpu frequency scaling algorithms only allow the CPU frequency to be set
+to predefined fixed values.  In order to offer dynamic frequency
+scaling, the cpufreq core must be able to tell these drivers of a
+"target frequency". So these specific drivers will be transformed to
+offer a "->target/target_index/fast_switch()" call instead of the
+"->setpolicy()" call. For set_policy drivers, all stays the same,
+though.
 
 How to decide what frequency within the CPUfreq policy should be used?
-That's done using "cpufreq governors". Two are already in this patch
--- they're the already existing "powersave" and "performance" which
-set the frequency statically to the lowest or highest frequency,
-respectively. At least two more such governors will be ready for
-addition in the near future, but likely many more as there are various
-different theories and models about dynamic frequency scaling
-around. Using such a generic interface as cpufreq offers to scaling
-governors, these can be tested extensively, and the best one can be
-selected for each specific use.
+That's done using "cpufreq governors".
 
 Basically, it's the following flow graph:
 
@@ -71,7 +68,7 @@ CPU can be set to switch independently         |         CPU can only be set
                    /                          the limits of policy->{min,max}
                   /                                \
                  /                                  \
-       Using the ->setpolicy call,              Using the ->target/target_index call,
+       Using the ->setpolicy call,              Using the ->target/target_index/fast_switch call,
            the limits and the                    the frequency closest
             "policy" is set.                     to target_freq is set.
                                                  It is assured that it
@@ -109,114 +106,159 @@ directory.
 2.4 Ondemand
 ------------
 
-The CPUfreq governor "ondemand" sets the CPU depending on the
-current usage. To do this the CPU must have the capability to
-switch the frequency very quickly.  There are a number of sysfs file
-accessible parameters:
-
-sampling_rate: measured in uS (10^-6 seconds), this is how often you
-want the kernel to look at the CPU usage and to make decisions on
-what to do about the frequency.  Typically this is set to values of
-around '10000' or more. It's default value is (cmp. with users-guide.txt):
-transition_latency * 1000
-Be aware that transition latency is in ns and sampling_rate is in us, so you
-get the same sysfs value by default.
-Sampling rate should always get adjusted considering the transition latency
-To set the sampling rate 750 times as high as the transition latency
-in the bash (as said, 1000 is default), do:
-echo `$(($(cat cpuinfo_transition_latency) * 750 / 1000)) \
-    >ondemand/sampling_rate
-
-sampling_rate_min:
-The sampling rate is limited by the HW transition latency:
-transition_latency * 100
-Or by kernel restrictions:
-If CONFIG_NO_HZ_COMMON is set, the limit is 10ms fixed.
-If CONFIG_NO_HZ_COMMON is not set or nohz=off boot parameter is used, the
-limits depend on the CONFIG_HZ option:
-HZ=1000: min=20000us  (20ms)
-HZ=250:  min=80000us  (80ms)
-HZ=100:  min=200000us (200ms)
-The highest value of kernel and HW latency restrictions is shown and
-used as the minimum sampling rate.
-
-up_threshold: defines what the average CPU usage between the samplings
-of 'sampling_rate' needs to be for the kernel to make a decision on
-whether it should increase the frequency.  For example when it is set
-to its default value of '95' it means that between the checking
-intervals the CPU needs to be on average more than 95% in use to then
-decide that the CPU frequency needs to be increased.  
-
-ignore_nice_load: this parameter takes a value of '0' or '1'. When
-set to '0' (its default), all processes are counted towards the
-'cpu utilisation' value.  When set to '1', the processes that are
-run with a 'nice' value will not count (and thus be ignored) in the
-overall usage calculation.  This is useful if you are running a CPU
-intensive calculation on your laptop that you do not care how long it
-takes to complete as you can 'nice' it and prevent it from taking part
-in the deciding process of whether to increase your CPU frequency.
-
-sampling_down_factor: this parameter controls the rate at which the
-kernel makes a decision on when to decrease the frequency while running
-at top speed. When set to 1 (the default) decisions to reevaluate load
-are made at the same interval regardless of current clock speed. But
-when set to greater than 1 (e.g. 100) it acts as a multiplier for the
-scheduling interval for reevaluating load when the CPU is at its top
-speed due to high load. This improves performance by reducing the overhead
-of load evaluation and helping the CPU stay at its top speed when truly
-busy, rather than shifting back and forth in speed. This tunable has no
-effect on behavior at lower speeds/lower CPU loads.
-
-powersave_bias: this parameter takes a value between 0 to 1000. It
-defines the percentage (times 10) value of the target frequency that
-will be shaved off of the target. For example, when set to 100 -- 10%,
-when ondemand governor would have targeted 1000 MHz, it will target
-1000 MHz - (10% of 1000 MHz) = 900 MHz instead. This is set to 0
-(disabled) by default.
-When AMD frequency sensitivity powersave bias driver --
-drivers/cpufreq/amd_freq_sensitivity.c is loaded, this parameter
-defines the workload frequency sensitivity threshold in which a lower
-frequency is chosen instead of ondemand governor's original target.
-The frequency sensitivity is a hardware reported (on AMD Family 16h
-Processors and above) value between 0 to 100% that tells software how
-the performance of the workload running on a CPU will change when
-frequency changes. A workload with sensitivity of 0% (memory/IO-bound)
-will not perform any better on higher core frequency, whereas a
-workload with sensitivity of 100% (CPU-bound) will perform better
-higher the frequency. When the driver is loaded, this is set to 400
-by default -- for CPUs running workloads with sensitivity value below
-40%, a lower frequency is chosen. Unloading the driver or writing 0
-will disable this feature.
+The CPUfreq governor "ondemand" sets the CPU frequency depending on the
+current system load. Load estimation is triggered by the scheduler
+through the update_util_data->func hook; when triggered, cpufreq checks
+the CPU-usage statistics over the last period and the governor sets the
+CPU accordingly.  The CPU must have the capability to switch the
+frequency very quickly.
+
+Sysfs files:
+
+* sampling_rate:
+
+  Measured in uS (10^-6 seconds), this is how often you want the kernel
+  to look at the CPU usage and to make decisions on what to do about the
+  frequency.  Typically this is set to values of around '10000' or more.
+  It's default value is (cmp. with users-guide.txt): transition_latency
+  * 1000.  Be aware that transition latency is in ns and sampling_rate
+  is in us, so you get the same sysfs value by default.  Sampling rate
+  should always get adjusted considering the transition latency to set
+  the sampling rate 750 times as high as the transition latency in the
+  bash (as said, 1000 is default), do:
+
+  $ echo `$(($(cat cpuinfo_transition_latency) * 750 / 1000)) > ondemand/sampling_rate
+
+* sampling_rate_min:
+
+  The sampling rate is limited by the HW transition latency:
+  transition_latency * 100
+
+  Or by kernel restrictions:
+  - If CONFIG_NO_HZ_COMMON is set, the limit is 10ms fixed.
+  - If CONFIG_NO_HZ_COMMON is not set or nohz=off boot parameter is
+    used, the limits depend on the CONFIG_HZ option:
+    HZ=1000: min=20000us  (20ms)
+    HZ=250:  min=80000us  (80ms)
+    HZ=100:  min=200000us (200ms)
+
+  The highest value of kernel and HW latency restrictions is shown and
+  used as the minimum sampling rate.
+
+* up_threshold:
+
+  This defines what the average CPU usage between the samplings of
+  'sampling_rate' needs to be for the kernel to make a decision on
+  whether it should increase the frequency.  For example when it is set
+  to its default value of '95' it means that between the checking
+  intervals the CPU needs to be on average more than 95% in use to then
+  decide that the CPU frequency needs to be increased.
+
+* ignore_nice_load:
+
+  This parameter takes a value of '0' or '1'. When set to '0' (its
+  default), all processes are counted towards the 'cpu utilisation'
+  value.  When set to '1', the processes that are run with a 'nice'
+  value will not count (and thus be ignored) in the overall usage
+  calculation.  This is useful if you are running a CPU intensive
+  calculation on your laptop that you do not care how long it takes to
+  complete as you can 'nice' it and prevent it from taking part in the
+  deciding process of whether to increase your CPU frequency.
+
+* sampling_down_factor:
+
+  This parameter controls the rate at which the kernel makes a decision
+  on when to decrease the frequency while running at top speed. When set
+  to 1 (the default) decisions to reevaluate load are made at the same
+  interval regardless of current clock speed. But when set to greater
+  than 1 (e.g. 100) it acts as a multiplier for the scheduling interval
+  for reevaluating load when the CPU is at its top speed due to high
+  load. This improves performance by reducing the overhead of load
+  evaluation and helping the CPU stay at its top speed when truly busy,
+  rather than shifting back and forth in speed. This tunable has no
+  effect on behavior at lower speeds/lower CPU loads.
+
+* powersave_bias:
+
+  This parameter takes a value between 0 to 1000. It defines the
+  percentage (times 10) value of the target frequency that will be
+  shaved off of the target. For example, when set to 100 -- 10%, when
+  ondemand governor would have targeted 1000 MHz, it will target
+  1000 MHz - (10% of 1000 MHz) = 900 MHz instead. This is set to 0
+  (disabled) by default.
+
+  When AMD frequency sensitivity powersave bias driver --
+  drivers/cpufreq/amd_freq_sensitivity.c is loaded, this parameter
+  defines the workload frequency sensitivity threshold in which a lower
+  frequency is chosen instead of ondemand governor's original target.
+  The frequency sensitivity is a hardware reported (on AMD Family 16h
+  Processors and above) value between 0 to 100% that tells software how
+  the performance of the workload running on a CPU will change when
+  frequency changes. A workload with sensitivity of 0% (memory/IO-bound)
+  will not perform any better on higher core frequency, whereas a
+  workload with sensitivity of 100% (CPU-bound) will perform better
+  higher the frequency. When the driver is loaded, this is set to 400 by
+  default -- for CPUs running workloads with sensitivity value below
+  40%, a lower frequency is chosen. Unloading the driver or writing 0
+  will disable this feature.
 
 
 2.5 Conservative
 ----------------
 
 The CPUfreq governor "conservative", much like the "ondemand"
-governor, sets the CPU depending on the current usage.  It differs in
-behaviour in that it gracefully increases and decreases the CPU speed
-rather than jumping to max speed the moment there is any load on the
-CPU.  This behaviour more suitable in a battery powered environment.
-The governor is tweaked in the same manner as the "ondemand" governor
-through sysfs with the addition of:
-
-freq_step: this describes what percentage steps the cpu freq should be
-increased and decreased smoothly by.  By default the cpu frequency will
-increase in 5% chunks of your maximum cpu frequency.  You can change this
-value to anywhere between 0 and 100 where '0' will effectively lock your
-CPU at a speed regardless of its load whilst '100' will, in theory, make
-it behave identically to the "ondemand" governor.
-
-down_threshold: same as the 'up_threshold' found for the "ondemand"
-governor but for the opposite direction.  For example when set to its
-default value of '20' it means that if the CPU usage needs to be below
-20% between samples to have the frequency decreased.
-
-sampling_down_factor: similar functionality as in "ondemand" governor.
-But in "conservative", it controls the rate at which the kernel makes
-a decision on when to decrease the frequency while running in any
-speed. Load for frequency increase is still evaluated every
-sampling rate.
+governor, sets the CPU frequency depending on the current usage.  It
+differs in behaviour in that it gracefully increases and decreases the
+CPU speed rather than jumping to max speed the moment there is any load
+on the CPU. This behaviour is more suitable in a battery powered
+environment.  The governor is tweaked in the same manner as the
+"ondemand" governor through sysfs with the addition of:
+
+* freq_step:
+
+  This describes what percentage steps the cpu freq should be increased
+  and decreased smoothly by.  By default the cpu frequency will increase
+  in 5% chunks of your maximum cpu frequency.  You can change this value
+  to anywhere between 0 and 100 where '0' will effectively lock your CPU
+  at a speed regardless of its load whilst '100' will, in theory, make
+  it behave identically to the "ondemand" governor.
+
+* down_threshold:
+
+  Same as the 'up_threshold' found for the "ondemand" governor but for
+  the opposite direction.  For example when set to its default value of
+  '20' it means that if the CPU usage needs to be below 20% between
+  samples to have the frequency decreased.
+
+* sampling_down_factor:
+
+  Similar functionality as in "ondemand" governor.  But in
+  "conservative", it controls the rate at which the kernel makes a
+  decision on when to decrease the frequency while running in any speed.
+  Load for frequency increase is still evaluated every sampling rate.
+
+
+2.6 Schedutil
+-------------
+
+The "schedutil" governor aims at better integration with the Linux
+kernel scheduler.  Load estimation is achieved through the scheduler's
+Per-Entity Load Tracking (PELT) mechanism, which also provides
+information about the recent load [1].  This governor currently does
+load based DVFS only for tasks managed by CFS. RT and DL scheduler tasks
+are always run at the highest frequency.  Unlike all the other
+governors, the code is located under the kernel/sched/ directory.
+
+Sysfs files:
+
+* rate_limit_us:
+
+  This contains a value in microseconds. The governor waits for
+  rate_limit_us time before reevaluating the load again, after it has
+  evaluated the load once.
+
+For an in-depth comparison with the other governors refer to [2].
+
 
 3. The Governor Interface in the CPUfreq Core
 =============================================
@@ -225,26 +267,10 @@ A new governor must register itself with the CPUfreq core using
 "cpufreq_register_governor". The struct cpufreq_governor, which has to
 be passed to that function, must contain the following values:
 
-governor->name -           A unique name for this governor
-governor->governor -       The governor callback function
-governor->owner        -           .THIS_MODULE for the governor module (if 
-                           appropriate)
-
-The governor->governor callback is called with the current (or to-be-set)
-cpufreq_policy struct for that CPU, and an unsigned int event. The
-following events are currently defined:
-
-CPUFREQ_GOV_START:   This governor shall start its duty for the CPU
-                    policy->cpu
-CPUFREQ_GOV_STOP:    This governor shall end its duty for the CPU
-                    policy->cpu
-CPUFREQ_GOV_LIMITS:  The limits for CPU policy->cpu have changed to
-                    policy->min and policy->max.
-
-If you need other "events" externally of your driver, _only_ use the
-cpufreq_governor_l(unsigned int cpu, unsigned int event) call to the
-CPUfreq core to ensure proper locking.
+governor->name - A unique name for this governor.
+governor->owner - .THIS_MODULE for the governor module (if appropriate).
 
+plus a set of hooks to the functions implementing the governor's logic.
 
 The CPUfreq governor may call the CPU processor driver using one of
 these two functions:
@@ -258,12 +284,18 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
                                    unsigned int relation);
 
 target_freq must be within policy->min and policy->max, of course.
-What's the difference between these two functions? When your governor
-still is in a direct code path of a call to governor->governor, the
-per-CPU cpufreq lock is still held in the cpufreq core, and there's
-no need to lock it again (in fact, this would cause a deadlock). So
-use __cpufreq_driver_target only in these cases. In all other cases 
-(for example, when there's a "daemonized" function that wakes up 
-every second), use cpufreq_driver_target to lock the cpufreq per-CPU
-lock before the command is passed to the cpufreq processor driver.
+What's the difference between these two functions? When your governor is
+in a direct code path of a call to governor callbacks, like
+governor->start(), the policy->rwsem is still held in the cpufreq core,
+and there's no need to lock it again (in fact, this would cause a
+deadlock). So use __cpufreq_driver_target only in these cases. In all
+other cases (for example, when there's a "daemonized" function that
+wakes up every second), use cpufreq_driver_target to take policy->rwsem
+before the command is passed to the cpufreq driver.
+
+4. References
+=============
+
+[1] Per-entity load tracking: https://lwn.net/Articles/531853/
+[2] Improvements in CPU frequency management: https://lwn.net/Articles/682391/
 
index dc024ab4054fc9d3728f0cda79cc9891e4178544..ef1d39247b054f332fc671bb0f781146866258c3 100644 (file)
 
 Documents in this directory:
 ----------------------------
+
+amd-powernow.txt -     AMD powernow driver specific file.
+
+boost.txt -            Frequency boosting support.
+
 core.txt       -       General description of the CPUFreq core and
-                       of CPUFreq notifiers
+                       of CPUFreq notifiers.
+
+cpu-drivers.txt -      How to implement a new cpufreq processor driver.
 
-cpu-drivers.txt -      How to implement a new cpufreq processor driver
+cpufreq-nforce2.txt -  nVidia nForce2 platform specific file.
+
+cpufreq-stats.txt -    General description of sysfs cpufreq stats.
 
 governors.txt  -       What are cpufreq governors and how to
                        implement them?
 
 index.txt      -       File index, Mailing list and Links (this document)
 
+intel-pstate.txt -     Intel pstate cpufreq driver specific file.
+
+pcc-cpufreq.txt -      PCC cpufreq driver specific file.
+
 user-guide.txt -       User Guide to CPUFreq
 
 
@@ -35,9 +48,7 @@ Mailing List
 ------------
 There is a CPU frequency changing CVS commit and general list where
 you can report bugs, problems or submit patches. To post a message,
-send an email to linux-pm@vger.kernel.org, to subscribe go to
-http://vger.kernel.org/vger-lists.html#linux-pm and follow the
-instructions there.
+send an email to linux-pm@vger.kernel.org.
 
 Links
 -----
@@ -48,7 +59,7 @@ how to access the CVS repository:
 * http://cvs.arm.linux.org.uk/
 
 the CPUFreq Mailing list:
-* http://vger.kernel.org/vger-lists.html#cpufreq
+* http://vger.kernel.org/vger-lists.html#linux-pm
 
 Clock and voltage scaling for the SA-1100:
 * http://www.lartmaker.nl/projects/scaling
index 1953994ef5e6bfe4b5897bdd427b087f361c63e0..3fdcdfd968ba1237ef61856c51463d123b9321a1 100644 (file)
@@ -85,6 +85,21 @@ Sysfs will show :
 Refer to "Intel® 64 and IA-32 Architectures Software Developer’s Manual
 Volume 3: System Programming Guide" to understand ratios.
 
+There is one more sysfs attribute in /sys/devices/system/cpu/intel_pstate/
+that can be used for controlling the operation mode of the driver:
+
+      status: Three settings are possible:
+      "off"     - The driver is not in use at this time.
+      "active"  - The driver works as a P-state governor (default).
+      "passive" - The driver works as a regular cpufreq one and collaborates
+                  with the generic cpufreq governors (it sets P-states as
+                  requested by those governors).
+      The current setting is returned by reads from this attribute.  Writing one
+      of the above strings to it changes the operation mode as indicated by that
+      string, if possible.  If HW-managed P-states (HWP) are enabled, it is not
+      possible to change the driver's operation mode and attempts to write to
+      this attribute will fail.
+
 cpufreq sysfs for Intel P-State
 
 Since this driver registers with cpufreq, cpufreq sysfs is also presented.
index 109e97bbab7717e8b9dd721b47a992ba5773ea31..107f6fdd7d14b126016dd9a8179452900d0d5b97 100644 (file)
@@ -18,7 +18,7 @@
 Contents:
 ---------
 1. Supported Architectures and Processors
-1.1 ARM
+1.1 ARM and ARM64
 1.2 x86
 1.3 sparc64
 1.4 ppc
@@ -37,16 +37,10 @@ Contents:
 1. Supported Architectures and Processors
 =========================================
 
-1.1 ARM
--------
-
-The following ARM processors are supported by cpufreq:
-
-ARM Integrator
-ARM-SA1100
-ARM-SA1110
-Intel PXA
+1.1 ARM and ARM64
+-----------------
 
+Almost all ARM and ARM64 platforms support CPU frequency scaling.
 
 1.2 x86
 -------
@@ -69,6 +63,7 @@ Transmeta Crusoe
 Transmeta Efficeon
 VIA Cyrix 3 / C3
 various processors on some ACPI 2.0-compatible systems [*]
+And many more
 
 [*] Only if "ACPI Processor Performance States" are available
 to the ACPI<->BIOS interface.
@@ -147,10 +142,19 @@ mounted it at /sys, the cpufreq interface is located in a subdirectory
 "cpufreq" within the cpu-device directory
 (e.g. /sys/devices/system/cpu/cpu0/cpufreq/ for the first CPU).
 
+affected_cpus :                        List of Online CPUs that require software
+                               coordination of frequency.
+
+cpuinfo_cur_freq :             Current frequency of the CPU as obtained from
+                               the hardware, in KHz. This is the frequency
+                               the CPU actually runs at.
+
 cpuinfo_min_freq :             this file shows the minimum operating
                                frequency the processor can run at(in kHz) 
+
 cpuinfo_max_freq :             this file shows the maximum operating
                                frequency the processor can run at(in kHz) 
+
 cpuinfo_transition_latency     The time it takes on this CPU to
                                switch between two frequencies in nano
                                seconds. If unknown or known to be
@@ -163,25 +167,30 @@ cpuinfo_transition_latency        The time it takes on this CPU to
                                userspace daemon. Make sure to not
                                switch the frequency too often
                                resulting in performance loss.
-scaling_driver :               this file shows what cpufreq driver is
-                               used to set the frequency on this CPU
+
+related_cpus :                 List of Online + Offline CPUs that need software
+                               coordination of frequency.
+
+scaling_available_frequencies : List of available frequencies, in KHz.
 
 scaling_available_governors :  this file shows the CPUfreq governors
                                available in this kernel. You can see the
                                currently activated governor in
 
+scaling_cur_freq :             Current frequency of the CPU as determined by
+                               the governor and cpufreq core, in KHz. This is
+                               the frequency the kernel thinks the CPU runs
+                               at.
+
+scaling_driver :               this file shows what cpufreq driver is
+                               used to set the frequency on this CPU
+
 scaling_governor,              and by "echoing" the name of another
                                governor you can change it. Please note
                                that some governors won't load - they only
                                work on some specific architectures or
                                processors.
 
-cpuinfo_cur_freq :             Current frequency of the CPU as obtained from
-                               the hardware, in KHz. This is the frequency
-                               the CPU actually runs at.
-
-scaling_available_frequencies : List of available frequencies, in KHz.
-
 scaling_min_freq and
 scaling_max_freq               show the current "policy limits" (in
                                kHz). By echoing new values into these
@@ -190,16 +199,11 @@ scaling_max_freq          show the current "policy limits" (in
                                first set scaling_max_freq, then
                                scaling_min_freq.
 
-affected_cpus :                        List of Online CPUs that require software
-                               coordination of frequency.
-
-related_cpus :                 List of Online + Offline CPUs that need software
-                               coordination of frequency.
-
-scaling_cur_freq :             Current frequency of the CPU as determined by
-                               the governor and cpufreq core, in KHz. This is
-                               the frequency the kernel thinks the CPU runs
-                               at.
+scaling_setspeed               This can be read to get the currently programmed
+                               value by the governor. This can be written to
+                               change the current frequency for a group of
+                               CPUs, represented by a policy. This is supported
+                               currently only by the userspace governor.
 
 bios_limit :                   If the BIOS tells the OS to limit a CPU to
                                lower frequencies, the user can read out the
index 785eab87aa71dc68aceeb970676a614c9c2c6381..f228604ddbcd6890c1db0ef2778422a499cbd480 100644 (file)
@@ -207,6 +207,10 @@ Optional feature arguments are:
                   block, then the cache block is invalidated.
                   To enable passthrough mode the cache must be clean.
 
+   metadata2   : use version 2 of the metadata.  This stores the dirty bits
+                  in a separate btree, which improves speed of shutting
+                 down the cache.
+
 A policy called 'default' is always registered.  This is an alias for
 the policy we currently think is giving best all round performance.
 
index 5e3786fd9ea74f3966b6dc7ff5ce8fe1a5fd7612..0d199353e4776b60e40062cd3f57f98be6166cb7 100644 (file)
@@ -161,6 +161,15 @@ The target is named "raid" and it accepts the following parameters:
                the RAID type (i.e. the allocation algorithm) as well, e.g.
                changing from raid5_ls to raid5_n.
 
+       [journal_dev <dev>]
+               This option adds a journal device to raid4/5/6 raid sets and
+               uses it to close the 'write hole' caused by the non-atomic updates
+               to the component devices which can cause data loss during recovery.
+               The journal device is used as writethrough thus causing writes to
+               be throttled versus non-journaled raid4/5/6 sets.
+               Takeover/reshape is not possible with a raid4/5/6 journal device;
+               it has to be deconfigured before requesting these.
+
 <#raid_devs>: The number of devices composing the array.
        Each device consists of two entries.  The first is the device
        containing the metadata (if any); the second is the one containing the
@@ -245,6 +254,9 @@ recovery.  Here is a fuller description of the individual fields:
        <data_offset>   The current data offset to the start of the user data on
                        each component device of a raid set (see the respective
                        raid parameter to support out-of-place reshaping).
+       <journal_char>  'A' - active raid4/5/6 journal device.
+                       'D' - dead journal device.
+                       '-' - no journal device.
 
 
 Message Interface
@@ -314,3 +326,8 @@ Version History
 1.9.0   Add support for RAID level takeover/reshape/region size
        and set size reduction.
 1.9.1   Fix activation of existing RAID 4/10 mapped devices
+1.9.2   Don't emit '- -' on the status table line in case the constructor
+       fails reading a superblock. Correctly emit 'maj:min1 maj:min2' and
+       'D' on the status line.  If '- -' is passed into the constructor, emit
+       '- -' on the table line and '-' as the status line health character.
+1.10.0  Add support for raid4/5/6 journal device
diff --git a/Documentation/devicetree/bindings/cpufreq/ti-cpufreq.txt b/Documentation/devicetree/bindings/cpufreq/ti-cpufreq.txt
new file mode 100644 (file)
index 0000000..ba0e15a
--- /dev/null
@@ -0,0 +1,128 @@
+TI CPUFreq and OPP bindings
+================================
+
+Certain TI SoCs, like those in the am335x, am437x, am57xx, and dra7xx
+families support different OPPs depending on the silicon variant in use.
+The ti-cpufreq driver can use revision and an efuse value from the SoC to
+provide the OPP framework with supported hardware information. This is
+used to determine which OPPs from the operating-points-v2 table get enabled
+when it is parsed by the OPP framework.
+
+Required properties:
+--------------------
+In 'cpus' nodes:
+- operating-points-v2: Phandle to the operating-points-v2 table to use.
+
+In 'operating-points-v2' table:
+- compatible: Should be
+       - 'operating-points-v2-ti-cpu' for am335x, am43xx, and dra7xx/am57xx SoCs
+- syscon: A phandle pointing to a syscon node representing the control module
+         register space of the SoC.
+
+Optional properties:
+--------------------
+For each opp entry in 'operating-points-v2' table:
+- opp-supported-hw: Two bitfields indicating:
+       1. Which revision of the SoC the OPP is supported by
+       2. Which eFuse bits indicate this OPP is available
+
+       A bitwise AND is performed against these values and if any bit
+       matches, the OPP gets enabled.
+
+Example:
+--------
+
+/* From arch/arm/boot/dts/am33xx.dtsi */
+cpus {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       cpu@0 {
+               compatible = "arm,cortex-a8";
+               device_type = "cpu";
+               reg = <0>;
+
+               operating-points-v2 = <&cpu0_opp_table>;
+
+               clocks = <&dpll_mpu_ck>;
+               clock-names = "cpu";
+
+               clock-latency = <300000>; /* From omap-cpufreq driver */
+       };
+};
+
+/*
+ * cpu0 has different OPPs depending on SoC revision and some on revisions
+ * 0x2 and 0x4 have eFuse bits that indicate if they are available or not
+ */
+cpu0_opp_table: opp-table {
+       compatible = "operating-points-v2-ti-cpu";
+       syscon = <&scm_conf>;
+
+       /*
+        * The three following nodes are marked with opp-suspend
+        * because they can not be enabled simultaneously on a
+        * single SoC.
+        */
+       opp50@300000000 {
+               opp-hz = /bits/ 64 <300000000>;
+               opp-microvolt = <950000 931000 969000>;
+               opp-supported-hw = <0x06 0x0010>;
+               opp-suspend;
+       };
+
+       opp100@275000000 {
+               opp-hz = /bits/ 64 <275000000>;
+               opp-microvolt = <1100000 1078000 1122000>;
+               opp-supported-hw = <0x01 0x00FF>;
+               opp-suspend;
+       };
+
+       opp100@300000000 {
+               opp-hz = /bits/ 64 <300000000>;
+               opp-microvolt = <1100000 1078000 1122000>;
+               opp-supported-hw = <0x06 0x0020>;
+               opp-suspend;
+       };
+
+       opp100@500000000 {
+               opp-hz = /bits/ 64 <500000000>;
+               opp-microvolt = <1100000 1078000 1122000>;
+               opp-supported-hw = <0x01 0xFFFF>;
+       };
+
+       opp100@600000000 {
+               opp-hz = /bits/ 64 <600000000>;
+               opp-microvolt = <1100000 1078000 1122000>;
+               opp-supported-hw = <0x06 0x0040>;
+       };
+
+       opp120@600000000 {
+               opp-hz = /bits/ 64 <600000000>;
+               opp-microvolt = <1200000 1176000 1224000>;
+               opp-supported-hw = <0x01 0xFFFF>;
+       };
+
+       opp120@720000000 {
+               opp-hz = /bits/ 64 <720000000>;
+               opp-microvolt = <1200000 1176000 1224000>;
+               opp-supported-hw = <0x06 0x0080>;
+       };
+
+       oppturbo@720000000 {
+               opp-hz = /bits/ 64 <720000000>;
+               opp-microvolt = <1260000 1234800 1285200>;
+               opp-supported-hw = <0x01 0xFFFF>;
+       };
+
+       oppturbo@800000000 {
+               opp-hz = /bits/ 64 <800000000>;
+               opp-microvolt = <1260000 1234800 1285200>;
+               opp-supported-hw = <0x06 0x0100>;
+       };
+
+       oppnitro@1000000000 {
+               opp-hz = /bits/ 64 <1000000000>;
+               opp-microvolt = <1325000 1298500 1351500>;
+               opp-supported-hw = <0x04 0x0200>;
+       };
+};
index d3ec8e676b6bf306309b42bdd4678403a1682c82..d085ef90d27c1f8b82645177169f71c3eb42d00f 100644 (file)
@@ -123,6 +123,20 @@ Detailed correlation between sub-blocks and power line according to Exynos SoC:
                |--- FSYS
                |--- FSYS2
 
+- In case of Exynos5433, there is VDD_INT power line as following:
+       VDD_INT |--- G2D (parent device)
+               |--- MSCL
+               |--- GSCL
+               |--- JPEG
+               |--- MFC
+               |--- HEVC
+               |--- BUS0
+               |--- BUS1
+               |--- BUS2
+               |--- PERIS (Fixed clock rate)
+               |--- PERIC (Fixed clock rate)
+               |--- FSYS  (Fixed clock rate)
+
 Example1:
        Show the AXI buses of Exynos3250 SoC. Exynos3250 divides the buses to
        power line (regulator). The MIF (Memory Interface) AXI bus is used to
index 70cd13f1588abea6f266afe65e3ad4b4f66683ca..4408af693d0cc75298e66c3c56af8f7521d3eb23 100644 (file)
@@ -40,8 +40,7 @@ Example:
 
 DMA clients connected to the STM32 DMA controller must use the format
 described in the dma.txt file, using a five-cell specifier for each
-channel: a phandle plus four integer cells.
-The four cells in order are:
+channel: a phandle to the DMA controller plus the following four integer cells:
 
 1. The channel id
 2. The request line number
@@ -61,7 +60,7 @@ The four cells in order are:
        0x1: medium
        0x2: high
        0x3: very high
-5. A 32bit mask specifying the DMA FIFO threshold configuration which are device
+4. A 32bit mask specifying the DMA FIFO threshold configuration which are device
    dependent:
  -bit 0-1: Fifo threshold
        0x0: 1/4 full FIFO
index 488edcb264c4fea49441bb21ea7deb02a0056882..28e8bd8b7d640b34dceadae6b7fe5cf36d392527 100644 (file)
@@ -17,6 +17,22 @@ Required properties:
 - interrupt-parent: the phandle for the interrupt controller
 - interrupts: interrupt line
 
+Additional optional properties:
+
+Some devices may support additional optional properties to help with, e.g.,
+power sequencing. The following properties can be supported by one or more
+device-specific compatible properties, which should be used in addition to the
+"hid-over-i2c" string.
+
+- compatible:
+  * "wacom,w9013" (Wacom W9013 digitizer). Supports:
+    - vdd-supply
+    - post-power-on-delay-ms
+
+- vdd-supply: phandle of the regulator that provides the supply voltage.
+- post-power-on-delay-ms: time required by the device after enabling its regulators
+  before it is ready for communication. Must be used with 'vdd-supply'.
+
 Example:
 
        i2c-hid-dev@2c {
index 696be57926257817e061e5e21657ab4939f38345..24b6560140899aa8e956efa942f2074873e1f26b 100644 (file)
@@ -61,16 +61,24 @@ property can be omitted.
 
 Examples:
 
-system-status {
-       label = "Status";
-       linux,default-trigger = "heartbeat";
-       ...
+gpio-leds {
+       compatible = "gpio-leds";
+
+       system-status {
+               label = "Status";
+               linux,default-trigger = "heartbeat";
+               gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>;
+       };
 };
 
-camera-flash {
-       label = "Flash";
-       led-sources = <0>, <1>;
-       led-max-microamp = <50000>;
-       flash-max-microamp = <320000>;
-       flash-max-timeout-us = <500000>;
+max77693-led {
+       compatible = "maxim,max77693-led";
+
+       camera-flash {
+               label = "Flash";
+               led-sources = <0>, <1>;
+               led-max-microamp = <50000>;
+               flash-max-microamp = <320000>;
+               flash-max-timeout-us = <500000>;
+       };
 };
diff --git a/Documentation/devicetree/bindings/leds/irled/spi-ir-led.txt b/Documentation/devicetree/bindings/leds/irled/spi-ir-led.txt
new file mode 100644 (file)
index 0000000..896b699
--- /dev/null
@@ -0,0 +1,29 @@
+Device tree bindings for IR LED connected through SPI bus which is used as
+remote controller.
+
+The IR LED switch is connected to the MOSI line of the SPI device and the data
+are delivered thourgh that.
+
+Required properties:
+       - compatible: should be "ir-spi-led".
+
+Optional properties:
+       - duty-cycle: 8 bit balue that represents the percentage of one period
+         in which the signal is active.  It can be 50, 60, 70, 75, 80 or 90.
+       - led-active-low: boolean value that specifies whether the output is
+         negated with a NOT gate.
+       - power-supply: specifies the power source. It can either be a regulator
+         or a gpio which enables a regulator, i.e. a regulator-fixed as
+         described in
+         Documentation/devicetree/bindings/regulator/fixed-regulator.txt
+
+Example:
+
+       irled@0 {
+               compatible = "ir-spi-led";
+               reg = <0x0>;
+               spi-max-frequency = <5000000>;
+               power-supply = <&vdd_led>;
+               led-active-low;
+               duty-cycle = /bits/ 8 <60>;
+       };
diff --git a/Documentation/devicetree/bindings/media/fsl-vdoa.txt b/Documentation/devicetree/bindings/media/fsl-vdoa.txt
new file mode 100644 (file)
index 0000000..6c56285
--- /dev/null
@@ -0,0 +1,21 @@
+Freescale Video Data Order Adapter
+==================================
+
+The Video Data Order Adapter (VDOA) is present on the i.MX6q. Its sole purpose
+is to reorder video data from the macroblock tiled order produced by the CODA
+960 VPU to the conventional raster-scan order for scanout.
+
+Required properties:
+- compatible: must be "fsl,imx6q-vdoa"
+- reg: the register base and size for the device registers
+- interrupts: the VDOA interrupt
+- clocks: the vdoa clock
+
+Example:
+
+vdoa@21e4000 {
+        compatible = "fsl,imx6q-vdoa";
+        reg = <0x021e4000 0x4000>;
+        interrupts = <0 18 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&clks IMX6QDL_CLK_VDOA>;
+};
index 56e726ef4bf26f0faa561e5f5aec663d7def9a1c..58261fb7b408981d709832eadf9c28282a67a822 100644 (file)
@@ -5,7 +5,8 @@ Required properties:
        - gpios: specifies GPIO used for IR signal reception.
 
 Optional properties:
-       - linux,rc-map-name: Linux specific remote control map name.
+       - linux,rc-map-name: see rc.txt file in the same
+         directory.
 
 Example node:
 
index 54e1bede6244f4981b3cdec70ec58dd765cc3e2d..13ebc0fac9ea2faaae8b19b75e494ffa0950ede4 100644 (file)
@@ -10,7 +10,7 @@ Required properties:
        - clocks: clock phandle and specifier pair.
 
 Optional properties:
-       - linux,rc-map-name : Remote control map name.
+       - linux,rc-map-name: see rc.txt file in the same directory.
        - hisilicon,power-syscon: DEPRECATED. Don't use this in new dts files.
                Provide correct clocks instead.
 
diff --git a/Documentation/devicetree/bindings/media/i2c/toshiba,et8ek8.txt b/Documentation/devicetree/bindings/media/i2c/toshiba,et8ek8.txt
new file mode 100644 (file)
index 0000000..0b7b6a4
--- /dev/null
@@ -0,0 +1,48 @@
+Toshiba et8ek8 5MP sensor
+
+Toshiba et8ek8 5MP sensor is an image sensor found in Nokia N900 device
+
+More detailed documentation can be found in
+Documentation/devicetree/bindings/media/video-interfaces.txt .
+
+
+Mandatory properties
+--------------------
+
+- compatible: "toshiba,et8ek8"
+- reg: I2C address (0x3e, or an alternative address)
+- vana-supply: Analogue voltage supply (VANA), 2.8 volts
+- clocks: External clock to the sensor
+- clock-frequency: Frequency of the external clock to the sensor. Camera
+  driver will set this frequency on the external clock. The clock frequency is
+  a pre-determined frequency known to be suitable to the board.
+- reset-gpios: XSHUTDOWN GPIO. The XSHUTDOWN signal is active low. The sensor
+  is in hardware standby mode when the signal is in the low state.
+
+
+Endpoint node mandatory properties
+----------------------------------
+
+- remote-endpoint: A phandle to the bus receiver's endpoint node.
+
+
+Example
+-------
+
+&i2c3 {
+       clock-frequency = <400000>;
+
+       cam1: camera@3e {
+               compatible = "toshiba,et8ek8";
+               reg = <0x3e>;
+               vana-supply = <&vaux4>;
+               clocks = <&isp 0>;
+               clock-frequency = <9600000>;
+               reset-gpio = <&gpio4 6 GPIO_ACTIVE_HIGH>; /* 102 */
+               port {
+                       csi_cam1: endpoint {
+                               remote-endpoint = <&csi_out1>;
+                       };
+               };
+       };
+};
index e7e3f3c4fc8f697d9fc5c0b9917cb89cff2198ab..efd9d29a8f103f3003dffd82c84df1eb1d614973 100644 (file)
@@ -8,6 +8,9 @@ Required properties:
  - reg         : physical base address and length of the device registers
  - interrupts  : a single specifier for the interrupt from the device
 
+Optional properties:
+ - linux,rc-map-name:  see rc.txt file in the same directory.
+
 Example:
 
        ir-receiver@c8100480 {
diff --git a/Documentation/devicetree/bindings/media/mtk-cir.txt b/Documentation/devicetree/bindings/media/mtk-cir.txt
new file mode 100644 (file)
index 0000000..2be2005
--- /dev/null
@@ -0,0 +1,24 @@
+Device-Tree bindings for Mediatek consumer IR controller
+found in Mediatek SoC family
+
+Required properties:
+- compatible       : "mediatek,mt7623-cir"
+- clocks           : list of clock specifiers, corresponding to
+                     entries in clock-names property;
+- clock-names      : should contain "clk" entries;
+- interrupts       : should contain IR IRQ number;
+- reg              : should contain IO map address for IR.
+
+Optional properties:
+- linux,rc-map-name : see rc.txt file in the same directory.
+
+Example:
+
+cir: cir@10013000 {
+       compatible = "mediatek,mt7623-cir";
+       reg = <0 0x10013000 0 0x1000>;
+       interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_LOW>;
+       clocks = <&infracfg CLK_INFRA_IRRX>;
+       clock-names = "clk";
+       linux,rc-map-name = "rc-rc6-mce";
+};
diff --git a/Documentation/devicetree/bindings/media/rc.txt b/Documentation/devicetree/bindings/media/rc.txt
new file mode 100644 (file)
index 0000000..d3e7a01
--- /dev/null
@@ -0,0 +1,117 @@
+The following properties are common to the infrared remote controllers:
+
+- linux,rc-map-name: string, specifies the scancode/key mapping table
+  defined in-kernel for the remote controller. Support values are:
+  * "rc-adstech-dvb-t-pci"
+  * "rc-alink-dtu-m"
+  * "rc-anysee"
+  * "rc-apac-viewcomp"
+  * "rc-asus-pc39"
+  * "rc-asus-ps3-100"
+  * "rc-ati-tv-wonder-hd-600"
+  * "rc-ati-x10"
+  * "rc-avermedia-a16d"
+  * "rc-avermedia-cardbus"
+  * "rc-avermedia-dvbt"
+  * "rc-avermedia-m135a"
+  * "rc-avermedia-m733a-rm-k6"
+  * "rc-avermedia-rm-ks"
+  * "rc-avermedia"
+  * "rc-avertv-303"
+  * "rc-azurewave-ad-tu700"
+  * "rc-behold-columbus"
+  * "rc-behold"
+  * "rc-budget-ci-old"
+  * "rc-cec"
+  * "rc-cinergy-1400"
+  * "rc-cinergy"
+  * "rc-delock-61959"
+  * "rc-dib0700-nec"
+  * "rc-dib0700-rc5"
+  * "rc-digitalnow-tinytwin"
+  * "rc-digittrade"
+  * "rc-dm1105-nec"
+  * "rc-dntv-live-dvbt-pro"
+  * "rc-dntv-live-dvb-t"
+  * "rc-dtt200u"
+  * "rc-dvbsky"
+  * "rc-empty"
+  * "rc-em-terratec"
+  * "rc-encore-enltv2"
+  * "rc-encore-enltv-fm53"
+  * "rc-encore-enltv"
+  * "rc-evga-indtube"
+  * "rc-eztv"
+  * "rc-flydvb"
+  * "rc-flyvideo"
+  * "rc-fusionhdtv-mce"
+  * "rc-gadmei-rm008z"
+  * "rc-geekbox"
+  * "rc-genius-tvgo-a11mce"
+  * "rc-gotview7135"
+  * "rc-hauppauge"
+  * "rc-imon-mce"
+  * "rc-imon-pad"
+  * "rc-iodata-bctv7e"
+  * "rc-it913x-v1"
+  * "rc-it913x-v2"
+  * "rc-kaiomy"
+  * "rc-kworld-315u"
+  * "rc-kworld-pc150u"
+  * "rc-kworld-plus-tv-analog"
+  * "rc-leadtek-y04g0051"
+  * "rc-lirc"
+  * "rc-lme2510"
+  * "rc-manli"
+  * "rc-medion-x10"
+  * "rc-medion-x10-digitainer"
+  * "rc-medion-x10-or2x"
+  * "rc-msi-digivox-ii"
+  * "rc-msi-digivox-iii"
+  * "rc-msi-tvanywhere-plus"
+  * "rc-msi-tvanywhere"
+  * "rc-nebula"
+  * "rc-nec-terratec-cinergy-xs"
+  * "rc-norwood"
+  * "rc-npgtech"
+  * "rc-pctv-sedna"
+  * "rc-pinnacle-color"
+  * "rc-pinnacle-grey"
+  * "rc-pinnacle-pctv-hd"
+  * "rc-pixelview-new"
+  * "rc-pixelview"
+  * "rc-pixelview-002t"
+  * "rc-pixelview-mk12"
+  * "rc-powercolor-real-angel"
+  * "rc-proteus-2309"
+  * "rc-purpletv"
+  * "rc-pv951"
+  * "rc-hauppauge"
+  * "rc-rc5-tv"
+  * "rc-rc6-mce"
+  * "rc-real-audio-220-32-keys"
+  * "rc-reddo"
+  * "rc-snapstream-firefly"
+  * "rc-streamzap"
+  * "rc-tbs-nec"
+  * "rc-technisat-ts35"
+  * "rc-technisat-usb2"
+  * "rc-terratec-cinergy-c-pci"
+  * "rc-terratec-cinergy-s2-hd"
+  * "rc-terratec-cinergy-xs"
+  * "rc-terratec-slim"
+  * "rc-terratec-slim-2"
+  * "rc-tevii-nec"
+  * "rc-tivo"
+  * "rc-total-media-in-hand"
+  * "rc-total-media-in-hand-02"
+  * "rc-trekstor"
+  * "rc-tt-1500"
+  * "rc-twinhan-dtv-cab-ci"
+  * "rc-twinhan1027"
+  * "rc-videomate-k100"
+  * "rc-videomate-s350"
+  * "rc-videomate-tv-pvr"
+  * "rc-winfast"
+  * "rc-winfast-usbii-deluxe"
+  * "rc-su3000"
diff --git a/Documentation/devicetree/bindings/media/st,st-delta.txt b/Documentation/devicetree/bindings/media/st,st-delta.txt
new file mode 100644 (file)
index 0000000..a538ab3
--- /dev/null
@@ -0,0 +1,17 @@
+* STMicroelectronics DELTA multi-format video decoder
+
+Required properties:
+- compatible: should be "st,st-delta".
+- clocks: from common clock binding: handle hardware IP needed clocks, the
+  number of clocks may depend on the SoC type.
+  See ../clock/clock-bindings.txt for details.
+- clock-names: names of the clocks listed in clocks property in the same order.
+
+Example:
+       delta0 {
+               compatible = "st,st-delta";
+               clock-names = "delta", "delta-st231", "delta-flash-promip";
+               clocks = <&clk_s_c0_flexgen CLK_VID_DMU>,
+                        <&clk_s_c0_flexgen CLK_ST231_DMU>,
+                        <&clk_s_c0_flexgen CLK_FLASH_PROMIP>;
+       };
index 1811a067c72cc8b21267298ec4892dd136ebf7bd..302a0b183cb883245c0804e1effa878cf4d11139 100644 (file)
@@ -9,7 +9,7 @@ Required properties:
 - reg              : should contain IO map address for IR.
 
 Optional properties:
-- linux,rc-map-name : Remote control map name.
+- linux,rc-map-name: see rc.txt file in the same directory.
 - resets : phandle + reset specifier pair
 
 Example:
diff --git a/Documentation/devicetree/bindings/media/ti,da850-vpif.txt b/Documentation/devicetree/bindings/media/ti,da850-vpif.txt
new file mode 100644 (file)
index 0000000..6d25d7f
--- /dev/null
@@ -0,0 +1,83 @@
+Texas Instruments VPIF
+----------------------
+
+The TI Video Port InterFace (VPIF) is the primary component for video
+capture and display on the DA850/AM18x family of TI DaVinci/Sitara
+SoCs.
+
+TI Document reference: SPRUH82C, Chapter 35
+http://www.ti.com/lit/pdf/spruh82
+
+Required properties:
+- compatible: must be "ti,da850-vpif"
+- reg: physical base address and length of the registers set for the device;
+- interrupts: should contain IRQ line for the VPIF
+
+Video Capture:
+
+VPIF has a 16-bit parallel bus input, supporting 2 8-bit channels or a
+single 16-bit channel.  It should contain at least one port child node
+with child 'endpoint' node. Please refer to the bindings defined in
+Documentation/devicetree/bindings/media/video-interfaces.txt.
+
+Example using 2 8-bit input channels, one of which is connected to an
+I2C-connected TVP5147 decoder:
+
+       vpif: vpif@217000 {
+               compatible = "ti,da850-vpif";
+               reg = <0x217000 0x1000>;
+               interrupts = <92>;
+
+               port {
+                       vpif_ch0: endpoint@0 {
+                                 reg = <0>;
+                                 bus-width = <8>;
+                                 remote-endpoint = <&composite>;
+                       };
+
+                       vpif_ch1: endpoint@1 {
+                                 reg = <1>;
+                                 bus-width = <8>;
+                                 data-shift = <8>;
+                       };
+               };
+       };
+
+[ ... ]
+
+&i2c0 {
+
+       tvp5147@5d {
+               compatible = "ti,tvp5147";
+               reg = <0x5d>;
+               status = "okay";
+
+               port {
+                       composite: endpoint {
+                               hsync-active = <1>;
+                               vsync-active = <1>;
+                               pclk-sample = <0>;
+
+                               /* VPIF channel 0 (lower 8-bits) */
+                               remote-endpoint = <&vpif_ch0>;
+                               bus-width = <8>;
+                       };
+               };
+       };
+};
+
+
+Alternatively, an example when the bus is configured as a single
+16-bit input (e.g. for raw-capture mode):
+
+       vpif: vpif@217000 {
+               compatible = "ti,da850-vpif";
+               reg = <0x217000 0x1000>;
+               interrupts = <92>;
+
+               port {
+                       vpif_ch0: endpoint {
+                                 bus-width = <16>;
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/mips/img/pistachio-marduk.txt b/Documentation/devicetree/bindings/mips/img/pistachio-marduk.txt
new file mode 100644 (file)
index 0000000..2d5126d
--- /dev/null
@@ -0,0 +1,10 @@
+Imagination Technologies' Pistachio SoC based Marduk Board
+==========================================================
+
+Compatible string must be "img,pistachio-marduk", "img,pistachio"
+
+Hardware and other related documentation is available at
+https://docs.creatordev.io/ci40/
+
+It is also known as Creator Ci40. Marduk is legacy name and will
+be there for decades.
index 7f95ec400863e84497c544d5a398f3d81f284904..50bf611a4d2c01a3488c538a17334af3d1706093 100644 (file)
@@ -17,7 +17,7 @@ Required properties:
        "core" - Main peripheral bus clock
        "clkin0" - Parent clock of internal mux
        "clkin1" - Other parent clock of internal mux
-  The driver has an interal mux clock which switches between clkin0 and clkin1 depending on the
+  The driver has an internal mux clock which switches between clkin0 and clkin1 depending on the
   clock rate requested by the MMC core.
 
 Example:
diff --git a/Documentation/devicetree/bindings/mmc/mmc-pwrseq-sd8787.txt b/Documentation/devicetree/bindings/mmc/mmc-pwrseq-sd8787.txt
new file mode 100644 (file)
index 0000000..22e9340
--- /dev/null
@@ -0,0 +1,16 @@
+* Marvell SD8787 power sequence provider
+
+Required properties:
+- compatible: must be "mmc-pwrseq-sd8787".
+- powerdown-gpios: contains a power down GPIO specifier with the
+                  default active state
+- reset-gpios: contains a reset GPIO specifier with the default
+                  active state
+
+Example:
+
+       wifi_pwrseq: wifi_pwrseq {
+               compatible = "mmc-pwrseq-sd8787";
+               powerdown-gpios = <&twl_gpio 0 GPIO_ACTIVE_LOW>;
+               reset-gpios = <&twl_gpio 1 GPIO_ACTIVE_LOW>;
+       }
index 8a377827695bd2d13d169adc162b4129a043a422..c7f4a0ec48eda788359a06ce07e6330d932da9d5 100644 (file)
@@ -40,6 +40,7 @@ Optional properties:
 - cap-mmc-hw-reset: eMMC hardware reset is supported
 - cap-sdio-irq: enable SDIO IRQ signalling on this interface
 - full-pwr-cycle: full power cycle of the card is supported
+- mmc-ddr-3_3v: eMMC high-speed DDR mode(3.3V I/O) is supported
 - mmc-ddr-1_8v: eMMC high-speed DDR mode(1.8V I/O) is supported
 - mmc-ddr-1_2v: eMMC high-speed DDR mode(1.2V I/O) is supported
 - mmc-hs200-1_8v: eMMC HS200 mode(1.8V I/O) is supported
index 3cd4c43a32601957038eea8595c1e5d42651f94d..230fd696eb922fabc5820509a8f9c355f94a1f93 100644 (file)
@@ -38,7 +38,7 @@ Optional properties:
 - bus-width:           Number of data lines.
                        See:  Documentation/devicetree/bindings/mmc/mmc.txt.
 
-- max-frequency:       Can be 200MHz, 100Mz or 50MHz (default) and used for
+- max-frequency:       Can be 200MHz, 100MHz or 50MHz (default) and used for
                        configuring the CCONFIG3 in the mmcss.
                        See:  Documentation/devicetree/bindings/mmc/mmc.txt.
 
index 1c95a1a555c3d4d58ee8b25706806fcb02a6c9d8..0e9923a64024f4ded9a94dc5ce06e631f637b091 100644 (file)
@@ -5,7 +5,7 @@ host controllers refer to the mmc[1] bindings.
 
 Optional properties:
 - sdhci-caps-mask: The sdhci capabilities register is incorrect. This 64bit
-  property corresponds to the bits in the sdhci capabilty register. If the bit
+  property corresponds to the bits in the sdhci capability register. If the bit
   is on in the mask then the bit is incorrect in the register and should be
   turned off, before applying sdhci-caps.
 - sdhci-caps: The sdhci capabilities register is incorrect. This 64bit
index 55cdd804cdbac0b078ea4e6ddbcd59d35813b989..7d53a799f140edf378412909dfbd14be4a5fb973 100644 (file)
@@ -13,6 +13,7 @@ Required properties:
    * "allwinner,sun5i-a13-mmc"
    * "allwinner,sun7i-a20-mmc"
    * "allwinner,sun9i-a80-mmc"
+   * "allwinner,sun50i-a64-emmc"
    * "allwinner,sun50i-a64-mmc"
  - reg : mmc controller base registers
  - clocks : a list with 4 phandle + clock specifier pairs
index 7fd17c3da11626a8759f6dcf9895ae1f93c48388..9cb55ca5746135a104d9e6d4722b87d888be63af 100644 (file)
@@ -16,7 +16,7 @@ Required Properties:
   each child-node representing a supported slot. There should be atleast one
   child node representing a card slot. The name of the child node representing
   the slot is recommended to be slot@n where n is the unique number of the slot
-  connnected to the controller. The following are optional properties which
+  connected to the controller. The following are optional properties which
   can be included in the slot child node.
 
        * reg: specifies the physical slot number. The valid values of this
@@ -75,6 +75,17 @@ Optional properties:
 * card-detect-delay: Delay in milli-seconds before detecting card after card
   insert event. The default value is 0.
 
+* data-addr: Override fifo address with value provided by DT. The default FIFO reg
+  offset is assumed as 0x100 (version < 0x240A) and 0x200(version >= 0x240A) by
+  driver. If the controller does not follow this rule, please use this property
+  to set fifo address in device tree.
+
+* fifo-watermark-aligned: Data done irq is expected if data length is less than
+  watermark in PIO mode. But fifo watermark is requested to be aligned with data
+  length in some SoC so that TX/RX irq can be generated with data done irq. Add this
+  watermark quirk to mark this requirement and force fifo watermark setting
+  accordingly.
+
 * vmmc-supply: The phandle to the regulator to use for vmmc.  If this is
   specified we'll defer probe until we can find this regulator.
 
@@ -102,6 +113,8 @@ board specific portions as listed below.
                interrupts = <0 75 0>;
                #address-cells = <1>;
                #size-cells = <0>;
+               data-addr = <0x200>;
+               fifo-watermark-aligned;
                resets = <&rst 20>;
                reset-names = "reset";
        };
index a1650edfd2b706cea003d7e242e43fbceeb23f27..4fd8b7acc510c57453b092d70637c32cc252b85b 100644 (file)
@@ -25,6 +25,19 @@ Required properties:
                "renesas,sdhi-r8a7795" - SDHI IP on R8A7795 SoC
                "renesas,sdhi-r8a7796" - SDHI IP on R8A7796 SoC
 
+- clocks: Most controllers only have 1 clock source per channel. However, on
+         some variations of this controller, the internal card detection
+         logic that exists in this controller is sectioned off to be run by a
+         separate second clock source to allow the main core clock to be turned
+         off to save power.
+         If 2 clocks are specified by the hardware, you must name them as
+         "core" and "cd". If the controller only has 1 clock, naming is not
+         required.
+         Below is the number clocks for each supported SoC:
+          1: SH73A0, R8A73A4, R8A7740, R8A7778, R8A7779, R8A7790
+             R8A7791, R8A7792, R8A7793, R8A7794, R8A7795, R8A7796
+          2: R7S72100
+
 Optional properties:
 - toshiba,mmc-wrprotect-disable: write-protect detection is unavailable
 - pinctrl-names: should be "default", "state_uhs"
diff --git a/Documentation/devicetree/bindings/mmc/zx-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/zx-dw-mshc.txt
new file mode 100644 (file)
index 0000000..eaade0e
--- /dev/null
@@ -0,0 +1,33 @@
+* ZTE specific extensions to the Synopsys Designware Mobile Storage
+  Host Controller
+
+The Synopsys designware mobile storage host controller is used to interface
+a SoC with storage medium such as eMMC or SD/MMC cards. This file documents
+differences between the core Synopsys dw mshc controller properties described
+by synopsys-dw-mshc.txt and the properties used by the ZTE specific
+extensions to the Synopsys Designware Mobile Storage Host Controller.
+
+Required Properties:
+
+* compatible: should be
+       - "zte,zx296718-dw-mshc": for ZX SoCs
+
+Example:
+
+       mmc1: mmc@1110000 {
+               compatible = "zte,zx296718-dw-mshc";
+               reg = <0x01110000 0x1000>;
+               interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+               fifo-depth = <32>;
+               data-addr = <0x200>;
+               fifo-watermark-aligned;
+               bus-width = <4>;
+               clock-frequency = <50000000>;
+               clocks = <&topcrm SD0_AHB>, <&topcrm SD0_WCLK>;
+               clock-names = "biu", "ciu";
+               num-slots = <1>;
+               max-frequency = <50000000>;
+               cap-sdio-irq;
+               cap-sd-highspeed;
+               status = "disabled";
+       };
index 980b16df74c387021bef3e8a64d34f67417729ab..0854451ff91d79a2f4b224abc3f3c5b4ebee9496 100644 (file)
@@ -1,4 +1,4 @@
-Marvell 8897/8997 (sd8897/sd8997/pcie8997) SDIO/PCIE devices
+Marvell 8787/8897/8997 (sd8787/sd8897/sd8997/pcie8997) SDIO/PCIE devices
 ------
 
 This node provides properties for controlling the Marvell SDIO/PCIE wireless device.
@@ -8,6 +8,7 @@ connects the device to the system.
 Required properties:
 
   - compatible : should be one of the following:
+       * "marvell,sd8787"
        * "marvell,sd8897"
        * "marvell,sd8997"
        * "pci11ab,2b42"
@@ -34,6 +35,9 @@ Optional properties:
                 so that the wifi chip can wakeup host platform under certain condition.
                 during system resume, the irq will be disabled to make sure
                 unnecessary interrupt is not received.
+  - vmmc-supply: a phandle of a regulator, supplying VCC to the card
+  - mmc-pwrseq:  phandle to the MMC power sequence node. See "mmc-pwrseq-*"
+                for documentation of MMC power sequence bindings.
 
 Example:
 
@@ -46,6 +50,7 @@ so that firmware can wakeup host using this device side pin.
 &mmc3 {
        status = "okay";
        vmmc-supply = <&wlan_en_reg>;
+       mmc-pwrseq = <&wifi_pwrseq>;
        bus-width = <4>;
        cap-power-off-card;
        keep-power-in-suspend;
index de1378b4efadca8bc6b39c428f486a1c77c3aad0..7c85dca4221abc71ab873158eef0cbb80d3d31c1 100644 (file)
@@ -23,6 +23,7 @@ Required properties:
   "allwinner,sun8i-h3-pinctrl"
   "allwinner,sun8i-h3-r-pinctrl"
   "allwinner,sun50i-a64-pinctrl"
+  "allwinner,sun50i-h5-r-pinctrl"
   "nextthing,gr8-pinctrl"
 
 - reg: Should contain the register physical address and length for the
index 457b2c68d47b6caa817acc7a8e048b69ff5eb4f5..8c5d27c5b56217e469acf4322309739d7ff50dea 100644 (file)
@@ -19,7 +19,7 @@ iomuxc: iomuxc@30330000 {
        reg = <0x30330000 0x10000>;
 };
 
-Pheriparials using pads from iomuxc-lpsr support low state retention power
+Peripherals using pads from iomuxc-lpsr support low state retention power
 state, under LPSR mode GPIO's state of pads are retain.
 
 Please refer to fsl,imx-pinctrl.txt in this directory for common binding part
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,armada-98dx3236-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,armada-98dx3236-pinctrl.txt
new file mode 100644 (file)
index 0000000..97aef67
--- /dev/null
@@ -0,0 +1,46 @@
+* Marvell 98dx3236 pinctrl driver for mpp
+
+Please refer to marvell,mvebu-pinctrl.txt in this directory for common binding
+part and usage
+
+Required properties:
+- compatible: "marvell,98dx3236-pinctrl" or "marvell,98dx4251-pinctrl"
+- reg: register specifier of MPP registers
+
+This driver supports all 98dx3236, 98dx3336 and 98dx4251 variants
+
+name          pins     functions
+================================================================================
+mpp0          0        gpo, spi0(mosi), dev(ad8)
+mpp1          1        gpio, spi0(miso), dev(ad9)
+mpp2          2        gpo, spi0(sck), dev(ad10)
+mpp3          3        gpio, spi0(cs0), dev(ad11)
+mpp4          4        gpio, spi0(cs1), smi(mdc), dev(cs0)
+mpp5          5        gpio, pex(rsto), sd0(cmd), dev(bootcs)
+mpp6          6        gpo, sd0(clk), dev(a2)
+mpp7          7        gpio, sd0(d0), dev(ale0)
+mpp8          8        gpio, sd0(d1), dev(ale1)
+mpp9          9        gpio, sd0(d2), dev(ready0)
+mpp10         10       gpio, sd0(d3), dev(ad12)
+mpp11         11       gpio, uart1(rxd), uart0(cts), dev(ad13)
+mpp12         12       gpo, uart1(txd), uart0(rts), dev(ad14)
+mpp13         13       gpio, intr(out), dev(ad15)
+mpp14         14       gpio, i2c0(sck)
+mpp15         15       gpio, i2c0(sda)
+mpp16         16       gpo, dev(oe)
+mpp17         17       gpo, dev(clkout)
+mpp18         18       gpio, uart1(txd)
+mpp19         19       gpio, uart1(rxd), dev(rb)
+mpp20         20       gpo, dev(we0)
+mpp21         21       gpo, dev(ad0)
+mpp22         22       gpo, dev(ad1)
+mpp23         23       gpo, dev(ad2)
+mpp24         24       gpo, dev(ad3)
+mpp25         25       gpo, dev(ad4)
+mpp26         26       gpo, dev(ad5)
+mpp27         27       gpo, dev(ad6)
+mpp28         28       gpo, dev(ad7)
+mpp29         29       gpo, dev(a0)
+mpp30         30       gpo, dev(a1)
+mpp31         31       gpio, slv_smi(mdc), smi(mdc), dev(we1)
+mpp32         32       gpio, slv_smi(mdio), smi(mdio), dev(cs1)
index 730444a9a4de8a3aba0e6be2864f974b4f5da1a5..6c0ea155b708980c7a6cdaeeccc962bd383f66cf 100644 (file)
@@ -44,16 +44,16 @@ mpp16         16       gpio, sdio(d2), uart0(cts), uart1(rxd), mii(crs)
 mpp17         17       gpio, sdio(d3)
 mpp18         18       gpo, nand(io0)
 mpp19         19       gpo, nand(io1)
-mpp20         20       gpio, mii(rxerr)
-mpp21         21       gpio, audio(spdifi)
-mpp22         22       gpio, audio(spdifo)
-mpp23         23       gpio, audio(rmclk)
-mpp24         24       gpio, audio(bclk)
-mpp25         25       gpio, audio(sdo)
-mpp26         26       gpio, audio(lrclk)
-mpp27         27       gpio, audio(mclk)
-mpp28         28       gpio, audio(sdi)
-mpp29         29       gpio, audio(extclk)
+mpp35         35       gpio, mii(rxerr)
+mpp36         36       gpio, audio(spdifi)
+mpp37         37       gpio, audio(spdifo)
+mpp38         38       gpio, audio(rmclk)
+mpp39         39       gpio, audio(bclk)
+mpp40         40       gpio, audio(sdo)
+mpp41         41       gpio, audio(lrclk)
+mpp42         42       gpio, audio(mclk)
+mpp43         43       gpio, audio(sdi)
+mpp44         44       gpio, audio(extclk)
 
 * Marvell Kirkwood 88f6190
 
index 2ad18c4ea55c5f022f0181c78896d5a8e33d4e74..b98e6f030da84e0582b443124e305ed7fd6b0634 100644 (file)
@@ -1,25 +1,38 @@
+======================
 Aspeed Pin Controllers
-----------------------
+======================
 
 The Aspeed SoCs vary in functionality inside a generation but have a common mux
 device register layout.
 
-Required properties:
-- compatible : Should be any one of the following:
-               "aspeed,ast2400-pinctrl"
-               "aspeed,g4-pinctrl"
-               "aspeed,ast2500-pinctrl"
-               "aspeed,g5-pinctrl"
+Required properties for g4:
+- compatible :                         Should be one of the following:
+                               "aspeed,ast2400-pinctrl"
+                               "aspeed,g4-pinctrl"
 
-The pin controller node should be a child of a syscon node with the required
+Required properties for g5:
+- compatible :                         Should be one of the following:
+                               "aspeed,ast2500-pinctrl"
+                               "aspeed,g5-pinctrl"
+
+- aspeed,external-nodes:       A cell of phandles to external controller nodes:
+                               0: compatible with "aspeed,ast2500-gfx", "syscon"
+                               1: compatible with "aspeed,ast2500-lhc", "syscon"
+
+The pin controller node should be the child of a syscon node with the required
 property:
-- compatible: "syscon", "simple-mfd"
+
+- compatible :                 Should be one of the following:
+                       "aspeed,ast2400-scu", "syscon", "simple-mfd"
+                       "aspeed,g4-scu", "syscon", "simple-mfd"
+                       "aspeed,ast2500-scu", "syscon", "simple-mfd"
+                       "aspeed,g5-scu", "syscon", "simple-mfd"
 
 Refer to the the bindings described in
 Documentation/devicetree/bindings/mfd/syscon.txt
 
 Subnode Format
---------------
+==============
 
 The required properties of child nodes are (as defined in pinctrl-bindings):
 - function
@@ -31,26 +44,43 @@ supported:
 
 aspeed,ast2400-pinctrl, aspeed,g4-pinctrl:
 
-ACPI BMCINT DDCCLK DDCDAT FLACK FLBUSY FLWP GPID0 GPIE0 GPIE2 GPIE4 GPIE6 I2C10
-I2C11 I2C12 I2C13 I2C3 I2C4 I2C5 I2C6 I2C7 I2C8 I2C9 LPCPD LPCPME LPCSMI MDIO1
-MDIO2 NCTS1 NCTS3 NCTS4 NDCD1 NDCD3 NDCD4 NDSR1 NDSR3 NDTR1 NDTR3 NRI1 NRI3
-NRI4 NRTS1 NRTS3 PWM0 PWM1 PWM2 PWM3 PWM4 PWM5 PWM6 PWM7 RGMII1 RMII1 ROM16
-ROM8 ROMCS1 ROMCS2 ROMCS3 ROMCS4 RXD1 RXD3 RXD4 SD1 SGPMI SIOPBI SIOPBO TIMER3
-TIMER5 TIMER6 TIMER7 TIMER8 TXD1 TXD3 TXD4 UART6 VGAHS VGAVS VPI18 VPI24 VPI30
-VPO12 VPO24
+ACPI ADC0 ADC1 ADC10 ADC11 ADC12 ADC13 ADC14 ADC15 ADC2 ADC3 ADC4 ADC5 ADC6
+ADC7 ADC8 ADC9 BMCINT DDCCLK DDCDAT EXTRST FLACK FLBUSY FLWP GPID GPID0 GPID2
+GPID4 GPID6 GPIE0 GPIE2 GPIE4 GPIE6 I2C10 I2C11 I2C12 I2C13 I2C14 I2C3 I2C4
+I2C5 I2C6 I2C7 I2C8 I2C9 LPCPD LPCPME LPCRST LPCSMI MAC1LINK MAC2LINK MDIO1
+MDIO2 NCTS1 NCTS2 NCTS3 NCTS4 NDCD1 NDCD2 NDCD3 NDCD4 NDSR1 NDSR2 NDSR3 NDSR4
+NDTR1 NDTR2 NDTR3 NDTR4 NDTS4 NRI1 NRI2 NRI3 NRI4 NRTS1 NRTS2 NRTS3 OSCCLK PWM0
+PWM1 PWM2 PWM3 PWM4 PWM5 PWM6 PWM7 RGMII1 RGMII2 RMII1 RMII2 ROM16 ROM8 ROMCS1
+ROMCS2 ROMCS3 ROMCS4 RXD1 RXD2 RXD3 RXD4 SALT1 SALT2 SALT3 SALT4 SD1 SD2 SGPMCK
+SGPMI SGPMLD SGPMO SGPSCK SGPSI0 SGPSI1 SGPSLD SIOONCTRL SIOPBI SIOPBO SIOPWREQ
+SIOPWRGD SIOS3 SIOS5 SIOSCI SPI1 SPI1DEBUG SPI1PASSTHRU SPICS1 TIMER3 TIMER4
+TIMER5 TIMER6 TIMER7 TIMER8 TXD1 TXD2 TXD3 TXD4 UART6 USBCKI VGABIOS_ROM VGAHS
+VGAVS VPI18 VPI24 VPI30 VPO12 VPO24 WDTRST1 WDTRST2
 
 aspeed,ast2500-pinctrl, aspeed,g5-pinctrl:
 
-GPID0 GPID2 GPIE0 I2C10 I2C11 I2C12 I2C13 I2C14 I2C3 I2C4 I2C5 I2C6 I2C7 I2C8
-I2C9 MAC1LINK MDIO1 MDIO2 OSCCLK PEWAKE PWM0 PWM1 PWM2 PWM3 PWM4 PWM5 PWM6 PWM7
-RGMII1 RGMII2 RMII1 RMII2 SD1 SPI1 SPI1DEBUG SPI1PASSTHRU TIMER4 TIMER5 TIMER6
-TIMER7 TIMER8 VGABIOSROM
-
-
-Examples:
+ACPI ADC0 ADC1 ADC10 ADC11 ADC12 ADC13 ADC14 ADC15 ADC2 ADC3 ADC4 ADC5 ADC6
+ADC7 ADC8 ADC9 BMCINT DDCCLK DDCDAT ESPI FWSPICS1 FWSPICS2 GPID0 GPID2 GPID4
+GPID6 GPIE0 GPIE2 GPIE4 GPIE6 I2C10 I2C11 I2C12 I2C13 I2C14 I2C3 I2C4 I2C5 I2C6
+I2C7 I2C8 I2C9 LAD0 LAD1 LAD2 LAD3 LCLK LFRAME LPCHC LPCPD LPCPLUS LPCPME
+LPCRST LPCSMI LSIRQ MAC1LINK MAC2LINK MDIO1 MDIO2 NCTS1 NCTS2 NCTS3 NCTS4 NDCD1
+NDCD2 NDCD3 NDCD4 NDSR1 NDSR2 NDSR3 NDSR4 NDTR1 NDTR2 NDTR3 NDTR4 NRI1 NRI2
+NRI3 NRI4 NRTS1 NRTS2 NRTS3 NRTS4 OSCCLK PEWAKE PNOR PWM0 PWM1 PWM2 PWM3 PWM4
+PWM5 PWM6 PWM7 RGMII1 RGMII2 RMII1 RMII2 RXD1 RXD2 RXD3 RXD4 SALT1 SALT10
+SALT11 SALT12 SALT13 SALT14 SALT2 SALT3 SALT4 SALT5 SALT6 SALT7 SALT8 SALT9
+SCL1 SCL2 SD1 SD2 SDA1 SDA2 SGPS1 SGPS2 SIOONCTRL SIOPBI SIOPBO SIOPWREQ
+SIOPWRGD SIOS3 SIOS5 SIOSCI SPI1 SPI1CS1 SPI1DEBUG SPI1PASSTHRU SPI2CK SPI2CS0
+SPI2CS1 SPI2MISO SPI2MOSI TIMER3 TIMER4 TIMER5 TIMER6 TIMER7 TIMER8 TXD1 TXD2
+TXD3 TXD4 UART6 USBCKI VGABIOSROM VGAHS VGAVS VPI24 VPO WDTRST1 WDTRST2
+
+Examples
+========
+
+g4 Example
+----------
 
 syscon: scu@1e6e2000 {
-       compatible = "syscon", "simple-mfd";
+       compatible = "aspeed,ast2400-scu", "syscon", "simple-mfd";
        reg = <0x1e6e2000 0x1a8>;
 
        pinctrl: pinctrl {
@@ -63,5 +93,56 @@ syscon: scu@1e6e2000 {
        };
 };
 
+g5 Example
+----------
+
+ahb {
+       apb {
+               syscon: scu@1e6e2000 {
+                       compatible = "aspeed,ast2500-scu", "syscon", "simple-mfd";
+                       reg = <0x1e6e2000 0x1a8>;
+
+                       pinctrl: pinctrl {
+                               compatible = "aspeed,g5-pinctrl";
+                               aspeed,external-nodes = <&gfx &lhc>;
+
+                               pinctrl_i2c3_default: i2c3_default {
+                                       function = "I2C3";
+                                       groups = "I2C3";
+                               };
+                       };
+               };
+
+               gfx: display@1e6e6000 {
+                       compatible = "aspeed,ast2500-gfx", "syscon";
+                       reg = <0x1e6e6000 0x1000>;
+               };
+       };
+
+       lpc: lpc@1e789000 {
+               compatible = "aspeed,ast2500-lpc", "simple-mfd";
+               reg = <0x1e789000 0x1000>;
+
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0x0 0x1e789000 0x1000>;
+
+               lpc_host: lpc-host@80 {
+                       compatible = "aspeed,ast2500-lpc-host", "simple-mfd", "syscon";
+                       reg = <0x80 0x1e0>;
+                       reg-io-width = <4>;
+
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x80 0x1e0>;
+
+                       lhc: lhc@20 {
+                              compatible = "aspeed,ast2500-lhc";
+                              reg = <0x20 0x24 0x48 0x8>;
+                       };
+               };
+       };
+};
+
 Please refer to pinctrl-bindings.txt in this directory for details of the
 common pinctrl bindings used by client devices.
index 1baf19eecabf982d62be1458ea26af8dd7ef8148..5e00a21de2bfb82fd0e4c6a0c09688b53691b78a 100644 (file)
@@ -13,6 +13,7 @@ Required Properties:
   - "samsung,s3c2450-pinctrl": for S3C2450-compatible pin-controller,
   - "samsung,s3c64xx-pinctrl": for S3C64xx-compatible pin-controller,
   - "samsung,s5pv210-pinctrl": for S5PV210-compatible pin-controller,
+  - "samsung,exynos3250-pinctrl": for Exynos3250 compatible pin-controller.
   - "samsung,exynos4210-pinctrl": for Exynos4210 compatible pin-controller.
   - "samsung,exynos4x12-pinctrl": for Exynos4x12 compatible pin-controller.
   - "samsung,exynos5250-pinctrl": for Exynos5250 compatible pin-controller.
index b24583aa34c3bf45363e3eee4ceac292d713b67d..eac20aa33907a647377571995cb3f863dc8df27d 100644 (file)
@@ -8,8 +8,9 @@ controllers onto these pads.
 Pin controller node:
 Required properies:
  - compatible: value should be one of the following:
-   (a) "st,stm32f429-pinctrl"
-   (b) "st,stm32f746-pinctrl"
+   "st,stm32f429-pinctrl"
+   "st,stm32f746-pinctrl"
+   "st,stm32h743-pinctrl"
  - #address-cells: The value of this property must be 1
  - #size-cells : The value of this property must be 1
  - ranges      : defines mapping between pin controller node (parent) to
@@ -37,8 +38,23 @@ Optional properties:
  - st,syscfg: Should be phandle/offset pair. The phandle to the syscon node
    which includes IRQ mux selection register, and the offset of the IRQ mux
    selection register.
+ - ngpios: Number of gpios in a bank (to use if bank gpio numbers is less
+   than 16).
+ - gpio-ranges: Define a dedicated mapping between a pin-controller and
+   a gpio controller. Format is <&phandle a b c> with:
+       -(phandle): phandle of pin-controller.
+       -(a): gpio base offset in range.
+       -(b): pin base offset in range.
+       -(c): gpio count in range
+   This entry has to be used either if there are holes inside a bank:
+       GPIOB0/B1/B2/B14/B15 (see example 2)
+   or if banks are not contiguous:
+       GPIOA/B/C/E...
+   NOTE: If "gpio-ranges" is used for a gpio controller, all gpio-controller
+   have to use a "gpio-ranges" entry.
+   More details in Documentation/devicetree/bindings/gpio/gpio.txt.
 
-Example:
+Example 1:
 #include <dt-bindings/pinctrl/stm32f429-pinfunc.h>
 ...
 
@@ -60,6 +76,43 @@ Example:
                pin-functions nodes follow...
        };
 
+Example 2:
+#include <dt-bindings/pinctrl/stm32f429-pinfunc.h>
+...
+
+       pinctrl: pin-controller {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "st,stm32f429-pinctrl";
+               ranges = <0 0x40020000 0x3000>;
+               pins-are-numbered;
+
+               gpioa: gpio@40020000 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       reg = <0x0 0x400>;
+                       resets = <&reset_ahb1 0>;
+                       st,bank-name = "GPIOA";
+                       gpio-ranges = <&pinctrl 0 0 16>;
+               };
+
+               gpiob: gpio@40020400 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       reg = <0x0 0x400>;
+                       resets = <&reset_ahb1 0>;
+                       st,bank-name = "GPIOB";
+                       ngpios = 4;
+                       gpio-ranges = <&pinctrl 0 16 3>,
+                                     <&pinctrl 14 30 2>;
+               };
+
+
+               ...
+               pin-functions nodes follow...
+       };
+
+
 Contents of function subnode node:
 ----------------------------------
 Subnode format
diff --git a/Documentation/devicetree/bindings/pinctrl/ti,iodelay.txt b/Documentation/devicetree/bindings/pinctrl/ti,iodelay.txt
new file mode 100644 (file)
index 0000000..c3ed123
--- /dev/null
@@ -0,0 +1,47 @@
+* Pin configuration for TI IODELAY controller
+
+TI dra7 based SoCs such as am57xx have a controller for setting the IO delay
+for each pin. For most part the IO delay values are programmed by the bootloader,
+but some pins need to be configured dynamically by the kernel such as the
+MMC pins.
+
+Required Properties:
+
+  - compatible: Must be "ti,dra7-iodelay"
+  - reg: Base address and length of the memory resource used
+  - #address-cells: Number of address cells
+  - #size-cells: Size of cells
+  - #pinctrl-cells: Number of pinctrl cells, must be 2. See also
+    Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
+
+Example
+-------
+
+In the SoC specific dtsi file:
+
+       dra7_iodelay_core: padconf@4844a000 {
+               compatible = "ti,dra7-iodelay";
+               reg = <0x4844a000 0x0d1c>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               #pinctrl-cells = <2>;
+       };
+
+In board-specific file:
+
+&dra7_iodelay_core {
+       mmc2_iodelay_3v3_conf: mmc2_iodelay_3v3_conf {
+               pinctrl-pin-array = <
+               0x18c A_DELAY_PS(0) G_DELAY_PS(120)     /* CFG_GPMC_A19_IN */
+               0x1a4 A_DELAY_PS(265) G_DELAY_PS(360)   /* CFG_GPMC_A20_IN */
+               0x1b0 A_DELAY_PS(0) G_DELAY_PS(120)     /* CFG_GPMC_A21_IN */
+               0x1bc A_DELAY_PS(0) G_DELAY_PS(120)     /* CFG_GPMC_A22_IN */
+               0x1c8 A_DELAY_PS(287) G_DELAY_PS(420)   /* CFG_GPMC_A23_IN */
+               0x1d4 A_DELAY_PS(144) G_DELAY_PS(240)   /* CFG_GPMC_A24_IN */
+               0x1e0 A_DELAY_PS(0) G_DELAY_PS(0)       /* CFG_GPMC_A25_IN */
+               0x1ec A_DELAY_PS(120) G_DELAY_PS(0)     /* CFG_GPMC_A26_IN */
+               0x1f8 A_DELAY_PS(120) G_DELAY_PS(180)   /* CFG_GPMC_A27_IN */
+               0x360 A_DELAY_PS(0) G_DELAY_PS(0)       /* CFG_GPMC_CS1_IN */
+               >;
+       };
+};
index 37c4ea076f88e694b773a6233e37c8dd68dc5192..1d58c8cfdbc01d8fffad426774dd730a987af2d1 100644 (file)
@@ -14,6 +14,7 @@ Optional properties:
 - anatop-delay-bit-shift: Bit shift for the step time register
 - anatop-delay-bit-width: Number of bits used in the step time register
 - vin-supply: The supply for this regulator
+- anatop-enable-bit: Regulator enable bit offset
 
 Any property defined as part of the core regulator
 binding, defined in regulator.txt, can also be used.
diff --git a/Documentation/devicetree/bindings/regulator/cpcap-regulator.txt b/Documentation/devicetree/bindings/regulator/cpcap-regulator.txt
new file mode 100644 (file)
index 0000000..675f443
--- /dev/null
@@ -0,0 +1,34 @@
+Motorola CPCAP PMIC voltage regulators
+------------------------------------
+
+Requires node properties:
+- "compatible" value one of:
+    "motorola,cpcap-regulator"
+    "motorola,mapphone-cpcap-regulator"
+
+Required regulator properties:
+- "regulator-name"
+- "regulator-enable-ramp-delay"
+- "regulator-min-microvolt"
+- "regulator-max-microvolt"
+
+Optional regulator properties:
+- "regulator-boot-on"
+
+See Documentation/devicetree/bindings/regulator/regulator.txt
+for more details about the regulator properties.
+
+Example:
+
+cpcap_regulator: regulator {
+       compatible = "motorola,cpcap-regulator";
+
+       cpcap_regulators: regulators {
+               sw5: SW5 {
+                       regulator-min-microvolt = <5050000>;
+                       regulator-max-microvolt = <5050000>;
+                       regulator-enable-ramp-delay = <50000>;
+                       regulator-boot-on;
+               };
+       };
+};
index e5cac1e0ca8a734d43549ad125a837beef457e13..dd1ed789728e0702a1d1d39aecf223fc1f22ef71 100644 (file)
@@ -13,7 +13,7 @@ Optional properties:
 - startup-delay-us     : Startup time in microseconds.
 - enable-active-high   : Polarity of GPIO is active high (default is low).
 - regulator-type       : Specifies what is being regulated, must be either
-                         "voltage" or "current", defaults to current.
+                         "voltage" or "current", defaults to voltage.
 
 Any property defined as part of the core regulator binding defined in
 regulator.txt can also be used.
index 1f8d6f84b657d3f63257b9f0d999ba07732cbff0..4e3dfb5b5f1661b60784f86ef2a835b61a1ca8bc 100644 (file)
@@ -22,6 +22,7 @@ Regulator nodes are identified by their compatible:
                    "qcom,rpm-pm8841-regulators"
                    "qcom,rpm-pm8916-regulators"
                    "qcom,rpm-pm8941-regulators"
+                   "qcom,rpm-pm8994-regulators"
                    "qcom,rpm-pma8084-regulators"
 
 - vdd_s1-supply:
@@ -68,6 +69,56 @@ Regulator nodes are identified by their compatible:
        Definition: reference to regulator supplying the input pin, as
                    described in the data sheet
 
+- vdd_s1-supply:
+- vdd_s2-supply:
+- vdd_s3-supply:
+- vdd_s4-supply:
+- vdd_s5-supply:
+- vdd_s6-supply:
+- vdd_s7-supply:
+- vdd_s8-supply:
+- vdd_s9-supply:
+- vdd_s10-supply:
+- vdd_s11-supply:
+- vdd_s12-supply:
+- vdd_l1-supply:
+- vdd_l2_l26_l28-supply:
+- vdd_l3_l11-supply:
+- vdd_l4_l27_l31-supply:
+- vdd_l5_l7-supply:
+- vdd_l6_l12_l32-supply:
+- vdd_l5_l7-supply:
+- vdd_l8_l16_l30-supply:
+- vdd_l9_l10_l18_l22-supply:
+- vdd_l9_l10_l18_l22-supply:
+- vdd_l3_l11-supply:
+- vdd_l6_l12_l32-supply:
+- vdd_l13_l19_l23_l24-supply:
+- vdd_l14_l15-supply:
+- vdd_l14_l15-supply:
+- vdd_l8_l16_l30-supply:
+- vdd_l17_l29-supply:
+- vdd_l9_l10_l18_l22-supply:
+- vdd_l13_l19_l23_l24-supply:
+- vdd_l20_l21-supply:
+- vdd_l20_l21-supply:
+- vdd_l9_l10_l18_l22-supply:
+- vdd_l13_l19_l23_l24-supply:
+- vdd_l13_l19_l23_l24-supply:
+- vdd_l25-supply:
+- vdd_l2_l26_l28-supply:
+- vdd_l4_l27_l31-supply:
+- vdd_l2_l26_l28-supply:
+- vdd_l17_l29-supply:
+- vdd_l8_l16_l30-supply:
+- vdd_l4_l27_l31-supply:
+- vdd_l6_l12_l32-supply:
+- vdd_lvs1_2-supply:
+       Usage: optional (pm8994 only)
+       Value type: <phandle>
+       Definition: reference to regulator supplying the input pin, as
+                   described in the data sheet
+
 - vdd_s1-supply:
 - vdd_s2-supply:
 - vdd_s3-supply:
@@ -113,6 +164,11 @@ pm8941:
        l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, lvs1, lvs2,
        lvs3, 5vs1, 5vs2
 
+pm8994:
+       s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, l1, l2, l3, l4, l5,
+       l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19, l20,
+       l21, l22, l23, l24, l25, l26, l27, l28, l29, l30, l31, l32, lvs1, lvs2
+
 pma8084:
        s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, l1, l2, l3, l4, l5,
        l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19, l20,
diff --git a/Documentation/devicetree/bindings/spi/spi-lantiq-ssc.txt b/Documentation/devicetree/bindings/spi/spi-lantiq-ssc.txt
new file mode 100644 (file)
index 0000000..6069b95
--- /dev/null
@@ -0,0 +1,29 @@
+Lantiq Synchronous Serial Controller (SSC) SPI master driver
+
+Required properties:
+- compatible: "lantiq,ase-spi", "lantiq,falcon-spi", "lantiq,xrx100-spi"
+- #address-cells: see spi-bus.txt
+- #size-cells: see spi-bus.txt
+- reg: address and length of the spi master registers
+- interrupts: should contain the "spi_rx", "spi_tx" and "spi_err" interrupt.
+
+
+Optional properties:
+- clocks: spi clock phandle
+- num-cs: see spi-bus.txt, set to 8 if unset
+- base-cs: the number of the first chip select, set to 1 if unset.
+
+Example:
+
+
+spi: spi@E100800 {
+       compatible = "lantiq,xrx200-spi", "lantiq,xrx100-spi";
+       reg = <0xE100800 0x100>;
+       interrupt-parent = <&icu0>;
+       interrupts = <22 23 24>;
+       interrupt-names = "spi_rx", "spi_tx", "spi_err";
+       #address-cells = <1>;
+       #size-cells = <1>;
+       num-cs = <6>;
+       base-cs = <1>;
+};
index d2ca153614f912fcd06cca8e1e65090030eba96e..83da4931d832688f51e19a56aaa03af8482e721a 100644 (file)
@@ -31,6 +31,10 @@ Optional Properties:
 - rx-sample-delay-ns: nanoseconds to delay after the SCLK edge before sampling
                Rx data (may need to be fine tuned for high capacitance lines).
                No delay (0) by default.
+- pinctrl-names: Names for the pin configuration(s); may be "default" or
+               "sleep", where the "sleep" configuration may describe the state
+               the pins should be in during system suspend. See also
+               pinctrl/pinctrl-bindings.txt.
 
 
 Example:
@@ -46,4 +50,7 @@ Example:
                interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&cru SCLK_SPI0>, <&cru PCLK_SPI0>;
                clock-names = "spiclk", "apb_pclk";
+               pinctrl-0 = <&spi1_pins>;
+               pinctrl-1 = <&spi1_sleep>;
+               pinctrl-names = "default", "sleep";
        };
index 747c721776ed07fac9f329e0c2990a4fe732d24c..ad8f0c0cd13fe351d646deacec7a7d2d148c4664 100644 (file)
@@ -146,10 +146,11 @@ a pull-up resistor is needed on the outgoing rail to complete the circuit, and
 in the second case, a pull-down resistor is needed on the rail.
 
 Hardware that supports open drain or open source or both, can implement a
-special callback in the gpio_chip: .set_single_ended() that takes an enum flag
-telling whether to configure the line as open drain, open source or push-pull.
-This will happen in response to the GPIO_OPEN_DRAIN or GPIO_OPEN_SOURCE flag
-set in the machine file, or coming from other hardware descriptions.
+special callback in the gpio_chip: .set_config() that takes a generic
+pinconf packed value telling whether to configure the line as open drain,
+open source or push-pull. This will happen in response to the
+GPIO_OPEN_DRAIN or GPIO_OPEN_SOURCE flag set in the machine file, or coming
+from other hardware descriptions.
 
 If this state can not be configured in hardware, i.e. if the GPIO hardware does
 not support open drain/open source in hardware, the GPIO library will instead
index f1f7ec9f5cc555630040640cbbc7d55b5dedaffa..836cb16d6f09fe4b70b0ad16585ddcdb6f455336 100644 (file)
@@ -65,6 +65,21 @@ LED subsystem core exposes following API for setting brightness:
                blinking, returns -EBUSY if software blink fallback is enabled.
 
 
+LED registration API
+====================
+
+A driver wanting to register a LED classdev for use by other drivers /
+userspace needs to allocate and fill a led_classdev struct and then call
+[devm_]led_classdev_register. If the non devm version is used the driver
+must call led_classdev_unregister from its remove function before
+free-ing the led_classdev struct.
+
+If the driver can detect hardware initiated brightness changes and thus
+wants to have a brightness_hw_changed attribute then the LED_BRIGHT_HW_CHANGED
+flag must be set in flags before registering. Calling
+led_classdev_notify_brightness_hw_changed on a classdev not registered with
+the LED_BRIGHT_HW_CHANGED flag is a bug and will trigger a WARN_ON.
+
 Hardware accelerated blink of LEDs
 ==================================
 
index 1a738e5f6056cc7ec8225eb31dbd2f99e36301af..0c05503eaf1fa6c7c0a109cfac1460cc0c4afe2b 100644 (file)
@@ -162,13 +162,13 @@ framework provides a depth-first graph traversal API for that purpose.
    currently defined as 16.
 
 Drivers initiate a graph traversal by calling
-:c:func:`media_entity_graph_walk_start()`
+:c:func:`media_graph_walk_start()`
 
 The graph structure, provided by the caller, is initialized to start graph
 traversal at the given entity.
 
 Drivers can then retrieve the next entity by calling
-:c:func:`media_entity_graph_walk_next()`
+:c:func:`media_graph_walk_next()`
 
 When the graph traversal is complete the function will return ``NULL``.
 
@@ -206,7 +206,7 @@ Pipelines and media streams
 
 When starting streaming, drivers must notify all entities in the pipeline to
 prevent link states from being modified during streaming by calling
-:c:func:`media_entity_pipeline_start()`.
+:c:func:`media_pipeline_start()`.
 
 The function will mark all entities connected to the given entity through
 enabled links, either directly or indirectly, as streaming.
@@ -218,17 +218,17 @@ in higher-level pipeline structures and can then access the
 pipeline through the struct :c:type:`media_entity`
 pipe field.
 
-Calls to :c:func:`media_entity_pipeline_start()` can be nested.
+Calls to :c:func:`media_pipeline_start()` can be nested.
 The pipeline pointer must be identical for all nested calls to the function.
 
-:c:func:`media_entity_pipeline_start()` may return an error. In that case,
+:c:func:`media_pipeline_start()` may return an error. In that case,
 it will clean up any of the changes it did by itself.
 
 When stopping the stream, drivers must notify the entities with
-:c:func:`media_entity_pipeline_stop()`.
+:c:func:`media_pipeline_stop()`.
 
-If multiple calls to :c:func:`media_entity_pipeline_start()` have been
-made the same number of :c:func:`media_entity_pipeline_stop()` calls
+If multiple calls to :c:func:`media_pipeline_start()` have been
+made the same number of :c:func:`media_pipeline_stop()` calls
 are required to stop streaming.
 The :c:type:`media_entity`.\ ``pipe`` field is reset to ``NULL`` on the last
 nested stop call.
@@ -245,7 +245,7 @@ operation must be done with the media_device graph_mutex held.
 Link validation
 ^^^^^^^^^^^^^^^
 
-Link validation is performed by :c:func:`media_entity_pipeline_start()`
+Link validation is performed by :c:func:`media_pipeline_start()`
 for any entity which has sink pads in the pipeline. The
 :c:type:`media_entity`.\ ``link_validate()`` callback is used for that
 purpose. In ``link_validate()`` callback, entity driver should check
index 6e983b9880fce2df7112e7f3b14365057a6db3da..d39e34d1b19dd09e3e994927341294c52dc688b1 100644 (file)
@@ -94,9 +94,17 @@ Generic Error Codes
        -  Permission denied. Can be returned if the device needs write
          permission, or some special capabilities is needed (e. g. root)
 
+    -  .. row 11
+
+       -  ``EIO``
+
+       -  I/O error. Typically used when there are problems communicating with
+          a hardware device. This could indicate broken or flaky hardware.
+         It's a 'Something is wrong, I give up!' type of error.
+
 .. note::
 
-  #. This list is not exaustive; ioctls may return other error codes.
+  #. This list is not exhaustive; ioctls may return other error codes.
      Since errors may have side effects such as a driver reset,
      applications should abort on unexpected errors, or otherwise
      assume that the device is in a bad state.
index 6fb944fe21fdb49e4c8b72887e759a557f03b749..3476ae29708f7e4068bbb5166c5d6ee66ef29e16 100644 (file)
@@ -92,15 +92,16 @@ This value may be reset to 0 if the current protocol is altered.
 Reading this file returns a list of available protocols to use for the
 wakeup filter, something like:
 
-``rc5 rc6 nec jvc [sony]``
+``rc-5 nec nec-x rc-6-0 rc-6-6a-24 [rc-6-6a-32] rc-6-mce``
 
-The enabled wakeup protocol is shown in [] brackets.
+Note that protocol variants are listed, so "nec", "sony", "rc-5", "rc-6"
+have their different bit length encodings listed if available.
 
-Writing "+proto" will add a protocol to the list of enabled wakeup
-protocols.
+Note that all protocol variants are listed.
 
-Writing "-proto" will remove a protocol from the list of enabled wakeup
-protocols.
+The enabled wakeup protocol is shown in [] brackets.
+
+Only one protocol can be selected at a time.
 
 Writing "proto" will use "proto" for wakeup events.
 
index 0d3b9ce0a0b90575fbeff83bec518139ae609154..54bd5faa8782258f72b134f1aaca684c15a00eb6 100644 (file)
@@ -79,9 +79,7 @@ int __init foo_probe(void)
 {
        struct pinctrl_dev *pctl;
 
-       pctl = pinctrl_register(&foo_desc, <PARENT>, NULL);
-       if (!pctl)
-               pr_err("could not register foo pin driver\n");
+       return pinctrl_register_and_init(&foo_desc, <PARENT>, NULL, &pctl);
 }
 
 To enable the pinctrl subsystem and the subgroups for PINMUX and PINCONF and
index c6279c2be47c20116dc56590b450f56a96a1ad5b..0c007e250cd1f9a38de0ebe6ced205fe6d9378d4 100644 (file)
@@ -79,22 +79,6 @@ dependent subsystems such as cpufreq are left to the discretion of the SoC
 specific framework which uses the OPP library. Similar care needs to be taken
 care to refresh the cpufreq table in cases of these operations.
 
-WARNING on OPP List locking mechanism:
--------------------------------------------------
-OPP library uses RCU for exclusivity. RCU allows the query functions to operate
-in multiple contexts and this synchronization mechanism is optimal for a read
-intensive operations on data structure as the OPP library caters to.
-
-To ensure that the data retrieved are sane, the users such as SoC framework
-should ensure that the section of code operating on OPP queries are locked
-using RCU read locks. The opp_find_freq_{exact,ceil,floor},
-opp_get_{voltage, freq, opp_count} fall into this category.
-
-opp_{add,enable,disable} are updaters which use mutex and implement it's own
-RCU locking mechanisms. These functions should *NOT* be called under RCU locks
-and other contexts that prevent blocking functions in RCU or mutex operations
-from working.
-
 2. Initial OPP List Registration
 ================================
 The SoC implementation calls dev_pm_opp_add function iteratively to add OPPs per
@@ -137,15 +121,18 @@ functions return the matching pointer representing the opp if a match is
 found, else returns error. These errors are expected to be handled by standard
 error checks such as IS_ERR() and appropriate actions taken by the caller.
 
+Callers of these functions shall call dev_pm_opp_put() after they have used the
+OPP. Otherwise the memory for the OPP will never get freed and result in
+memleak.
+
 dev_pm_opp_find_freq_exact - Search for an OPP based on an *exact* frequency and
        availability. This function is especially useful to enable an OPP which
        is not available by default.
        Example: In a case when SoC framework detects a situation where a
        higher frequency could be made available, it can use this function to
        find the OPP prior to call the dev_pm_opp_enable to actually make it available.
-        rcu_read_lock();
         opp = dev_pm_opp_find_freq_exact(dev, 1000000000, false);
-        rcu_read_unlock();
+        dev_pm_opp_put(opp);
         /* dont operate on the pointer.. just do a sanity check.. */
         if (IS_ERR(opp)) {
                pr_err("frequency not disabled!\n");
@@ -163,9 +150,8 @@ dev_pm_opp_find_freq_floor - Search for an available OPP which is *at most* the
        frequency.
        Example: To find the highest opp for a device:
         freq = ULONG_MAX;
-        rcu_read_lock();
-        dev_pm_opp_find_freq_floor(dev, &freq);
-        rcu_read_unlock();
+        opp = dev_pm_opp_find_freq_floor(dev, &freq);
+        dev_pm_opp_put(opp);
 
 dev_pm_opp_find_freq_ceil - Search for an available OPP which is *at least* the
        provided frequency. This function is useful while searching for a
@@ -173,17 +159,15 @@ dev_pm_opp_find_freq_ceil - Search for an available OPP which is *at least* the
        frequency.
        Example 1: To find the lowest opp for a device:
         freq = 0;
-        rcu_read_lock();
-        dev_pm_opp_find_freq_ceil(dev, &freq);
-        rcu_read_unlock();
+        opp = dev_pm_opp_find_freq_ceil(dev, &freq);
+        dev_pm_opp_put(opp);
        Example 2: A simplified implementation of a SoC cpufreq_driver->target:
         soc_cpufreq_target(..)
         {
                /* Do stuff like policy checks etc. */
                /* Find the best frequency match for the req */
-               rcu_read_lock();
                opp = dev_pm_opp_find_freq_ceil(dev, &freq);
-               rcu_read_unlock();
+               dev_pm_opp_put(opp);
                if (!IS_ERR(opp))
                        soc_switch_to_freq_voltage(freq);
                else
@@ -208,9 +192,8 @@ dev_pm_opp_enable - Make a OPP available for operation.
        implementation might choose to do something as follows:
         if (cur_temp < temp_low_thresh) {
                /* Enable 1GHz if it was disabled */
-               rcu_read_lock();
                opp = dev_pm_opp_find_freq_exact(dev, 1000000000, false);
-               rcu_read_unlock();
+               dev_pm_opp_put(opp);
                /* just error check */
                if (!IS_ERR(opp))
                        ret = dev_pm_opp_enable(dev, 1000000000);
@@ -224,9 +207,8 @@ dev_pm_opp_disable - Make an OPP to be not available for operation
        choose to do something as follows:
         if (cur_temp > temp_high_thresh) {
                /* Disable 1GHz if it was enabled */
-               rcu_read_lock();
                opp = dev_pm_opp_find_freq_exact(dev, 1000000000, true);
-               rcu_read_unlock();
+               dev_pm_opp_put(opp);
                /* just error check */
                if (!IS_ERR(opp))
                        ret = dev_pm_opp_disable(dev, 1000000000);
@@ -249,10 +231,9 @@ dev_pm_opp_get_voltage - Retrieve the voltage represented by the opp pointer.
         soc_switch_to_freq_voltage(freq)
         {
                /* do things */
-               rcu_read_lock();
                opp = dev_pm_opp_find_freq_ceil(dev, &freq);
                v = dev_pm_opp_get_voltage(opp);
-               rcu_read_unlock();
+               dev_pm_opp_put(opp);
                if (v)
                        regulator_set_voltage(.., v);
                /* do other things */
@@ -266,12 +247,12 @@ dev_pm_opp_get_freq - Retrieve the freq represented by the opp pointer.
         {
                /* do things.. */
                 max_freq = ULONG_MAX;
-                rcu_read_lock();
                 max_opp = dev_pm_opp_find_freq_floor(dev,&max_freq);
                 requested_opp = dev_pm_opp_find_freq_ceil(dev,&freq);
                 if (!IS_ERR(max_opp) && !IS_ERR(requested_opp))
                        r = soc_test_validity(max_opp, requested_opp);
-                rcu_read_unlock();
+                dev_pm_opp_put(max_opp);
+                dev_pm_opp_put(requested_opp);
                /* do other things */
         }
         soc_test_validity(..)
@@ -289,7 +270,6 @@ dev_pm_opp_get_opp_count - Retrieve the number of available opps for a device
         soc_notify_coproc_available_frequencies()
         {
                /* Do things */
-               rcu_read_lock();
                num_available = dev_pm_opp_get_opp_count(dev);
                speeds = kzalloc(sizeof(u32) * num_available, GFP_KERNEL);
                /* populate the table in increasing order */
@@ -298,8 +278,8 @@ dev_pm_opp_get_opp_count - Retrieve the number of available opps for a device
                        speeds[i] = freq;
                        freq++;
                        i++;
+                       dev_pm_opp_put(opp);
                }
-               rcu_read_unlock();
 
                soc_notify_coproc(AVAILABLE_FREQs, speeds, num_available);
                /* Do other things */
index 008ecb588317bc1d354bb5f50513605d6154237c..bc4548245a2431349b3d24655ab3b73794b7a10a 100644 (file)
@@ -25,7 +25,7 @@ to be used subsequently to change to the one represented by that string.
 Consequently, there are two ways to cause the system to go into the
 Suspend-To-Idle sleep state.  The first one is to write "freeze" directly to
 /sys/power/state.  The second one is to write "s2idle" to /sys/power/mem_sleep
-and then to wrtie "mem" to /sys/power/state.  Similarly, there are two ways
+and then to write "mem" to /sys/power/state.  Similarly, there are two ways
 to cause the system to go into the Power-On Suspend sleep state (the strings to
 write to the control files in that case are "standby" or "shallow" and "mem",
 respectively) if that state is supported by the platform.  In turn, there is
index 3db7e671c440050a4046fbd5263e7b1b4959f9b9..c2683f28ed367b51118a81c37be8ab696743dda4 100644 (file)
@@ -22,6 +22,13 @@ system, building their checks on top of the defined capability hooks.
 For more details on capabilities, see capabilities(7) in the Linux
 man-pages project.
 
+A list of the active security modules can be found by reading
+/sys/kernel/security/lsm. This is a comma separated list, and
+will always include the capability module. The list reflects the
+order in which checks are made. The capability module will always
+be first, followed by any "minor" modules (e.g. Yama) and then
+the one "major" module (e.g. SELinux) if there is one configured.
+
 Based on https://lkml.org/lkml/2007/10/26/215,
 a new LSM is accepted into the kernel when its intent (a description of
 what it tries to protect against and in what cases one would expect to
diff --git a/Documentation/spi/ep93xx_spi b/Documentation/spi/ep93xx_spi
deleted file mode 100644 (file)
index 832ddce..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-Cirrus EP93xx SPI controller driver HOWTO
-=========================================
-
-ep93xx_spi driver brings SPI master support for EP93xx SPI controller.  Chip
-selects are implemented with GPIO lines.
-
-NOTE: If possible, don't use SFRMOUT (SFRM1) signal as a chip select. It will
-not work correctly (it cannot be controlled by software). Use GPIO lines
-instead.
-
-Sample configuration
-====================
-
-Typically driver configuration is done in platform board files (the files under
-arch/arm/mach-ep93xx/*.c). In this example we configure MMC over SPI through
-this driver on TS-7260 board. You can adapt the code to suit your needs.
-
-This example uses EGPIO9 as SD/MMC card chip select (this is wired in DIO1
-header on the board).
-
-You need to select CONFIG_MMC_SPI to use mmc_spi driver.
-
-arch/arm/mach-ep93xx/ts72xx.c:
-
-...
-#include <linux/gpio.h>
-#include <linux/spi/spi.h>
-
-#include <linux/platform_data/spi-ep93xx.h>
-
-/* this is our GPIO line used for chip select */
-#define MMC_CHIP_SELECT_GPIO EP93XX_GPIO_LINE_EGPIO9
-
-static int ts72xx_mmc_spi_setup(struct spi_device *spi)
-{
-       int err;
-
-       err = gpio_request(MMC_CHIP_SELECT_GPIO, spi->modalias);
-       if (err)
-               return err;
-
-       gpio_direction_output(MMC_CHIP_SELECT_GPIO, 1);
-
-       return 0;
-}
-
-static void ts72xx_mmc_spi_cleanup(struct spi_device *spi)
-{
-       gpio_set_value(MMC_CHIP_SELECT_GPIO, 1);
-       gpio_direction_input(MMC_CHIP_SELECT_GPIO);
-       gpio_free(MMC_CHIP_SELECT_GPIO);
-}
-
-static void ts72xx_mmc_spi_cs_control(struct spi_device *spi, int value)
-{
-       gpio_set_value(MMC_CHIP_SELECT_GPIO, value);
-}
-
-static struct ep93xx_spi_chip_ops ts72xx_mmc_spi_ops = {
-       .setup          = ts72xx_mmc_spi_setup,
-       .cleanup        = ts72xx_mmc_spi_cleanup,
-       .cs_control     = ts72xx_mmc_spi_cs_control,
-};
-
-static struct spi_board_info ts72xx_spi_devices[] __initdata = {
-       {
-               .modalias               = "mmc_spi",
-               .controller_data        = &ts72xx_mmc_spi_ops,
-               /*
-                * We use 10 MHz even though the maximum is 7.4 MHz. The driver
-                * will limit it automatically to max. frequency.
-                */
-               .max_speed_hz           = 10 * 1000 * 1000,
-               .bus_num                = 0,
-               .chip_select            = 0,
-               .mode                   = SPI_MODE_0,
-       },
-};
-
-static struct ep93xx_spi_info ts72xx_spi_info = {
-       .num_chipselect = ARRAY_SIZE(ts72xx_spi_devices),
-};
-
-static void __init ts72xx_init_machine(void)
-{
-       ...
-       ep93xx_register_spi(&ts72xx_spi_info, ts72xx_spi_devices,
-                           ARRAY_SIZE(ts72xx_spi_devices));
-}
-
-The driver can use DMA for the transfers also. In this case ts72xx_spi_info
-becomes:
-
-static struct ep93xx_spi_info ts72xx_spi_info = {
-       .num_chipselect = ARRAY_SIZE(ts72xx_spi_devices),
-       .use_dma        = true;
-};
-
-Note that CONFIG_EP93XX_DMA should be enabled as well.
-
-Thanks to
-=========
-Martin Guy, H. Hartley Sweeten and others who helped me during development of
-the driver. Simplemachines.it donated me a Sim.One board which I used testing
-the driver on EP9307.
index 6f39cf610ecfdf4387ce3eb68a3d70e1a49e6a9b..2f9f345a15b77f03f0a81c7ef61db9701a7c6bfd 100644 (file)
@@ -2423,6 +2423,14 @@ W:       https://linuxtv.org
 S:     Supported
 F:     drivers/media/platform/sti/bdisp
 
+DELTA ST MEDIA DRIVER
+M:     Hugues Fruchet <hugues.fruchet@st.com>
+L:     linux-media@vger.kernel.org
+T:     git git://linuxtv.org/media_tree.git
+W:     https://linuxtv.org
+S:     Supported
+F:     drivers/media/platform/sti/delta
+
 BEFS FILE SYSTEM
 M:     Luis de Bethencourt <luisbg@osg.samsung.com>
 M:     Salah Triki <salah.triki@gmail.com>
@@ -2692,6 +2700,13 @@ F:       drivers/irqchip/irq-brcmstb*
 F:     include/linux/bcm963xx_nvram.h
 F:     include/linux/bcm963xx_tag.h
 
+BROADCOM BMIPS CPUFREQ DRIVER
+M:     Markus Mayer <mmayer@broadcom.com>
+M:     bcm-kernel-feedback-list@broadcom.com
+L:     linux-pm@vger.kernel.org
+S:     Maintained
+F:     drivers/cpufreq/bmips-cpufreq.c
+
 BROADCOM TG3 GIGABIT ETHERNET DRIVER
 M:     Siva Reddy Kallam <siva.kallam@broadcom.com>
 M:     Prashant Sreedharan <prashant@broadcom.com>
@@ -5274,7 +5289,7 @@ M:        Jaegeuk Kim <jaegeuk@kernel.org>
 L:     linux-fsdevel@vger.kernel.org
 S:     Supported
 F:     fs/crypto/
-F:     include/linux/fscrypto.h
+F:     include/linux/fscrypt*.h
 
 F2FS FILE SYSTEM
 M:     Jaegeuk Kim <jaegeuk@kernel.org>
@@ -5731,16 +5746,6 @@ L:       linux-parisc@vger.kernel.org
 S:     Maintained
 F:     sound/parisc/harmony.*
 
-HD29L2 MEDIA DRIVER
-M:     Antti Palosaari <crope@iki.fi>
-L:     linux-media@vger.kernel.org
-W:     https://linuxtv.org
-W:     http://palosaari.fi/linux/
-Q:     http://patchwork.linuxtv.org/project/linux-media/list/
-T:     git git://linuxtv.org/anttip/media_tree.git
-S:     Maintained
-F:     drivers/media/dvb-frontends/hd29l2*
-
 HEWLETT PACKARD ENTERPRISE ILO NMI WATCHDOG DRIVER
 M:     Jimmy Vance <jimmy.vance@hpe.com>
 S:     Supported
@@ -7700,6 +7705,12 @@ W:       http://www.kernel.org/doc/man-pages
 L:     linux-man@vger.kernel.org
 S:     Maintained
 
+MARDUK (CREATOR CI40) DEVICE TREE SUPPORT
+M:     Rahul Bedarkar <rahul.bedarkar@imgtec.com>
+L:     linux-mips@linux-mips.org
+S:     Maintained
+F:     arch/mips/boot/dts/img/pistachio_marduk.dts
+
 MARVELL 88E6XXX ETHERNET SWITCH FABRIC DRIVER
 M:     Andrew Lunn <andrew@lunn.ch>
 M:     Vivien Didelot <vivien.didelot@savoirfairelinux.com>
@@ -8613,10 +8624,10 @@ S:      Maintained
 F:     drivers/net/ethernet/netronome/
 
 NETWORK BLOCK DEVICE (NBD)
-M:     Markus Pargmann <mpa@pengutronix.de>
+M:     Josef Bacik <jbacik@fb.com>
 S:     Maintained
+L:     linux-block@vger.kernel.org
 L:     nbd-general@lists.sourceforge.net
-T:     git git://git.pengutronix.de/git/mpa/linux-nbd.git
 F:     Documentation/blockdev/nbd.txt
 F:     drivers/block/nbd.c
 F:     include/uapi/linux/nbd.h
@@ -8812,6 +8823,22 @@ T:       git git://git.kernel.org/pub/scm/linux/kernel/git/lftan/nios2.git
 S:     Maintained
 F:     arch/nios2/
 
+NOKIA N900 CAMERA SUPPORT (ET8EK8 SENSOR, AD5820 FOCUS)
+M:     Pavel Machek <pavel@ucw.cz>
+M:     Sakari Ailus <sakari.ailus@iki.fi>
+L:     linux-media@vger.kernel.org
+S:     Maintained
+F:     drivers/media/i2c/et8ek8
+F:     drivers/media/i2c/ad5820.c
+
+NOKIA N900 CAMERA SUPPORT (ET8EK8 SENSOR, AD5820 FOCUS)
+M:     Pavel Machek <pavel@ucw.cz>
+M:     Sakari Ailus <sakari.ailus@iki.fi>
+L:     linux-media@vger.kernel.org
+S:     Maintained
+F:     drivers/media/i2c/et8ek8
+F:     drivers/media/i2c/ad5820.c
+
 NOKIA N900 POWER SUPPLY DRIVERS
 R:     Pali Rohár <pali.rohar@gmail.com>
 F:     include/linux/power/bq2415x_charger.h
@@ -9788,7 +9815,7 @@ L:      linux-mips@linux-mips.org
 S:      Maintained
 F:      arch/mips/pistachio/
 F:      arch/mips/include/asm/mach-pistachio/
-F:      arch/mips/boot/dts/pistachio/
+F:      arch/mips/boot/dts/img/pistachio*
 F:      arch/mips/configs/pistachio*_defconfig
 
 PKTCDVD DRIVER
@@ -10887,7 +10914,6 @@ SYNOPSYS DESIGNWARE MMC/SD/SDIO DRIVER
 M:     Jaehoon Chung <jh80.chung@samsung.com>
 L:     linux-mmc@vger.kernel.org
 S:     Maintained
-F:     include/linux/mmc/dw_mmc.h
 F:     drivers/mmc/host/dw_mmc*
 
 SYSTEM TRACE MODULE CLASS
@@ -11090,6 +11116,17 @@ L:     linux-mmc@vger.kernel.org
 S:     Maintained
 F:     drivers/mmc/host/sdhci-spear.c
 
+SECURE ENCRYPTING DEVICE (SED) OPAL DRIVER
+M:     Scott Bauer <scott.bauer@intel.com>
+M:     Jonathan Derrick <jonathan.derrick@intel.com>
+M:     Rafael Antognolli <rafael.antognolli@intel.com>
+L:     linux-block@vger.kernel.org
+S:     Supported
+F:     block/sed*
+F:     block/opal_proto.h
+F:     include/linux/sed*
+F:     include/uapi/linux/sed*
+
 SECURITY SUBSYSTEM
 M:     James Morris <james.l.morris@oracle.com>
 M:     "Serge E. Hallyn" <serge@hallyn.com>
@@ -13637,6 +13674,24 @@ L:     zd1211-devs@lists.sourceforge.net (subscribers-only)
 S:     Maintained
 F:     drivers/net/wireless/zydas/zd1211rw/
 
+ZD1301_DEMOD MEDIA DRIVER
+M:     Antti Palosaari <crope@iki.fi>
+L:     linux-media@vger.kernel.org
+W:     https://linuxtv.org/
+W:     http://palosaari.fi/linux/
+Q:     https://patchwork.linuxtv.org/project/linux-media/list/
+S:     Maintained
+F:     drivers/media/dvb-frontends/zd1301_demod*
+
+ZD1301 MEDIA DRIVER
+M:     Antti Palosaari <crope@iki.fi>
+L:     linux-media@vger.kernel.org
+W:     https://linuxtv.org/
+W:     http://palosaari.fi/linux/
+Q:     https://patchwork.linuxtv.org/project/linux-media/list/
+S:     Maintained
+F:     drivers/media/usb/dvb-usb-v2/zd1301*
+
 ZPOOL COMPRESSED PAGE STORAGE API
 M:     Dan Streetman <ddstreet@ieee.org>
 L:     linux-mm@kvack.org
index 3328af7c2776416d5182d61bdf332554d17b6cdc..af2994206b4b8ba2e367cbd92ea020ebae752f5a 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/sched.h>
 #include <linux/tty.h>
 #include <linux/delay.h>
-#include <linux/module.h>
+#include <linux/extable.h>
 #include <linux/kallsyms.h>
 #include <linux/ratelimit.h>
 
index 83e9eee57a55a165d57ffec0c6fe58c4b78300ea..47948b4dd1574ba5685aab4edef529dfb5bc0a4f 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/mman.h>
 #include <linux/smp.h>
 #include <linux/interrupt.h>
-#include <linux/module.h>
+#include <linux/extable.h>
 #include <linux/uaccess.h>
 
 extern void die_if_kernel(char *,struct pt_regs *,long, unsigned long *);
index aa652e28132407d5d6b0757cd8f81a96079da597..c86906b41bfe75c155755112059007e618f02464 100644 (file)
@@ -8,7 +8,8 @@
  * Borrowed heavily from MIPS
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/extable.h>
 #include <linux/uaccess.h>
 
 int fixup_exception(struct pt_regs *regs)
index e7d30f45b161ebb09f9d904f690638ec46c20ce7..6d37d9af5f1d79f1c972bb4e541626b0d92c6973 100644 (file)
                        };
 
                        vdoa@021e4000 {
+                               compatible = "fsl,imx6q-vdoa";
                                reg = <0x021e4000 0x4000>;
                                interrupts = <0 18 IRQ_TYPE_LEVEL_HIGH>;
+                               clocks = <&clks IMX6QDL_CLK_VDOA>;
                        };
 
                        uart2: serial@021e8000 {
index ace97e8576dbd9ae34d112b4aa8ec991647134e5..4c72dae2aefa00378e4dea9e72bc6004091bf09c 100644 (file)
 
                        status = "disabled";
                };
+
+               delta0 {
+                       compatible = "st,st-delta";
+                       clock-names = "delta",
+                                     "delta-st231",
+                                     "delta-flash-promip";
+                       clocks = <&clk_s_c0_flexgen CLK_VID_DMU>,
+                                <&clk_s_c0_flexgen CLK_ST231_DMU>,
+                                <&clk_s_c0_flexgen CLK_FLASH_PROMIP>;
+               };
        };
 };
index 79c415c33f693e9d6fb20389bac592aad3c62b66..809f0bf3042ae4ed90f069e68defd3b590044461 100644 (file)
@@ -24,7 +24,7 @@ CONFIG_ARM_APPENDED_DTB=y
 CONFIG_ARM_ATAG_DTB_COMPAT=y
 CONFIG_CMDLINE="root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC1,115200 init=/linuxrc mem=256M"
 CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPU_FREQ_STAT=y
 CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=m
 CONFIG_CPU_FREQ_GOV_USERSPACE=m
index 361686a362f1360a3d33182132c437cc120475a7..69a4bd13eea594352630cfcd81d9fae5b5ca385c 100644 (file)
@@ -58,7 +58,7 @@ CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_ARM_APPENDED_DTB=y
 CONFIG_ARM_ATAG_DTB_COMPAT=y
 CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPU_FREQ_STAT=y
 CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
 CONFIG_CPU_IDLE=y
 CONFIG_ARM_KIRKWOOD_CPUIDLE=y
index f57ec511e7ae41d8d3d35351b11a15d708f0647e..affffa7c415b327b6cb6c0930d241b5e742cd133 100644 (file)
@@ -132,7 +132,7 @@ CONFIG_ARM_ATAG_DTB_COMPAT=y
 CONFIG_KEXEC=y
 CONFIG_EFI=y
 CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPU_FREQ_STAT=y
 CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=m
 CONFIG_CPU_FREQ_GOV_USERSPACE=m
@@ -569,6 +569,7 @@ CONFIG_VIDEO_SAMSUNG_S5P_MFC=m
 CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC=m
 CONFIG_VIDEO_STI_BDISP=m
 CONFIG_VIDEO_STI_HVA=m
+CONFIG_VIDEO_STI_DELTA=m
 CONFIG_VIDEO_RENESAS_JPU=m
 CONFIG_VIDEO_RENESAS_VSP1=m
 CONFIG_V4L_TEST_DRIVERS=y
index f7f6039419aa916b659250a328d8f82c0cf22552..4b598da0d086eb1fe5da1cc2a62d0f81fd737834 100644 (file)
@@ -44,7 +44,7 @@ CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_ARM_APPENDED_DTB=y
 CONFIG_ARM_ATAG_DTB_COMPAT=y
 CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPU_FREQ_STAT=y
 CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
 CONFIG_CPU_IDLE=y
 CONFIG_ARM_KIRKWOOD_CPUIDLE=y
index e4314b1227a34cc2324e8aaf5e3cb43f28b78721..271dc7e78e439a2da4c2c1718521cae7a8904259 100644 (file)
@@ -97,7 +97,7 @@ CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="root=/dev/ram0 ro"
 CONFIG_KEXEC=y
 CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPU_FREQ_STAT=y
 CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=m
 CONFIG_CPU_FREQ_GOV_USERSPACE=m
index 1b0f8ae36fb30402b18d65b22e540978b147a2a8..adeaecd831a4d0ad8551918804f7760fd7e714f3 100644 (file)
@@ -38,7 +38,7 @@ CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_ARM_APPENDED_DTB=y
 CONFIG_KEXEC=y
 CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPU_FREQ_STAT=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
 CONFIG_CPU_FREQ_GOV_ONDEMAND=y
index aac3ab1a044fb10f961d54a9ae37588c2f652b72..df3ca38778afd63587e901d43fe2d5a9573c00f1 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/gpio/machine.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/leds.h>
 #include <linux/i2c.h>
 #include <linux/platform_data/at24.h>
 #include <linux/platform_data/pca953x.h>
index 521e409772654123ef852c778a85ccf09f94b8dd..023480b75244a263b35ec1550f2ac1194c2849a2 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/videodev2.h>
 #include <linux/v4l2-dv-timings.h>
 #include <linux/export.h>
+#include <linux/leds.h>
 
 #include <media/i2c/tvp514x.h>
 
index ad10017203c1a0ccac0382d5e1c3c81ac6ca7d4d..0a7838852649945bf634815db383c66fe536a5fc 100644 (file)
@@ -25,6 +25,7 @@
  */
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
+#include <linux/leds.h>
 #include <linux/mtd/partitions.h>
 #include <linux/platform_data/gpio-davinci.h>
 #include <linux/platform_data/i2c-davinci.h>
index 41d5500996b2d3f0da547c0725a5230f28c991f8..a3e78074be701a3a6abec03ff7e5586f79acfcbe 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/console.h>
+#include <linux/interrupt.h>
 #include <linux/gpio.h>
 #include <linux/gpio/machine.h>
 #include <linux/platform_data/gpio-davinci.h>
index ad92d9f7e4df3e09b305bb40520d58c081b27eb4..0ac176386789428be26631ad1c9f75ad343e8951 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/i2c-gpio.h>
 #include <linux/spi/spi.h>
@@ -106,33 +105,10 @@ static struct cs4271_platform_data edb93xx_cs4271_data = {
        .gpio_nreset    = -EINVAL,      /* filled in later */
 };
 
-static int edb93xx_cs4271_hw_setup(struct spi_device *spi)
-{
-       return gpio_request_one(EP93XX_GPIO_LINE_EGPIO6,
-                               GPIOF_OUT_INIT_HIGH, spi->modalias);
-}
-
-static void edb93xx_cs4271_hw_cleanup(struct spi_device *spi)
-{
-       gpio_free(EP93XX_GPIO_LINE_EGPIO6);
-}
-
-static void edb93xx_cs4271_hw_cs_control(struct spi_device *spi, int value)
-{
-       gpio_set_value(EP93XX_GPIO_LINE_EGPIO6, value);
-}
-
-static struct ep93xx_spi_chip_ops edb93xx_cs4271_hw = {
-       .setup          = edb93xx_cs4271_hw_setup,
-       .cleanup        = edb93xx_cs4271_hw_cleanup,
-       .cs_control     = edb93xx_cs4271_hw_cs_control,
-};
-
 static struct spi_board_info edb93xx_spi_board_info[] __initdata = {
        {
                .modalias               = "cs4271",
                .platform_data          = &edb93xx_cs4271_data,
-               .controller_data        = &edb93xx_cs4271_hw,
                .max_speed_hz           = 6000000,
                .bus_num                = 0,
                .chip_select            = 0,
@@ -140,8 +116,13 @@ static struct spi_board_info edb93xx_spi_board_info[] __initdata = {
        },
 };
 
+static int edb93xx_spi_chipselects[] __initdata = {
+       EP93XX_GPIO_LINE_EGPIO6,
+};
+
 static struct ep93xx_spi_info edb93xx_spi_info __initdata = {
-       .num_chipselect = ARRAY_SIZE(edb93xx_spi_board_info),
+       .chipselect     = edb93xx_spi_chipselects,
+       .num_chipselect = ARRAY_SIZE(edb93xx_spi_chipselects),
 };
 
 static void __init edb93xx_register_spi(void)
index 7bb540c421ee30314b93eb8c0f5247070b349b19..c7a40f245892885b403621e40bb33b4405111d5d 100644 (file)
@@ -48,56 +48,6 @@ static struct ep93xxfb_mach_info __initdata simone_fb_info = {
  */
 #define MMC_CARD_DETECT_GPIO EP93XX_GPIO_LINE_EGPIO0
 
-/*
- * Up to v1.3, the Sim.One used SFRMOUT as SD card chip select, but this goes
- * low between multi-message command blocks. From v1.4, it uses a GPIO instead.
- * v1.3 parts will still work, since the signal on SFRMOUT is automatic.
- */
-#define MMC_CHIP_SELECT_GPIO EP93XX_GPIO_LINE_EGPIO1
-
-/*
- * MMC SPI chip select GPIO handling. If you are using SFRMOUT (SFRM1) signal,
- * you can leave these empty and pass NULL as .controller_data.
- */
-
-static int simone_mmc_spi_setup(struct spi_device *spi)
-{
-       unsigned int gpio = MMC_CHIP_SELECT_GPIO;
-       int err;
-
-       err = gpio_request(gpio, spi->modalias);
-       if (err)
-               return err;
-
-       err = gpio_direction_output(gpio, 1);
-       if (err) {
-               gpio_free(gpio);
-               return err;
-       }
-
-       return 0;
-}
-
-static void simone_mmc_spi_cleanup(struct spi_device *spi)
-{
-       unsigned int gpio = MMC_CHIP_SELECT_GPIO;
-
-       gpio_set_value(gpio, 1);
-       gpio_direction_input(gpio);
-       gpio_free(gpio);
-}
-
-static void simone_mmc_spi_cs_control(struct spi_device *spi, int value)
-{
-       gpio_set_value(MMC_CHIP_SELECT_GPIO, value);
-}
-
-static struct ep93xx_spi_chip_ops simone_mmc_spi_ops = {
-       .setup          = simone_mmc_spi_setup,
-       .cleanup        = simone_mmc_spi_cleanup,
-       .cs_control     = simone_mmc_spi_cs_control,
-};
-
 /*
  * MMC card detection GPIO setup.
  */
@@ -152,7 +102,6 @@ static struct mmc_spi_platform_data simone_mmc_spi_data = {
 static struct spi_board_info simone_spi_devices[] __initdata = {
        {
                .modalias               = "mmc_spi",
-               .controller_data        = &simone_mmc_spi_ops,
                .platform_data          = &simone_mmc_spi_data,
                /*
                 * We use 10 MHz even though the maximum is 3.7 MHz. The driver
@@ -165,8 +114,18 @@ static struct spi_board_info simone_spi_devices[] __initdata = {
        },
 };
 
+/*
+ * Up to v1.3, the Sim.One used SFRMOUT as SD card chip select, but this goes
+ * low between multi-message command blocks. From v1.4, it uses a GPIO instead.
+ * v1.3 parts will still work, since the signal on SFRMOUT is automatic.
+ */
+static int simone_spi_chipselects[] __initdata = {
+       EP93XX_GPIO_LINE_EGPIO1,
+};
+
 static struct ep93xx_spi_info simone_spi_info __initdata = {
-       .num_chipselect = ARRAY_SIZE(simone_spi_devices),
+       .chipselect     = simone_spi_chipselects,
+       .num_chipselect = ARRAY_SIZE(simone_spi_chipselects),
        .use_dma = 1,
 };
 
index 5cced5988498f7c7fbe065b42a065e37b8f6b703..1daf9441058c8ded557463daad4f7dcef44381bd 100644 (file)
@@ -175,33 +175,9 @@ static struct cs4271_platform_data vision_cs4271_data = {
        .gpio_nreset    = EP93XX_GPIO_LINE_H(2),
 };
 
-static int vision_cs4271_hw_setup(struct spi_device *spi)
-{
-       return gpio_request_one(EP93XX_GPIO_LINE_EGPIO6,
-                               GPIOF_OUT_INIT_HIGH, spi->modalias);
-}
-
-static void vision_cs4271_hw_cleanup(struct spi_device *spi)
-{
-       gpio_free(EP93XX_GPIO_LINE_EGPIO6);
-}
-
-static void vision_cs4271_hw_cs_control(struct spi_device *spi, int value)
-{
-       gpio_set_value(EP93XX_GPIO_LINE_EGPIO6, value);
-}
-
-static struct ep93xx_spi_chip_ops vision_cs4271_hw = {
-       .setup          = vision_cs4271_hw_setup,
-       .cleanup        = vision_cs4271_hw_cleanup,
-       .cs_control     = vision_cs4271_hw_cs_control,
-};
-
 /*************************************************************************
  * SPI Flash
  *************************************************************************/
-#define VISION_SPI_FLASH_CS    EP93XX_GPIO_LINE_EGPIO7
-
 static struct mtd_partition vision_spi_flash_partitions[] = {
        {
                .name   = "SPI bootstrap",
@@ -224,68 +200,20 @@ static struct flash_platform_data vision_spi_flash_data = {
        .nr_parts       = ARRAY_SIZE(vision_spi_flash_partitions),
 };
 
-static int vision_spi_flash_hw_setup(struct spi_device *spi)
-{
-       return gpio_request_one(VISION_SPI_FLASH_CS, GPIOF_INIT_HIGH,
-                               spi->modalias);
-}
-
-static void vision_spi_flash_hw_cleanup(struct spi_device *spi)
-{
-       gpio_free(VISION_SPI_FLASH_CS);
-}
-
-static void vision_spi_flash_hw_cs_control(struct spi_device *spi, int value)
-{
-       gpio_set_value(VISION_SPI_FLASH_CS, value);
-}
-
-static struct ep93xx_spi_chip_ops vision_spi_flash_hw = {
-       .setup          = vision_spi_flash_hw_setup,
-       .cleanup        = vision_spi_flash_hw_cleanup,
-       .cs_control     = vision_spi_flash_hw_cs_control,
-};
-
 /*************************************************************************
  * SPI SD/MMC host
  *************************************************************************/
-#define VISION_SPI_MMC_CS      EP93XX_GPIO_LINE_G(2)
-#define VISION_SPI_MMC_WP      EP93XX_GPIO_LINE_F(0)
-#define VISION_SPI_MMC_CD      EP93XX_GPIO_LINE_EGPIO15
-
 static struct mmc_spi_platform_data vision_spi_mmc_data = {
        .detect_delay   = 100,
        .powerup_msecs  = 100,
        .ocr_mask       = MMC_VDD_32_33 | MMC_VDD_33_34,
        .flags          = MMC_SPI_USE_CD_GPIO | MMC_SPI_USE_RO_GPIO,
-       .cd_gpio        = VISION_SPI_MMC_CD,
+       .cd_gpio        = EP93XX_GPIO_LINE_EGPIO15,
        .cd_debounce    = 1,
-       .ro_gpio        = VISION_SPI_MMC_WP,
+       .ro_gpio        = EP93XX_GPIO_LINE_F(0),
        .caps2          = MMC_CAP2_RO_ACTIVE_HIGH,
 };
 
-static int vision_spi_mmc_hw_setup(struct spi_device *spi)
-{
-       return gpio_request_one(VISION_SPI_MMC_CS, GPIOF_INIT_HIGH,
-                               spi->modalias);
-}
-
-static void vision_spi_mmc_hw_cleanup(struct spi_device *spi)
-{
-       gpio_free(VISION_SPI_MMC_CS);
-}
-
-static void vision_spi_mmc_hw_cs_control(struct spi_device *spi, int value)
-{
-       gpio_set_value(VISION_SPI_MMC_CS, value);
-}
-
-static struct ep93xx_spi_chip_ops vision_spi_mmc_hw = {
-       .setup          = vision_spi_mmc_hw_setup,
-       .cleanup        = vision_spi_mmc_hw_cleanup,
-       .cs_control     = vision_spi_mmc_hw_cs_control,
-};
-
 /*************************************************************************
  * SPI Bus
  *************************************************************************/
@@ -293,7 +221,6 @@ static struct spi_board_info vision_spi_board_info[] __initdata = {
        {
                .modalias               = "cs4271",
                .platform_data          = &vision_cs4271_data,
-               .controller_data        = &vision_cs4271_hw,
                .max_speed_hz           = 6000000,
                .bus_num                = 0,
                .chip_select            = 0,
@@ -301,7 +228,6 @@ static struct spi_board_info vision_spi_board_info[] __initdata = {
        }, {
                .modalias               = "sst25l",
                .platform_data          = &vision_spi_flash_data,
-               .controller_data        = &vision_spi_flash_hw,
                .max_speed_hz           = 20000000,
                .bus_num                = 0,
                .chip_select            = 1,
@@ -309,7 +235,6 @@ static struct spi_board_info vision_spi_board_info[] __initdata = {
        }, {
                .modalias               = "mmc_spi",
                .platform_data          = &vision_spi_mmc_data,
-               .controller_data        = &vision_spi_mmc_hw,
                .max_speed_hz           = 20000000,
                .bus_num                = 0,
                .chip_select            = 2,
@@ -317,8 +242,15 @@ static struct spi_board_info vision_spi_board_info[] __initdata = {
        },
 };
 
+static int vision_spi_chipselects[] __initdata = {
+       EP93XX_GPIO_LINE_EGPIO6,
+       EP93XX_GPIO_LINE_EGPIO7,
+       EP93XX_GPIO_LINE_G(2),
+};
+
 static struct ep93xx_spi_info vision_spi_master __initdata = {
-       .num_chipselect = ARRAY_SIZE(vision_spi_board_info),
+       .chipselect     = vision_spi_chipselects,
+       .num_chipselect = ARRAY_SIZE(vision_spi_chipselects),
        .use_dma        = 1,
 };
 
index 06332f6265652e16dbd5503dcce3f45425e4fefb..10bc753624bec1f4b8fb7003012b88d18f769b31 100644 (file)
@@ -57,7 +57,6 @@ struct exynos_wkup_irq {
 struct exynos_pm_data {
        const struct exynos_wkup_irq *wkup_irq;
        unsigned int wake_disable_mask;
-       unsigned int *release_ret_regs;
 
        void (*pm_prepare)(void);
        void (*pm_resume_prepare)(void);
@@ -95,47 +94,6 @@ static const struct exynos_wkup_irq exynos5250_wkup_irq[] = {
        { /* sentinel */ },
 };
 
-static unsigned int exynos_release_ret_regs[] = {
-       S5P_PAD_RET_MAUDIO_OPTION,
-       S5P_PAD_RET_GPIO_OPTION,
-       S5P_PAD_RET_UART_OPTION,
-       S5P_PAD_RET_MMCA_OPTION,
-       S5P_PAD_RET_MMCB_OPTION,
-       S5P_PAD_RET_EBIA_OPTION,
-       S5P_PAD_RET_EBIB_OPTION,
-       REG_TABLE_END,
-};
-
-static unsigned int exynos3250_release_ret_regs[] = {
-       S5P_PAD_RET_MAUDIO_OPTION,
-       S5P_PAD_RET_GPIO_OPTION,
-       S5P_PAD_RET_UART_OPTION,
-       S5P_PAD_RET_MMCA_OPTION,
-       S5P_PAD_RET_MMCB_OPTION,
-       S5P_PAD_RET_EBIA_OPTION,
-       S5P_PAD_RET_EBIB_OPTION,
-       S5P_PAD_RET_MMC2_OPTION,
-       S5P_PAD_RET_SPI_OPTION,
-       REG_TABLE_END,
-};
-
-static unsigned int exynos5420_release_ret_regs[] = {
-       EXYNOS_PAD_RET_DRAM_OPTION,
-       EXYNOS_PAD_RET_MAUDIO_OPTION,
-       EXYNOS_PAD_RET_JTAG_OPTION,
-       EXYNOS5420_PAD_RET_GPIO_OPTION,
-       EXYNOS5420_PAD_RET_UART_OPTION,
-       EXYNOS5420_PAD_RET_MMCA_OPTION,
-       EXYNOS5420_PAD_RET_MMCB_OPTION,
-       EXYNOS5420_PAD_RET_MMCC_OPTION,
-       EXYNOS5420_PAD_RET_HSI_OPTION,
-       EXYNOS_PAD_RET_EBIA_OPTION,
-       EXYNOS_PAD_RET_EBIB_OPTION,
-       EXYNOS5420_PAD_RET_SPI_OPTION,
-       EXYNOS5420_PAD_RET_DRAM_COREBLK_OPTION,
-       REG_TABLE_END,
-};
-
 static int exynos_irq_set_wake(struct irq_data *data, unsigned int state)
 {
        const struct exynos_wkup_irq *wkup_irq;
@@ -442,15 +400,6 @@ static int exynos5420_pm_suspend(void)
        return 0;
 }
 
-static void exynos_pm_release_retention(void)
-{
-       unsigned int i;
-
-       for (i = 0; (pm_data->release_ret_regs[i] != REG_TABLE_END); i++)
-               pmu_raw_writel(EXYNOS_WAKEUP_FROM_LOWPWR,
-                               pm_data->release_ret_regs[i]);
-}
-
 static void exynos_pm_resume(void)
 {
        u32 cpuid = read_cpuid_part();
@@ -458,9 +407,6 @@ static void exynos_pm_resume(void)
        if (exynos_pm_central_resume())
                goto early_wakeup;
 
-       /* For release retention */
-       exynos_pm_release_retention();
-
        if (cpuid == ARM_CPU_PART_CORTEX_A9)
                scu_enable(S5P_VA_SCU);
 
@@ -482,9 +428,6 @@ static void exynos3250_pm_resume(void)
        if (exynos_pm_central_resume())
                goto early_wakeup;
 
-       /* For release retention */
-       exynos_pm_release_retention();
-
        pmu_raw_writel(S5P_USE_STANDBY_WFI_ALL, S5P_CENTRAL_SEQ_OPTION);
 
        if (call_firmware_op(resume) == -ENOSYS
@@ -522,9 +465,6 @@ static void exynos5420_pm_resume(void)
        if (exynos_pm_central_resume())
                goto early_wakeup;
 
-       /* For release retention */
-       exynos_pm_release_retention();
-
        pmu_raw_writel(exynos_pmu_spare3, S5P_PMU_SPARE3);
 
 early_wakeup:
@@ -637,7 +577,6 @@ static const struct platform_suspend_ops exynos_suspend_ops = {
 static const struct exynos_pm_data exynos3250_pm_data = {
        .wkup_irq       = exynos3250_wkup_irq,
        .wake_disable_mask = ((0xFF << 8) | (0x1F << 1)),
-       .release_ret_regs = exynos3250_release_ret_regs,
        .pm_suspend     = exynos_pm_suspend,
        .pm_resume      = exynos3250_pm_resume,
        .pm_prepare     = exynos3250_pm_prepare,
@@ -647,7 +586,6 @@ static const struct exynos_pm_data exynos3250_pm_data = {
 static const struct exynos_pm_data exynos4_pm_data = {
        .wkup_irq       = exynos4_wkup_irq,
        .wake_disable_mask = ((0xFF << 8) | (0x1F << 1)),
-       .release_ret_regs = exynos_release_ret_regs,
        .pm_suspend     = exynos_pm_suspend,
        .pm_resume      = exynos_pm_resume,
        .pm_prepare     = exynos_pm_prepare,
@@ -657,7 +595,6 @@ static const struct exynos_pm_data exynos4_pm_data = {
 static const struct exynos_pm_data exynos5250_pm_data = {
        .wkup_irq       = exynos5250_wkup_irq,
        .wake_disable_mask = ((0xFF << 8) | (0x1F << 1)),
-       .release_ret_regs = exynos_release_ret_regs,
        .pm_suspend     = exynos_pm_suspend,
        .pm_resume      = exynos_pm_resume,
        .pm_prepare     = exynos_pm_prepare,
@@ -667,7 +604,6 @@ static const struct exynos_pm_data exynos5250_pm_data = {
 static const struct exynos_pm_data exynos5420_pm_data = {
        .wkup_irq       = exynos5250_wkup_irq,
        .wake_disable_mask = (0x7F << 7) | (0x1F << 1),
-       .release_ret_regs = exynos5420_release_ret_regs,
        .pm_resume_prepare = exynos5420_prepare_pm_resume,
        .pm_resume      = exynos5420_pm_resume,
        .pm_suspend     = exynos5420_pm_suspend,
index 70c004794880e0efd567e269eebc0f7484ca5140..67498aad2654f39698c1dbb244a1aded8d321e84 100644 (file)
@@ -484,15 +484,15 @@ static struct pwm_omap_dmtimer_pdata pwm_dmtimer_pdata = {
 };
 #endif
 
-static struct lirc_rx51_platform_data __maybe_unused rx51_lirc_data = {
+static struct ir_rx51_platform_data __maybe_unused rx51_ir_data = {
        .set_max_mpu_wakeup_lat = omap_pm_set_max_mpu_wakeup_lat,
 };
 
-static struct platform_device __maybe_unused rx51_lirc_device = {
-       .name           = "lirc_rx51",
+static struct platform_device __maybe_unused rx51_ir_device = {
+       .name           = "ir_rx51",
        .id             = -1,
        .dev            = {
-               .platform_data = &rx51_lirc_data,
+               .platform_data = &rx51_ir_data,
        },
 };
 
@@ -533,7 +533,7 @@ static struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
                       &omap3_iommu_pdata),
        OF_DEV_AUXDATA("ti,omap3-hsmmc", 0x4809c000, "4809c000.mmc", &mmc_pdata[0]),
        OF_DEV_AUXDATA("ti,omap3-hsmmc", 0x480b4000, "480b4000.mmc", &mmc_pdata[1]),
-       OF_DEV_AUXDATA("nokia,n900-ir", 0, "n900-ir", &rx51_lirc_data),
+       OF_DEV_AUXDATA("nokia,n900-ir", 0, "n900-ir", &rx51_ir_data),
        /* Only on am3517 */
        OF_DEV_AUXDATA("ti,davinci_mdio", 0x5c030000, "davinci_mdio.0", NULL),
        OF_DEV_AUXDATA("ti,am3517-emac", 0x5c000000, "davinci_emac.0",
index 76b0454ddc4994220c2e6a2680ab596824caf7f6..0598630c17786242d20277fe59e9bbdb9cc9e928 100644 (file)
@@ -130,17 +130,16 @@ static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name,
        freq = clk_get_rate(clk);
        clk_put(clk);
 
-       rcu_read_lock();
        opp = dev_pm_opp_find_freq_ceil(dev, &freq);
        if (IS_ERR(opp)) {
-               rcu_read_unlock();
                pr_err("%s: unable to find boot up OPP for vdd_%s\n",
                        __func__, vdd_name);
                goto exit;
        }
 
        bootup_volt = dev_pm_opp_get_voltage(opp);
-       rcu_read_unlock();
+       dev_pm_opp_put(opp);
+
        if (!bootup_volt) {
                pr_err("%s: unable to find voltage corresponding to the bootup OPP for vdd_%s\n",
                       __func__, vdd_name);
index 8a3c409294bfb542188e953f603e3989c1418246..d452a49c039647097f77dae28764b2570ad9ee3b 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
+#include <linux/leds.h>
 #include <linux/sched.h>
 #include <linux/bitops.h>
 #include <linux/fb.h>
index 8cff770e6a00561dc55e32e5c863e7d8e63f1c1b..d7cf47d0361882dfe810ce325d5d433718ea0682 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/gpio.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/leds.h>
 #include <linux/ioport.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
index 183cd3446f25aa9a8cef893c8f9cfbd0988de006..7270f0db343216f33cec1189c5fba9f87e0cf472 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/major.h>
 #include <linux/fs.h>
 #include <linux/interrupt.h>
+#include <linux/leds.h>
 #include <linux/mmc/host.h>
 #include <linux/mtd/physmap.h>
 #include <linux/pm.h>
index ea78bc5c419875d060b671b31daca90a31bdc649..3dd13b44c311534dfae7338fbff5ee6f037d374a 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
+#include <linux/leds.h>
 #include <linux/export.h>
 #include <linux/sched.h>
 #include <linux/bitops.h>
index c006ee902a8f85a36c242dfdfd18eb7bdde4a9cd..70ab3ad282379026b58943ca8d903d5ab949ee5a 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/irq.h>
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
+#include <linux/leds.h>
 #include <linux/gpio.h>
 #include <linux/usb/gpio_vbus.h>
 #include <linux/mtd/mtd.h>
index 3b94ecfb942657b3c93337cb745c737e37046081..ecbcaee5a2d5f8980c6946853cd638da78fd6838 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/cpufreq.h>
 #include <linux/interrupt.h>
+#include <linux/leds.h>
 #include <linux/irq.h>
 #include <linux/pm.h>
 #include <linux/gpio.h>
index 3642389b301ac3a34ab8565a12f8d8e78556e134..4268552d600d6cd9b0db37473f843f37e95e55b8 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
+#include <linux/leds.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
index 21b4b13c5ab787f0707c00c5125b285f73dcdd60..7d69666de5ba2dd6b3c5c705d608ba4ad182767b 100644 (file)
@@ -155,13 +155,6 @@ static const struct platform_suspend_ops s5pv210_suspend_ops = {
  */
 static void s5pv210_pm_resume(void)
 {
-       u32 tmp;
-
-       tmp = __raw_readl(S5P_OTHERS);
-       tmp |= (S5P_OTHERS_RET_IO | S5P_OTHERS_RET_CF |\
-               S5P_OTHERS_RET_MMC | S5P_OTHERS_RET_UART);
-       __raw_writel(tmp , S5P_OTHERS);
-
        s3c_pm_do_restore_core(s5pv210_core_save, ARRAY_SIZE(s5pv210_core_save));
 }
 
index 4640f0f03c12ccaaf01b8fb5f72690a6f0eb01a9..fb3eb77412dbdf2d6321bfe278c81970631aab72 100644 (file)
 #define S5P_SLEEP_CFG_USBOSC_EN                (1 << 1)
 
 /* OTHERS Resgister */
-#define S5P_OTHERS_RET_IO              (1 << 31)
-#define S5P_OTHERS_RET_CF              (1 << 30)
-#define S5P_OTHERS_RET_MMC             (1 << 29)
-#define S5P_OTHERS_RET_UART            (1 << 28)
 #define S5P_OTHERS_USB_SIG_MASK                (1 << 16)
 
 /* S5P_DAC_CONTROL */
index 312e15e6d00b8a6b909747305166e1bc7f581bf0..f436f7439e46d585777ee620fe3262b5897c204f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  linux/arch/arm/mm/extable.c
  */
-#include <linux/module.h>
+#include <linux/extable.h>
 #include <linux/uaccess.h>
 
 int fixup_exception(struct pt_regs *regs)
index 0122ad1a60270cda8c53faf69296b8a93a902851..c2b5b9892fd17dd096691a395d6a635cdf2db8a7 100644 (file)
@@ -8,7 +8,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#include <linux/module.h>
+#include <linux/extable.h>
 #include <linux/signal.h>
 #include <linux/mm.h>
 #include <linux/hardirq.h>
index 11d9f2898b16441b4ccac1dc111fe6c6c5a9ed7d..81e3217b12d3349a365852c060dfc9b17fe17c63 100644 (file)
@@ -457,4 +457,5 @@ EXPORT_SYMBOL_GPL(HYPERVISOR_tmem_op);
 EXPORT_SYMBOL_GPL(HYPERVISOR_platform_op);
 EXPORT_SYMBOL_GPL(HYPERVISOR_multicall);
 EXPORT_SYMBOL_GPL(HYPERVISOR_vm_assist);
+EXPORT_SYMBOL_GPL(HYPERVISOR_dm_op);
 EXPORT_SYMBOL_GPL(privcmd_call);
index a648dfc3be30ea9b6804384378d3c18809cb33b2..b0b80c0f09f31e30aba022e317b4d9a19daaccbd 100644 (file)
@@ -92,6 +92,7 @@ HYPERCALL1(tmem_op);
 HYPERCALL1(platform_op_raw);
 HYPERCALL2(multicall);
 HYPERCALL2(vm_assist);
+HYPERCALL3(dm_op);
 
 ENTRY(privcmd_call)
        stmdb sp!, {r4}
index 947830a459d2ca6ef83fb92a4d168b55ea5c659d..401ceb71540c7440256fe7e6f7d71bbf982f529f 100644 (file)
@@ -84,6 +84,7 @@ HYPERCALL1(tmem_op);
 HYPERCALL1(platform_op_raw);
 HYPERCALL2(multicall);
 HYPERCALL2(vm_assist);
+HYPERCALL3(dm_op);
 
 ENTRY(privcmd_call)
        mov x16, x0
index d79666aefd71c7ddfee719b007a7bfd426fcbf3d..ad6174e217c93232cb64c7879333067cc3a10d09 100644 (file)
@@ -3,7 +3,7 @@
  */
 
 #include <linux/ptrace.h>
-#include <linux/module.h>
+#include <linux/extable.h>
 #include <linux/uaccess.h>
 #include <hwregs/supp_reg.h>
 #include <hwregs/intr_vect_defs.h>
index 9a641c1b085a326315153be4c7925a064ee71714..a0e8b3e03e4cbfec6edd753207eae23f333af246 100644 (file)
@@ -2,7 +2,7 @@
  * linux/arch/frv/mm/extable.c
  */
 
-#include <linux/module.h>
+#include <linux/extable.h>
 #include <linux/spinlock.h>
 #include <linux/uaccess.h>
 
index de863d6d802b899e79b436160dec66dfd949e918..489875fd2be459ffb843a0a5a9b2d0dcdb9b021d 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/uaccess.h>
 #include <linux/mm.h>
 #include <linux/signal.h>
-#include <linux/module.h>
+#include <linux/extable.h>
 #include <linux/hardirq.h>
 
 /*
diff --git a/arch/ia64/include/asm/exception.h b/arch/ia64/include/asm/exception.h
new file mode 100644 (file)
index 0000000..6bb246d
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_EXCEPTION_H
+#define __ASM_EXCEPTION_H
+
+struct pt_regs;
+struct exception_table_entry;
+
+extern void ia64_handle_exception(struct pt_regs *regs,
+                                 const struct exception_table_entry *e);
+
+#define ia64_done_with_exception(regs)                                   \
+({                                                                       \
+       int __ex_ret = 0;                                                 \
+       const struct exception_table_entry *e;                            \
+       e = search_exception_tables((regs)->cr_iip + ia64_psr(regs)->ri); \
+       if (e) {                                                          \
+               ia64_handle_exception(regs, e);                           \
+               __ex_ret = 1;                                             \
+       }                                                                 \
+       __ex_ret;                                                         \
+})
+
+#endif /* __ASM_EXCEPTION_H */
index bfe13196f7708f6e574f2ecdbbb34c2acc29855e..471044be2a3bdf5b418ea2f3b909c3cf3ef53798 100644 (file)
@@ -353,21 +353,6 @@ struct exception_table_entry {
        int fixup;      /* location-relative continuation addr.; if bit 2 is set, r9 is set to 0 */
 };
 
-extern void ia64_handle_exception (struct pt_regs *regs, const struct exception_table_entry *e);
-extern const struct exception_table_entry *search_exception_tables (unsigned long addr);
-
-static inline int
-ia64_done_with_exception (struct pt_regs *regs)
-{
-       const struct exception_table_entry *e;
-       e = search_exception_tables(regs->cr_iip + ia64_psr(regs)->ri);
-       if (e) {
-               ia64_handle_exception(regs, e);
-               return 1;
-       }
-       return 0;
-}
-
 #define ARCH_HAS_TRANSLATE_MEM_PTR     1
 static __inline__ void *
 xlate_dev_mem_ptr(phys_addr_t p)
index 9273e034b730360a21abeaeaa88aa2e6e2c5401c..7508c306aa9e0d8124f5270e5f8b62cf2b7467b6 100644 (file)
@@ -887,7 +887,8 @@ static int _acpi_map_lsapic(acpi_handle handle, int physid, int *pcpu)
 }
 
 /* wrapper to silence section mismatch warning */
-int __ref acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, int *pcpu)
+int __ref acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 acpi_id,
+                      int *pcpu)
 {
        return _acpi_map_lsapic(handle, physid, pcpu);
 }
index 45ff27e9edbb1cd0e179c0b185f151e9d027942a..f5f3a5e6fcd19d78c5f694ff7bbcae2160d93a2f 100644 (file)
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/preempt.h>
-#include <linux/moduleloader.h>
+#include <linux/extable.h>
 #include <linux/kdebug.h>
 
 #include <asm/pgtable.h>
 #include <asm/sections.h>
-#include <linux/uaccess.h>
+#include <asm/exception.h>
 
 extern void jprobe_inst_return(void);
 
index 095bfaff82d0b14f04734c5b24c58819fb54237a..8981ce98afb365c43bfe5ab1339cb34ea582f291 100644 (file)
 #include <linux/sched.h>
 #include <linux/tty.h>
 #include <linux/vt_kern.h>             /* For unblank_screen() */
-#include <linux/module.h>       /* for EXPORT_SYMBOL */
+#include <linux/export.h>
+#include <linux/extable.h>
 #include <linux/hardirq.h>
 #include <linux/kprobes.h>
 #include <linux/delay.h>               /* for ssleep() */
 #include <linux/kdebug.h>
+#include <linux/uaccess.h>
 
 #include <asm/fpswa.h>
 #include <asm/intrinsics.h>
 #include <asm/processor.h>
-#include <linux/uaccess.h>
+#include <asm/exception.h>
 #include <asm/setup.h>
 
 fpswa_interface_t *fpswa_interface;
index 9cd01c2200eee782a4c2ada82759cca02719a653..99348d7f2255ce1cd50c8ba111630126e9a89e03 100644 (file)
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/tty.h>
+#include <linux/extable.h>
 #include <linux/ratelimit.h>
+#include <linux/uaccess.h>
 
 #include <asm/intrinsics.h>
 #include <asm/processor.h>
 #include <asm/rse.h>
-#include <linux/uaccess.h>
+#include <asm/exception.h>
 #include <asm/unaligned.h>
 
 extern int die_if_kernel(char *str, struct pt_regs *regs, long err);
index fa6ad95e992e3690d623dd267e3c651b76f9bb9d..7f2feb21753c8be1c6073072440cb5ef8d6a4309 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/extable.h>
 #include <linux/interrupt.h>
 #include <linux/kprobes.h>
 #include <linux/kdebug.h>
@@ -15,6 +16,7 @@
 
 #include <asm/pgtable.h>
 #include <asm/processor.h>
+#include <asm/exception.h>
 
 extern int die(char *, struct pt_regs *, long);
 
index 40ccf80d29cf5457b472b3af3af5fba4a9ddcf87..8ac8ba6ef60c47db41474bc097ebed6d26084f57 100644 (file)
@@ -2,7 +2,7 @@
  * linux/arch/m32r/mm/extable.c
  */
 
-#include <linux/module.h>
+#include <linux/extable.h>
 #include <linux/uaccess.h>
 
 int fixup_exception(struct pt_regs *regs)
index a3785d3644c233f7f8e3ca6406cae54f3531ee11..a05dc31845940db842997f691e5a5d7c440ab77a 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/tty.h>
 #include <linux/vt_kern.h>             /* For unblank_screen() */
 #include <linux/highmem.h>
-#include <linux/module.h>
+#include <linux/extable.h>
 #include <linux/uaccess.h>
 
 #include <asm/m32r.h>
index 2a21eaebe84d1096cc37fe65f393b613732b3587..3aa90b78b43d4d0a25c53052d358d77ecc41d746 100644 (file)
@@ -1,5 +1,4 @@
-
-#include <linux/module.h>
+#include <linux/extable.h>
 #include <linux/uaccess.h>
 
 int fixup_exception(struct pt_regs *regs)
index abb678ccde6ff5ddc7829de582245a5aaa811293..f91b30f8aaa8c112b129b95bbaefcc70980eb391 100644 (file)
@@ -17,7 +17,7 @@
  *
  */
 
-#include <linux/module.h>
+#include <linux/extable.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
index b3c5bde43d34f85afc50c8eb955745b88836386c..a008a9f03072deb900409ad2ef93a6bd65cdb48e 100644 (file)
@@ -9,10 +9,13 @@ config MIPS
        select HAVE_CONTEXT_TRACKING
        select HAVE_GENERIC_DMA_COHERENT
        select HAVE_IDE
+       select HAVE_IRQ_EXIT_ON_IRQ_STACK
        select HAVE_OPROFILE
        select HAVE_PERF_EVENTS
        select PERF_USE_VMALLOC
        select HAVE_ARCH_KGDB
+       select HAVE_ARCH_MMAP_RND_BITS if MMU
+       select HAVE_ARCH_MMAP_RND_COMPAT_BITS if MMU && COMPAT
        select HAVE_ARCH_SECCOMP_FILTER
        select HAVE_ARCH_TRACEHOOK
        select HAVE_CBPF_JIT if !CPU_MICROMIPS
@@ -94,6 +97,7 @@ config MIPS_GENERIC
        select PCI_DRIVERS_GENERIC
        select PINCTRL
        select SMP_UP if SMP
+       select SWAP_IO_SPACE
        select SYS_HAS_CPU_MIPS32_R1
        select SYS_HAS_CPU_MIPS32_R2
        select SYS_HAS_CPU_MIPS32_R6
@@ -478,6 +482,7 @@ config MACH_XILFPGA
        select SYS_SUPPORTS_ZBOOT_UART16550
        select USE_OF
        select USE_GENERIC_EARLY_PRINTK_8250
+       select XILINX_INTC
        help
          This enables support for the IMG University Program MIPSfpga platform.
 
@@ -909,6 +914,7 @@ config CAVIUM_OCTEON_SOC
        select NR_CPUS_DEFAULT_16
        select BUILTIN_DTB
        select MTD_COMPLEX_MAPPINGS
+       select SYS_SUPPORTS_RELOCATABLE
        help
          This option supports all of the Octeon reference boards from Cavium
          Networks. It builds a kernel that dynamically determines the Octeon
@@ -1427,7 +1433,6 @@ config CPU_LOONGSON1C
        bool "Loongson 1C"
        depends on SYS_HAS_CPU_LOONGSON1C
        select CPU_LOONGSON1
-       select ARCH_WANT_OPTIONAL_GPIOLIB
        select LEDS_GPIO_REGISTER
        help
          The Loongson 1C is a 32-bit SoC, which implements the MIPS32
@@ -1703,6 +1708,8 @@ config CPU_BMIPS
        select WEAK_ORDERING
        select CPU_SUPPORTS_HIGHMEM
        select CPU_HAS_PREFETCH
+       select CPU_SUPPORTS_CPUFREQ
+       select MIPS_EXTERNAL_TIMER
        help
          Support for BMIPS32/3300/4350/4380 and BMIPS5000 processors.
 
@@ -2286,7 +2293,7 @@ config MIPS_MT_FPAFF
 
 config MIPSR2_TO_R6_EMULATOR
        bool "MIPS R2-to-R6 emulator"
-       depends on CPU_MIPSR6 && !SMP
+       depends on CPU_MIPSR6
        default y
        help
          Choose this option if you want to run non-R6 MIPS userland code.
@@ -2294,8 +2301,6 @@ config MIPSR2_TO_R6_EMULATOR
          default. You can enable it using the 'mipsr2emu' kernel option.
          The only reason this is a build-time option is to save ~14K from the
          final kernel image.
-comment "MIPS R2-to-R6 emulator is only available for UP kernels"
-       depends on SMP && CPU_MIPSR6
 
 config MIPS_VPE_LOADER
        bool "VPE loader support."
@@ -2570,7 +2575,7 @@ config SYS_SUPPORTS_NUMA
 
 config RELOCATABLE
        bool "Relocatable kernel"
-       depends on SYS_SUPPORTS_RELOCATABLE && (CPU_MIPS32_R2 || CPU_MIPS64_R2 || CPU_MIPS32_R6 || CPU_MIPS64_R6)
+       depends on SYS_SUPPORTS_RELOCATABLE && (CPU_MIPS32_R2 || CPU_MIPS64_R2 || CPU_MIPS32_R6 || CPU_MIPS64_R6 || CAVIUM_OCTEON_SOC)
        help
          This builds a kernel image that retains relocation information
          so it can be loaded someplace besides the default 1MB.
@@ -2826,8 +2831,8 @@ config KEXEC
          made.
 
 config CRASH_DUMP
-         bool "Kernel crash dumps"
-         help
+       bool "Kernel crash dumps"
+       help
          Generate crash dump after being started by kexec.
          This should be normally only set in special crash dump kernels
          which are loaded in the main kernel with kexec-tools into
@@ -2837,11 +2842,11 @@ config CRASH_DUMP
          PHYSICAL_START.
 
 config PHYSICAL_START
-         hex "Physical address where the kernel is loaded"
-         default "0xffffffff84000000" if 64BIT
-         default "0x84000000" if 32BIT
-         depends on CRASH_DUMP
-         help
+       hex "Physical address where the kernel is loaded"
+       default "0xffffffff84000000" if 64BIT
+       default "0x84000000" if 32BIT
+       depends on CRASH_DUMP
+       help
          This gives the CKSEG0 or KSEG0 address where the kernel is loaded.
          If you plan to use kernel for capturing the crash dump change
          this value to start of the reserved region (the "X" value as
@@ -3073,6 +3078,20 @@ config MMU
        bool
        default y
 
+config ARCH_MMAP_RND_BITS_MIN
+       default 12 if 64BIT
+       default 8
+
+config ARCH_MMAP_RND_BITS_MAX
+       default 18 if 64BIT
+       default 15
+
+config ARCH_MMAP_RND_COMPAT_BITS_MIN
+       default 8
+
+config ARCH_MMAP_RND_COMPAT_BITS_MAX
+       default 15
+
 config I8253
        bool
        select CLKSRC_I8253
index 1a6bac7b076f31934d397f22c5ccac600e36b4b4..8ef9c02747fa95a753ea79b77ed2a177a60ac6ad 100644 (file)
@@ -131,6 +131,21 @@ cflags-$(CONFIG_CPU_LITTLE_ENDIAN) += $(shell $(CC) -dumpmachine |grep -q 'mips.
 
 cflags-$(CONFIG_SB1XXX_CORELIS)        += $(call cc-option,-mno-sched-prolog) \
                                   -fno-omit-frame-pointer
+
+# Some distribution-specific toolchains might pass the -fstack-check
+# option during the build, which adds a simple stack-probe at the beginning
+# of every function.  This stack probe is to ensure that there is enough
+# stack space, else a SEGV is generated.  This is not desirable for MIPS
+# as kernel stacks are small, placed in unmapped virtual memory, and do not
+# grow when overflowed.  Especially on SGI IP27 platforms, this check will
+# lead to a NULL pointer dereference in _raw_spin_lock_irq.
+#
+# In disassembly, this stack probe appears at the top of a function as:
+#    sd                zero,<offset>(sp)
+# Where <offset> is a negative value.
+#
+cflags-y += -fno-stack-check
+
 #
 # CPU-dependent compiler/assembler options for optimization.
 #
@@ -320,6 +335,9 @@ bootz-y                     := vmlinuz
 bootz-y                        += vmlinuz.bin
 bootz-y                        += vmlinuz.ecoff
 bootz-y                        += vmlinuz.srec
+ifeq ($(shell expr $(zload-y) \< 0xffffffff80000000 2> /dev/null), 0)
+bootz-y                        += uzImage.bin
+endif
 
 ifdef CONFIG_LASAT
 rom.bin rom.sw: vmlinux
@@ -327,10 +345,6 @@ rom.bin rom.sw: vmlinux
                $(bootvars-y) $@
 endif
 
-CMD_RELOCS = arch/mips/boot/tools/relocs
-quiet_cmd_relocs = RELOCS  $<
-      cmd_relocs = $(CMD_RELOCS) $<
-
 #
 # Some machines like the Indy need 32-bit ELF binaries for booting purposes.
 # Other need ECOFF, so we build a 32-bit ELF binary for them which we then
@@ -339,11 +353,6 @@ quiet_cmd_relocs = RELOCS  $<
 quiet_cmd_32 = OBJCOPY $@
        cmd_32 = $(OBJCOPY) -O $(32bit-bfd) $(OBJCOPYFLAGS) $< $@
 vmlinux.32: vmlinux
-ifeq ($(CONFIG_RELOCATABLE)$(CONFIG_64BIT),yy)
-# Currently, objcopy fails to handle the relocations in the elf64
-# So the relocs tool must be run here to remove them first
-       $(call cmd,relocs)
-endif
        $(call cmd,32)
 
 #
@@ -359,9 +368,6 @@ all:        $(all-y)
 
 # boot
 $(boot-y): $(vmlinux-32) FORCE
-ifeq ($(CONFIG_RELOCATABLE)$(CONFIG_32BIT),yy)
-       $(call cmd,relocs)
-endif
        $(Q)$(MAKE) $(build)=arch/mips/boot VMLINUX=$(vmlinux-32) \
                $(bootvars-y) arch/mips/boot/$@
 
@@ -395,11 +401,11 @@ dtbs_install:
 
 archprepare:
 ifdef CONFIG_MIPS32_N32
-       @echo '  Checking missing-syscalls for N32'
+       @$(kecho) '  Checking missing-syscalls for N32'
        $(Q)$(MAKE) $(build)=. missing-syscalls missing_syscalls_flags="-mabi=n32"
 endif
 ifdef CONFIG_MIPS32_O32
-       @echo '  Checking missing-syscalls for O32'
+       @$(kecho) '  Checking missing-syscalls for O32'
        $(Q)$(MAKE) $(build)=. missing-syscalls missing_syscalls_flags="-mabi=32"
 endif
 
@@ -433,6 +439,7 @@ define archhelp
        echo '  uImage.gz            - U-Boot image (gzip)'
        echo '  uImage.lzma          - U-Boot image (lzma)'
        echo '  uImage.lzo           - U-Boot image (lzo)'
+       echo '  uzImage.bin          - U-Boot image (self-extracting)'
        echo '  dtbs                 - Device-tree blobs for enabled boards'
        echo '  dtbs_install         - Install dtbs to $(INSTALL_DTBS_PATH)'
        echo
diff --git a/arch/mips/Makefile.postlink b/arch/mips/Makefile.postlink
new file mode 100644 (file)
index 0000000..4b7f5a6
--- /dev/null
@@ -0,0 +1,35 @@
+# ===========================================================================
+# Post-link MIPS pass
+# ===========================================================================
+#
+# 1. Insert relocations into vmlinux
+
+PHONY := __archpost
+__archpost:
+
+-include include/config/auto.conf
+include scripts/Kbuild.include
+
+CMD_RELOCS = arch/mips/boot/tools/relocs
+quiet_cmd_relocs = RELOCS $@
+      cmd_relocs = $(CMD_RELOCS) $@
+
+# `@true` prevents complaint when there is nothing to be done
+
+vmlinux: FORCE
+       @true
+ifeq ($(CONFIG_RELOCATABLE),y)
+       $(call if_changed,relocs)
+endif
+
+%.ko: FORCE
+       @true
+
+clean:
+       @true
+
+PHONY += FORCE clean
+
+FORCE:
+
+.PHONY: $(PHONY)
index 79efe4c6e636a3a6482553db53e3310b1cfcc6ed..6fb6b3faa15810a7599dd6c68c28edc1402710fc 100644 (file)
@@ -236,7 +236,6 @@ static struct platform_device gpr_i2c_device = {
 static struct i2c_board_info gpr_i2c_info[] __initdata = {
        {
                I2C_BOARD_INFO("lm83", 0x18),
-               .type = "lm83"
        }
 };
 
index f2f264b5aafe224c2efe7bc489d34b4b7c145aad..fc482d900dddba69eca81d08df77ccff5fb10998 100644 (file)
@@ -35,7 +35,7 @@
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/syscore_ops.h>
 #include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-au1x00/au1xxx_dbdma.h>
index 4fb6207b883b2342f022357a922e7c67bf616375..973049b5bd61826535cca16b67bc9fdd1a32308a 100644 (file)
@@ -31,7 +31,7 @@
  */
 
 #include <linux/init.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/spinlock.h>
index e6b90e72c23fb1f84a3aed6eaf2638b1a52eb74d..7d5da5edd74d7eac9ccd0b996b4e9446218b2462 100644 (file)
@@ -32,7 +32,6 @@
 
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/gpio.h>
 #include <asm/mach-au1x00/gpio-au1000.h>
index 5340210596297fa54c8723e866aebaeb8c20269e..af312b5e33f65981eb739fdb8ede2145afb7077e 100644 (file)
@@ -33,7 +33,6 @@
  *  675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/string.h>
 
index 297805ade849811f7baeb982d22066f5b973013e..634edd3ded38a6aed6b93a6e4619835126bb9b21 100644 (file)
@@ -10,9 +10,9 @@
  */
 
 #include <linux/clk.h>
+#include <linux/export.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/syscore_ops.h>
 #include <asm/cpu.h>
index d23b1444d3657c385186e5c2b74d1b0967dc3240..a7bd32e9831b4a23c0a378950318cae84e879db2 100644 (file)
@@ -6,7 +6,7 @@
  * for various media blocks are enabled/disabled.
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/spinlock.h>
 #include <asm/mach-au1x00/au1000.h>
 
index faeddf119fd4247ea4ad5b0c87c611b466ef58a1..c1a2daaf300a5819d858989bfa76ccaffb37f31e 100644 (file)
@@ -9,7 +9,8 @@
 
 #include <linux/interrupt.h>
 #include <linux/irqchip/chained_irq.h>
-#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/export.h>
 #include <linux/spinlock.h>
 #include <linux/irq.h>
 #include <asm/addrspace.h>
index d3c087f59f1a9fa4d7f9a69dcad346f3aabe3b9a..a5504f57cb00f595e097c545cbd25ba4d89715a4 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/i2c.h>
 #include <linux/io.h>
 #include <linux/leds.h>
+#include <linux/interrupt.h>
 #include <linux/ata_platform.h>
 #include <linux/mmc/host.h>
 #include <linux/module.h>
index 2460f9d23f1bee098a03efecfe2181abaeef1988..dda422a0f36cdc17f9c897bfbdb5455b72e7e072 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/types.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/delay.h>
 #include <linux/gcd.h>
 #include <linux/io.h>
index ed5b3d297caf33cac75e77fdd5a870542d2a705b..4eee7e9e26ee2877be528d41e3c4b8ee28b16a38 100644 (file)
@@ -18,7 +18,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/export.h>
 #include <linux/gpio.h>
 
 #include <asm/mach-ar7/ar7.h>
index 92dfa481205b066ddf4ca29a62506bcab139e568..0332f0514d0508913048522c76328ae6de7e0127 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/bootmem.h>
 #include <linux/init.h>
 #include <linux/mm.h>
-#include <linux/module.h>
 #include <linux/pfn.h>
 #include <linux/proc_fs.h>
 #include <linux/string.h>
index 58fca9ad5fcc1650b432afb57743c3476b6b50e1..df7acea3747ad0b4547f3c67846215063d16d296 100644 (file)
@@ -19,7 +19,6 @@
 
 #include <linux/init.h>
 #include <linux/types.h>
-#include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
index a23adc49d50fa2348ac4788d4feb38211318989d..4fd83336131acf21bb09fba4070fe4b7ba471b63 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/kernel.h>
 #include <linux/serial_reg.h>
 #include <linux/spinlock.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/string.h>
 #include <linux/io.h>
 #include <asm/bootinfo.h>
index cc3a1e33a600ec7a8dd6f73ca12354955065d44d..fa845953f736f87af7f62100a0b4ac149b3f331b 100644 (file)
@@ -12,7 +12,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/clk.h>
@@ -45,7 +44,7 @@ static struct clk *__init ath79_add_sys_clkdev(
        int err;
 
        clk = clk_register_fixed_rate(NULL, id, NULL, 0, rate);
-       if (!clk)
+       if (IS_ERR(clk))
                panic("failed to allocate %s clock structure", id);
 
        err = clk_register_clkdev(clk, id, NULL);
@@ -508,16 +507,19 @@ static void __init ath79_clocks_init_dt_ng(struct device_node *np)
                ar9330_clk_init(ref_clk, pll_base);
        else {
                pr_err("%s: could not find any appropriate clk_init()\n", dnfn);
-               goto err_clk;
+               goto err_iounmap;
        }
 
        if (of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data)) {
                pr_err("%s: could not register clk provider\n", dnfn);
-               goto err_clk;
+               goto err_iounmap;
        }
 
        return;
 
+err_iounmap:
+       iounmap(pll_base);
+
 err_clk:
        clk_put(ref_clk);
 
index d071a3a0f87698ffb6384c6fa4dfa5d7bda5da40..10a405d593df3b5c64fa84ce9ae27eaa7ba222df 100644 (file)
@@ -13,7 +13,7 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/types.h>
 #include <linux/spinlock.h>
 
index a88975a55c4db1f2b04c36ef1abfd9552bb7034d..8cbe60cc51d42e056e3bb446a99e8063b5034df1 100644 (file)
@@ -149,6 +149,15 @@ struct bcm47xx_board_type_list2 bcm47xx_board_list_boot_hw[] __initconst = {
 /* board_id */
 static const
 struct bcm47xx_board_type_list1 bcm47xx_board_list_board_id[] __initconst = {
+       {{BCM47XX_BOARD_LUXUL_ABR_4400_V1, "Luxul ABR-4400 V1"}, "luxul_abr4400_v1"},
+       {{BCM47XX_BOARD_LUXUL_XAP_310_V1, "Luxul XAP-310 V1"}, "luxul_xap310_v1"},
+       {{BCM47XX_BOARD_LUXUL_XAP_1210_V1, "Luxul XAP-1210 V1"}, "luxul_xap1210_v1"},
+       {{BCM47XX_BOARD_LUXUL_XAP_1230_V1, "Luxul XAP-1230 V1"}, "luxul_xap1230_v1"},
+       {{BCM47XX_BOARD_LUXUL_XAP_1240_V1, "Luxul XAP-1240 V1"}, "luxul_xap1240_v1"},
+       {{BCM47XX_BOARD_LUXUL_XAP_1500_V1, "Luxul XAP-1500 V1"}, "luxul_xap1500_v1"},
+       {{BCM47XX_BOARD_LUXUL_XBR_4400_V1, "Luxul XBR-4400 V1"}, "luxul_xbr4400_v1"},
+       {{BCM47XX_BOARD_LUXUL_XVW_P30_V1, "Luxul XVW-P30 V1"}, "luxul_xvwp30_v1"},
+       {{BCM47XX_BOARD_LUXUL_XWR_600_V1, "Luxul XWR-600 V1"}, "luxul_xwr600_v1"},
        {{BCM47XX_BOARD_LUXUL_XWR_1750_V1, "Luxul XWR-1750 V1"}, "luxul_xwr1750_v1"},
        {{BCM47XX_BOARD_NETGEAR_WGR614V8, "Netgear WGR614 V8"}, "U12H072T00_NETGEAR"},
        {{BCM47XX_BOARD_NETGEAR_WGR614V9, "Netgear WGR614 V9"}, "U12H094T00_NETGEAR"},
index 52caa75bfe4e5eb1ec43b0e4152fbb1230d0ae21..8a760d80189529349c7f0dff5871bd54677eff99 100644 (file)
                .active_low     = 1,                                    \
        }
 
+#define BCM47XX_GPIO_KEY_H(_gpio, _code)                               \
+       {                                                               \
+               .code           = _code,                                \
+               .gpio           = _gpio,                                \
+       }
+
 /* Asus */
 
 static const struct gpio_keys_button
@@ -79,8 +85,8 @@ bcm47xx_buttons_asus_wl500gpv2[] __initconst = {
 
 static const struct gpio_keys_button
 bcm47xx_buttons_asus_wl500w[] __initconst = {
-       BCM47XX_GPIO_KEY(6, KEY_RESTART),
-       BCM47XX_GPIO_KEY(7, KEY_WPS_BUTTON),
+       BCM47XX_GPIO_KEY_H(6, KEY_RESTART),
+       BCM47XX_GPIO_KEY_H(7, KEY_WPS_BUTTON),
 };
 
 static const struct gpio_keys_button
@@ -301,6 +307,51 @@ bcm47xx_buttons_linksys_wrtsl54gs[] __initconst = {
 
 /* Luxul */
 
+static const struct gpio_keys_button
+bcm47xx_buttons_luxul_abr_4400_v1[] = {
+       BCM47XX_GPIO_KEY(14, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_luxul_xap_310_v1[] = {
+       BCM47XX_GPIO_KEY(20, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_luxul_xap_1210_v1[] = {
+       BCM47XX_GPIO_KEY(8, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_luxul_xap_1230_v1[] = {
+       BCM47XX_GPIO_KEY(8, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_luxul_xap_1240_v1[] = {
+       BCM47XX_GPIO_KEY(8, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_luxul_xap_1500_v1[] = {
+       BCM47XX_GPIO_KEY(14, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_luxul_xbr_4400_v1[] = {
+       BCM47XX_GPIO_KEY(14, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_luxul_xvw_p30_v1[] = {
+       BCM47XX_GPIO_KEY(20, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_luxul_xwr_600_v1[] = {
+       BCM47XX_GPIO_KEY(8, KEY_RESTART),
+};
+
 static const struct gpio_keys_button
 bcm47xx_buttons_luxul_xwr_1750_v1[] = {
        BCM47XX_GPIO_KEY(14, BTN_TASK),
@@ -561,6 +612,33 @@ int __init bcm47xx_buttons_register(void)
                err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrtsl54gs);
                break;
 
+       case BCM47XX_BOARD_LUXUL_ABR_4400_V1:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_luxul_abr_4400_v1);
+               break;
+       case BCM47XX_BOARD_LUXUL_XAP_310_V1:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_luxul_xap_310_v1);
+               break;
+       case BCM47XX_BOARD_LUXUL_XAP_1210_V1:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_luxul_xap_1210_v1);
+               break;
+       case BCM47XX_BOARD_LUXUL_XAP_1230_V1:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_luxul_xap_1230_v1);
+               break;
+       case BCM47XX_BOARD_LUXUL_XAP_1240_V1:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_luxul_xap_1240_v1);
+               break;
+       case BCM47XX_BOARD_LUXUL_XAP_1500_V1:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_luxul_xap_1500_v1);
+               break;
+       case BCM47XX_BOARD_LUXUL_XBR_4400_V1:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_luxul_xbr_4400_v1);
+               break;
+       case BCM47XX_BOARD_LUXUL_XVW_P30_V1:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_luxul_xvw_p30_v1);
+               break;
+       case BCM47XX_BOARD_LUXUL_XWR_600_V1:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_luxul_xwr_600_v1);
+               break;
        case BCM47XX_BOARD_LUXUL_XWR_1750_V1:
                err = bcm47xx_copy_bdata(bcm47xx_buttons_luxul_xwr_1750_v1);
                break;
index d20ae63eb3c2e051579f60cac8eab4360c331b33..a35f1d5cde9fd175fbb2f42039edd5094cc06062 100644 (file)
@@ -372,6 +372,60 @@ bcm47xx_leds_linksys_wrtsl54gs[] __initconst = {
 
 /* Luxul */
 
+static const struct gpio_led
+bcm47xx_leds_luxul_abr_4400_v1[] __initconst = {
+       BCM47XX_GPIO_LED(12, "green", "usb", 0, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED_TRIGGER(15, "green", "status", 0, "timer"),
+};
+
+static const struct gpio_led
+bcm47xx_leds_luxul_xap_310_v1[] __initconst = {
+       BCM47XX_GPIO_LED_TRIGGER(6, "green", "status", 1, "timer"),
+};
+
+static const struct gpio_led
+bcm47xx_leds_luxul_xap_1210_v1[] __initconst = {
+       BCM47XX_GPIO_LED_TRIGGER(6, "green", "status", 1, "timer"),
+};
+
+static const struct gpio_led
+bcm47xx_leds_luxul_xap_1230_v1[] __initconst = {
+       BCM47XX_GPIO_LED(3, "blue", "2ghz", 0, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(4, "green", "bridge", 0, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED_TRIGGER(6, "green", "status", 1, "timer"),
+};
+
+static const struct gpio_led
+bcm47xx_leds_luxul_xap_1240_v1[] __initconst = {
+       BCM47XX_GPIO_LED(3, "blue", "2ghz", 0, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(4, "green", "bridge", 0, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED_TRIGGER(6, "green", "status", 1, "timer"),
+};
+
+static const struct gpio_led
+bcm47xx_leds_luxul_xap_1500_v1[] __initconst = {
+       BCM47XX_GPIO_LED_TRIGGER(13, "green", "status", 1, "timer"),
+};
+
+static const struct gpio_led
+bcm47xx_leds_luxul_xbr_4400_v1[] __initconst = {
+       BCM47XX_GPIO_LED(12, "green", "usb", 0, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED_TRIGGER(15, "green", "status", 0, "timer"),
+};
+
+static const struct gpio_led
+bcm47xx_leds_luxul_xvw_p30_v1[] __initconst = {
+       BCM47XX_GPIO_LED_TRIGGER(0, "blue", "status", 1, "timer"),
+       BCM47XX_GPIO_LED(1, "green", "link", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_luxul_xwr_600_v1[] __initconst = {
+       BCM47XX_GPIO_LED(3, "green", "wps", 0, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED_TRIGGER(6, "green", "status", 1, "timer"),
+       BCM47XX_GPIO_LED(9, "green", "usb", 0, LEDS_GPIO_DEFSTATE_OFF),
+};
+
 static const struct gpio_led
 bcm47xx_leds_luxul_xwr_1750_v1[] __initconst = {
        BCM47XX_GPIO_LED(5, "green", "5ghz", 0, LEDS_GPIO_DEFSTATE_OFF),
@@ -633,6 +687,33 @@ void __init bcm47xx_leds_register(void)
                bcm47xx_set_pdata(bcm47xx_leds_linksys_wrtsl54gs);
                break;
 
+       case BCM47XX_BOARD_LUXUL_ABR_4400_V1:
+               bcm47xx_set_pdata(bcm47xx_leds_luxul_abr_4400_v1);
+               break;
+       case BCM47XX_BOARD_LUXUL_XAP_310_V1:
+               bcm47xx_set_pdata(bcm47xx_leds_luxul_xap_310_v1);
+               break;
+       case BCM47XX_BOARD_LUXUL_XAP_1210_V1:
+               bcm47xx_set_pdata(bcm47xx_leds_luxul_xap_1210_v1);
+               break;
+       case BCM47XX_BOARD_LUXUL_XAP_1230_V1:
+               bcm47xx_set_pdata(bcm47xx_leds_luxul_xap_1230_v1);
+               break;
+       case BCM47XX_BOARD_LUXUL_XAP_1240_V1:
+               bcm47xx_set_pdata(bcm47xx_leds_luxul_xap_1240_v1);
+               break;
+       case BCM47XX_BOARD_LUXUL_XAP_1500_V1:
+               bcm47xx_set_pdata(bcm47xx_leds_luxul_xap_1500_v1);
+               break;
+       case BCM47XX_BOARD_LUXUL_XBR_4400_V1:
+               bcm47xx_set_pdata(bcm47xx_leds_luxul_xbr_4400_v1);
+               break;
+       case BCM47XX_BOARD_LUXUL_XVW_P30_V1:
+               bcm47xx_set_pdata(bcm47xx_leds_luxul_xvw_p30_v1);
+               break;
+       case BCM47XX_BOARD_LUXUL_XWR_600_V1:
+               bcm47xx_set_pdata(bcm47xx_leds_luxul_xwr_600_v1);
+               break;
        case BCM47XX_BOARD_LUXUL_XWR_1750_V1:
                bcm47xx_set_pdata(bcm47xx_leds_luxul_xwr_1750_v1);
                break;
index b49fc9cb9cad2de2c3768ba93e54da41177ff0a7..73626040e4d6a1150f8ac02719eef9b6f7a31d4d 100644 (file)
@@ -6,7 +6,8 @@
  * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
  */
 
-#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/export.h>
 #include <linux/mutex.h>
 #include <linux/err.h>
 #include <linux/clk.h>
index 1c7c3fbfa1f330afae049d30e48b731cd6b46499..f61c16f57a97544c5e6e73d5307f67570df27026 100644 (file)
@@ -8,7 +8,7 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/cpu.h>
 #include <asm/cpu.h>
 #include <asm/cpu-info.h>
index 50d8190bbf7b25a53400be516392793145946d8f..29205badcf67611ce9f0a76744bf3abcfff45c8a 100644 (file)
@@ -7,7 +7,8 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/export.h>
 #include <linux/spinlock.h>
 #include <linux/log2.h>
 #include <bcm63xx_cpu.h>
index 7c256dadb1665380100ed6d0833566f8a19d0fed..16f353ac3441f54b4e8384dabeeb206ce49380a2 100644 (file)
@@ -8,7 +8,7 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/spinlock.h>
 #include <linux/platform_device.h>
 #include <linux/gpio/driver.h>
index c96139097ae270c9fbf6252d086611159bd6503d..ec694b9628c0371ed8b1ed527b0dd907cfa2102e 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <linux/module.h>
 #include <linux/irq.h>
 #include <linux/spinlock.h>
 #include <asm/irq_cpu.h>
index d1fe51edf5e6d005a6c0b202256c3d992d47e814..a2af38cf28a701b7cd3f3d2f1c8f5da3d391ba82 100644 (file)
@@ -6,7 +6,8 @@
  * Copyright (C) 2012 Jonas Gorski <jonas.gorski@gmail.com>
  */
 
-#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/export.h>
 #include <linux/mutex.h>
 #include <linux/err.h>
 #include <linux/clk.h>
index 2110359c00e5cb79cf1b04b21c73c83e81f79ea8..a86065854c0c8c6c92254c4d7746fda8e6801250 100644 (file)
@@ -8,7 +8,8 @@
 
 #include <linux/kernel.h>
 #include <linux/err.h>
-#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/export.h>
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
 #include <linux/clk.h>
index 90aca95fe3149696d772e3ae41cdcfa388d79b80..c675eece389a41c036c4ff2e1aeaf89509368a1f 100644 (file)
@@ -18,14 +18,14 @@ include $(srctree)/arch/mips/Kbuild.platforms
 BOOT_HEAP_SIZE := 0x400000
 
 # Disable Function Tracer
-KBUILD_CFLAGS := $(shell echo $(KBUILD_CFLAGS) | sed -e "s/-pg//")
+KBUILD_CFLAGS := $(filter-out -pg, $(KBUILD_CFLAGS))
 
 KBUILD_CFLAGS := $(filter-out -fstack-protector, $(KBUILD_CFLAGS))
 
-KBUILD_CFLAGS := $(LINUXINCLUDE) $(KBUILD_CFLAGS) -D__KERNEL__ \
+KBUILD_CFLAGS := $(KBUILD_CFLAGS) -D__KERNEL__ \
        -DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE) -D"VMLINUX_LOAD_ADDRESS_ULL=$(VMLINUX_LOAD_ADDRESS)ull"
 
-KBUILD_AFLAGS := $(LINUXINCLUDE) $(KBUILD_AFLAGS) -D__ASSEMBLY__ \
+KBUILD_AFLAGS := $(KBUILD_AFLAGS) -D__ASSEMBLY__ \
        -DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE) \
        -DKERNEL_ENTRY=$(VMLINUX_ENTRY_ADDRESS)
 
@@ -84,6 +84,7 @@ else
 VMLINUZ_LOAD_ADDRESS = $(shell $(obj)/calc_vmlinuz_load_addr \
                $(obj)/vmlinux.bin $(VMLINUX_LOAD_ADDRESS))
 endif
+UIMAGE_LOADADDR = $(VMLINUZ_LOAD_ADDRESS)
 
 vmlinuzobjs-y += $(obj)/piggy.o
 
@@ -129,4 +130,7 @@ OBJCOPYFLAGS_vmlinuz.srec := $(OBJCOPYFLAGS) -S -O srec
 vmlinuz.srec: vmlinuz
        $(call cmd,objcopy)
 
+uzImage.bin: vmlinuz.bin FORCE
+       $(call if_changed,uimage,none)
+
 clean-files := $(objtree)/vmlinuz $(objtree)/vmlinuz.{32,ecoff,bin,srec}
index fc7a0a98e9bfc159ef3ba75ba2c791aa76e5c9a2..b9db49203e0c08a1d427fee24864074891c146b2 100644 (file)
@@ -1,5 +1,6 @@
 dts-dirs       += brcm
 dts-dirs       += cavium-octeon
+dts-dirs       += img
 dts-dirs       += ingenic
 dts-dirs       += lantiq
 dts-dirs       += mti
index bbd00f65ce397a7a83b762f7dc5da316efa427fb..79f838ed96c5e681d50f2754437c5bde72044df7 100644 (file)
                        compatible = "brcm,bcm7120-l2-intc";
                        reg = <0x406780 0x8>;
 
-                       brcm,int-map-mask = <0x44>, <0xf000000>;
+                       brcm,int-map-mask = <0x44>, <0xf000000>, <0x100000>;
                        brcm,int-fwd-mask = <0x70000>;
 
                        interrupt-controller;
                        #interrupt-cells = <1>;
 
                        interrupt-parent = <&periph_intc>;
-                       interrupts = <18>, <19>;
-                       interrupt-names = "upg_main", "upg_bsc";
+                       interrupts = <18>, <19>, <20>;
+                       interrupt-names = "upg_main", "upg_bsc", "upg_spi";
                };
 
                sun_top_ctrl: syscon@404000 {
                        interrupts = <61>;
                        status = "disabled";
                };
+
+               spi_l2_intc: interrupt-controller@411d00 {
+                       compatible = "brcm,l2-intc";
+                       reg = <0x411d00 0x30>;
+                       interrupt-controller;
+                       #interrupt-cells = <1>;
+                       interrupt-parent = <&periph_intc>;
+                       interrupts = <79>;
+               };
+
+               qspi: spi@443000 {
+                       #address-cells = <0x1>;
+                       #size-cells = <0x0>;
+                       compatible = "brcm,spi-bcm-qspi",
+                                    "brcm,spi-brcmstb-qspi";
+                       clocks = <&upg_clk>;
+                       reg = <0x440920 0x4 0x443200 0x188 0x443000 0x50>;
+                       reg-names = "cs_reg", "hif_mspi", "bspi";
+                       interrupts = <0x0 0x1 0x2 0x3 0x4 0x5 0x6>;
+                       interrupt-parent = <&spi_l2_intc>;
+                       interrupt-names = "spi_lr_fullness_reached",
+                                         "spi_lr_session_aborted",
+                                         "spi_lr_impatient",
+                                         "spi_lr_session_done",
+                                         "spi_lr_overread",
+                                         "mspi_done",
+                                         "mspi_halted";
+                       status = "disabled";
+               };
+
+               mspi: spi@406400 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "brcm,spi-bcm-qspi",
+                                    "brcm,spi-brcmstb-mspi";
+                       clocks = <&upg_clk>;
+                       reg = <0x406400 0x180>;
+                       reg-names = "mspi";
+                       interrupts = <0x14>;
+                       interrupt-parent = <&upg_irq0_intc>;
+                       interrupt-names = "mspi_done";
+                       status = "disabled";
+               };
        };
 };
index 4bbcc95f1c15d6dee9f2124d4318d60fba246b99..da7bfa45a57d1b01cc055291c62a81ae08bdebfb 100644 (file)
                        interrupts = <85>;
                        status = "disabled";
                };
+
+               spi_l2_intc: interrupt-controller@411d00 {
+                       compatible = "brcm,l2-intc";
+                       reg = <0x411d00 0x30>;
+                       interrupt-controller;
+                       #interrupt-cells = <1>;
+                       interrupt-parent = <&periph_intc>;
+                       interrupts = <31>;
+               };
+
+               qspi: spi@413000 {
+                       #address-cells = <0x1>;
+                       #size-cells = <0x0>;
+                       compatible = "brcm,spi-bcm-qspi",
+                                    "brcm,spi-brcmstb-qspi";
+                       clocks = <&upg_clk>;
+                       reg = <0x410920 0x4 0x413200 0x188 0x413000 0x50>;
+                       reg-names = "cs_reg", "hif_mspi", "bspi";
+                       interrupts = <0x0 0x1 0x2 0x3 0x4 0x5 0x6>;
+                       interrupt-parent = <&spi_l2_intc>;
+                       interrupt-names = "spi_lr_fullness_reached",
+                                         "spi_lr_session_aborted",
+                                         "spi_lr_impatient",
+                                         "spi_lr_session_done",
+                                         "spi_lr_overread",
+                                         "mspi_done",
+                                         "mspi_halted";
+                       status = "disabled";
+               };
+
+               mspi: spi@408a00 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "brcm,spi-bcm-qspi",
+                                    "brcm,spi-brcmstb-mspi";
+                       clocks = <&upg_clk>;
+                       reg = <0x408a00 0x180>;
+                       reg-names = "mspi";
+                       interrupts = <0x14>;
+                       interrupt-parent = <&upg_aon_irq0_intc>;
+                       interrupt-names = "mspi_done";
+                       status = "disabled";
+               };
        };
 };
index 3e42535c8d290907705172bcdb86387983564c34..9b05760453f0913d36316826c30c8c5abdf9befb 100644 (file)
                        interrupts = <24>;
                        status = "disabled";
                };
+
+               spi_l2_intc: interrupt-controller@411d00 {
+                       compatible = "brcm,l2-intc";
+                       reg = <0x411d00 0x30>;
+                       interrupt-controller;
+                       #interrupt-cells = <1>;
+                       interrupt-parent = <&periph_intc>;
+                       interrupts = <31>;
+               };
+
+               qspi: spi@413000 {
+                       #address-cells = <0x1>;
+                       #size-cells = <0x0>;
+                       compatible = "brcm,spi-bcm-qspi",
+                                    "brcm,spi-brcmstb-qspi";
+                       clocks = <&upg_clk>;
+                       reg = <0x410920 0x4 0x413200 0x188 0x413000 0x50>;
+                       reg-names = "cs_reg", "hif_mspi", "bspi";
+                       interrupts = <0x0 0x1 0x2 0x3 0x4 0x5 0x6>;
+                       interrupt-parent = <&spi_l2_intc>;
+                       interrupt-names = "spi_lr_fullness_reached",
+                                         "spi_lr_session_aborted",
+                                         "spi_lr_impatient",
+                                         "spi_lr_session_done",
+                                         "spi_lr_overread",
+                                         "mspi_done",
+                                         "mspi_halted";
+                       status = "disabled";
+               };
+
+               mspi: spi@408a00 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "brcm,spi-bcm-qspi",
+                                    "brcm,spi-brcmstb-mspi";
+                       clocks = <&upg_clk>;
+                       reg = <0x408a00 0x180>;
+                       reg-names = "mspi";
+                       interrupts = <0x14>;
+                       interrupt-parent = <&upg_aon_irq0_intc>;
+                       interrupt-names = "mspi_done";
+                       status = "disabled";
+               };
        };
 };
index 112a5571c5961c2b5939a81881967121515bf802..57b613c6acf27ba635f277fbbcec068bddd7a00b 100644 (file)
                        interrupts = <82>;
                        status = "disabled";
                };
+
+               spi_l2_intc: interrupt-controller@411d00 {
+                       compatible = "brcm,l2-intc";
+                       reg = <0x411d00 0x30>;
+                       interrupt-controller;
+                       #interrupt-cells = <1>;
+                       interrupt-parent = <&periph_intc>;
+                       interrupts = <31>;
+               };
+
+               qspi: spi@413000 {
+                       #address-cells = <0x1>;
+                       #size-cells = <0x0>;
+                       compatible = "brcm,spi-bcm-qspi",
+                                    "brcm,spi-brcmstb-qspi";
+                       clocks = <&upg_clk>;
+                       reg = <0x410920 0x4 0x413200 0x188 0x413000 0x50>;
+                       reg-names = "cs_reg", "hif_mspi", "bspi";
+                       interrupts = <0x0 0x1 0x2 0x3 0x4 0x5 0x6>;
+                       interrupt-parent = <&spi_l2_intc>;
+                       interrupt-names = "spi_lr_fullness_reached",
+                                         "spi_lr_session_aborted",
+                                         "spi_lr_impatient",
+                                         "spi_lr_session_done",
+                                         "spi_lr_overread",
+                                         "mspi_done",
+                                         "mspi_halted";
+                       status = "disabled";
+               };
+
+               mspi: spi@408a00 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "brcm,spi-bcm-qspi",
+                                    "brcm,spi-brcmstb-mspi";
+                       clocks = <&upg_clk>;
+                       reg = <0x408a00 0x180>;
+                       reg-names = "mspi";
+                       interrupts = <0x14>;
+                       interrupt-parent = <&upg_aon_irq0_intc>;
+                       interrupt-names = "mspi_done";
+                       status = "disabled";
+               };
        };
 };
index 34abfb0b07e79406e23bd2bd63396aea282992a5..c2a2843aaa9a7b0573aba98681bf732b28224bc8 100644 (file)
                        interrupts = <82>;
                        status = "disabled";
                };
+
+               spi_l2_intc: interrupt-controller@411d00 {
+                       compatible = "brcm,l2-intc";
+                       reg = <0x411d00 0x30>;
+                       interrupt-controller;
+                       #interrupt-cells = <1>;
+                       interrupt-parent = <&periph_intc>;
+                       interrupts = <31>;
+               };
+
+               qspi: spi@413000 {
+                       #address-cells = <0x1>;
+                       #size-cells = <0x0>;
+                       compatible = "brcm,spi-bcm-qspi",
+                                    "brcm,spi-brcmstb-qspi";
+                       clocks = <&upg_clk>;
+                       reg = <0x410920 0x4 0x413200 0x188 0x413000 0x50>;
+                       reg-names = "cs_reg", "hif_mspi", "bspi";
+                       interrupts = <0x0 0x1 0x2 0x3 0x4 0x5 0x6>;
+                       interrupt-parent = <&spi_l2_intc>;
+                       interrupt-names = "spi_lr_fullness_reached",
+                                         "spi_lr_session_aborted",
+                                         "spi_lr_impatient",
+                                         "spi_lr_session_done",
+                                         "spi_lr_overread",
+                                         "mspi_done",
+                                         "mspi_halted";
+                       status = "disabled";
+               };
+
+               mspi: spi@408a00 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "brcm,spi-bcm-qspi",
+                                    "brcm,spi-brcmstb-mspi";
+                       clocks = <&upg_clk>;
+                       reg = <0x408a00 0x180>;
+                       reg-names = "mspi";
+                       interrupts = <0x14>;
+                       interrupt-parent = <&upg_aon_irq0_intc>;
+                       interrupt-names = "mspi_done";
+                       status = "disabled";
+               };
        };
 };
index b143723c674e8d4b15f50940175d4e87f5b0cc47..532fc8a157962c789ed96bb3d6b5ff02303c2a03 100644 (file)
                        compatible = "brcm,bcm7120-l2-intc";
                        reg = <0x406780 0x8>;
 
-                       brcm,int-map-mask = <0x44>, <0x1f000000>;
+                       brcm,int-map-mask = <0x44>, <0x1f000000>, <0x100000>;
                        brcm,int-fwd-mask = <0x70000>;
 
                        interrupt-controller;
                        #interrupt-cells = <1>;
 
                        interrupt-parent = <&periph_intc>;
-                       interrupts = <18>, <19>;
-                       interrupt-names = "upg_main", "upg_bsc";
+                       interrupts = <18>, <19>, <20>;
+                       interrupt-names = "upg_main", "upg_bsc", "upg_spi";
                };
 
                sun_top_ctrl: syscon@404000 {
                        interrupts = <62>;
                        status = "disabled";
                };
+
+               spi_l2_intc: interrupt-controller@411d00 {
+                       compatible = "brcm,l2-intc";
+                       reg = <0x411d00 0x30>;
+                       interrupt-controller;
+                       #interrupt-cells = <1>;
+                       interrupt-parent = <&periph_intc>;
+                       interrupts = <78>;
+               };
+
+               qspi: spi@443000 {
+                       #address-cells = <0x1>;
+                       #size-cells = <0x0>;
+                       compatible = "brcm,spi-bcm-qspi",
+                                    "brcm,spi-brcmstb-qspi";
+                       clocks = <&upg_clk>;
+                       reg = <0x440920 0x4 0x443200 0x188 0x443000 0x50>;
+                       reg-names = "cs_reg", "hif_mspi", "bspi";
+                       interrupts = <0x0 0x1 0x2 0x3 0x4 0x5 0x6>;
+                       interrupt-parent = <&spi_l2_intc>;
+                       interrupt-names = "spi_lr_fullness_reached",
+                                         "spi_lr_session_aborted",
+                                         "spi_lr_impatient",
+                                         "spi_lr_session_done",
+                                         "spi_lr_overread",
+                                         "mspi_done",
+                                         "mspi_halted";
+                       status = "disabled";
+               };
+
+               mspi: spi@406400 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "brcm,spi-bcm-qspi",
+                                    "brcm,spi-brcmstb-mspi";
+                       clocks = <&upg_clk>;
+                       reg = <0x406400 0x180>;
+                       reg-names = "mspi";
+                       interrupts = <0x14>;
+                       interrupt-parent = <&upg_irq0_intc>;
+                       interrupt-names = "mspi_done";
+                       status = "disabled";
+               };
        };
 };
index 2488d2f61f6017a26f0d1d9198421e5ee6ae35a4..f56fb25f2e6b5ce7894a3e08aeb8879f28e7fe1f 100644 (file)
                        mmc-hs200-1_8v;
                        status = "disabled";
                };
+
+               spi_l2_intc: interrupt-controller@41ad00 {
+                       compatible = "brcm,l2-intc";
+                       reg = <0x41ad00 0x30>;
+                       interrupt-controller;
+                       #interrupt-cells = <1>;
+                       interrupt-parent = <&periph_intc>;
+                       interrupts = <25>;
+               };
+
+               qspi: spi@41c000 {
+                       #address-cells = <0x1>;
+                       #size-cells = <0x0>;
+                       compatible = "brcm,spi-bcm-qspi",
+                                    "brcm,spi-brcmstb-qspi";
+                       clocks = <&upg_clk>;
+                       reg = <0x419920 0x4 0x41c200 0x188 0x41c000 0x50>;
+                       reg-names = "cs_reg", "hif_mspi", "bspi";
+                       interrupts = <0x0 0x1 0x2 0x3 0x4 0x5 0x6>;
+                       interrupt-parent = <&spi_l2_intc>;
+                       interrupt-names = "spi_lr_fullness_reached",
+                                         "spi_lr_session_aborted",
+                                         "spi_lr_impatient",
+                                         "spi_lr_session_done",
+                                         "spi_lr_overread",
+                                         "mspi_done",
+                                         "mspi_halted";
+                       status = "disabled";
+               };
+
+               mspi: spi@409200 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "brcm,spi-bcm-qspi",
+                                    "brcm,spi-brcmstb-mspi";
+                       clocks = <&upg_clk>;
+                       reg = <0x409200 0x180>;
+                       reg-names = "mspi";
+                       interrupts = <0x14>;
+                       interrupt-parent = <&upg_aon_irq0_intc>;
+                       interrupt-names = "mspi_done";
+                       status = "disabled";
+               };
        };
 };
index 19fa259b968b3fc7b1ab476a4ed27125b6af8862..f2cead2eae5c0037caae6fa68e81ea0ddfb46011 100644 (file)
                        mmc-hs200-1_8v;
                        status = "disabled";
                };
+
+               spi_l2_intc: interrupt-controller@41bd00 {
+                       compatible = "brcm,l2-intc";
+                       reg = <0x41bd00 0x30>;
+                       interrupt-controller;
+                       #interrupt-cells = <1>;
+                       interrupt-parent = <&periph_intc>;
+                       interrupts = <25>;
+               };
+
+               qspi: spi@41d200 {
+                       #address-cells = <0x1>;
+                       #size-cells = <0x0>;
+                       compatible = "brcm,spi-bcm-qspi",
+                                    "brcm,spi-brcmstb-qspi";
+                       clocks = <&upg_clk>;
+                       reg = <0x41a920 0x4 0x41d400 0x188 0x41d200 0x50>;
+                       reg-names = "cs_reg", "hif_mspi", "bspi";
+                       interrupts = <0x0 0x1 0x2 0x3 0x4 0x5 0x6>;
+                       interrupt-parent = <&spi_l2_intc>;
+                       interrupt-names = "spi_lr_fullness_reached",
+                                         "spi_lr_session_aborted",
+                                         "spi_lr_impatient",
+                                         "spi_lr_session_done",
+                                         "spi_lr_overread",
+                                         "mspi_done",
+                                         "mspi_halted";
+                       status = "disabled";
+               };
+
+               mspi: spi@409200 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "brcm,spi-bcm-qspi",
+                                    "brcm,spi-brcmstb-mspi";
+                       clocks = <&upg_clk>;
+                       reg = <0x409200 0x180>;
+                       reg-names = "mspi";
+                       interrupts = <0x14>;
+                       interrupt-parent = <&upg_aon_irq0_intc>;
+                       interrupt-names = "mspi_done";
+                       status = "disabled";
+               };
        };
 };
index 5c24eacd72ddce0a5b354275664f528896af6e83..d72bc423ceaaed1229b81ec10f0a173eafc4c1ca 100644 (file)
@@ -57,3 +57,7 @@
 &ohci0 {
        status = "disabled";
 };
+
+&mspi {
+       status = "okay";
+};
index e67eaf30de3d131ac4432ed0f8a7097a6a8d89a6..ea52d7b5772f88137bb2e4b29f239adcbddbf47c 100644 (file)
 &sdhci0 {
        status = "okay";
 };
+
+&mspi {
+       status = "okay";
+};
index ee4607fae47accb047197ded65b43e09aea7addb..71357fdc19afe57b8b8e44a2d5a4b312d0361a94 100644 (file)
 &nand {
        status = "okay";
 };
+
+&qspi {
+       status = "okay";
+
+       m25p80@0 {
+               compatible = "m25p80";
+               reg = <0>;
+               spi-max-frequency = <40000000>;
+               spi-cpol;
+               spi-cpha;
+               use-bspi;
+               m25p,fast-read;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       flash0.cfe@0 {
+                               reg = <0x0 0x200000>;
+                       };
+
+                       flash0.mac@200000 {
+                               reg = <0x200000 0x40000>;
+                       };
+
+                       flash0.nvram@240000 {
+                               reg = <0x240000 0x10000>;
+                       };
+               };
+       };
+};
+
+&mspi {
+       status = "okay";
+};
index bed821b030139599e7fddb0f0de2c38d77fffb7d..e2fed406c6ee5db1d5ab98d72d291d27044b8ee5 100644 (file)
 &sdhci0 {
        status = "okay";
 };
+
+&qspi {
+       status = "okay";
+
+       m25p80@0 {
+               compatible = "m25p80";
+               reg = <0>;
+               spi-max-frequency = <40000000>;
+               spi-cpol;
+               spi-cpha;
+               use-bspi;
+               m25p,fast-read;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       flash0.cfe@0 {
+                               reg = <0x0 0x200000>;
+                       };
+
+                       flash0.mac@200000 {
+                               reg = <0x200000 0x40000>;
+                       };
+
+                       flash0.nvram@240000 {
+                               reg = <0x240000 0x10000>;
+                       };
+               };
+       };
+};
+
+&mspi {
+       status = "okay";
+};
index 68fd823868e07a3f580ca97960a93f78d36afaae..78bffdf1187203573d29c3677aa895bf85cb109c 100644 (file)
@@ -73,3 +73,7 @@
 &sdhci0 {
        status = "okay";
 };
+
+&mspi {
+       status = "okay";
+};
index e66271af055e74fd19c41f8390019c19c2fd08b9..d62b448a152dee118b1f8cc93034075516580215 100644 (file)
@@ -79,3 +79,7 @@
 &ohci1 {
        status = "okay";
 };
+
+&mspi {
+       status = "okay";
+};
index f95ba1bf3e5806d0a4b4467621b16eb2490cc2ed..73aa006bd9ce11c46d1695252f5537ad281b8861 100644 (file)
 &sdhci1 {
        status = "okay";
 };
+
+&qspi {
+       status = "okay";
+
+       m25p80@0 {
+               compatible = "m25p80";
+               reg = <0>;
+               spi-max-frequency = <40000000>;
+               spi-cpol;
+               spi-cpha;
+               use-bspi;
+               m25p,fast-read;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       flash0.cfe@0 {
+                               reg = <0x0 0x200000>;
+                       };
+
+                       flash0.mac@200000 {
+                               reg = <0x200000 0x40000>;
+                       };
+
+                       flash0.nvram@240000 {
+                               reg = <0x240000 0x10000>;
+                       };
+               };
+       };
+};
+
+&mspi {
+       status = "okay";
+};
index fb37b7111bf4f39bbcac24af96a9f0fdf4dd9a02..0a915f3feab6c304609413f361dec9f10b9d1e45 100644 (file)
 &sdhci1 {
        status = "okay";
 };
+
+&mspi {
+       status = "okay";
+};
diff --git a/arch/mips/boot/dts/img/Makefile b/arch/mips/boot/dts/img/Makefile
new file mode 100644 (file)
index 0000000..69a65f0
--- /dev/null
@@ -0,0 +1,9 @@
+dtb-$(CONFIG_MACH_PISTACHIO)   += pistachio_marduk.dtb
+
+obj-y                          += $(patsubst %.dtb, %.dtb.o, $(dtb-y))
+
+# Force kbuild to make empty built-in.o if necessary
+obj-                           += dummy.o
+
+always                         := $(dtb-y)
+clean-files                    := *.dtb *.dtb.S
diff --git a/arch/mips/boot/dts/img/pistachio.dtsi b/arch/mips/boot/dts/img/pistachio.dtsi
new file mode 100644 (file)
index 0000000..57809f6
--- /dev/null
@@ -0,0 +1,924 @@
+/*
+ * Copyright (C) 2015, 2016 Imagination Technologies Ltd.
+ * Copyright (C) 2015 Google, 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 <dt-bindings/clock/pistachio-clk.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/mips-gic.h>
+#include <dt-bindings/reset/pistachio-resets.h>
+
+/ {
+       compatible = "img,pistachio";
+
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       interrupt-parent = <&gic>;
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu0: cpu@0 {
+                       device_type = "cpu";
+                       compatible = "mti,interaptiv";
+                       reg = <0>;
+                       clocks = <&clk_core CLK_MIPS_PLL>;
+                       clock-names = "cpu";
+                       clock-latency = <1000>;
+                       operating-points = <
+                               /* kHz    uV(dummy) */
+                               546000 1150000
+                               520000 1100000
+                               494000 1000000
+                               468000 950000
+                               442000 900000
+                               416000 800000
+                       >;
+               };
+       };
+
+       i2c0: i2c@18100000 {
+               compatible = "img,scb-i2c";
+               reg = <0x18100000 0x200>;
+               interrupts = <GIC_SHARED 2 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&clk_periph PERIPH_CLK_I2C0>,
+                        <&cr_periph SYS_CLK_I2C0>;
+               clock-names = "scb", "sys";
+               assigned-clocks = <&clk_periph PERIPH_CLK_I2C0_PRE_DIV>,
+                                 <&clk_periph PERIPH_CLK_I2C0_DIV>;
+               assigned-clock-rates = <100000000>, <33333334>;
+               status = "disabled";
+               pinctrl-names = "default";
+               pinctrl-0 = <&i2c0_pins>;
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+
+       i2c1: i2c@18100200 {
+               compatible = "img,scb-i2c";
+               reg = <0x18100200 0x200>;
+               interrupts = <GIC_SHARED 3 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&clk_periph PERIPH_CLK_I2C1>,
+                        <&cr_periph SYS_CLK_I2C1>;
+               clock-names = "scb", "sys";
+               assigned-clocks = <&clk_periph PERIPH_CLK_I2C1_PRE_DIV>,
+                                 <&clk_periph PERIPH_CLK_I2C1_DIV>;
+               assigned-clock-rates = <100000000>, <33333334>;
+               status = "disabled";
+               pinctrl-names = "default";
+               pinctrl-0 = <&i2c1_pins>;
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+
+       i2c2: i2c@18100400 {
+               compatible = "img,scb-i2c";
+               reg = <0x18100400 0x200>;
+               interrupts = <GIC_SHARED 4 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&clk_periph PERIPH_CLK_I2C2>,
+                        <&cr_periph SYS_CLK_I2C2>;
+               clock-names = "scb", "sys";
+               assigned-clocks = <&clk_periph PERIPH_CLK_I2C2_PRE_DIV>,
+                                 <&clk_periph PERIPH_CLK_I2C2_DIV>;
+               assigned-clock-rates = <100000000>, <33333334>;
+               status = "disabled";
+               pinctrl-names = "default";
+               pinctrl-0 = <&i2c2_pins>;
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+
+       i2c3: i2c@18100600 {
+               compatible = "img,scb-i2c";
+               reg = <0x18100600 0x200>;
+               interrupts = <GIC_SHARED 5 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&clk_periph PERIPH_CLK_I2C3>,
+                        <&cr_periph SYS_CLK_I2C3>;
+               clock-names = "scb", "sys";
+               assigned-clocks = <&clk_periph PERIPH_CLK_I2C3_PRE_DIV>,
+                                 <&clk_periph PERIPH_CLK_I2C3_DIV>;
+               assigned-clock-rates = <100000000>, <33333334>;
+               status = "disabled";
+               pinctrl-names = "default";
+               pinctrl-0 = <&i2c3_pins>;
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+
+       i2s_in: i2s-in@18100800 {
+               compatible = "img,i2s-in";
+               reg = <0x18100800 0x200>;
+               interrupts = <GIC_SHARED 7 IRQ_TYPE_LEVEL_HIGH>;
+               dmas = <&mdc 30 0xffffffff 0>;
+               dma-names = "rx";
+               clocks = <&cr_periph SYS_CLK_I2S_IN>;
+               clock-names = "sys";
+               img,i2s-channels = <6>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&i2s_in_pins>;
+               status = "disabled";
+
+               #sound-dai-cells = <0>;
+       };
+
+       i2s_out: i2s-out@18100a00 {
+               compatible = "img,i2s-out";
+               reg = <0x18100a00 0x200>;
+               interrupts = <GIC_SHARED 13 IRQ_TYPE_LEVEL_HIGH>;
+               dmas = <&mdc 23 0xffffffff 0>;
+               dma-names = "tx";
+               clocks = <&cr_periph SYS_CLK_I2S_OUT>,
+                        <&clk_core CLK_I2S>;
+               clock-names = "sys", "ref";
+               assigned-clocks = <&clk_core CLK_I2S_DIV>;
+               assigned-clock-rates = <12288000>;
+               img,i2s-channels = <6>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&i2s_out_pins>;
+               status = "disabled";
+               resets = <&pistachio_reset PISTACHIO_RESET_I2S_OUT>;
+               reset-names = "rst";
+               #sound-dai-cells = <0>;
+       };
+
+       parallel_out: parallel-audio-out@18100c00 {
+               compatible = "img,parallel-out";
+               reg = <0x18100c00 0x100>;
+               interrupts = <GIC_SHARED 19 IRQ_TYPE_LEVEL_HIGH>;
+               dmas = <&mdc 16 0xffffffff 0>;
+               dma-names = "tx";
+               clocks = <&cr_periph SYS_CLK_PAUD_OUT>,
+                        <&clk_core CLK_AUDIO_DAC>;
+               clock-names = "sys", "ref";
+               assigned-clocks = <&clk_core CLK_AUDIO_DAC_DIV>;
+               assigned-clock-rates = <12288000>;
+               status = "disabled";
+               resets = <&pistachio_reset PISTACHIO_RESET_PRL_OUT>;
+               reset-names = "rst";
+               #sound-dai-cells = <0>;
+       };
+
+       spdif_out: spdif-out@18100d00 {
+               compatible = "img,spdif-out";
+               reg = <0x18100d00 0x100>;
+               interrupts = <GIC_SHARED 21 IRQ_TYPE_LEVEL_HIGH>;
+               dmas = <&mdc 14 0xffffffff 0>;
+               dma-names = "tx";
+               clocks = <&cr_periph SYS_CLK_SPDIF_OUT>,
+                        <&clk_core CLK_SPDIF>;
+               clock-names = "sys", "ref";
+               assigned-clocks = <&clk_core CLK_SPDIF_DIV>;
+               assigned-clock-rates = <12288000>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&spdif_out_pin>;
+               status = "disabled";
+               resets = <&pistachio_reset PISTACHIO_RESET_SPDIF_OUT>;
+               reset-names = "rst";
+               #sound-dai-cells = <0>;
+       };
+
+       spdif_in: spdif-in@18100e00 {
+               compatible = "img,spdif-in";
+               reg = <0x18100e00 0x100>;
+               interrupts = <GIC_SHARED 20 IRQ_TYPE_LEVEL_HIGH>;
+               dmas = <&mdc 15 0xffffffff 0>;
+               dma-names = "rx";
+               clocks = <&cr_periph SYS_CLK_SPDIF_IN>;
+               clock-names = "sys";
+               pinctrl-names = "default";
+               pinctrl-0 = <&spdif_in_pin>;
+               status = "disabled";
+
+               #sound-dai-cells = <0>;
+       };
+
+       internal_dac: internal-dac {
+               compatible = "img,pistachio-internal-dac";
+               img,cr-top = <&cr_top>;
+               img,voltage-select = <1>;
+
+               #sound-dai-cells = <0>;
+       };
+
+       spfi0: spi@18100f00 {
+               compatible = "img,spfi";
+               reg = <0x18100f00 0x100>;
+               interrupts = <GIC_SHARED 22 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&clk_core CLK_SPI0>, <&cr_periph SYS_CLK_SPI0_MASTER>;
+               clock-names = "sys", "spfi";
+               dmas = <&mdc 9 0xffffffff 0>, <&mdc 10 0xffffffff 0>;
+               dma-names = "rx", "tx";
+               spfi-max-frequency = <50000000>;
+               status = "disabled";
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+
+       spfi1: spi@18101000 {
+               compatible = "img,spfi";
+               reg = <0x18101000 0x100>;
+               interrupts = <GIC_SHARED 26 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&clk_core CLK_SPI1>, <&cr_periph SYS_CLK_SPI1>;
+               clock-names = "sys", "spfi";
+               dmas = <&mdc 1 0xffffffff 0>, <&mdc 2 0xffffffff 0>;
+               dma-names = "rx", "tx";
+               img,supports-quad-mode;
+               spfi-max-frequency = <50000000>;
+               status = "disabled";
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+
+       pwm: pwm@18101300 {
+               compatible = "img,pistachio-pwm";
+               reg = <0x18101300 0x100>;
+               clocks = <&clk_periph PERIPH_CLK_PWM>,
+                        <&cr_periph SYS_CLK_PWM>;
+               clock-names = "pwm", "sys";
+               img,cr-periph = <&cr_periph>;
+               #pwm-cells = <2>;
+               status = "disabled";
+       };
+
+       uart0: uart@18101400 {
+               compatible = "snps,dw-apb-uart";
+               reg = <0x18101400 0x100>;
+               interrupts = <GIC_SHARED 24 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&clk_core CLK_UART0>, <&cr_periph SYS_CLK_UART0>;
+               clock-names = "baudclk", "apb_pclk";
+               assigned-clocks = <&clk_core CLK_UART0_INTERNAL_DIV>,
+                                 <&clk_core CLK_UART0_DIV>;
+               reg-shift = <2>;
+               reg-io-width = <4>;
+               pinctrl-0 = <&uart0_pins>, <&uart0_rts_cts_pins>;
+               pinctrl-names = "default";
+               status = "disabled";
+       };
+
+       uart1: uart@18101500 {
+               compatible = "snps,dw-apb-uart";
+               reg = <0x18101500 0x100>;
+               interrupts = <GIC_SHARED 25 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&clk_core CLK_UART1>, <&cr_periph SYS_CLK_UART1>;
+               clock-names = "baudclk", "apb_pclk";
+               assigned-clocks = <&clk_core CLK_UART1_INTERNAL_DIV>,
+                                 <&clk_core CLK_UART1_DIV>;
+               assigned-clock-rates = <114278400>, <1843200>;
+               reg-shift = <2>;
+               reg-io-width = <4>;
+               pinctrl-0 = <&uart1_pins>;
+               pinctrl-names = "default";
+               status = "disabled";
+       };
+
+       adc: adc@18101600 {
+               compatible = "cosmic,10001-adc";
+               reg = <0x18101600 0x24>;
+               adc-reserved-channels = <0x30>;
+               clocks = <&clk_core CLK_AUX_ADC>;
+               clock-names = "adc";
+               assigned-clocks = <&clk_core CLK_AUX_ADC_INTERNAL_DIV>,
+                                 <&clk_core CLK_AUX_ADC_DIV>;
+               assigned-clock-rates = <100000000>, <1000000>;
+               status = "disabled";
+
+               #io-channel-cells = <1>;
+       };
+
+       pinctrl: pinctrl@18101c00 {
+               compatible = "img,pistachio-system-pinctrl";
+               reg = <0x18101c00 0x400>;
+
+               gpio0: gpio0 {
+                       interrupts = <GIC_SHARED 71 IRQ_TYPE_LEVEL_HIGH>;
+
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       gpio-ranges = <&pinctrl 0 0 16>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpio1: gpio1 {
+                       interrupts = <GIC_SHARED 72 IRQ_TYPE_LEVEL_HIGH>;
+
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       gpio-ranges = <&pinctrl 0 16 16>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpio2: gpio2 {
+                       interrupts = <GIC_SHARED 73 IRQ_TYPE_LEVEL_HIGH>;
+
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       gpio-ranges = <&pinctrl 0 32 16>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpio3: gpio3 {
+                       interrupts = <GIC_SHARED 74 IRQ_TYPE_LEVEL_HIGH>;
+
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       gpio-ranges = <&pinctrl 0 48 16>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpio4: gpio4 {
+                       interrupts = <GIC_SHARED 75 IRQ_TYPE_LEVEL_HIGH>;
+
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       gpio-ranges = <&pinctrl 0 64 16>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpio5: gpio5 {
+                       interrupts = <GIC_SHARED 76 IRQ_TYPE_LEVEL_HIGH>;
+
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       gpio-ranges = <&pinctrl 0 80 10>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               i2c0_pins: i2c0-pins {
+                       pin_i2c0: i2c0 {
+                               pins = "mfio28", "mfio29";
+                               function = "i2c0";
+                               drive-strength = <4>;
+                       };
+               };
+
+               i2c1_pins: i2c1-pins {
+                       pin_i2c1: i2c1 {
+                               pins = "mfio30", "mfio31";
+                               function = "i2c1";
+                               drive-strength = <4>;
+                       };
+               };
+
+               i2c2_pins: i2c2-pins {
+                       pin_i2c2: i2c2 {
+                               pins = "mfio32", "mfio33";
+                               function = "i2c2";
+                               drive-strength = <4>;
+                       };
+               };
+
+               i2c3_pins: i2c3-pins {
+                       pin_i2c3: i2c3 {
+                               pins = "mfio34", "mfio35";
+                               function = "i2c3";
+                               drive-strength = <4>;
+                       };
+               };
+
+               spim0_pins: spim0-pins {
+                       pin_spim0: spim0 {
+                               pins = "mfio9", "mfio10";
+                               function = "spim0";
+                               drive-strength = <4>;
+                       };
+                       spim0_clk: spim0-clk {
+                               pins = "mfio8";
+                               function = "spim0";
+                               drive-strength = <4>;
+                       };
+               };
+
+               spim0_cs0_alt_pin: spim0-cs0-alt-pin {
+                       spim0-cs0 {
+                               pins = "mfio2";
+                               drive-strength = <2>;
+                       };
+               };
+
+               spim0_cs1_pin: spim0-cs1-pin {
+                       spim0-cs1 {
+                               pins = "mfio1";
+                               drive-strength = <2>;
+                       };
+               };
+
+               spim0_cs2_pin: spim0-cs2-pin {
+                       spim0-cs2 {
+                               pins = "mfio55";
+                               drive-strength = <2>;
+                       };
+               };
+
+               spim0_cs2_alt_pin: spim0-cs2-alt-pin {
+                       spim0-cs2 {
+                               pins = "mfio28";
+                               drive-strength = <2>;
+                       };
+               };
+
+               spim0_cs3_pin: spim0-cs3-pin {
+                       spim0-cs3 {
+                               pins = "mfio56";
+                               drive-strength = <2>;
+                       };
+               };
+
+               spim0_cs3_alt_pin: spim0-cs3-alt-pin {
+                       spim0-cs3 {
+                               pins = "mfio29";
+                               drive-strength = <2>;
+                       };
+               };
+
+               spim0_cs4_pin: spim0-cs4-pin {
+                       spim0-cs4 {
+                               pins = "mfio57";
+                               drive-strength = <2>;
+                       };
+               };
+
+               spim0_cs4_alt_pin: spim0-cs4-alt-pin {
+                       spim0-cs4 {
+                               pins = "mfio30";
+                               drive-strength = <2>;
+                       };
+               };
+
+               spim1_pins: spim1-pins {
+                       spim1 {
+                               pins = "mfio3", "mfio4", "mfio5";
+                               function = "spim1";
+                               drive-strength = <2>;
+                       };
+               };
+
+               spim1_quad_pins: spim1-quad-pins {
+                       spim1-quad {
+                               pins = "mfio6", "mfio7";
+                               function = "spim1";
+                               drive-strength = <2>;
+                       };
+               };
+
+               spim1_cs0_pin: spim1-cs0-pins {
+                       spim1-cs0 {
+                               pins = "mfio0";
+                               function = "spim1";
+                               drive-strength = <2>;
+                       };
+               };
+
+               spim1_cs1_pin: spim1-cs1-pin {
+                       spim1-cs1 {
+                               pins = "mfio1";
+                               function = "spim1";
+                               drive-strength = <2>;
+                       };
+               };
+
+               spim1_cs1_alt_pin: spim1-cs1-alt-pin {
+                       spim1-cs1 {
+                               pins = "mfio58";
+                               function = "spim1";
+                               drive-strength = <2>;
+                       };
+               };
+
+               spim1_cs2_pin: spim1-cs2-pin {
+                       spim1-cs2 {
+                               pins = "mfio2";
+                               function = "spim1";
+                               drive-strength = <2>;
+                       };
+               };
+
+               spim1_cs2_alt0_pin: spim1-cs2-alt0-pin {
+                       spim1-cs2 {
+                               pins = "mfio31";
+                               function = "spim1";
+                               drive-strength = <2>;
+                       };
+               };
+
+               spim1_cs2_alt1_pin: spim1-cs2-alt1-pin {
+                       spim1-cs2 {
+                               pins = "mfio55";
+                               function = "spim1";
+                               drive-strength = <2>;
+                       };
+               };
+
+               spim1_cs3_pin: spim1-cs3-pin {
+                       spim1-cs3 {
+                               pins = "mfio56";
+                               function = "spim1";
+                               drive-strength = <2>;
+                       };
+               };
+
+               spim1_cs4_pin: spim1-cs4-pin {
+                       spim1-cs4 {
+                               pins = "mfio57";
+                               function = "spim1";
+                               drive-strength = <2>;
+                       };
+               };
+
+               uart0_pins: uart0-pins {
+                       uart0 {
+                               pins = "mfio55", "mfio56";
+                               function = "uart0";
+                               drive-strength = <2>;
+                       };
+               };
+
+               uart0_rts_cts_pins: uart0-rts-cts-pins {
+                       uart0-rts-cts {
+                               pins = "mfio57", "mfio58";
+                               function = "uart0";
+                               drive-strength = <2>;
+                       };
+               };
+
+               uart1_pins: uart1-pins {
+                       uart1 {
+                               pins = "mfio59", "mfio60";
+                               function = "uart1";
+                               drive-strength = <2>;
+                       };
+               };
+
+               uart1_rts_cts_pins: uart1-rts-cts-pins {
+                       uart1-rts-cts {
+                                 pins = "mfio1", "mfio2";
+                                 function = "uart1";
+                                 drive-strength = <2>;
+                       };
+               };
+
+               enet_pins: enet-pins {
+                       pin_enet: enet {
+                               pins = "mfio63", "mfio64", "mfio65", "mfio66",
+                                      "mfio67", "mfio68", "mfio69", "mfio70";
+                               function = "eth";
+                               slew-rate = <1>;
+                               drive-strength = <4>;
+                       };
+                       pin_enet_phy_clk: enet-phy-clk {
+                               pins = "mfio71";
+                               function = "eth";
+                               slew-rate = <1>;
+                               drive-strength = <8>;
+                       };
+               };
+
+               sdhost_pins: sdhost-pins {
+                       pin_sdhost_clk: sdhost-clk {
+                               pins = "mfio15";
+                               function = "sdhost";
+                               slew-rate = <1>;
+                               drive-strength = <4>;
+                       };
+                       pin_sdhost_cmd: sdhost-cmd {
+                               pins = "mfio16";
+                               function = "sdhost";
+                               slew-rate = <1>;
+                               drive-strength = <4>;
+                       };
+                       pin_sdhost_data: sdhost-data {
+                               pins = "mfio17", "mfio18", "mfio19", "mfio20",
+                                      "mfio21", "mfio22", "mfio23", "mfio24";
+                               function = "sdhost";
+                               slew-rate = <1>;
+                               drive-strength = <4>;
+                       };
+                       pin_sdhost_power_select: sdhost-power-select {
+                               pins = "mfio25";
+                               function = "sdhost";
+                               slew-rate = <1>;
+                               drive-strength = <2>;
+                       };
+                       pin_sdhost_card_detect: sdhost-card-detect {
+                               pins = "mfio26";
+                               function = "sdhost";
+                               drive-strength = <2>;
+                       };
+                       pin_sdhost_write_protect: sdhost-write-protect {
+                               pins = "mfio27";
+                               function = "sdhost";
+                               drive-strength = <2>;
+                       };
+               };
+
+               ir_pin: ir-pin {
+                       ir-data {
+                               pins = "mfio72";
+                               function = "ir";
+                               drive-strength = <2>;
+                       };
+               };
+
+               pwmpdm0_pin: pwmpdm0-pin {
+                       pwmpdm0 {
+                               pins = "mfio73";
+                               function = "pwmpdm";
+                               drive-strength = <2>;
+                       };
+               };
+
+               pwmpdm1_pin: pwmpdm1-pin {
+                       pwmpdm1 {
+                               pins = "mfio74";
+                               function = "pwmpdm";
+                               drive-strength = <2>;
+                       };
+               };
+
+               pwmpdm2_pin: pwmpdm2-pin {
+                       pwmpdm2 {
+                               pins = "mfio75";
+                               function = "pwmpdm";
+                               drive-strength = <2>;
+                       };
+               };
+
+               pwmpdm3_pin: pwmpdm3-pin {
+                       pwmpdm3 {
+                               pins = "mfio76";
+                               function = "pwmpdm";
+                               drive-strength = <2>;
+                       };
+               };
+
+               dac_clk_pin: dac-clk-pin {
+                       pin_dac_clk: dac-clk {
+                               pins = "mfio45";
+                               function = "i2s_dac_clk";
+                               drive-strength = <4>;
+                       };
+               };
+
+               i2s_mclk_pin: i2s-mclk-pin {
+                       pin_i2s_mclk: i2s-mclk {
+                               pins = "mfio36";
+                               function = "i2s_out";
+                               drive-strength = <4>;
+                       };
+               };
+
+               spdif_out_pin: spdif-out-pin {
+                       spdif-out {
+                               pins = "mfio61";
+                               function = "spdif_out";
+                               slew-rate = <1>;
+                               drive-strength = <2>;
+                       };
+               };
+
+               spdif_in_pin: spdif-in-pin {
+                       spdif-in {
+                               pins = "mfio62";
+                               function = "spdif_in";
+                               drive-strength = <2>;
+                       };
+               };
+
+               i2s_out_pins: i2s-out-pins {
+                       pins_i2s_out_clk: i2s-out-clk {
+                               pins = "mfio37", "mfio38";
+                               function = "i2s_out";
+                               drive-strength = <4>;
+                       };
+                       pins_i2s_out: i2s-out {
+                               pins = "mfio39", "mfio40",
+                                      "mfio41", "mfio42",
+                                      "mfio43", "mfio44";
+                               function = "i2s_out";
+                               drive-strength = <2>;
+                       };
+               };
+
+               i2s_in_pins: i2s-in-pins {
+                       i2s-in {
+                               pins = "mfio47", "mfio48", "mfio49",
+                                      "mfio50", "mfio51", "mfio52",
+                                      "mfio53", "mfio54";
+                               function = "i2s_in";
+                               drive-strength = <2>;
+                       };
+               };
+       };
+
+       timer: timer@18102000 {
+               compatible = "img,pistachio-gptimer";
+               reg = <0x18102000 0x100>;
+               interrupts = <GIC_SHARED 60 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&clk_periph PERIPH_CLK_COUNTER_FAST>,
+                        <&cr_periph SYS_CLK_TIMER>;
+               clock-names = "fast", "sys";
+               img,cr-periph = <&cr_periph>;
+       };
+
+       wdt: watchdog@18102100 {
+               compatible = "img,pdc-wdt";
+               reg = <0x18102100 0x100>;
+               interrupts = <GIC_SHARED 52 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&clk_periph PERIPH_CLK_WD>, <&cr_periph SYS_CLK_WD>;
+               clock-names = "wdt", "sys";
+               assigned-clocks = <&clk_periph PERIPH_CLK_WD_PRE_DIV>,
+                                 <&clk_periph PERIPH_CLK_WD_DIV>;
+               assigned-clock-rates = <4000000>, <32768>;
+       };
+
+       ir: ir@18102200 {
+               compatible = "img,ir-rev1";
+               reg = <0x18102200 0x100>;
+               interrupts = <GIC_SHARED 51 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&clk_periph PERIPH_CLK_IR>, <&cr_periph SYS_CLK_IR>;
+               clock-names = "core", "sys";
+               assigned-clocks = <&clk_periph PERIPH_CLK_IR_PRE_DIV>,
+                                 <&clk_periph PERIPH_CLK_IR_DIV>;
+               assigned-clock-rates = <4000000>, <32768>;
+               pinctrl-0 = <&ir_pin>;
+               pinctrl-names = "default";
+               status = "disabled";
+       };
+
+       usb: usb@18120000 {
+               compatible = "snps,dwc2";
+               reg = <0x18120000 0x1c000>;
+               interrupts = <GIC_SHARED 49 IRQ_TYPE_LEVEL_HIGH>;
+               phys = <&usb_phy>;
+               phy-names = "usb2-phy";
+               g-tx-fifo-size = <256 256 256 256>;
+               status = "disabled";
+       };
+
+       enet: ethernet@18140000 {
+               compatible = "snps,dwmac";
+               reg = <0x18140000 0x2000>;
+               interrupts = <GIC_SHARED 50 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "macirq";
+               clocks = <&clk_core CLK_ENET>, <&cr_periph SYS_CLK_ENET>;
+               clock-names = "stmmaceth", "pclk";
+               assigned-clocks = <&clk_core CLK_ENET_MUX>,
+                                 <&clk_core CLK_ENET_DIV>;
+               assigned-clock-parents = <&clk_core CLK_SYS_INTERNAL_DIV>;
+               assigned-clock-rates = <0>, <50000000>;
+               pinctrl-0 = <&enet_pins>;
+               pinctrl-names = "default";
+               phy-mode = "rmii";
+               status = "disabled";
+       };
+
+       sdhost: mmc@18142000 {
+               compatible = "img,pistachio-dw-mshc";
+               reg = <0x18142000 0x400>;
+               interrupts = <GIC_SHARED 39 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&clk_core CLK_SD_HOST>, <&cr_periph SYS_CLK_SD_HOST>;
+               clock-names = "ciu", "biu";
+               pinctrl-0 = <&sdhost_pins>;
+               pinctrl-names = "default";
+               fifo-depth = <0x20>;
+               num-slots = <1>;
+               clock-frequency = <50000000>;
+               bus-width = <8>;
+               cap-mmc-highspeed;
+               cap-sd-highspeed;
+               status = "disabled";
+       };
+
+       sram: sram@1b000000 {
+               compatible = "mmio-sram";
+               reg = <0x1b000000 0x10000>;
+       };
+
+       mdc: dma-controller@18143000 {
+               compatible = "img,pistachio-mdc-dma";
+               reg = <0x18143000 0x1000>;
+               interrupts = <GIC_SHARED 27 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SHARED 28 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SHARED 29 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SHARED 30 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SHARED 31 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SHARED 32 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SHARED 33 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SHARED 34 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SHARED 35 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SHARED 36 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SHARED 37 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SHARED 38 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&cr_periph SYS_CLK_MDC>;
+               clock-names = "sys";
+
+               img,max-burst-multiplier = <16>;
+               img,cr-periph = <&cr_periph>;
+
+               #dma-cells = <3>;
+       };
+
+       clk_core: clk@18144000 {
+               compatible = "img,pistachio-clk", "syscon";
+               clocks = <&xtal>, <&cr_top EXT_CLK_AUDIO_IN>,
+                        <&cr_top EXT_CLK_ENET_IN>;
+               clock-names = "xtal", "audio_refclk_ext_gate",
+                             "ext_enet_in_gate";
+               reg = <0x18144000 0x800>;
+               #clock-cells = <1>;
+       };
+
+       clk_periph: clk@18144800 {
+               compatible = "img,pistachio-clk-periph";
+               reg = <0x18144800 0x1000>;
+               clocks = <&clk_core CLK_PERIPH_SYS>;
+               clock-names = "periph_sys_core";
+               #clock-cells = <1>;
+       };
+
+       cr_periph: clk@18148000 {
+               compatible = "img,pistachio-cr-periph", "syscon", "simple-bus";
+               reg = <0x18148000 0x1000>;
+               clocks = <&clk_periph PERIPH_CLK_SYS>;
+               clock-names = "sys";
+               #clock-cells = <1>;
+
+               pistachio_reset: reset-controller {
+                       compatible = "img,pistachio-reset";
+                       #reset-cells = <1>;
+               };
+       };
+
+       cr_top: clk@18149000 {
+               compatible = "img,pistachio-cr-top", "syscon";
+               reg = <0x18149000 0x200>;
+               #clock-cells = <1>;
+       };
+
+       hash: hash@18149600 {
+               compatible = "img,hash-accelerator";
+               reg = <0x18149600 0x100>, <0x18101100 0x4>;
+               interrupts = <GIC_SHARED 59 IRQ_TYPE_LEVEL_HIGH>;
+               dmas = <&mdc 8 0xffffffff 0>;
+               dma-names = "tx";
+               clocks = <&cr_periph SYS_CLK_HASH>,
+                        <&clk_periph PERIPH_CLK_ROM>;
+               clock-names = "sys", "hash";
+       };
+
+       gic: interrupt-controller@1bdc0000 {
+               compatible = "mti,gic";
+               reg = <0x1bdc0000 0x20000>;
+
+               interrupt-controller;
+               #interrupt-cells = <3>;
+
+               timer {
+                       compatible = "mti,gic-timer";
+                       interrupts = <GIC_LOCAL 1 IRQ_TYPE_NONE>;
+                       clocks = <&clk_core CLK_MIPS>;
+               };
+       };
+
+       usb_phy: usb-phy {
+               compatible = "img,pistachio-usb-phy";
+               clocks = <&clk_core CLK_USB_PHY>;
+               clock-names = "usb_phy";
+               assigned-clocks = <&clk_core CLK_USB_PHY_DIV>;
+               assigned-clock-rates = <50000000>;
+               img,refclk = <0x2>;
+               img,cr-top = <&cr_top>;
+               #phy-cells = <0>;
+       };
+
+       xtal: xtal {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <52000000>;
+               clock-output-names = "xtal";
+       };
+};
diff --git a/arch/mips/boot/dts/img/pistachio_marduk.dts b/arch/mips/boot/dts/img/pistachio_marduk.dts
new file mode 100644 (file)
index 0000000..cf9cebd
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2015, 2016 Imagination Technologies 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.
+ *
+ * IMG Marduk board is also known as Creator Ci40.
+ */
+
+/dts-v1/;
+
+#include "pistachio.dtsi"
+
+/ {
+       model = "IMG Marduk (Creator Ci40)";
+       compatible = "img,pistachio-marduk", "img,pistachio";
+
+       aliases {
+               serial0 = &uart0;
+               serial1 = &uart1;
+               ethernet0 = &enet;
+               spi0 = &spfi0;
+               spi1 = &spfi1;
+       };
+
+       chosen {
+               bootargs = "root=/dev/sda1 rootwait ro lpj=723968";
+               stdout-path = "serial1:115200";
+       };
+
+       memory {
+               device_type = "memory";
+               reg =  <0x00000000 0x10000000>;
+       };
+
+       reg_1v8: fixed-regulator {
+               compatible = "regulator-fixed";
+               regulator-name = "aux_adc_vref";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+               regulator-boot-on;
+       };
+
+       internal_dac_supply: internal-dac-supply {
+               compatible = "regulator-fixed";
+               regulator-name = "internal_dac_supply";
+               regulator-min-microvolt = <1800000>;
+               regulator-max-microvolt = <1800000>;
+       };
+
+       leds {
+               compatible = "pwm-leds";
+               heartbeat {
+                       label = "marduk:red:heartbeat";
+                       pwms = <&pwm 3 300000>;
+                       max-brightness = <255>;
+                       linux,default-trigger = "heartbeat";
+               };
+       };
+
+       keys {
+               compatible = "gpio-keys";
+               button@1 {
+                       label = "Button 1";
+                       linux,code = <0x101>; /* BTN_1 */
+                       gpios = <&gpio3 6 GPIO_ACTIVE_LOW>;
+               };
+               button@2 {
+                       label = "Button 2";
+                       linux,code = <0x102>; /* BTN_2 */
+                       gpios = <&gpio2 14 GPIO_ACTIVE_LOW>;
+               };
+       };
+};
+
+&internal_dac {
+       VDD-supply = <&internal_dac_supply>;
+};
+
+&spfi1 {
+       status = "okay";
+
+       pinctrl-0 = <&spim1_pins>, <&spim1_quad_pins>, <&spim1_cs0_pin>,
+                   <&spim1_cs1_pin>;
+       pinctrl-names = "default";
+       cs-gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>, <&gpio0 1 GPIO_ACTIVE_HIGH>;
+
+       flash@0 {
+               compatible = "spansion,s25fl016k", "jedec,spi-nor";
+               reg = <0>;
+               spi-max-frequency = <50000000>;
+       };
+};
+
+&uart0 {
+       status = "okay";
+       assigned-clock-rates = <114278400>, <1843200>;
+};
+
+&uart1 {
+       status = "okay";
+};
+
+&usb {
+       status = "okay";
+};
+
+&enet {
+       status = "okay";
+};
+
+&pin_enet {
+       drive-strength = <2>;
+};
+
+&pin_enet_phy_clk {
+       drive-strength = <2>;
+};
+
+&sdhost {
+       status = "okay";
+       bus-width = <4>;
+       disable-wp;
+};
+
+&pin_sdhost_cmd {
+       drive-strength = <2>;
+};
+
+&pin_sdhost_data {
+       drive-strength = <2>;
+};
+
+&pwm {
+       status = "okay";
+
+       pinctrl-0 = <&pwmpdm0_pin>, <&pwmpdm1_pin>, <&pwmpdm2_pin>,
+                   <&pwmpdm3_pin>;
+       pinctrl-names = "default";
+};
+
+&adc {
+       status = "okay";
+       vref-supply = <&reg_1v8>;
+       adc-reserved-channels = <0x10>;
+};
+
+&i2c2 {
+       status = "okay";
+       clock-frequency = <400000>;
+
+       tpm@20 {
+               compatible = "infineon,slb9645tt";
+               reg = <0x20>;
+       };
+
+};
+
+&i2c3 {
+       status = "okay";
+       clock-frequency = <400000>;
+};
index 48d21127c3f38b2f575f6f7e96e038c3b2393f16..09a62f2e2f8ffc8335e80943ba3c13444b626331 100644 (file)
                compatible = "mti,cpu-interrupt-controller";
        };
 
+       axi_intc: interrupt-controller@10200000 {
+               #interrupt-cells = <1>;
+               compatible = "xlnx,xps-intc-1.00.a";
+               interrupt-controller;
+               reg = <0x10200000 0x10000>;
+               xlnx,kind-of-intr = <0x0>;
+               xlnx,num-intr-inputs = <0x6>;
+
+               interrupt-parent = <&cpuintc>;
+               interrupts = <6>;
+       };
+
        axi_gpio: gpio@10600000 {
                #gpio-cells = <1>;
                compatible = "xlnx,xps-gpio-1.00.a";
                xlnx,tri-default = <0xffffffff>;
        } ;
 
+       axi_ethernetlite: ethernet@10e00000 {
+               compatible = "xlnx,xps-ethernetlite-3.00.a";
+               device_type = "network";
+               interrupt-parent = <&axi_intc>;
+               interrupts = <1>;
+               phy-handle = <&phy0>;
+               reg = <0x10e00000 0x10000>;
+               xlnx,duplex = <0x1>;
+               xlnx,include-global-buffers = <0x1>;
+               xlnx,include-internal-loopback = <0x0>;
+               xlnx,include-mdio = <0x1>;
+               xlnx,instance = "axi_ethernetlite_inst";
+               xlnx,rx-ping-pong = <0x1>;
+               xlnx,s-axi-id-width = <0x1>;
+               xlnx,tx-ping-pong = <0x1>;
+               xlnx,use-internal = <0x0>;
+               mdio {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       phy0: phy@1 {
+                               device_type = "ethernet-phy";
+                               reg = <1>;
+                       };
+               };
+       };
+
        axi_uart16550: serial@10400000 {
                compatible = "ns16550a";
                reg = <0x10400000 0x10000>;
                reg-offset = <0x1000>;
 
                clocks  = <&ext>;
+
+               interrupt-parent = <&axi_intc>;
+               interrupts = <0>;
        };
+
+       axi_i2c: i2c@10A00000 {
+           compatible = "xlnx,xps-iic-2.00.a";
+           interrupt-parent = <&axi_intc>;
+           interrupts = <4>;
+           reg = < 0x10A00000 0x10000 >;
+           clocks = <&ext>;
+           xlnx,clk-freq = <0x5f5e100>;
+           xlnx,family = "Artix7";
+           xlnx,gpo-width = <0x1>;
+           xlnx,iic-freq = <0x186a0>;
+           xlnx,scl-inertial-delay = <0x0>;
+           xlnx,sda-inertial-delay = <0x0>;
+           xlnx,ten-bit-adr = <0x0>;
+           #address-cells = <1>;
+           #size-cells = <0>;
+
+           ad7420@4B {
+               compatible = "adi,adt7420";
+               reg = <0x4B>;
+           };
+       } ;
 };
 
 &ext {
index 2a59265788413e3387cb358e35a9c720d1ba4a3b..7c02e542959a2cdd23e49283f656129e211b1266 100644 (file)
@@ -18,3 +18,4 @@ obj-y += crypto/
 obj-$(CONFIG_MTD)                    += flash_setup.o
 obj-$(CONFIG_SMP)                    += smp.o
 obj-$(CONFIG_OCTEON_ILM)             += oct_ilm.o
+obj-$(CONFIG_USB)                    += octeon-usb.o
index f66bd1adc7ff310880b27697cd0e83cd25a124b7..4d22365844af30b9bdd24cfd521b6a8e0a7f7cff 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #include <asm/cop2.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/interrupt.h>
 
 #include "octeon-crypto.h"
index fd69528b24fb3956818dc18cd143e5ada752318e..1226965e1e4f7527563450523f2be053265f377e 100644 (file)
@@ -164,19 +164,14 @@ static void *octeon_dma_alloc_coherent(struct device *dev, size_t size,
        /* ignore region specifiers */
        gfp &= ~(__GFP_DMA | __GFP_DMA32 | __GFP_HIGHMEM);
 
-#ifdef CONFIG_ZONE_DMA
-       if (dev == NULL)
+       if (IS_ENABLED(CONFIG_ZONE_DMA) && dev == NULL)
                gfp |= __GFP_DMA;
-       else if (dev->coherent_dma_mask <= DMA_BIT_MASK(24))
+       else if (IS_ENABLED(CONFIG_ZONE_DMA) &&
+                dev->coherent_dma_mask <= DMA_BIT_MASK(24))
                gfp |= __GFP_DMA;
-       else
-#endif
-#ifdef CONFIG_ZONE_DMA32
-            if (dev->coherent_dma_mask <= DMA_BIT_MASK(32))
+       else if (IS_ENABLED(CONFIG_ZONE_DMA32) &&
+                dev->coherent_dma_mask <= DMA_BIT_MASK(32))
                gfp |= __GFP_DMA32;
-       else
-#endif
-               ;
 
        /* Don't invoke OOM killer */
        gfp |= __GFP_NORETRY;
index b65a6c1ac0163b8cbbd9eba28fca27b7085ff59c..8d54d774933c560526831f5a3d76402cc2484820 100644 (file)
@@ -30,8 +30,8 @@
  * application start time.
  */
 
+#include <linux/export.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
 
 #include <asm/octeon/cvmx.h>
 #include <asm/octeon/cvmx-spinlock.h>
index 868659e64d4a5c7f63680b8c495decdad320be50..4b26fedecf467f944afd69ab4417d6ba0bb9923b 100644 (file)
@@ -33,7 +33,7 @@
  * these functions directly.
  *
  */
-#include <linux/module.h>
+#include <linux/export.h>
 
 #include <asm/octeon/octeon.h>
 
index 671ab1db272765ac50ad9aab1bb85a3ec548a8ef..ba4753c23b0373436293aca2c904bf85e89e3d52 100644 (file)
@@ -287,8 +287,7 @@ cvmx_helper_link_info_t __cvmx_helper_rgmii_link_get(int ipd_port)
  * Configure an IPD/PKO port for the specified link state. This
  * function does not influence auto negotiation at the PHY level.
  * The passed link state must always match the link state returned
- * by cvmx_helper_link_get(). It is normally best to use
- * cvmx_helper_link_autoconf() instead.
+ * by cvmx_helper_link_get().
  *
  * @ipd_port:  IPD/PKO port to configure
  * @link_info: The new link state
index 54375340afe8ba4e3795fb41c7f7af749f0126d5..57828335077671607003f09e30b9a5331b2325af 100644 (file)
@@ -500,8 +500,7 @@ cvmx_helper_link_info_t __cvmx_helper_sgmii_link_get(int ipd_port)
  * Configure an IPD/PKO port for the specified link state. This
  * function does not influence auto negotiation at the PHY level.
  * The passed link state must always match the link state returned
- * by cvmx_helper_link_get(). It is normally best to use
- * cvmx_helper_link_autoconf() instead.
+ * by cvmx_helper_link_get().
  *
  * @ipd_port:  IPD/PKO port to configure
  * @link_info: The new link state
index 1f3030c72d88706bee9d9558906360506ddbc970..ef16aa00167bbee0cef51515ba71d02eede8c3aa 100644 (file)
@@ -188,8 +188,7 @@ cvmx_helper_link_info_t __cvmx_helper_spi_link_get(int ipd_port)
  * Configure an IPD/PKO port for the specified link state. This
  * function does not influence auto negotiation at the PHY level.
  * The passed link state must always match the link state returned
- * by cvmx_helper_link_get(). It is normally best to use
- * cvmx_helper_link_autoconf() instead.
+ * by cvmx_helper_link_get().
  *
  * @ipd_port:  IPD/PKO port to configure
  * @link_info: The new link state
index d347fe13b66646121649af57a4fa8854319dd2f3..19d54e02c18567cf7f6f494ea80623138e3ca5fc 100644 (file)
@@ -295,8 +295,7 @@ cvmx_helper_link_info_t __cvmx_helper_xaui_link_get(int ipd_port)
  * Configure an IPD/PKO port for the specified link state. This
  * function does not influence auto negotiation at the PHY level.
  * The passed link state must always match the link state returned
- * by cvmx_helper_link_get(). It is normally best to use
- * cvmx_helper_link_autoconf() instead.
+ * by cvmx_helper_link_get().
  *
  * @ipd_port:  IPD/PKO port to configure
  * @link_info: The new link state
index 6456af6424719a5cc1adabaea0fc1ccd210c29df..f24be0b5db5075e911125e95f7ab6fa6a590bd5a 100644 (file)
@@ -69,10 +69,6 @@ void (*cvmx_override_ipd_port_setup) (int ipd_port);
 /* Port count per interface */
 static int interface_port_count[5];
 
-/* Port last configured link info index by IPD/PKO port */
-static cvmx_helper_link_info_t
-    port_link_info[CVMX_PIP_NUM_INPUT_PORTS];
-
 /**
  * Return the number of interfaces the chip has. Each interface
  * may have multiple ports. Most chips support two interfaces,
@@ -1135,41 +1131,6 @@ int cvmx_helper_initialize_packet_io_local(void)
        return cvmx_pko_initialize_local();
 }
 
-/**
- * Auto configure an IPD/PKO port link state and speed. This
- * function basically does the equivalent of:
- * cvmx_helper_link_set(ipd_port, cvmx_helper_link_get(ipd_port));
- *
- * @ipd_port: IPD/PKO port to auto configure
- *
- * Returns Link state after configure
- */
-cvmx_helper_link_info_t cvmx_helper_link_autoconf(int ipd_port)
-{
-       cvmx_helper_link_info_t link_info;
-       int interface = cvmx_helper_get_interface_num(ipd_port);
-       int index = cvmx_helper_get_interface_index_num(ipd_port);
-
-       if (index >= cvmx_helper_ports_on_interface(interface)) {
-               link_info.u64 = 0;
-               return link_info;
-       }
-
-       link_info = cvmx_helper_link_get(ipd_port);
-       if (link_info.u64 == port_link_info[ipd_port].u64)
-               return link_info;
-
-       /* If we fail to set the link speed, port_link_info will not change */
-       cvmx_helper_link_set(ipd_port, link_info);
-
-       /*
-        * port_link_info should be the current value, which will be
-        * different than expect if cvmx_helper_link_set() failed.
-        */
-       return port_link_info[ipd_port];
-}
-EXPORT_SYMBOL_GPL(cvmx_helper_link_autoconf);
-
 /**
  * Return the link state of an IPD/PKO port as returned by
  * auto negotiation. The result of this function may not match
@@ -1233,8 +1194,7 @@ EXPORT_SYMBOL_GPL(cvmx_helper_link_get);
  * Configure an IPD/PKO port for the specified link state. This
  * function does not influence auto negotiation at the PHY level.
  * The passed link state must always match the link state returned
- * by cvmx_helper_link_get(). It is normally best to use
- * cvmx_helper_link_autoconf() instead.
+ * by cvmx_helper_link_get().
  *
  * @ipd_port:  IPD/PKO port to configure
  * @link_info: The new link state
@@ -1276,11 +1236,6 @@ int cvmx_helper_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
        case CVMX_HELPER_INTERFACE_MODE_LOOP:
                break;
        }
-       /* Set the port_link_info here so that the link status is updated
-          no matter how cvmx_helper_link_set is called. We don't change
-          the value if link_set failed */
-       if (result == 0)
-               port_link_info[ipd_port].u64 = link_info.u64;
        return result;
 }
 EXPORT_SYMBOL_GPL(cvmx_helper_link_set);
index cc1b1d2a6fa1567e7030da90ab71f476af724e18..30ecba134e09a73722cb8a2c196f7675e709866d 100644 (file)
@@ -29,7 +29,7 @@
  * This module provides system/board/application information obtained
  * by the bootloader.
  */
-#include <linux/module.h>
+#include <linux/export.h>
 
 #include <asm/octeon/cvmx.h>
 #include <asm/octeon/cvmx-sysinfo.h>
index 64e08df51d65f76b79310b1df6d52e2aa78e2a97..cfd97f6448bba189f8b2b112ed4d656f92ce4a58 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <asm/asm.h>
 #include <asm/asm-offsets.h>
+#include <asm/export.h>
 #include <asm/regdef.h>
 
 #define dst a0
  * t7 is used as a flag to note inatomic mode.
  */
 LEAF(__copy_user_inatomic)
+EXPORT_SYMBOL(__copy_user_inatomic)
        b       __copy_user_common
         li     t7, 1
        END(__copy_user_inatomic)
@@ -154,9 +156,11 @@ LEAF(__copy_user_inatomic)
  */
        .align  5
 LEAF(memcpy)                                   /* a0=dst a1=src a2=len */
+EXPORT_SYMBOL(memcpy)
        move    v0, dst                         /* return value */
 __memcpy:
 FEXPORT(__copy_user)
+EXPORT_SYMBOL(__copy_user)
        li      t7, 0                           /* not inatomic */
 __copy_user_common:
        /*
@@ -208,18 +212,18 @@ EXC(      STORE   t2, UNIT(6)(dst),       s_exc_p10u)
        ADD     src, src, 16*NBYTES
 EXC(   STORE   t3, UNIT(7)(dst),       s_exc_p9u)
        ADD     dst, dst, 16*NBYTES
-EXC(   LOAD    t0, UNIT(-8)(src),      l_exc_copy)
-EXC(   LOAD    t1, UNIT(-7)(src),      l_exc_copy)
-EXC(   LOAD    t2, UNIT(-6)(src),      l_exc_copy)
-EXC(   LOAD    t3, UNIT(-5)(src),      l_exc_copy)
+EXC(   LOAD    t0, UNIT(-8)(src),      l_exc_copy_rewind16)
+EXC(   LOAD    t1, UNIT(-7)(src),      l_exc_copy_rewind16)
+EXC(   LOAD    t2, UNIT(-6)(src),      l_exc_copy_rewind16)
+EXC(   LOAD    t3, UNIT(-5)(src),      l_exc_copy_rewind16)
 EXC(   STORE   t0, UNIT(-8)(dst),      s_exc_p8u)
 EXC(   STORE   t1, UNIT(-7)(dst),      s_exc_p7u)
 EXC(   STORE   t2, UNIT(-6)(dst),      s_exc_p6u)
 EXC(   STORE   t3, UNIT(-5)(dst),      s_exc_p5u)
-EXC(   LOAD    t0, UNIT(-4)(src),      l_exc_copy)
-EXC(   LOAD    t1, UNIT(-3)(src),      l_exc_copy)
-EXC(   LOAD    t2, UNIT(-2)(src),      l_exc_copy)
-EXC(   LOAD    t3, UNIT(-1)(src),      l_exc_copy)
+EXC(   LOAD    t0, UNIT(-4)(src),      l_exc_copy_rewind16)
+EXC(   LOAD    t1, UNIT(-3)(src),      l_exc_copy_rewind16)
+EXC(   LOAD    t2, UNIT(-2)(src),      l_exc_copy_rewind16)
+EXC(   LOAD    t3, UNIT(-1)(src),      l_exc_copy_rewind16)
 EXC(   STORE   t0, UNIT(-4)(dst),      s_exc_p4u)
 EXC(   STORE   t1, UNIT(-3)(dst),      s_exc_p3u)
 EXC(   STORE   t2, UNIT(-2)(dst),      s_exc_p2u)
@@ -383,6 +387,10 @@ done:
         nop
        END(memcpy)
 
+l_exc_copy_rewind16:
+       /* Rewind src and dst by 16*NBYTES for l_exc_copy */
+       SUB     src, src, 16*NBYTES
+       SUB     dst, dst, 16*NBYTES
 l_exc_copy:
        /*
         * Copy bytes from src until faulting load address (or until a
@@ -459,6 +467,7 @@ s_exc:
 
        .align  5
 LEAF(memmove)
+EXPORT_SYMBOL(memmove)
        ADD     t0, a0, a2
        ADD     t1, a1, a2
        sltu    t0, a1, t0                      # dst + len <= src -> memcpy
index 37a932d9148c214e2cb3fe9668af7330f3f8bf52..16083cf9382028d89095d6a704546c6f164b6674 100644 (file)
@@ -448,6 +448,7 @@ static struct of_device_id __initdata octeon_ids[] = {
        { .compatible = "cavium,octeon-3860-bootbus", },
        { .compatible = "cavium,mdio-mux", },
        { .compatible = "gpio-leds", },
+       { .compatible = "cavium,octeon-7130-usb-uctl", },
        {},
 };
 
diff --git a/arch/mips/cavium-octeon/octeon-usb.c b/arch/mips/cavium-octeon/octeon-usb.c
new file mode 100644 (file)
index 0000000..542be1c
--- /dev/null
@@ -0,0 +1,552 @@
+/*
+ * XHCI HCD glue for Cavium Octeon III SOCs.
+ *
+ * Copyright (C) 2010-2017 Cavium Networks
+ *
+ * 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/module.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/of_platform.h>
+
+#include <asm/octeon/octeon.h>
+#include <asm/octeon/cvmx-gpio-defs.h>
+
+/* USB Control Register */
+union cvm_usbdrd_uctl_ctl {
+       uint64_t u64;
+       struct cvm_usbdrd_uctl_ctl_s {
+       /* 1 = BIST and set all USB RAMs to 0x0, 0 = BIST */
+       __BITFIELD_FIELD(uint64_t clear_bist:1,
+       /* 1 = Start BIST and cleared by hardware */
+       __BITFIELD_FIELD(uint64_t start_bist:1,
+       /* Reference clock select for SuperSpeed and HighSpeed PLLs:
+        *      0x0 = Both PLLs use DLMC_REF_CLK0 for reference clock
+        *      0x1 = Both PLLs use DLMC_REF_CLK1 for reference clock
+        *      0x2 = SuperSpeed PLL uses DLMC_REF_CLK0 for reference clock &
+        *            HighSpeed PLL uses PLL_REF_CLK for reference clck
+        *      0x3 = SuperSpeed PLL uses DLMC_REF_CLK1 for reference clock &
+        *            HighSpeed PLL uses PLL_REF_CLK for reference clck
+        */
+       __BITFIELD_FIELD(uint64_t ref_clk_sel:2,
+       /* 1 = Spread-spectrum clock enable, 0 = SS clock disable */
+       __BITFIELD_FIELD(uint64_t ssc_en:1,
+       /* Spread-spectrum clock modulation range:
+        *      0x0 = -4980 ppm downspread
+        *      0x1 = -4492 ppm downspread
+        *      0x2 = -4003 ppm downspread
+        *      0x3 - 0x7 = Reserved
+        */
+       __BITFIELD_FIELD(uint64_t ssc_range:3,
+       /* Enable non-standard oscillator frequencies:
+        *      [55:53] = modules -1
+        *      [52:47] = 2's complement push amount, 0 = Feature disabled
+        */
+       __BITFIELD_FIELD(uint64_t ssc_ref_clk_sel:9,
+       /* Reference clock multiplier for non-standard frequencies:
+        *      0x19 = 100MHz on DLMC_REF_CLK* if REF_CLK_SEL = 0x0 or 0x1
+        *      0x28 = 125MHz on DLMC_REF_CLK* if REF_CLK_SEL = 0x0 or 0x1
+        *      0x32 =  50MHz on DLMC_REF_CLK* if REF_CLK_SEL = 0x0 or 0x1
+        *      Other Values = Reserved
+        */
+       __BITFIELD_FIELD(uint64_t mpll_multiplier:7,
+       /* Enable reference clock to prescaler for SuperSpeed functionality.
+        * Should always be set to "1"
+        */
+       __BITFIELD_FIELD(uint64_t ref_ssp_en:1,
+       /* Divide the reference clock by 2 before entering the
+        * REF_CLK_FSEL divider:
+        *      If REF_CLK_SEL = 0x0 or 0x1, then only 0x0 is legal
+        *      If REF_CLK_SEL = 0x2 or 0x3, then:
+        *              0x1 = DLMC_REF_CLK* is 125MHz
+        *              0x0 = DLMC_REF_CLK* is another supported frequency
+        */
+       __BITFIELD_FIELD(uint64_t ref_clk_div2:1,
+       /* Select reference clock freqnuency for both PLL blocks:
+        *      0x27 = REF_CLK_SEL is 0x0 or 0x1
+        *      0x07 = REF_CLK_SEL is 0x2 or 0x3
+        */
+       __BITFIELD_FIELD(uint64_t ref_clk_fsel:6,
+       /* Reserved */
+       __BITFIELD_FIELD(uint64_t reserved_31_31:1,
+       /* Controller clock enable. */
+       __BITFIELD_FIELD(uint64_t h_clk_en:1,
+       /* Select bypass input to controller clock divider:
+        *      0x0 = Use divided coprocessor clock from H_CLKDIV
+        *      0x1 = Use clock from GPIO pins
+        */
+       __BITFIELD_FIELD(uint64_t h_clk_byp_sel:1,
+       /* Reset controller clock divider. */
+       __BITFIELD_FIELD(uint64_t h_clkdiv_rst:1,
+       /* Reserved */
+       __BITFIELD_FIELD(uint64_t reserved_27_27:1,
+       /* Clock divider select:
+        *      0x0 = divide by 1
+        *      0x1 = divide by 2
+        *      0x2 = divide by 4
+        *      0x3 = divide by 6
+        *      0x4 = divide by 8
+        *      0x5 = divide by 16
+        *      0x6 = divide by 24
+        *      0x7 = divide by 32
+        */
+       __BITFIELD_FIELD(uint64_t h_clkdiv_sel:3,
+       /* Reserved */
+       __BITFIELD_FIELD(uint64_t reserved_22_23:2,
+       /* USB3 port permanently attached: 0x0 = No, 0x1 = Yes */
+       __BITFIELD_FIELD(uint64_t usb3_port_perm_attach:1,
+       /* USB2 port permanently attached: 0x0 = No, 0x1 = Yes */
+       __BITFIELD_FIELD(uint64_t usb2_port_perm_attach:1,
+       /* Reserved */
+       __BITFIELD_FIELD(uint64_t reserved_19_19:1,
+       /* Disable SuperSpeed PHY: 0x0 = No, 0x1 = Yes */
+       __BITFIELD_FIELD(uint64_t usb3_port_disable:1,
+       /* Reserved */
+       __BITFIELD_FIELD(uint64_t reserved_17_17:1,
+       /* Disable HighSpeed PHY: 0x0 = No, 0x1 = Yes */
+       __BITFIELD_FIELD(uint64_t usb2_port_disable:1,
+       /* Reserved */
+       __BITFIELD_FIELD(uint64_t reserved_15_15:1,
+       /* Enable PHY SuperSpeed block power: 0x0 = No, 0x1 = Yes */
+       __BITFIELD_FIELD(uint64_t ss_power_en:1,
+       /* Reserved */
+       __BITFIELD_FIELD(uint64_t reserved_13_13:1,
+       /* Enable PHY HighSpeed block power: 0x0 = No, 0x1 = Yes */
+       __BITFIELD_FIELD(uint64_t hs_power_en:1,
+       /* Reserved */
+       __BITFIELD_FIELD(uint64_t reserved_5_11:7,
+       /* Enable USB UCTL interface clock: 0xx = No, 0x1 = Yes */
+       __BITFIELD_FIELD(uint64_t csclk_en:1,
+       /* Controller mode: 0x0 = Host, 0x1 = Device */
+       __BITFIELD_FIELD(uint64_t drd_mode:1,
+       /* PHY reset */
+       __BITFIELD_FIELD(uint64_t uphy_rst:1,
+       /* Software reset UAHC */
+       __BITFIELD_FIELD(uint64_t uahc_rst:1,
+       /* Software resets UCTL */
+       __BITFIELD_FIELD(uint64_t uctl_rst:1,
+       ;)))))))))))))))))))))))))))))))))
+       } s;
+};
+
+/* UAHC Configuration Register */
+union cvm_usbdrd_uctl_host_cfg {
+       uint64_t u64;
+       struct cvm_usbdrd_uctl_host_cfg_s {
+       /* Reserved */
+       __BITFIELD_FIELD(uint64_t reserved_60_63:4,
+       /* Indicates minimum value of all received BELT values */
+       __BITFIELD_FIELD(uint64_t host_current_belt:12,
+       /* Reserved */
+       __BITFIELD_FIELD(uint64_t reserved_38_47:10,
+       /* HS jitter adjustment */
+       __BITFIELD_FIELD(uint64_t fla:6,
+       /* Reserved */
+       __BITFIELD_FIELD(uint64_t reserved_29_31:3,
+       /* Bus-master enable: 0x0 = Disabled (stall DMAs), 0x1 = enabled */
+       __BITFIELD_FIELD(uint64_t bme:1,
+       /* Overcurrent protection enable: 0x0 = unavailable, 0x1 = available */
+       __BITFIELD_FIELD(uint64_t oci_en:1,
+       /* Overcurrent sene selection:
+        *      0x0 = Overcurrent indication from off-chip is active-low
+        *      0x1 = Overcurrent indication from off-chip is active-high
+        */
+       __BITFIELD_FIELD(uint64_t oci_active_high_en:1,
+       /* Port power control enable: 0x0 = unavailable, 0x1 = available */
+       __BITFIELD_FIELD(uint64_t ppc_en:1,
+       /* Port power control sense selection:
+        *      0x0 = Port power to off-chip is active-low
+        *      0x1 = Port power to off-chip is active-high
+        */
+       __BITFIELD_FIELD(uint64_t ppc_active_high_en:1,
+       /* Reserved */
+       __BITFIELD_FIELD(uint64_t reserved_0_23:24,
+       ;)))))))))))
+       } s;
+};
+
+/* UCTL Shim Features Register */
+union cvm_usbdrd_uctl_shim_cfg {
+       uint64_t u64;
+       struct cvm_usbdrd_uctl_shim_cfg_s {
+       /* Out-of-bound UAHC register access: 0 = read, 1 = write */
+       __BITFIELD_FIELD(uint64_t xs_ncb_oob_wrn:1,
+       /* Reserved */
+       __BITFIELD_FIELD(uint64_t reserved_60_62:3,
+       /* SRCID error log for out-of-bound UAHC register access:
+        *      [59:58] = chipID
+        *      [57] = Request source: 0 = core, 1 = NCB-device
+        *      [56:51] = Core/NCB-device number, [56] always 0 for NCB devices
+        *      [50:48] = SubID
+        */
+       __BITFIELD_FIELD(uint64_t xs_ncb_oob_osrc:12,
+       /* Error log for bad UAHC DMA access: 0 = Read log, 1 = Write log */
+       __BITFIELD_FIELD(uint64_t xm_bad_dma_wrn:1,
+       /* Reserved */
+       __BITFIELD_FIELD(uint64_t reserved_44_46:3,
+       /* Encoded error type for bad UAHC DMA */
+       __BITFIELD_FIELD(uint64_t xm_bad_dma_type:4,
+       /* Reserved */
+       __BITFIELD_FIELD(uint64_t reserved_13_39:27,
+       /* Select the IOI read command used by DMA accesses */
+       __BITFIELD_FIELD(uint64_t dma_read_cmd:1,
+       /* Reserved */
+       __BITFIELD_FIELD(uint64_t reserved_10_11:2,
+       /* Select endian format for DMA accesses to the L2c:
+        *      0x0 = Little endian
+        *`     0x1 = Big endian
+        *      0x2 = Reserved
+        *      0x3 = Reserved
+        */
+       __BITFIELD_FIELD(uint64_t dma_endian_mode:2,
+       /* Reserved */
+       __BITFIELD_FIELD(uint64_t reserved_2_7:6,
+       /* Select endian format for IOI CSR access to UAHC:
+        *      0x0 = Little endian
+        *`     0x1 = Big endian
+        *      0x2 = Reserved
+        *      0x3 = Reserved
+        */
+       __BITFIELD_FIELD(uint64_t csr_endian_mode:2,
+       ;))))))))))))
+       } s;
+};
+
+#define OCTEON_H_CLKDIV_SEL            8
+#define OCTEON_MIN_H_CLK_RATE          150000000
+#define OCTEON_MAX_H_CLK_RATE          300000000
+
+static DEFINE_MUTEX(dwc3_octeon_clocks_mutex);
+static uint8_t clk_div[OCTEON_H_CLKDIV_SEL] = {1, 2, 4, 6, 8, 16, 24, 32};
+
+
+static int dwc3_octeon_config_power(struct device *dev, u64 base)
+{
+#define UCTL_HOST_CFG  0xe0
+       union cvm_usbdrd_uctl_host_cfg uctl_host_cfg;
+       union cvmx_gpio_bit_cfgx gpio_bit;
+       uint32_t gpio_pwr[3];
+       int gpio, len, power_active_low;
+       struct device_node *node = dev->of_node;
+       int index = (base >> 24) & 1;
+
+       if (of_find_property(node, "power", &len) != NULL) {
+               if (len == 12) {
+                       of_property_read_u32_array(node, "power", gpio_pwr, 3);
+                       power_active_low = gpio_pwr[2] & 0x01;
+                       gpio = gpio_pwr[1];
+               } else if (len == 8) {
+                       of_property_read_u32_array(node, "power", gpio_pwr, 2);
+                       power_active_low = 0;
+                       gpio = gpio_pwr[1];
+               } else {
+                       dev_err(dev, "dwc3 controller clock init failure.\n");
+                       return -EINVAL;
+               }
+               if ((OCTEON_IS_MODEL(OCTEON_CN73XX) ||
+                   OCTEON_IS_MODEL(OCTEON_CNF75XX))
+                   && gpio <= 31) {
+                       gpio_bit.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(gpio));
+                       gpio_bit.s.tx_oe = 1;
+                       gpio_bit.cn73xx.output_sel = (index == 0 ? 0x14 : 0x15);
+                       cvmx_write_csr(CVMX_GPIO_BIT_CFGX(gpio), gpio_bit.u64);
+               } else if (gpio <= 15) {
+                       gpio_bit.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(gpio));
+                       gpio_bit.s.tx_oe = 1;
+                       gpio_bit.cn70xx.output_sel = (index == 0 ? 0x14 : 0x19);
+                       cvmx_write_csr(CVMX_GPIO_BIT_CFGX(gpio), gpio_bit.u64);
+               } else {
+                       gpio_bit.u64 = cvmx_read_csr(CVMX_GPIO_XBIT_CFGX(gpio));
+                       gpio_bit.s.tx_oe = 1;
+                       gpio_bit.cn70xx.output_sel = (index == 0 ? 0x14 : 0x19);
+                       cvmx_write_csr(CVMX_GPIO_XBIT_CFGX(gpio), gpio_bit.u64);
+               }
+
+               /* Enable XHCI power control and set if active high or low. */
+               uctl_host_cfg.u64 = cvmx_read_csr(base + UCTL_HOST_CFG);
+               uctl_host_cfg.s.ppc_en = 1;
+               uctl_host_cfg.s.ppc_active_high_en = !power_active_low;
+               cvmx_write_csr(base + UCTL_HOST_CFG, uctl_host_cfg.u64);
+       } else {
+               /* Disable XHCI power control and set if active high. */
+               uctl_host_cfg.u64 = cvmx_read_csr(base + UCTL_HOST_CFG);
+               uctl_host_cfg.s.ppc_en = 0;
+               uctl_host_cfg.s.ppc_active_high_en = 0;
+               cvmx_write_csr(base + UCTL_HOST_CFG, uctl_host_cfg.u64);
+               dev_warn(dev, "dwc3 controller clock init failure.\n");
+       }
+       return 0;
+}
+
+static int dwc3_octeon_clocks_start(struct device *dev, u64 base)
+{
+       union cvm_usbdrd_uctl_ctl uctl_ctl;
+       int ref_clk_sel = 2;
+       u64 div;
+       u32 clock_rate;
+       int mpll_mul;
+       int i;
+       u64 h_clk_rate;
+       u64 uctl_ctl_reg = base;
+
+       if (dev->of_node) {
+               const char *ss_clock_type;
+               const char *hs_clock_type;
+
+               i = of_property_read_u32(dev->of_node,
+                                        "refclk-frequency", &clock_rate);
+               if (i) {
+                       pr_err("No UCTL \"refclk-frequency\"\n");
+                       return -EINVAL;
+               }
+               i = of_property_read_string(dev->of_node,
+                                           "refclk-type-ss", &ss_clock_type);
+               if (i) {
+                       pr_err("No UCTL \"refclk-type-ss\"\n");
+                       return -EINVAL;
+               }
+               i = of_property_read_string(dev->of_node,
+                                           "refclk-type-hs", &hs_clock_type);
+               if (i) {
+                       pr_err("No UCTL \"refclk-type-hs\"\n");
+                       return -EINVAL;
+               }
+               if (strcmp("dlmc_ref_clk0", ss_clock_type) == 0) {
+                       if (strcmp(hs_clock_type, "dlmc_ref_clk0") == 0)
+                               ref_clk_sel = 0;
+                       else if (strcmp(hs_clock_type, "pll_ref_clk") == 0)
+                               ref_clk_sel = 2;
+                       else
+                               pr_err("Invalid HS clock type %s, using  pll_ref_clk instead\n",
+                                      hs_clock_type);
+               } else if (strcmp(ss_clock_type, "dlmc_ref_clk1") == 0) {
+                       if (strcmp(hs_clock_type, "dlmc_ref_clk1") == 0)
+                               ref_clk_sel = 1;
+                       else if (strcmp(hs_clock_type, "pll_ref_clk") == 0)
+                               ref_clk_sel = 3;
+                       else {
+                               pr_err("Invalid HS clock type %s, using  pll_ref_clk instead\n",
+                                      hs_clock_type);
+                               ref_clk_sel = 3;
+                       }
+               } else
+                       pr_err("Invalid SS clock type %s, using  dlmc_ref_clk0 instead\n",
+                              ss_clock_type);
+
+               if ((ref_clk_sel == 0 || ref_clk_sel == 1) &&
+                                 (clock_rate != 100000000))
+                       pr_err("Invalid UCTL clock rate of %u, using 100000000 instead\n",
+                              clock_rate);
+
+       } else {
+               pr_err("No USB UCTL device node\n");
+               return -EINVAL;
+       }
+
+       /*
+        * Step 1: Wait for all voltages to be stable...that surely
+        *         happened before starting the kernel. SKIP
+        */
+
+       /* Step 2: Select GPIO for overcurrent indication, if desired. SKIP */
+
+       /* Step 3: Assert all resets. */
+       uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
+       uctl_ctl.s.uphy_rst = 1;
+       uctl_ctl.s.uahc_rst = 1;
+       uctl_ctl.s.uctl_rst = 1;
+       cvmx_write_csr(uctl_ctl_reg, uctl_ctl.u64);
+
+       /* Step 4a: Reset the clock dividers. */
+       uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
+       uctl_ctl.s.h_clkdiv_rst = 1;
+       cvmx_write_csr(uctl_ctl_reg, uctl_ctl.u64);
+
+       /* Step 4b: Select controller clock frequency. */
+       for (div = 0; div < OCTEON_H_CLKDIV_SEL; div++) {
+               h_clk_rate = octeon_get_io_clock_rate() / clk_div[div];
+               if (h_clk_rate <= OCTEON_MAX_H_CLK_RATE &&
+                                h_clk_rate >= OCTEON_MIN_H_CLK_RATE)
+                       break;
+       }
+       uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
+       uctl_ctl.s.h_clkdiv_sel = div;
+       uctl_ctl.s.h_clk_en = 1;
+       cvmx_write_csr(uctl_ctl_reg, uctl_ctl.u64);
+       uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
+       if ((div != uctl_ctl.s.h_clkdiv_sel) || (!uctl_ctl.s.h_clk_en)) {
+               dev_err(dev, "dwc3 controller clock init failure.\n");
+                       return -EINVAL;
+       }
+
+       /* Step 4c: Deassert the controller clock divider reset. */
+       uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
+       uctl_ctl.s.h_clkdiv_rst = 0;
+       cvmx_write_csr(uctl_ctl_reg, uctl_ctl.u64);
+
+       /* Step 5a: Reference clock configuration. */
+       uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
+       uctl_ctl.s.ref_clk_sel = ref_clk_sel;
+       uctl_ctl.s.ref_clk_fsel = 0x07;
+       uctl_ctl.s.ref_clk_div2 = 0;
+       switch (clock_rate) {
+       default:
+               dev_err(dev, "Invalid ref_clk %u, using 100000000 instead\n",
+                       clock_rate);
+       case 100000000:
+               mpll_mul = 0x19;
+               if (ref_clk_sel < 2)
+                       uctl_ctl.s.ref_clk_fsel = 0x27;
+               break;
+       case 50000000:
+               mpll_mul = 0x32;
+               break;
+       case 125000000:
+               mpll_mul = 0x28;
+               break;
+       }
+       uctl_ctl.s.mpll_multiplier = mpll_mul;
+
+       /* Step 5b: Configure and enable spread-spectrum for SuperSpeed. */
+       uctl_ctl.s.ssc_en = 1;
+
+       /* Step 5c: Enable SuperSpeed. */
+       uctl_ctl.s.ref_ssp_en = 1;
+
+       /* Step 5d: Cofngiure PHYs. SKIP */
+
+       /* Step 6a & 6b: Power up PHYs. */
+       uctl_ctl.s.hs_power_en = 1;
+       uctl_ctl.s.ss_power_en = 1;
+       cvmx_write_csr(uctl_ctl_reg, uctl_ctl.u64);
+
+       /* Step 7: Wait 10 controller-clock cycles to take effect. */
+       udelay(10);
+
+       /* Step 8a: Deassert UCTL reset signal. */
+       uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
+       uctl_ctl.s.uctl_rst = 0;
+       cvmx_write_csr(uctl_ctl_reg, uctl_ctl.u64);
+
+       /* Step 8b: Wait 10 controller-clock cycles. */
+       udelay(10);
+
+       /* Steo 8c: Setup power-power control. */
+       if (dwc3_octeon_config_power(dev, base)) {
+               dev_err(dev, "Error configuring power.\n");
+               return -EINVAL;
+       }
+
+       /* Step 8d: Deassert UAHC reset signal. */
+       uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
+       uctl_ctl.s.uahc_rst = 0;
+       cvmx_write_csr(uctl_ctl_reg, uctl_ctl.u64);
+
+       /* Step 8e: Wait 10 controller-clock cycles. */
+       udelay(10);
+
+       /* Step 9: Enable conditional coprocessor clock of UCTL. */
+       uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
+       uctl_ctl.s.csclk_en = 1;
+       cvmx_write_csr(uctl_ctl_reg, uctl_ctl.u64);
+
+       /*Step 10: Set for host mode only. */
+       uctl_ctl.u64 = cvmx_read_csr(uctl_ctl_reg);
+       uctl_ctl.s.drd_mode = 0;
+       cvmx_write_csr(uctl_ctl_reg, uctl_ctl.u64);
+
+       return 0;
+}
+
+static void __init dwc3_octeon_set_endian_mode(u64 base)
+{
+#define UCTL_SHIM_CFG  0xe8
+       union cvm_usbdrd_uctl_shim_cfg shim_cfg;
+
+       shim_cfg.u64 = cvmx_read_csr(base + UCTL_SHIM_CFG);
+#ifdef __BIG_ENDIAN
+       shim_cfg.s.dma_endian_mode = 1;
+       shim_cfg.s.csr_endian_mode = 1;
+#else
+       shim_cfg.s.dma_endian_mode = 0;
+       shim_cfg.s.csr_endian_mode = 0;
+#endif
+       cvmx_write_csr(base + UCTL_SHIM_CFG, shim_cfg.u64);
+}
+
+#define CVMX_USBDRDX_UCTL_CTL(index)                           \
+               (CVMX_ADD_IO_SEG(0x0001180068000000ull) +       \
+               ((index & 1) * 0x1000000ull))
+static void __init dwc3_octeon_phy_reset(u64 base)
+{
+       union cvm_usbdrd_uctl_ctl uctl_ctl;
+       int index = (base >> 24) & 1;
+
+       uctl_ctl.u64 = cvmx_read_csr(CVMX_USBDRDX_UCTL_CTL(index));
+       uctl_ctl.s.uphy_rst = 0;
+       cvmx_write_csr(CVMX_USBDRDX_UCTL_CTL(index), uctl_ctl.u64);
+}
+
+static int __init dwc3_octeon_device_init(void)
+{
+       const char compat_node_name[] = "cavium,octeon-7130-usb-uctl";
+       struct platform_device *pdev;
+       struct device_node *node;
+       struct resource *res;
+       void __iomem *base;
+
+       /*
+        * There should only be three universal controllers, "uctl"
+        * in the device tree. Two USB and a SATA, which we ignore.
+        */
+       node = NULL;
+       do {
+               node = of_find_node_by_name(node, "uctl");
+               if (!node)
+                       return -ENODEV;
+
+               if (of_device_is_compatible(node, compat_node_name)) {
+                       pdev = of_find_device_by_node(node);
+                       if (!pdev)
+                               return -ENODEV;
+
+                       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+                       if (res == NULL) {
+                               dev_err(&pdev->dev, "No memory resources\n");
+                               return -ENXIO;
+                       }
+
+                       /*
+                        * The code below maps in the registers necessary for
+                        * setting up the clocks and reseting PHYs. We must
+                        * release the resources so the dwc3 subsystem doesn't
+                        * know the difference.
+                        */
+                       base = devm_ioremap_resource(&pdev->dev, res);
+                       if (IS_ERR(base))
+                               return PTR_ERR(base);
+
+                       mutex_lock(&dwc3_octeon_clocks_mutex);
+                       dwc3_octeon_clocks_start(&pdev->dev, (u64)base);
+                       dwc3_octeon_set_endian_mode((u64)base);
+                       dwc3_octeon_phy_reset((u64)base);
+                       dev_info(&pdev->dev, "clocks initialized.\n");
+                       mutex_unlock(&dwc3_octeon_clocks_mutex);
+                       devm_iounmap(&pdev->dev, base);
+                       devm_release_mem_region(&pdev->dev, res->start,
+                                               resource_size(res));
+               }
+       } while (node != NULL);
+
+       return 0;
+}
+device_initcall(dwc3_octeon_device_init);
+
+MODULE_AUTHOR("David Daney <david.daney@cavium.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("USB driver for OCTEON III SoC");
index 9a2db1c013d92e548fd04ef0a008ec442942350c..d9dbeb0b165bcd4d6720eb2a82ca2f00af22ba2d 100644 (file)
@@ -949,6 +949,29 @@ static __init void memory_exclude_page(u64 addr, u64 *mem, u64 *size)
 }
 #endif /* CONFIG_CRASH_DUMP */
 
+void __init fw_init_cmdline(void)
+{
+       int i;
+
+       octeon_boot_desc_ptr = (struct octeon_boot_descriptor *)fw_arg3;
+       for (i = 0; i < octeon_boot_desc_ptr->argc; i++) {
+               const char *arg =
+                       cvmx_phys_to_ptr(octeon_boot_desc_ptr->argv[i]);
+               if (strlen(arcs_cmdline) + strlen(arg) + 1 <
+                          sizeof(arcs_cmdline) - 1) {
+                       strcat(arcs_cmdline, " ");
+                       strcat(arcs_cmdline, arg);
+               }
+       }
+}
+
+void __init *plat_get_fdt(void)
+{
+       octeon_bootinfo =
+               cvmx_phys_to_ptr(octeon_boot_desc_ptr->cvmx_desc_vaddr);
+       return phys_to_virt(octeon_bootinfo->fdt_addr);
+}
+
 void __init plat_mem_setup(void)
 {
        uint64_t mem_alloc_size;
index 256fe6f65cf2dec815777a8ee736431481115e94..4355a4cf4d74b2c17478dc6d7f1448b98ca9a69a 100644 (file)
@@ -11,7 +11,8 @@
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/sched.h>
-#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/export.h>
 
 #include <asm/mmu_context.h>
 #include <asm/time.h>
 volatile unsigned long octeon_processor_boot = 0xff;
 volatile unsigned long octeon_processor_sp;
 volatile unsigned long octeon_processor_gp;
+#ifdef CONFIG_RELOCATABLE
+volatile unsigned long octeon_processor_relocated_kernel_entry;
+#endif /* CONFIG_RELOCATABLE */
 
 #ifdef CONFIG_HOTPLUG_CPU
 uint64_t octeon_bootloader_entry_addr;
 EXPORT_SYMBOL(octeon_bootloader_entry_addr);
 #endif
 
+extern void kernel_entry(unsigned long arg1, ...);
+
 static void octeon_icache_flush(void)
 {
        asm volatile ("synci 0($0)\n");
@@ -180,6 +186,19 @@ static void __init octeon_smp_setup(void)
        octeon_smp_hotplug_setup();
 }
 
+
+#ifdef CONFIG_RELOCATABLE
+int plat_post_relocation(long offset)
+{
+       unsigned long entry = (unsigned long)kernel_entry;
+
+       /* Send secondaries into relocated kernel */
+       octeon_processor_relocated_kernel_entry = entry + offset;
+
+       return 0;
+}
+#endif /* CONFIG_RELOCATABLE */
+
 /**
  * Firmware CPU startup hook
  *
@@ -272,7 +291,6 @@ static int octeon_cpu_disable(void)
 
        set_cpu_online(cpu, false);
        calculate_cpu_foreign_map();
-       cpumask_clear_cpu(cpu, &cpu_callin_map);
        octeon_fixup_irqs();
 
        __flush_cache_all();
@@ -333,8 +351,6 @@ void play_dead(void)
                ;
 }
 
-extern void kernel_entry(unsigned long arg1, ...);
-
 static void start_after_reset(void)
 {
        kernel_entry(0, 0, 0);  /* set a2 = 0 for secondary core */
index 4eb5d6e9cf8f1f256cbcf91b653746cb53ee0dde..3cefa6bc01ddf880320209187f574340c5e3996e 100644 (file)
@@ -9,13 +9,20 @@ CONFIG_MIPS_O32_FP64_SUPPORT=y
 # CONFIG_SWAP is not set
 CONFIG_NO_HZ=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_RD_GZIP=y
 CONFIG_EXPERT=y
 # CONFIG_VM_EVENT_COUNTERS is not set
 # CONFIG_SLUB_DEBUG is not set
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_IOSCHED_DEADLINE is not set
 # CONFIG_IOSCHED_CFQ is not set
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_STAT=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
+CONFIG_BMIPS_CPUFREQ=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_DIAG=y
@@ -24,7 +31,6 @@ CONFIG_INET=y
 # CONFIG_INET_XFRM_MODE_TRANSPORT is not set
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
 CONFIG_CFG80211=y
 CONFIG_NL80211_TESTMODE=y
@@ -34,8 +40,6 @@ CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
-CONFIG_PRINTK_TIME=y
-CONFIG_BRCMSTB_GISB_ARB=y
 CONFIG_MTD=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_INTELEXT=y
@@ -51,16 +55,15 @@ CONFIG_USB_USBNET=y
 # CONFIG_INPUT is not set
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
-# CONFIG_DEVKMEM is not set
 CONFIG_SERIAL_8250=y
 # CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_OF_PLATFORM=y
 # CONFIG_HW_RANDOM is not set
-CONFIG_POWER_SUPPLY=y
 CONFIG_POWER_RESET=y
 CONFIG_POWER_RESET_BRCMSTB=y
 CONFIG_POWER_RESET_SYSCON=y
+CONFIG_POWER_SUPPLY=y
 # CONFIG_HWMON is not set
 CONFIG_USB=y
 CONFIG_USB_EHCI_HCD=y
@@ -82,6 +85,7 @@ CONFIG_CIFS=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ASCII=y
 CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
 CONFIG_DEBUG_FS=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_CMDLINE_BOOL=y
index d470d08362c009ea2182d9021e3cb60155c9cf6f..31e3c4d9adb02a890711592d00113a5ce355f35a 100644 (file)
@@ -45,6 +45,7 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_LRO is not set
 CONFIG_IPV6=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
 # CONFIG_MTD_OF_PARTS is not set
index 5d83ff7555477f9284fcd952dfc5b8d9c33c1bd2..ec8e9684296d0149edfb93742009ae33b6444d3f 100644 (file)
@@ -67,8 +67,8 @@ CONFIG_NETFILTER_NETLINK_QUEUE=m
 CONFIG_NF_CONNTRACK=m
 CONFIG_NF_CONNTRACK_SECMARK=y
 CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_DCCP=m
-CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
 CONFIG_NF_CONNTRACK_AMANDA=m
 CONFIG_NF_CONNTRACK_FTP=m
 CONFIG_NF_CONNTRACK_H323=m
index 2b74aee320a12fae4a79cb439650e5ed2c2f575e..e582069b44fdf91cd439f78045593365b6ebcbb2 100644 (file)
@@ -133,7 +133,7 @@ CONFIG_LIBFC=m
 CONFIG_SCSI_QLOGIC_1280=y
 CONFIG_SCSI_PMCRAID=m
 CONFIG_SCSI_BFA_FC=m
-CONFIG_SCSI_DH=m
+CONFIG_SCSI_DH=y
 CONFIG_SCSI_DH_RDAC=m
 CONFIG_SCSI_DH_HP_SW=m
 CONFIG_SCSI_DH_EMC=m
@@ -205,7 +205,6 @@ CONFIG_MLX4_EN=m
 # CONFIG_MLX4_DEBUG is not set
 CONFIG_TEHUTI=m
 CONFIG_BNX2X=m
-CONFIG_QLGE=m
 CONFIG_SFC=m
 CONFIG_BE2NET=m
 CONFIG_LIBERTAS_THINFIRM=m
index 5da76e0e120f59fc788d98c11f0a949f9fbc30db..8df80c6383f26d35bea07e2bdc861075211be14f 100644 (file)
@@ -39,8 +39,7 @@ CONFIG_HIBERNATION=y
 CONFIG_PM_STD_PARTITION="/dev/hda3"
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_DEBUG=y
-CONFIG_CPU_FREQ_STAT=m
-CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPU_FREQ_STAT=y
 CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=m
 CONFIG_CPU_FREQ_GOV_USERSPACE=m
index c442f27685f4fd9338ea57cdc1d1a463a11eaf33..914c867887bd5d7f8569105c5757481de5f05512 100644 (file)
@@ -74,6 +74,10 @@ CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_LOONGSON1=y
 # CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+CONFIG_WATCHDOG_SYSFS=y
+CONFIG_LOONGSON1_WDT=y
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_HID_GENERIC=m
 CONFIG_USB_HID=m
index 2304d4165773083f5e477d6f89d7ee88ba03a30f..68e42eff908e2771a43ba66702738a6be40f892a 100644 (file)
@@ -75,6 +75,10 @@ CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_LOONGSON1=y
 # CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+CONFIG_WATCHDOG_SYSFS=y
+CONFIG_LOONGSON1_WDT=y
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_HID_GENERIC=m
 CONFIG_USB_HID=m
index 58d43f3c348d00fec15c975afbf2aa0693879385..078ecac071aba6f9a6a69510151144d8bea3da0e 100644 (file)
@@ -59,8 +59,8 @@ CONFIG_NETFILTER=y
 CONFIG_NF_CONNTRACK=m
 CONFIG_NF_CONNTRACK_SECMARK=y
 CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_DCCP=m
-CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
 CONFIG_NF_CONNTRACK_AMANDA=m
 CONFIG_NF_CONNTRACK_FTP=m
 CONFIG_NF_CONNTRACK_H323=m
index c8f7e2835840ddb5737008004be064d289c6182a..e233f878afef7ec52ed829fe1e45688f025bbc38 100644 (file)
@@ -60,8 +60,8 @@ CONFIG_NETFILTER=y
 CONFIG_NF_CONNTRACK=m
 CONFIG_NF_CONNTRACK_SECMARK=y
 CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_DCCP=m
-CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
 CONFIG_NF_CONNTRACK_AMANDA=m
 CONFIG_NF_CONNTRACK_FTP=m
 CONFIG_NF_CONNTRACK_H323=m
index d2f54e55356c8cfb427b7f6ca896110f16b205b9..fbe085c328abf447074df772dd6bd22b64402931 100644 (file)
@@ -59,8 +59,8 @@ CONFIG_NETFILTER=y
 CONFIG_NF_CONNTRACK=m
 CONFIG_NF_CONNTRACK_SECMARK=y
 CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_DCCP=m
-CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
 CONFIG_NF_CONNTRACK_AMANDA=m
 CONFIG_NF_CONNTRACK_FTP=m
 CONFIG_NF_CONNTRACK_H323=m
index 3d0d9cb9673f80d976033e969584308d92d3f446..2942610e408216d99a9491e8811757866064321a 100644 (file)
@@ -61,8 +61,8 @@ CONFIG_NETFILTER=y
 CONFIG_NF_CONNTRACK=m
 CONFIG_NF_CONNTRACK_SECMARK=y
 CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_DCCP=m
-CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
 CONFIG_NF_CONNTRACK_AMANDA=m
 CONFIG_NF_CONNTRACK_FTP=m
 CONFIG_NF_CONNTRACK_H323=m
index b496c25fced6c5935f64db81fe04d6e54a0934ba..07d01827a973137193dab97517e7531dbec22ca8 100644 (file)
@@ -110,7 +110,7 @@ CONFIG_NETFILTER=y
 CONFIG_NF_CONNTRACK=m
 CONFIG_NF_CONNTRACK_SECMARK=y
 CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CT_PROTO_UDPLITE=y
 CONFIG_NF_CONNTRACK_AMANDA=m
 CONFIG_NF_CONNTRACK_FTP=m
 CONFIG_NF_CONNTRACK_H323=m
index 8e99ad807a57c20c8ee7b288941deb6383de6812..f59969acb7243a4414f10aa69b49ea8b72a8fa52 100644 (file)
@@ -90,7 +90,7 @@ CONFIG_NETFILTER=y
 CONFIG_NF_CONNTRACK=m
 CONFIG_NF_CONNTRACK_SECMARK=y
 CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CT_PROTO_UDPLITE=y
 CONFIG_NF_CONNTRACK_AMANDA=m
 CONFIG_NF_CONNTRACK_FTP=m
 CONFIG_NF_CONNTRACK_H323=m
index ed1dce348320b5f2558c19f7ea8b5baee3e9b740..829c637be3fc5dec8e2c4d84cb36ab8cc490c436 100644 (file)
@@ -7,6 +7,12 @@ CONFIG_EMBEDDED=y
 CONFIG_SLAB=y
 # CONFIG_BLOCK is not set
 # CONFIG_SUSPEND is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
 # CONFIG_UEVENT_HELPER is not set
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
@@ -14,6 +20,30 @@ CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 # CONFIG_FW_LOADER is not set
 # CONFIG_ALLOW_DEV_COREDUMP is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NET_CORE is not set
+# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_CADENCE is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_EZCHIP is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NETRONOME is not set
+# CONFIG_NET_VENDOR_QUALCOMM is not set
+# CONFIG_NET_VENDOR_RENESAS is not set
+# CONFIG_NET_VENDOR_ROCKER is not set
+# CONFIG_NET_VENDOR_SAMSUNG is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_SYNOPSYS is not set
+# CONFIG_NET_VENDOR_VIA is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_XILINX_EMACLITE=y
+CONFIG_SMSC_PHY=y
+# CONFIG_WLAN is not set
 # CONFIG_INPUT_MOUSEDEV is not set
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
@@ -25,13 +55,18 @@ CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_OF_PLATFORM=y
 # CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_HELPER_AUTO is not set
+CONFIG_I2C_XILINX=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_XILINX=y
-# CONFIG_HWMON is not set
+CONFIG_SENSORS_ADT7410=y
 # CONFIG_USB_SUPPORT is not set
 # CONFIG_MIPS_PLATFORM_DEVICES is not set
 # CONFIG_IOMMU_SUPPORT is not set
 # CONFIG_PROC_PAGE_MONITOR is not set
+CONFIG_TMPFS=y
 # CONFIG_MISC_FILESYSTEMS is not set
 CONFIG_PANIC_ON_OOPS=y
 # CONFIG_SCHED_DEBUG is not set
index 8987846240f75fb08a8faef49fd17928bb04337e..4365108bef776759539ba3da0b1f1135a4340827 100644 (file)
@@ -1,12 +1,16 @@
 CONFIG_LANTIQ=y
+CONFIG_PCI_LANTIQ=y
 CONFIG_XRX200_PHY_FW=y
 CONFIG_CPU_MIPS32_R2=y
+CONFIG_MIPS_MT_SMP=y
+CONFIG_MIPS_VPE_LOADER=y
 # CONFIG_COMPACTION is not set
-# CONFIG_CROSS_MEMORY_ATTACH is not set
+CONFIG_NR_CPUS=2
 CONFIG_HZ_100=y
 # CONFIG_SECCOMP is not set
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
+# CONFIG_CROSS_MEMORY_ATTACH is not set
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_RD_GZIP is not set
@@ -22,8 +26,8 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
 CONFIG_PARTITION_ADVANCED=y
 # CONFIG_IOSCHED_CFQ is not set
+CONFIG_PCI=y
 # CONFIG_COREDUMP is not set
-# CONFIG_SUSPEND is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -35,12 +39,10 @@ CONFIG_IP_ROUTE_MULTIPATH=y
 CONFIG_IP_ROUTE_VERBOSE=y
 CONFIG_IP_MROUTE=y
 CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
-CONFIG_ARPD=y
 CONFIG_SYN_COOKIES=y
 # CONFIG_INET_XFRM_MODE_TRANSPORT is not set
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
 CONFIG_TCP_CONG_ADVANCED=y
 # CONFIG_TCP_CONG_BIC is not set
@@ -62,7 +64,6 @@ CONFIG_NETFILTER_XT_MATCH_MAC=m
 CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
 CONFIG_NETFILTER_XT_MATCH_STATE=m
 CONFIG_NF_CONNTRACK_IPV4=m
-# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
@@ -84,6 +85,8 @@ CONFIG_MTD_COMPLEX_MAPPINGS=y
 CONFIG_MTD_PHYSMAP=y
 CONFIG_MTD_PHYSMAP_OF=y
 CONFIG_MTD_LANTIQ=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_XWAY=y
 CONFIG_EEPROM_93CX6=m
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
@@ -91,6 +94,7 @@ CONFIG_NETDEVICES=y
 CONFIG_LANTIQ_ETOP=y
 # CONFIG_NET_VENDOR_WIZNET is not set
 CONFIG_PHYLIB=y
+CONFIG_INTEL_XWAY_PHY=y
 CONFIG_PPP=m
 CONFIG_PPP_FILTER=y
 CONFIG_PPP_MULTILINK=y
@@ -111,17 +115,21 @@ CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_RUNTIME_UARTS=2
 CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SERIAL_LANTIQ=y
 CONFIG_SPI=y
 CONFIG_GPIO_MM_LANTIQ=y
 CONFIG_GPIO_STP_XWAY=y
 # CONFIG_HWMON is not set
 CONFIG_WATCHDOG=y
+CONFIG_LANTIQ_WDT=y
 # CONFIG_HID is not set
 # CONFIG_USB_HID is not set
 CONFIG_USB=y
 CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_STORAGE_DEBUG=y
+CONFIG_USB_DWC2=y
+CONFIG_USB_DWC2_PCI=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_TRIGGERS=y
@@ -151,9 +159,6 @@ CONFIG_MAGIC_SYSRQ=y
 # CONFIG_SCHED_DEBUG is not set
 # CONFIG_FTRACE is not set
 CONFIG_CMDLINE_BOOL=y
-CONFIG_CRYPTO_MANAGER=m
 CONFIG_CRYPTO_ARC4=m
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRC_ITU_T=m
 CONFIG_CRC32_SARWATE=y
-CONFIG_AVERAGE=y
index 95e26f4bb38f023663f4f9c71190d43d5aa45511..0c14a9d6a84ae10f3e56f85790aa336b33abd3c6 100644 (file)
@@ -7,7 +7,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/mc146818rtc.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/string.h>
 #include <linux/types.h>
 
index 1c3bf9fe926ff50d4a07a58f584518561ef31158..61a0bf13e308379b034aac3cf4d54f2fc42c8911 100644 (file)
@@ -9,12 +9,12 @@
  * Copyright (C) 2000, 2001, 2002, 2003, 2005  Maciej W. Rozycki
  */
 #include <linux/console.h>
+#include <linux/export.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/irq.h>
 #include <linux/irqnr.h>
-#include <linux/module.h>
 #include <linux/param.h>
 #include <linux/percpu-defs.h>
 #include <linux/sched.h>
index 56bda4a396b5c112e8563bef2b440697a58f5deb..dad64d1789b2e20c06461f9812ce1121146e28cf 100644 (file)
@@ -14,6 +14,7 @@
  * Copyright (C) 2002 Maciej W. Rozycki
  */
 
+#include <linux/export.h>
 #include <linux/init.h>
 
 #include <asm/bootinfo.h>
@@ -88,7 +89,4 @@ static void wbflush_mips(void)
 {
        __fast_iob();
 }
-
-#include <linux/module.h>
-
 EXPORT_SYMBOL(__wbflush);
index 9100122e5cef891c18767fee89c98858df661f11..44ff64a80255587fc0e7cb4f65e5a1d234decaff 100644 (file)
@@ -90,7 +90,7 @@ void __init plat_time_init(void)
 static void markeins_board_init(void);
 extern void markeins_irq_setup(void);
 
-static void inline __init markeins_sio_setup(void)
+static inline void __init markeins_sio_setup(void)
 {
 }
 
index 7c66494151db52d6d402f3f89e9e5588021e924a..acb9b6d62b16b13b786e5a339daf9efde6a6f72e 100644 (file)
@@ -13,3 +13,4 @@ obj-y += irq.o
 obj-y += proc.o
 
 obj-$(CONFIG_LEGACY_BOARD_SEAD3)       += board-sead3.o
+obj-$(CONFIG_KEXEC)                    += kexec.o
index d493ccbf274af0dccfcc0639d4446a0460eca284..4af619215410a09946ef82c7c2cb37755423ba59 100644 (file)
@@ -88,6 +88,19 @@ void __init *plat_get_fdt(void)
        return (void *)fdt;
 }
 
+void __init plat_fdt_relocated(void *new_location)
+{
+       /*
+        * reset fdt as the cached value would point to the location
+        * before relocations happened and update the location argument
+        * if it was passed using UHI
+        */
+       fdt = NULL;
+
+       if (fw_arg0 == -2)
+               fw_arg1 = (unsigned long)new_location;
+}
+
 void __init plat_mem_setup(void)
 {
        if (mach && mach->fixup_fdt)
diff --git a/arch/mips/generic/kexec.c b/arch/mips/generic/kexec.c
new file mode 100644 (file)
index 0000000..e9fb735
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 Imagination Technologies
+ * Author: Marcin Nowakowski <marcin.nowakowski@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kexec.h>
+#include <linux/libfdt.h>
+#include <linux/uaccess.h>
+
+static int generic_kexec_prepare(struct kimage *image)
+{
+       int i;
+
+       for (i = 0; i < image->nr_segments; i++) {
+               struct fdt_header fdt;
+
+               if (image->segment[i].memsz <= sizeof(fdt))
+                       continue;
+
+               if (copy_from_user(&fdt, image->segment[i].buf, sizeof(fdt)))
+                       continue;
+
+               if (fdt_check_header(&fdt))
+                       continue;
+
+               kexec_args[0] = -2;
+               kexec_args[1] = (unsigned long)
+                       phys_to_virt((unsigned long)image->segment[i].mem);
+               break;
+       }
+       return 0;
+}
+
+static int __init register_generic_kexec(void)
+{
+       _machine_kexec_prepare = generic_kexec_prepare;
+       return 0;
+}
+arch_initcall(register_generic_kexec);
index 994b1c4392bedcc067b3a6b7f52a48ceab5c738f..2535c7b4c48210e5d8f4e5d68de64cf9bad7759c 100644 (file)
@@ -4,6 +4,7 @@ generic-y += clkdev.h
 generic-y += current.h
 generic-y += dma-contiguous.h
 generic-y += emergency-restart.h
+generic-y += export.h
 generic-y += irq_work.h
 generic-y += local64.h
 generic-y += mcs_spinlock.h
@@ -15,6 +16,7 @@ generic-y += sections.h
 generic-y += segment.h
 generic-y += serial.h
 generic-y += trace_clock.h
+generic-y += unaligned.h
 generic-y += user.h
 generic-y += word-at-a-time.h
 generic-y += xor.h
diff --git a/arch/mips/include/asm/asm-prototypes.h b/arch/mips/include/asm/asm-prototypes.h
new file mode 100644 (file)
index 0000000..a160cf6
--- /dev/null
@@ -0,0 +1,5 @@
+#include <asm/checksum.h>
+#include <asm/page.h>
+#include <asm/fpu.h>
+#include <asm-generic/asm-prototypes.h>
+#include <asm/uaccess.h>
index 7c26b28bf2526856f7a96e1a2c39c61b78bf4e59..859cf7048347bf4b0ebad1f619507202976f74b3 100644 (file)
@@ -54,7 +54,8 @@
                .align  2;                              \
                .type   symbol, @function;              \
                .ent    symbol, 0;                      \
-symbol:                .frame  sp, 0, ra
+symbol:                .frame  sp, 0, ra;                      \
+               .insn
 
 /*
  * NESTED - declare nested routine entry point
@@ -63,8 +64,9 @@ symbol:               .frame  sp, 0, ra
                .globl  symbol;                         \
                .align  2;                              \
                .type   symbol, @function;              \
-               .ent    symbol, 0;                       \
-symbol:                .frame  sp, framesize, rpc
+               .ent    symbol, 0;                      \
+symbol:                .frame  sp, framesize, rpc;             \
+               .insn
 
 /*
  * END - mark end of function
@@ -86,7 +88,7 @@ symbol:
 #define FEXPORT(symbol)                                        \
                .globl  symbol;                         \
                .type   symbol, @function;              \
-symbol:
+symbol:                .insn
 
 /*
  * ABS - export absolute symbol
index ee9f5f2d18fc00e0f51705c745174c7d95bbccf4..e26a093bb17a2e34e2079f1e5cda21a66052e843 100644 (file)
@@ -164,6 +164,19 @@ static inline void plat_swiotlb_setup(void) {}
  * Return: Pointer to the flattened device tree blob.
  */
 extern void *plat_get_fdt(void);
+
+#ifdef CONFIG_RELOCATABLE
+
+/**
+ * plat_fdt_relocated() - Update platform's information about relocated dtb
+ *
+ * This function provides a platform-independent API to set platform's
+ * information about relocated DTB if it needs to be moved due to kernel
+ * relocation occurring at boot.
+ */
+void plat_fdt_relocated(void *new_location);
+
+#endif /* CONFIG_RELOCATABLE */
 #endif /* CONFIG_USE_OF */
 
 #endif /* _ASM_BOOTINFO_H */
index 7749daf2a46594cbf9c2dc9a6334fbcd514ca3a5..c8b574f7e0ccc293c4e1ae7d1a862328ac906648 100644 (file)
@@ -186,7 +186,9 @@ static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
        "       daddu   %0, %4          \n"
        "       dsll32  $1, %0, 0       \n"
        "       daddu   %0, $1          \n"
+       "       sltu    $1, %0, $1      \n"
        "       dsra32  %0, %0, 0       \n"
+       "       addu    %0, $1          \n"
 #endif
        "       .set    pop"
        : "=r" (sum)
index 2b3dc29736700b657ae2192ed484b6f9e79eb648..7a6c466e5f2a01669b0685288980ab20362da553 100644 (file)
@@ -210,6 +210,9 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG];
 typedef double elf_fpreg_t;
 typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
 
+void mips_dump_regs32(u32 *uregs, const struct pt_regs *regs);
+void mips_dump_regs64(u64 *uregs, const struct pt_regs *regs);
+
 #ifdef CONFIG_32BIT
 /*
  * This is used to ensure we don't load something for the wrong architecture.
@@ -221,6 +224,9 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
  */
 #define ELF_CLASS      ELFCLASS32
 
+#define ELF_CORE_COPY_REGS(dest, regs) \
+       mips_dump_regs32((u32 *)&(dest), (regs));
+
 #endif /* CONFIG_32BIT */
 
 #ifdef CONFIG_64BIT
@@ -234,6 +240,9 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
  */
 #define ELF_CLASS      ELFCLASS64
 
+#define ELF_CORE_COPY_REGS(dest, regs) \
+       mips_dump_regs64((u64 *)&(dest), (regs));
+
 #endif /* CONFIG_64BIT */
 
 /*
index 64f2500d891b279493f422129fcb2093180a2527..d34536e7653f6a29fe85b5b1e15b67c19a8c9b3e 100644 (file)
@@ -25,9 +25,6 @@
 #include <asm/cpu-features.h>
 #include <asm/kmap_types.h>
 
-/* undef for production */
-#define HIGHMEM_DEBUG 1
-
 /* declarations for highmem.c */
 extern unsigned long highstart_pfn, highend_pfn;
 
index 32229c77906a1efb8b151bd3f491a452ef2c24d7..47543d56438aa38c3e2e7ad39e8f15918348ddd7 100644 (file)
@@ -40,7 +40,6 @@ extern raw_spinlock_t i8259A_lock;
 extern void make_8259A_irq(unsigned int irq);
 
 extern void init_i8259_irqs(void);
-extern int i8259_of_init(struct device_node *node, struct device_node *parent);
 
 /**
  * i8159_set_poll() - Override the i8259 polling function
index 6bf10e796553838bbd165dc31e117fb1ae9e4234..956db6e201d1877ca6f6b3f8d48fc9ecd6799396 100644 (file)
 
 #include <irq.h>
 
+#define IRQ_STACK_SIZE                 THREAD_SIZE
+
+extern void *irq_stack[NR_CPUS];
+
+static inline bool on_irq_stack(int cpu, unsigned long sp)
+{
+       unsigned long low = (unsigned long)irq_stack[cpu];
+       unsigned long high = low + IRQ_STACK_SIZE;
+
+       return (low <= sp && sp <= high);
+}
+
 #ifdef CONFIG_I8259
 static inline int irq_canonicalize(int irq)
 {
index 2afb84072ad01b4aeff3a1d53d3134a928117024..ee3d4fe515a09b24bb420ae05e8b00517cb1eb0f 100644 (file)
@@ -80,6 +80,15 @@ enum bcm47xx_board {
        BCM47XX_BOARD_LINKSYS_WRT610NV2,
        BCM47XX_BOARD_LINKSYS_WRTSL54GS,
 
+       BCM47XX_BOARD_LUXUL_ABR_4400_V1,
+       BCM47XX_BOARD_LUXUL_XAP_310_V1,
+       BCM47XX_BOARD_LUXUL_XAP_1210_V1,
+       BCM47XX_BOARD_LUXUL_XAP_1230_V1,
+       BCM47XX_BOARD_LUXUL_XAP_1240_V1,
+       BCM47XX_BOARD_LUXUL_XAP_1500_V1,
+       BCM47XX_BOARD_LUXUL_XBR_4400_V1,
+       BCM47XX_BOARD_LUXUL_XVW_P30_V1,
+       BCM47XX_BOARD_LUXUL_XWR_600_V1,
        BCM47XX_BOARD_LUXUL_XWR_1750_V1,
 
        BCM47XX_BOARD_MICROSOFT_MN700,
index c4873e8594ef126aac8257e92b35e4cb1b3d118b..c38b38ce5a3d821a548a8eb973663568b84b2991 100644 (file)
        # to begin
        #
 
-       # This is the variable where the next core to boot os stored
-       PTR_LA  t0, octeon_processor_boot
 octeon_spin_wait_boot:
+#ifdef CONFIG_RELOCATABLE
+       PTR_LA  t0, octeon_processor_relocated_kernel_entry
+       LONG_L  t0, (t0)
+       beq     zero, t0, 1f
+       nop
+
+       jr      t0
+       nop
+1:
+#endif /* CONFIG_RELOCATABLE */
+
+       # This is the variable where the next core to boot is stored
+       PTR_LA  t0, octeon_processor_boot
        # Get the core id of the next to be booted
        LONG_L  t1, (t0)
        # Keep looping if it isn't me
index 4775a1136a5b45eea2359b74bfe530320e95d9df..24d5e31bcfa6d661c20eebcb248f4d65c02cb96f 100644 (file)
 
 /*
  * IP27 uses the R10000's uncached attribute feature.  Attribute 3 selects
- * uncached memory addressing.
+ * uncached memory addressing. Hide the definitions on 32-bit compilation
+ * of the compat-vdso code.
  */
-
+#ifdef CONFIG_64BIT
 #define HSPEC_BASE             0x9000000000000000
 #define IO_BASE                        0x9200000000000000
 #define MSPEC_BASE             0x9400000000000000
 #define UNCAC_BASE             0x9600000000000000
 #define CAC_BASE               0xa800000000000000
+#endif
 
 #define TO_MSPEC(x)            (MSPEC_BASE | ((x) & TO_PHYS_MASK))
 #define TO_HSPEC(x)            (HSPEC_BASE | ((x) & TO_PHYS_MASK))
index 3584c40caf796d1995d3b389b3a4aab2fd612a18..84c28a8995ae2c8a4320f6bfe6c0a3fa3eff3018 100644 (file)
@@ -3,9 +3,9 @@
  *
  * Register mappings for Loongson 1
  *
- * 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
+ * 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.
  */
 
@@ -13,7 +13,7 @@
 #define __ASM_MACH_LOONGSON32_LOONGSON1_H
 
 #if defined(CONFIG_LOONGSON1_LS1B)
-#define DEFAULT_MEMSIZE                        256     /* If no memsize provided */
+#define DEFAULT_MEMSIZE                        64      /* If no memsize provided */
 #elif defined(CONFIG_LOONGSON1_LS1C)
 #define DEFAULT_MEMSIZE                        32
 #endif
@@ -52,6 +52,7 @@
 #include <regs-clk.h>
 #include <regs-mux.h>
 #include <regs-pwm.h>
+#include <regs-rtc.h>
 #include <regs-wdt.h>
 
 #endif /* __ASM_MACH_LOONGSON32_LOONGSON1_H */
index 7adc313649395265c168178528d928d16b7483ac..8f8fa43ba095dd35a04a12cbc7af599c86ba9dda 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@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
+ * 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.
  */
 
@@ -25,11 +25,12 @@ extern struct platform_device ls1x_gpio0_pdev;
 extern struct platform_device ls1x_gpio1_pdev;
 extern struct platform_device ls1x_nand_pdev;
 extern struct platform_device ls1x_rtc_pdev;
+extern struct platform_device ls1x_wdt_pdev;
 
 void __init ls1x_clk_init(void);
 void __init ls1x_dma_set_platdata(struct plat_ls1x_dma *pdata);
 void __init ls1x_nand_set_platdata(struct plat_ls1x_nand *pdata);
-void __init ls1x_serial_set_uartclk(struct platform_device *pdev);
 void __init ls1x_rtc_set_extclk(struct platform_device *pdev);
+void __init ls1x_serial_set_uartclk(struct platform_device *pdev);
 
 #endif /* __ASM_MACH_LOONGSON32_PLATFORM_H */
diff --git a/arch/mips/include/asm/mach-loongson32/regs-rtc.h b/arch/mips/include/asm/mach-loongson32/regs-rtc.h
new file mode 100644 (file)
index 0000000..e67fda2
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2016 Yang Ling <gnaygnil@gmail.com>
+ *
+ * Loongson 1 RTC timer Register Definitions.
+ *
+ * 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 __ASM_MACH_LOONGSON32_REGS_RTC_H
+#define __ASM_MACH_LOONGSON32_REGS_RTC_H
+
+#define LS1X_RTC_REG(x) \
+               ((void __iomem *)KSEG1ADDR(LS1X_RTC_BASE + (x)))
+
+#define LS1X_RTC_CTRL  LS1X_RTC_REG(0x40)
+
+#define RTC_EXTCLK_OK  (BIT(5) | BIT(8))
+#define RTC_EXTCLK_EN  BIT(8)
+
+#endif /* __ASM_MACH_LOONGSON32_REGS_RTC_H */
index a73350b07fdf0bca66443d480ff2139def92c758..66af4ccb5c6c1e3cc3ec11cff3bc89e60e40842f 100644 (file)
 #define MT7620_GPIO_MODE_WDT_MASK      0x3
 #define MT7620_GPIO_MODE_WDT_SHIFT     21
 
+#define MT7620_GPIO_MODE_MDIO          0
+#define MT7620_GPIO_MODE_MDIO_REFCLK   1
+#define MT7620_GPIO_MODE_MDIO_GPIO     2
+#define MT7620_GPIO_MODE_MDIO_MASK     0x3
+#define MT7620_GPIO_MODE_MDIO_SHIFT    7
+
 #define MT7620_GPIO_MODE_I2C           0
 #define MT7620_GPIO_MODE_UART1         5
-#define MT7620_GPIO_MODE_MDIO          8
 #define MT7620_GPIO_MODE_RGMII1                9
 #define MT7620_GPIO_MODE_RGMII2                10
 #define MT7620_GPIO_MODE_SPI           11
index 2e4180797b21828c3bc93a76d214b51f94f1392e..cfdbab0157697f74cf0eedf048d2791f2b4dd643 100644 (file)
@@ -187,6 +187,7 @@ BUILD_CM_R_(config,         MIPS_CM_GCB_OFS + 0x00)
 BUILD_CM_RW(base,              MIPS_CM_GCB_OFS + 0x08)
 BUILD_CM_RW(access,            MIPS_CM_GCB_OFS + 0x20)
 BUILD_CM_R_(rev,               MIPS_CM_GCB_OFS + 0x30)
+BUILD_CM_RW(err_control,       MIPS_CM_GCB_OFS + 0x38)
 BUILD_CM_RW(error_mask,                MIPS_CM_GCB_OFS + 0x40)
 BUILD_CM_RW(error_cause,       MIPS_CM_GCB_OFS + 0x48)
 BUILD_CM_RW(error_addr,                MIPS_CM_GCB_OFS + 0x50)
@@ -266,6 +267,12 @@ BUILD_CM_Cx_R_(tcid_8_priority,    0x80)
 #define CM_REV_CM2_5                           CM_ENCODE_REV(7, 0)
 #define CM_REV_CM3                             CM_ENCODE_REV(8, 0)
 
+/* GCR_ERR_CONTROL register fields */
+#define CM_GCR_ERR_CONTROL_L2_ECC_EN_SHF       1
+#define CM_GCR_ERR_CONTROL_L2_ECC_EN_MSK       (_ULCAST_(0x1) << 1)
+#define CM_GCR_ERR_CONTROL_L2_ECC_SUPPORT_SHF  0
+#define CM_GCR_ERR_CONTROL_L2_ECC_SUPPORT_MSK  (_ULCAST_(0x1) << 0)
+
 /* GCR_ERROR_CAUSE register fields */
 #define CM_GCR_ERROR_CAUSE_ERRTYPE_SHF         27
 #define CM_GCR_ERROR_CAUSE_ERRTYPE_MSK         (_ULCAST_(0x1f) << 27)
index df78b2ca70ebd8c6b57348f9e62f304394f4f3d0..f8d1d2f1d80d55a3969b9eeb1ff05d7d484b18a9 100644 (file)
 #define MIPS_WATCHHI_W         (_ULCAST_(1) << 0)
 #define MIPS_WATCHHI_IRW       (_ULCAST_(0x7) << 0)
 
+/* PerfCnt control register definitions */
+#define MIPS_PERFCTRL_EXL      (_ULCAST_(1) << 0)
+#define MIPS_PERFCTRL_K                (_ULCAST_(1) << 1)
+#define MIPS_PERFCTRL_S                (_ULCAST_(1) << 2)
+#define MIPS_PERFCTRL_U                (_ULCAST_(1) << 3)
+#define MIPS_PERFCTRL_IE       (_ULCAST_(1) << 4)
+#define MIPS_PERFCTRL_EVENT_S  5
+#define MIPS_PERFCTRL_EVENT    (_ULCAST_(0x3ff) << MIPS_PERFCTRL_EVENT_S)
+#define MIPS_PERFCTRL_PCTD     (_ULCAST_(1) << 15)
+#define MIPS_PERFCTRL_EC       (_ULCAST_(0x3) << 23)
+#define MIPS_PERFCTRL_EC_R     (_ULCAST_(0) << 23)
+#define MIPS_PERFCTRL_EC_RI    (_ULCAST_(1) << 23)
+#define MIPS_PERFCTRL_EC_G     (_ULCAST_(2) << 23)
+#define MIPS_PERFCTRL_EC_GRI   (_ULCAST_(3) << 23)
+#define MIPS_PERFCTRL_W                (_ULCAST_(1) << 30)
+#define MIPS_PERFCTRL_M                (_ULCAST_(1) << 31)
+
+/* PerfCnt control register MT extensions used by MIPS cores */
+#define MIPS_PERFCTRL_VPEID_S  16
+#define MIPS_PERFCTRL_VPEID    (_ULCAST_(0xf) << MIPS_PERFCTRL_VPEID_S)
+#define MIPS_PERFCTRL_TCID_S   22
+#define MIPS_PERFCTRL_TCID     (_ULCAST_(0xff) << MIPS_PERFCTRL_TCID_S)
+#define MIPS_PERFCTRL_MT_EN    (_ULCAST_(0x3) << 20)
+#define MIPS_PERFCTRL_MT_EN_ALL        (_ULCAST_(0) << 20)
+#define MIPS_PERFCTRL_MT_EN_VPE        (_ULCAST_(1) << 20)
+#define MIPS_PERFCTRL_MT_EN_TC (_ULCAST_(2) << 20)
+
+/* PerfCnt control register MT extensions used by BMIPS5000 */
+#define BRCM_PERFCTRL_TC       (_ULCAST_(1) << 30)
+
+/* PerfCnt control register MT extensions used by Netlogic XLR */
+#define XLR_PERFCTRL_ALLTHREADS        (_ULCAST_(1) << 13)
+
 /* MAAR bit definitions */
 #define MIPS_MAAR_ADDR         ((BIT_ULL(BITS_PER_LONG - 12) - 1) << 12)
 #define MIPS_MAAR_ADDR_SHIFT   12
index 4719fcfa8865920a11ca8734a2e599eb71cbebf2..8123b82093692b5aef6851ab692af7b18cbd8406 100644 (file)
@@ -46,7 +46,8 @@ union cvmx_gpio_bit_cfgx {
        uint64_t u64;
        struct cvmx_gpio_bit_cfgx_s {
 #ifdef __BIG_ENDIAN_BITFIELD
-               uint64_t reserved_17_63:47;
+               uint64_t reserved_21_63:42;
+               uint64_t output_sel:5;
                uint64_t synce_sel:2;
                uint64_t clk_gen:1;
                uint64_t clk_sel:2;
@@ -66,7 +67,8 @@ union cvmx_gpio_bit_cfgx {
                uint64_t clk_sel:2;
                uint64_t clk_gen:1;
                uint64_t synce_sel:2;
-               uint64_t reserved_17_63:47;
+               uint64_t output_sel:5;
+               uint64_t reserved_21_63:42;
 #endif
        } s;
        struct cvmx_gpio_bit_cfgx_cn30xx {
@@ -126,6 +128,8 @@ union cvmx_gpio_bit_cfgx {
        struct cvmx_gpio_bit_cfgx_s cn66xx;
        struct cvmx_gpio_bit_cfgx_s cn68xx;
        struct cvmx_gpio_bit_cfgx_s cn68xxp1;
+       struct cvmx_gpio_bit_cfgx_s cn70xx;
+       struct cvmx_gpio_bit_cfgx_s cn73xx;
        struct cvmx_gpio_bit_cfgx_s cnf71xx;
 };
 
index 4d7a3db3a9f69fc4c0deaf3ef5039fcf0f90b09f..f89775be76541c179c7f41d7da6d9e30708d8b21 100644 (file)
@@ -80,8 +80,7 @@ extern cvmx_helper_link_info_t __cvmx_helper_rgmii_link_get(int ipd_port);
  * Configure an IPD/PKO port for the specified link state. This
  * function does not influence auto negotiation at the PHY level.
  * The passed link state must always match the link state returned
- * by cvmx_helper_link_get(). It is normally best to use
- * cvmx_helper_link_autoconf() instead.
+ * by cvmx_helper_link_get().
  *
  * @ipd_port:  IPD/PKO port to configure
  * @link_info: The new link state
index 4debb1c5153d692e3b983abec214ad9df23b3a79..63fd21335e4b0bc716c9a50bb7cf84111f2340f2 100644 (file)
@@ -74,8 +74,7 @@ extern cvmx_helper_link_info_t __cvmx_helper_sgmii_link_get(int ipd_port);
  * Configure an IPD/PKO port for the specified link state. This
  * function does not influence auto negotiation at the PHY level.
  * The passed link state must always match the link state returned
- * by cvmx_helper_link_get(). It is normally best to use
- * cvmx_helper_link_autoconf() instead.
+ * by cvmx_helper_link_get().
  *
  * @ipd_port:  IPD/PKO port to configure
  * @link_info: The new link state
index 9f1c6b968f9145f0b523236b1e7281ed1fb52544..d5adf8592773578f1c52bec1e8a4f3352a711813 100644 (file)
@@ -71,8 +71,7 @@ extern cvmx_helper_link_info_t __cvmx_helper_spi_link_get(int ipd_port);
  * Configure an IPD/PKO port for the specified link state. This
  * function does not influence auto negotiation at the PHY level.
  * The passed link state must always match the link state returned
- * by cvmx_helper_link_get(). It is normally best to use
- * cvmx_helper_link_autoconf() instead.
+ * by cvmx_helper_link_get().
  *
  * @ipd_port:  IPD/PKO port to configure
  * @link_info: The new link state
index 5e89ed703eaa7f85dd777443bdaef2d1026471b3..f8ce53f6f28ff7f4c07baca1bf8a28489ae5e5c1 100644 (file)
@@ -74,8 +74,7 @@ extern cvmx_helper_link_info_t __cvmx_helper_xaui_link_get(int ipd_port);
  * Configure an IPD/PKO port for the specified link state. This
  * function does not influence auto negotiation at the PHY level.
  * The passed link state must always match the link state returned
- * by cvmx_helper_link_get(). It is normally best to use
- * cvmx_helper_link_autoconf() instead.
+ * by cvmx_helper_link_get().
  *
  * @ipd_port:  IPD/PKO port to configure
  * @link_info: The new link state
index 5a3090dc6f2f530f810111c4d9fc206164d98a50..0ed87cb67e7fba6a9291811b367ee3e86890a4b8 100644 (file)
@@ -155,17 +155,6 @@ extern int cvmx_helper_get_number_of_interfaces(void);
 extern cvmx_helper_interface_mode_t cvmx_helper_interface_get_mode(int
                                                                   interface);
 
-/**
- * Auto configure an IPD/PKO port link state and speed. This
- * function basically does the equivalent of:
- * cvmx_helper_link_set(ipd_port, cvmx_helper_link_get(ipd_port));
- *
- * @ipd_port: IPD/PKO port to auto configure
- *
- * Returns Link state after configure
- */
-extern cvmx_helper_link_info_t cvmx_helper_link_autoconf(int ipd_port);
-
 /**
  * Return the link state of an IPD/PKO port as returned by
  * auto negotiation. The result of this function may not match
@@ -182,8 +171,7 @@ extern cvmx_helper_link_info_t cvmx_helper_link_get(int ipd_port);
  * Configure an IPD/PKO port for the specified link state. This
  * function does not influence auto negotiation at the PHY level.
  * The passed link state must always match the link state returned
- * by cvmx_helper_link_get(). It is normally best to use
- * cvmx_helper_link_autoconf() instead.
+ * by cvmx_helper_link_get().
  *
  * @ipd_port:  IPD/PKO port to configure
  * @link_info: The new link state
index a03e86969f78a86a9989897ad95cfad1b7798d73..a8705f6c81808f786076d93909d3a34fc2f637d5 100644 (file)
@@ -43,21 +43,7 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
  * Initialize a new pgd / pmd table with invalid pointers.
  */
 extern void pgd_init(unsigned long page);
-
-static inline pgd_t *pgd_alloc(struct mm_struct *mm)
-{
-       pgd_t *ret, *init;
-
-       ret = (pgd_t *) __get_free_pages(GFP_KERNEL, PGD_ORDER);
-       if (ret) {
-               init = pgd_offset(&init_mm, 0UL);
-               pgd_init((unsigned long)ret);
-               memcpy(ret + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
-                      (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
-       }
-
-       return ret;
-}
+extern pgd_t *pgd_alloc(struct mm_struct *mm);
 
 static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
index b42b513007a2c3da70480fd7dd86d990bb0bc874..55fd94e6cd0b1f2c79294f59bf4bc3b0bc702c66 100644 (file)
@@ -147,49 +147,66 @@ static inline void flush_scache_line(unsigned long addr)
 }
 
 #define protected_cache_op(op,addr)                            \
+({                                                             \
+       int __err = 0;                                          \
        __asm__ __volatile__(                                   \
        "       .set    push                    \n"             \
        "       .set    noreorder               \n"             \
        "       .set "MIPS_ISA_ARCH_LEVEL"      \n"             \
-       "1:     cache   %0, (%1)                \n"             \
-       "2:     .set    pop                     \n"             \
+       "1:     cache   %1, (%2)                \n"             \
+       "2:     .insn                           \n"             \
+       "       .set    pop                     \n"             \
+       "       .section .fixup,\"ax\"          \n"             \
+       "3:     li      %0, %3                  \n"             \
+       "       j       2b                      \n"             \
+       "       .previous                       \n"             \
        "       .section __ex_table,\"a\"       \n"             \
-       "       "STR(PTR)" 1b, 2b               \n"             \
+       "       "STR(PTR)" 1b, 3b               \n"             \
        "       .previous"                                      \
-       :                                                       \
-       : "i" (op), "r" (addr))
+       : "+r" (__err)                                          \
+       : "i" (op), "r" (addr), "i" (-EFAULT));                 \
+       __err;                                                  \
+})
+
 
 #define protected_cachee_op(op,addr)                           \
+({                                                             \
+       int __err = 0;                                          \
        __asm__ __volatile__(                                   \
        "       .set    push                    \n"             \
        "       .set    noreorder               \n"             \
        "       .set    mips0                   \n"             \
        "       .set    eva                     \n"             \
-       "1:     cachee  %0, (%1)                \n"             \
-       "2:     .set    pop                     \n"             \
+       "1:     cachee  %1, (%2)                \n"             \
+       "2:     .insn                           \n"             \
+       "       .set    pop                     \n"             \
+       "       .section .fixup,\"ax\"          \n"             \
+       "3:     li      %0, %3                  \n"             \
+       "       j       2b                      \n"             \
+       "       .previous                       \n"             \
        "       .section __ex_table,\"a\"       \n"             \
-       "       "STR(PTR)" 1b, 2b               \n"             \
+       "       "STR(PTR)" 1b, 3b               \n"             \
        "       .previous"                                      \
-       :                                                       \
-       : "i" (op), "r" (addr))
+       : "+r" (__err)                                          \
+       : "i" (op), "r" (addr), "i" (-EFAULT));                 \
+       __err;                                                  \
+})
 
 /*
  * The next two are for badland addresses like signal trampolines.
  */
-static inline void protected_flush_icache_line(unsigned long addr)
+static inline int protected_flush_icache_line(unsigned long addr)
 {
        switch (boot_cpu_type()) {
        case CPU_LOONGSON2:
-               protected_cache_op(Hit_Invalidate_I_Loongson2, addr);
-               break;
+               return protected_cache_op(Hit_Invalidate_I_Loongson2, addr);
 
        default:
 #ifdef CONFIG_EVA
-               protected_cachee_op(Hit_Invalidate_I, addr);
+               return protected_cachee_op(Hit_Invalidate_I, addr);
 #else
-               protected_cache_op(Hit_Invalidate_I, addr);
+               return protected_cache_op(Hit_Invalidate_I, addr);
 #endif
-               break;
        }
 }
 
@@ -199,21 +216,21 @@ static inline void protected_flush_icache_line(unsigned long addr)
  * caches.  We're talking about one cacheline unnecessarily getting invalidated
  * here so the penalty isn't overly hard.
  */
-static inline void protected_writeback_dcache_line(unsigned long addr)
+static inline int protected_writeback_dcache_line(unsigned long addr)
 {
 #ifdef CONFIG_EVA
-       protected_cachee_op(Hit_Writeback_Inv_D, addr);
+       return protected_cachee_op(Hit_Writeback_Inv_D, addr);
 #else
-       protected_cache_op(Hit_Writeback_Inv_D, addr);
+       return protected_cache_op(Hit_Writeback_Inv_D, addr);
 #endif
 }
 
-static inline void protected_writeback_scache_line(unsigned long addr)
+static inline int protected_writeback_scache_line(unsigned long addr)
 {
 #ifdef CONFIG_EVA
-       protected_cachee_op(Hit_Writeback_Inv_SD, addr);
+       return protected_cachee_op(Hit_Writeback_Inv_SD, addr);
 #else
-       protected_cache_op(Hit_Writeback_Inv_SD, addr);
+       return protected_cache_op(Hit_Writeback_Inv_SD, addr);
 #endif
 }
 
index 060f23ff181718fb6b9dec3f3a206f1013452956..98a117a05fbce1af774dc0f6833e78163036e8ce 100644 (file)
@@ -42,11 +42,7 @@ extern int __cpu_logical_map[NR_CPUS];
 #define SMP_CALL_FUNCTION      0x2
 /* Octeon - Tell another core to flush its icache */
 #define SMP_ICACHE_FLUSH       0x4
-/* Used by kexec crashdump to save all cpu's state */
-#define SMP_DUMP               0x8
-#define SMP_ASK_C0COUNT                0x10
-
-extern cpumask_t cpu_callin_map;
+#define SMP_ASK_C0COUNT                0x8
 
 /* Mask of CPUs which are currently definitely operating coherently */
 extern cpumask_t cpu_coherent_mask;
@@ -113,8 +109,4 @@ static inline void arch_send_call_function_ipi_mask(const struct cpumask *mask)
        mp_ops->send_ipi_mask(mask, SMP_CALL_FUNCTION);
 }
 
-#if defined(CONFIG_KEXEC)
-extern void (*dump_ipi_function_ptr)(void *);
-void dump_send_ipi(void (*dump_ipi_callback)(void *));
-#endif
 #endif /* __ASM_SMP_H */
index eebf3954960644daf75dd5ae0d6e7eca1c50f34a..eaa5a4d7d5e572aa91a0e08ab059796a270556bc 100644 (file)
                LONG_S  $25, PT_R25(sp)
                LONG_S  $28, PT_R28(sp)
                LONG_S  $31, PT_R31(sp)
+
+               /* Set thread_info if we're coming from user mode */
+               mfc0    k0, CP0_STATUS
+               sll     k0, 3           /* extract cu0 bit */
+               bltz    k0, 9f
+
                ori     $28, sp, _THREAD_MASK
                xori    $28, _THREAD_MASK
 #ifdef CONFIG_CPU_CAVIUM_OCTEON
                .set    mips64
                pref    0, 0($28)       /* Prefetch the current pointer */
 #endif
+9:
                .set    pop
                .endm
 
 
                .macro  RESTORE_SP_AND_RET
                LONG_L  sp, PT_R29(sp)
+#ifdef CONFIG_CPU_MIPSR6
+               eretnc
+#else
                .set    arch=r4000
                eret
                .set    mips0
+#endif
                .endm
 
 #endif
                RESTORE_SP
                .endm
 
-               .macro  RESTORE_ALL_AND_RET
-               RESTORE_TEMP
-               RESTORE_STATIC
-               RESTORE_AT
-               RESTORE_SOME
-               RESTORE_SP_AND_RET
-               .endm
-
 /*
  * Move to kernel mode and disable interrupts.
  * Set cp0 enable bit as sign that we're running on the kernel stack
index c0ae27971e3108093fdc3952969d15bb3bfd5f30..e610473d61b8c9841c74c604e5ed970921eab1f0 100644 (file)
@@ -66,13 +66,18 @@ do {                                                                        \
 #define __mips_mt_fpaff_switch_to(prev) do { (void) (prev); } while (0)
 #endif
 
-#define __clear_software_ll_bit()                                      \
-do {   if (cpu_has_rw_llb) {                                           \
+/*
+ * Clear LLBit during context switches on MIPSr6 such that eretnc can be used
+ * unconditionally when returning to userland in entry.S.
+ */
+#define __clear_r6_hw_ll_bit() do {                                    \
+       if (cpu_has_mips_r6)                                            \
                write_c0_lladdr(0);                                     \
-       } else {                                                        \
-               if (!__builtin_constant_p(cpu_has_llsc) || !cpu_has_llsc)\
-                       ll_bit = 0;                                     \
-       }                                                               \
+} while (0)
+
+#define __clear_software_ll_bit() do {                                 \
+       if (!__builtin_constant_p(cpu_has_llsc) || !cpu_has_llsc)       \
+               ll_bit = 0;                                             \
 } while (0)
 
 /*
@@ -120,6 +125,7 @@ do {                                                                        \
                }                                                       \
                clear_c0_status(ST0_CU2);                               \
        }                                                               \
+       __clear_r6_hw_ll_bit();                                         \
        __clear_software_ll_bit();                                      \
        if (cpu_has_userlocal)                                          \
                write_c0_userlocal(task_thread_info(next)->tp_value);   \
index e309d8fcb5167b40abdca4f07c82d5d97665d1bc..b439e512792ba45c328c40167992e5fa5b365043 100644 (file)
@@ -27,7 +27,6 @@ struct thread_info {
        unsigned long           tp_value;       /* thread pointer */
        __u32                   cpu;            /* current CPU */
        int                     preempt_count;  /* 0 => preemptable, <0 => BUG */
-       int                     r2_emul_return; /* 1 => Returning from R2 emulator */
        mm_segment_t            addr_limit;     /*
                                                 * thread address space limit:
                                                 * 0x7fffffff for user-thead
diff --git a/arch/mips/include/asm/tlbex.h b/arch/mips/include/asm/tlbex.h
new file mode 100644 (file)
index 0000000..53050e9
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef __ASM_TLBEX_H
+#define __ASM_TLBEX_H
+
+#include <asm/uasm.h>
+
+/*
+ * Write random or indexed TLB entry, and care about the hazards from
+ * the preceding mtc0 and for the following eret.
+ */
+enum tlb_write_entry {
+       tlb_random,
+       tlb_indexed
+};
+
+extern int pgd_reg;
+
+void build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
+                     unsigned int tmp, unsigned int ptr);
+void build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr);
+void build_get_ptep(u32 **p, unsigned int tmp, unsigned int ptr);
+void build_update_entries(u32 **p, unsigned int tmp, unsigned int ptep);
+void build_tlb_write_entry(u32 **p, struct uasm_label **l,
+                          struct uasm_reloc **r,
+                          enum tlb_write_entry wmode);
+
+#endif /* __ASM_TLBEX_H */
index 89fa5c0b1579cf63ecdaf7bdf097214183a979a5..5347cfe15af246497d73c44337b5c831556911a5 100644 (file)
@@ -1241,6 +1241,9 @@ extern size_t __copy_in_user_eva(void *__to, const void *__from, size_t __n);
        __cu_len;                                                       \
 })
 
+extern __kernel_size_t __bzero_kernel(void __user *addr, __kernel_size_t size);
+extern __kernel_size_t __bzero(void __user *addr, __kernel_size_t size);
+
 /*
  * __clear_user: - Zero a block of memory in user space, with less checking.
  * @to:          Destination address, in user space.
@@ -1293,6 +1296,9 @@ __clear_user(void __user *addr, __kernel_size_t size)
        __cl_size;                                                      \
 })
 
+extern long __strncpy_from_kernel_nocheck_asm(char *__to, const char __user *__from, long __len);
+extern long __strncpy_from_user_nocheck_asm(char *__to, const char __user *__from, long __len);
+
 /*
  * __strncpy_from_user: - Copy a NUL terminated string from userspace, with less checking.
  * @dst:   Destination address, in kernel space.  This buffer must be at
@@ -1344,6 +1350,9 @@ __strncpy_from_user(char *__to, const char __user *__from, long __len)
        return res;
 }
 
+extern long __strncpy_from_kernel_asm(char *__to, const char __user *__from, long __len);
+extern long __strncpy_from_user_asm(char *__to, const char __user *__from, long __len);
+
 /*
  * strncpy_from_user: - Copy a NUL terminated string from userspace.
  * @dst:   Destination address, in kernel space.  This buffer must be at
@@ -1393,6 +1402,9 @@ strncpy_from_user(char *__to, const char __user *__from, long __len)
        return res;
 }
 
+extern long __strlen_kernel_asm(const char __user *s);
+extern long __strlen_user_asm(const char __user *s);
+
 /*
  * strlen_user: - Get the size of a string in user space.
  * @str: The string to measure.
@@ -1434,6 +1446,9 @@ static inline long strlen_user(const char __user *s)
        return res;
 }
 
+extern long __strnlen_kernel_nocheck_asm(const char __user *s, long n);
+extern long __strnlen_user_nocheck_asm(const char __user *s, long n);
+
 /* Returns: 0 if bad, string length+1 (memory size) of string if ok */
 static inline long __strnlen_user(const char __user *s, long n)
 {
@@ -1463,6 +1478,9 @@ static inline long __strnlen_user(const char __user *s, long n)
        return res;
 }
 
+extern long __strnlen_kernel_asm(const char __user *s, long n);
+extern long __strnlen_user_asm(const char __user *s, long n);
+
 /*
  * strnlen_user: - Get the size of a string in user space.
  * @str: The string to measure.
index f7929f65f7ca27bf4926deb8e51d73d724c935bb..e9a9e2ade1d216db0d0260b2a796b50b334518e3 100644 (file)
@@ -9,6 +9,9 @@
  * Copyright (C) 2012, 2013  MIPS Technologies, Inc.  All rights reserved.
  */
 
+#ifndef __ASM_UASM_H
+#define __ASM_UASM_H
+
 #include <linux/types.h>
 
 #ifdef CONFIG_EXPORT_UASM
@@ -309,3 +312,5 @@ void uasm_il_bltz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
 void uasm_il_bne(u32 **p, struct uasm_reloc **r, unsigned int reg1,
                 unsigned int reg2, int lid);
 void uasm_il_bnez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
+
+#endif /* __ASM_UASM_H */
diff --git a/arch/mips/include/asm/unaligned.h b/arch/mips/include/asm/unaligned.h
deleted file mode 100644 (file)
index 42f66c3..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.org)
- */
-#ifndef _ASM_MIPS_UNALIGNED_H
-#define _ASM_MIPS_UNALIGNED_H
-
-#include <linux/compiler.h>
-#if defined(__MIPSEB__)
-# include <linux/unaligned/be_struct.h>
-# include <linux/unaligned/le_byteshift.h>
-# define get_unaligned __get_unaligned_be
-# define put_unaligned __put_unaligned_be
-#elif defined(__MIPSEL__)
-# include <linux/unaligned/le_struct.h>
-# include <linux/unaligned/be_byteshift.h>
-# define get_unaligned __get_unaligned_le
-# define put_unaligned __put_unaligned_le
-#else
-#  error "MIPS, but neither __MIPSEB__, nor __MIPSEL__???"
-#endif
-
-# include <linux/unaligned/generic.h>
-
-#endif /* _ASM_MIPS_UNALIGNED_H */
index 1900f39588ae07a6ad351c110157d52ff46821c0..11172fdaeffcd447b7593fb219bb79eff70c6149 100644 (file)
@@ -9,7 +9,7 @@
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/errno.h>
 #include <linux/mm.h>
 #include <linux/bootmem.h>
index b765773ab8aaf8921a51265e850d98f5fb263a93..cac1ccde2214c00cfd0e3e58c7c3c1b94ba15cfc 100644 (file)
@@ -14,7 +14,7 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/init.h>
 
 #include <linux/io.h>
index 6984683c90d03250735070172aaab7dde8c15247..47e857194ce66aaa5e1b8428c14871d630745fac 100644 (file)
@@ -13,7 +13,6 @@
  *
  */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/string.h>
index 4992461787aa4f9c12486fc61955dcc7facdcb35..777877feef712a339504d5e8727f3fefd92b3b3d 100644 (file)
  *
  */
 
+#include <linux/export.h>
 #include <linux/io.h>
+#include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
 
 #include <asm/mach-jz4740/base.h>
 #include <asm/mach-jz4740/timer.h>
index 4a603a3ea657e288406c7ce81d114d464e125ac7..9a0e37b92ce0743c7fe9c3cb29b5a0b1d8ec73d6 100644 (file)
@@ -7,7 +7,7 @@ extra-y         := head.o vmlinux.lds
 obj-y          += cpu-probe.o branch.o elf.o entry.o genex.o idle.o irq.o \
                   process.o prom.o ptrace.o reset.o setup.o signal.o \
                   syscall.o time.o topology.o traps.o unaligned.o watch.o \
-                  vdso.o
+                  vdso.o cacheinfo.o
 
 ifdef CONFIG_FUNCTION_TRACER
 CFLAGS_REMOVE_ftrace.o = -pg
@@ -30,7 +30,7 @@ obj-$(CONFIG_SYNC_R4K)                += sync-r4k.o
 
 obj-$(CONFIG_DEBUG_FS)         += segment.o
 obj-$(CONFIG_STACKTRACE)       += stacktrace.o
-obj-$(CONFIG_MODULES)          += mips_ksyms.o module.o
+obj-$(CONFIG_MODULES)          += module.o
 obj-$(CONFIG_MODULES_USE_ELF_RELA) += module-rela.o
 
 obj-$(CONFIG_FTRACE_SYSCALLS)  += ftrace.o
index 6080582a26d1153b724474038b6471728ad6dafc..bb5c5d34ba8152459eb4f9bfeace3e04315b7528 100644 (file)
@@ -97,11 +97,11 @@ void output_thread_info_defines(void)
        OFFSET(TI_TP_VALUE, thread_info, tp_value);
        OFFSET(TI_CPU, thread_info, cpu);
        OFFSET(TI_PRE_COUNT, thread_info, preempt_count);
-       OFFSET(TI_R2_EMUL_RET, thread_info, r2_emul_return);
        OFFSET(TI_ADDR_LIMIT, thread_info, addr_limit);
        OFFSET(TI_REGS, thread_info, regs);
        DEFINE(_THREAD_SIZE, THREAD_SIZE);
        DEFINE(_THREAD_MASK, THREAD_MASK);
+       DEFINE(_IRQ_STACK_SIZE, IRQ_STACK_SIZE);
        BLANK();
 }
 
diff --git a/arch/mips/kernel/cacheinfo.c b/arch/mips/kernel/cacheinfo.c
new file mode 100644 (file)
index 0000000..97d5239
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * MIPS cacheinfo support
+ *
+ * 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 "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; 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/cacheinfo.h>
+
+/* Populates leaf and increments to next leaf */
+#define populate_cache(cache, leaf, c_level, c_type)           \
+do {                                                           \
+       leaf->type = c_type;                                    \
+       leaf->level = c_level;                                  \
+       leaf->coherency_line_size = c->cache.linesz;            \
+       leaf->number_of_sets = c->cache.sets;                   \
+       leaf->ways_of_associativity = c->cache.ways;            \
+       leaf->size = c->cache.linesz * c->cache.sets *          \
+               c->cache.ways;                                  \
+       leaf++;                                                 \
+} while (0)
+
+static int __init_cache_level(unsigned int cpu)
+{
+       struct cpuinfo_mips *c = &current_cpu_data;
+       struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+       int levels = 0, leaves = 0;
+
+       /*
+        * If Dcache is not set, we assume the cache structures
+        * are not properly initialized.
+        */
+       if (c->dcache.waysize)
+               levels += 1;
+       else
+               return -ENOENT;
+
+
+       leaves += (c->icache.waysize) ? 2 : 1;
+
+       if (c->scache.waysize) {
+               levels++;
+               leaves++;
+       }
+
+       if (c->tcache.waysize) {
+               levels++;
+               leaves++;
+       }
+
+       this_cpu_ci->num_levels = levels;
+       this_cpu_ci->num_leaves = leaves;
+       return 0;
+}
+
+static int __populate_cache_leaves(unsigned int cpu)
+{
+       struct cpuinfo_mips *c = &current_cpu_data;
+       struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+       struct cacheinfo *this_leaf = this_cpu_ci->info_list;
+
+       if (c->icache.waysize) {
+               populate_cache(dcache, this_leaf, 1, CACHE_TYPE_DATA);
+               populate_cache(icache, this_leaf, 1, CACHE_TYPE_INST);
+       } else {
+               populate_cache(dcache, this_leaf, 1, CACHE_TYPE_UNIFIED);
+       }
+
+       if (c->scache.waysize)
+               populate_cache(scache, this_leaf, 2, CACHE_TYPE_UNIFIED);
+
+       if (c->tcache.waysize)
+               populate_cache(tcache, this_leaf, 3, CACHE_TYPE_UNIFIED);
+
+       return 0;
+}
+
+DEFINE_SMP_CALL_CACHE_FUNCTION(init_cache_level)
+DEFINE_SMP_CALL_CACHE_FUNCTION(populate_cache_leaves)
index a378e44688f50f1023dfb86c3c706b77ea5b4de6..c9e8622b5a168b1213b71e289bf4e5e99bd1279a 100644 (file)
@@ -148,11 +148,11 @@ static inline void check_mult_sh(void)
                        bug = 1;
 
        if (bug == 0) {
-               printk("no.\n");
+               pr_cont("no.\n");
                return;
        }
 
-       printk("yes, workaround... ");
+       pr_cont("yes, workaround... ");
 
        fix = 1;
        for (i = 0; i < 8; i++)
@@ -160,11 +160,11 @@ static inline void check_mult_sh(void)
                        fix = 0;
 
        if (fix == 1) {
-               printk("yes.\n");
+               pr_cont("yes.\n");
                return;
        }
 
-       printk("no.\n");
+       pr_cont("no.\n");
        panic(bug64hit, !R4000_WAR ? r4kwar : nowar);
 }
 
@@ -218,11 +218,11 @@ static inline void check_daddi(void)
        local_irq_restore(flags);
 
        if (daddi_ov) {
-               printk("no.\n");
+               pr_cont("no.\n");
                return;
        }
 
-       printk("yes, workaround... ");
+       pr_cont("yes, workaround... ");
 
        local_irq_save(flags);
        handler = set_except_vector(EXCCODE_OV, handle_daddi_ov);
@@ -236,11 +236,11 @@ static inline void check_daddi(void)
        local_irq_restore(flags);
 
        if (daddi_ov) {
-               printk("yes.\n");
+               pr_cont("yes.\n");
                return;
        }
 
-       printk("no.\n");
+       pr_cont("no.\n");
        panic(bug64hit, !DADDI_WAR ? daddiwar : nowar);
 }
 
@@ -288,11 +288,11 @@ static inline void check_daddiu(void)
        daddiu_bug = v != w;
 
        if (!daddiu_bug) {
-               printk("no.\n");
+               pr_cont("no.\n");
                return;
        }
 
-       printk("yes, workaround... ");
+       pr_cont("yes, workaround... ");
 
        asm volatile(
                "addiu  %2, $0, %3\n\t"
@@ -304,11 +304,11 @@ static inline void check_daddiu(void)
                : "I" (0xffffffffffffdb9aUL), "I" (0x1234));
 
        if (v == w) {
-               printk("yes.\n");
+               pr_cont("yes.\n");
                return;
        }
 
-       printk("no.\n");
+       pr_cont("no.\n");
        panic(bug64hit, !DADDI_WAR ? daddiwar : nowar);
 }
 
index 1723b17622976da35170caba062fe956a0fcd245..5a71518be0f10b550187135741e994a852c900b3 100644 (file)
@@ -56,7 +56,7 @@ static void crash_kexec_prepare_cpus(void)
 
        ncpus = num_online_cpus() - 1;/* Excluding the panic cpu */
 
-       dump_send_ipi(crash_shutdown_secondary);
+       smp_call_function(crash_shutdown_secondary, NULL, 0);
        smp_wmb();
 
        /*
index 7791840cf22c0f7c058d32f3abb722eb132f90f8..8d83fc2a96b7196b47367fe8bfb6a39b0f67730e 100644 (file)
@@ -47,11 +47,6 @@ resume_userspace:
        local_irq_disable               # make sure we dont miss an
                                        # interrupt setting need_resched
                                        # between sampling and return
-#ifdef CONFIG_MIPSR2_TO_R6_EMULATOR
-       lw      k0, TI_R2_EMUL_RET($28)
-       bnez    k0, restore_all_from_r2_emul
-#endif
-
        LONG_L  a2, TI_FLAGS($28)       # current->work
        andi    t0, a2, _TIF_WORK_MASK  # (ignoring syscall_trace)
        bnez    t0, work_pending
@@ -120,19 +115,6 @@ restore_partial:           # restore partial frame
        RESTORE_SP_AND_RET
        .set    at
 
-#ifdef CONFIG_MIPSR2_TO_R6_EMULATOR
-restore_all_from_r2_emul:                      # restore full frame
-       .set    noat
-       sw      zero, TI_R2_EMUL_RET($28)       # reset it
-       RESTORE_TEMP
-       RESTORE_AT
-       RESTORE_STATIC
-       RESTORE_SOME
-       LONG_L  sp, PT_R29(sp)
-       eretnc
-       .set    at
-#endif
-
 work_pending:
        andi    t0, a2, _TIF_NEED_RESCHED # a2 is preloaded with TI_FLAGS
        beqz    t0, work_notifysig
index dc0b2961289136f6a17755106bb93a9c99919f98..7ec9612cb0078a4c6ca9825f2e5f2a80e05d3508 100644 (file)
@@ -187,9 +187,44 @@ NESTED(handle_int, PT_SIZE, sp)
 
        LONG_L  s0, TI_REGS($28)
        LONG_S  sp, TI_REGS($28)
-       PTR_LA  ra, ret_from_irq
-       PTR_LA  v0, plat_irq_dispatch
-       jr      v0
+
+       /*
+        * SAVE_ALL ensures we are using a valid kernel stack for the thread.
+        * Check if we are already using the IRQ stack.
+        */
+       move    s1, sp # Preserve the sp
+
+       /* Get IRQ stack for this CPU */
+       ASM_CPUID_MFC0  k0, ASM_SMP_CPUID_REG
+#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
+       lui     k1, %hi(irq_stack)
+#else
+       lui     k1, %highest(irq_stack)
+       daddiu  k1, %higher(irq_stack)
+       dsll    k1, 16
+       daddiu  k1, %hi(irq_stack)
+       dsll    k1, 16
+#endif
+       LONG_SRL        k0, SMP_CPUID_PTRSHIFT
+       LONG_ADDU       k1, k0
+       LONG_L  t0, %lo(irq_stack)(k1)
+
+       # Check if already on IRQ stack
+       PTR_LI  t1, ~(_THREAD_SIZE-1)
+       and     t1, t1, sp
+       beq     t0, t1, 2f
+
+       /* Switch to IRQ stack */
+       li      t1, _IRQ_STACK_SIZE
+       PTR_ADD sp, t0, t1
+
+2:
+       jal     plat_irq_dispatch
+
+       /* Restore sp */
+       move    sp, s1
+
+       j       ret_from_irq
 #ifdef CONFIG_CPU_MICROMIPS
        nop
 #endif
@@ -262,8 +297,44 @@ NESTED(except_vec_vi_handler, 0, sp)
 
        LONG_L  s0, TI_REGS($28)
        LONG_S  sp, TI_REGS($28)
-       PTR_LA  ra, ret_from_irq
-       jr      v0
+
+       /*
+        * SAVE_ALL ensures we are using a valid kernel stack for the thread.
+        * Check if we are already using the IRQ stack.
+        */
+       move    s1, sp # Preserve the sp
+
+       /* Get IRQ stack for this CPU */
+       ASM_CPUID_MFC0  k0, ASM_SMP_CPUID_REG
+#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
+       lui     k1, %hi(irq_stack)
+#else
+       lui     k1, %highest(irq_stack)
+       daddiu  k1, %higher(irq_stack)
+       dsll    k1, 16
+       daddiu  k1, %hi(irq_stack)
+       dsll    k1, 16
+#endif
+       LONG_SRL        k0, SMP_CPUID_PTRSHIFT
+       LONG_ADDU       k1, k0
+       LONG_L  t0, %lo(irq_stack)(k1)
+
+       # Check if already on IRQ stack
+       PTR_LI  t1, ~(_THREAD_SIZE-1)
+       and     t1, t1, sp
+       beq     t0, t1, 2f
+
+       /* Switch to IRQ stack */
+       li      t1, _IRQ_STACK_SIZE
+       PTR_ADD sp, t0, t1
+
+2:
+       jalr    v0
+
+       /* Restore sp */
+       move    sp, s1
+
+       j       ret_from_irq
        END(except_vec_vi_handler)
 
 /*
index f8f5836eb3c1b202a4bc40dc8fcb433cae46444f..ba150c755fccebe8ed3e60fc3af89fa8cd943bfa 100644 (file)
@@ -25,6 +25,8 @@
 #include <linux/atomic.h>
 #include <linux/uaccess.h>
 
+void *irq_stack[NR_CPUS];
+
 /*
  * 'what should we do if we get a hw irq event on an illegal vector'.
  * each architecture has to answer this themselves.
@@ -58,6 +60,15 @@ void __init init_IRQ(void)
                clear_c0_status(ST0_IM);
 
        arch_init_irq();
+
+       for_each_possible_cpu(i) {
+               int irq_pages = IRQ_STACK_SIZE / PAGE_SIZE;
+               void *s = (void *)__get_free_pages(GFP_KERNEL, irq_pages);
+
+               irq_stack[i] = s;
+               pr_debug("CPU%d IRQ stack at 0x%p - 0x%p\n", i,
+                       irq_stack[i], irq_stack[i] + IRQ_STACK_SIZE);
+       }
 }
 
 #ifdef CONFIG_DEBUG_STACKOVERFLOW
index 0352f742d07714fda6d1a758f92886e7977b53de..b01bdef101a85f5178d59b3b1333a1e8d96dddf2 100644 (file)
@@ -64,15 +64,10 @@ SYSCALL_DEFINE6(32_mmap2, unsigned long, addr, unsigned long, len,
        unsigned long, prot, unsigned long, flags, unsigned long, fd,
        unsigned long, pgoff)
 {
-       unsigned long error;
-
-       error = -EINVAL;
        if (pgoff & (~PAGE_MASK >> 12))
-               goto out;
-       error = sys_mmap_pgoff(addr, len, prot, flags, fd,
-                              pgoff >> (PAGE_SHIFT-12));
-out:
-       return error;
+               return -EINVAL;
+       return sys_mmap_pgoff(addr, len, prot, flags, fd,
+                             pgoff >> (PAGE_SHIFT-12));
 }
 
 #define RLIM_INFINITY32 0x7fffffff
index 59725204105c2b50aa476e1d0e5cb2e61d73cb7c..8b574bcd39ba8868364c7d22e355e96cd4e46d70 100644 (file)
@@ -28,9 +28,31 @@ atomic_t kexec_ready_to_reboot = ATOMIC_INIT(0);
 void (*_crash_smp_send_stop)(void) = NULL;
 #endif
 
+static void kexec_image_info(const struct kimage *kimage)
+{
+       unsigned long i;
+
+       pr_debug("kexec kimage info:\n");
+       pr_debug("  type:        %d\n", kimage->type);
+       pr_debug("  start:       %lx\n", kimage->start);
+       pr_debug("  head:        %lx\n", kimage->head);
+       pr_debug("  nr_segments: %lu\n", kimage->nr_segments);
+
+       for (i = 0; i < kimage->nr_segments; i++) {
+               pr_debug("    segment[%lu]: %016lx - %016lx, 0x%lx bytes, %lu pages\n",
+                       i,
+                       kimage->segment[i].mem,
+                       kimage->segment[i].mem + kimage->segment[i].memsz,
+                       (unsigned long)kimage->segment[i].memsz,
+                       (unsigned long)kimage->segment[i].memsz /  PAGE_SIZE);
+       }
+}
+
 int
 machine_kexec_prepare(struct kimage *kimage)
 {
+       kexec_image_info(kimage);
+
        if (_machine_kexec_prepare)
                return _machine_kexec_prepare(kimage);
        return 0;
index 2f7c734771f4e0ad283bb6bf5ee11a0f4b57d707..f2ee7e1e3342e498be961f8995fc91b1de1f2744 100644 (file)
@@ -10,6 +10,7 @@
  * Author: Wu Zhangjin <wuzhangjin@gmail.com>
  */
 
+#include <asm/export.h>
 #include <asm/regdef.h>
 #include <asm/stackframe.h>
 #include <asm/ftrace.h>
@@ -66,6 +67,7 @@
 NESTED(ftrace_caller, PT_SIZE, ra)
        .globl _mcount
 _mcount:
+EXPORT_SYMBOL(_mcount)
        b       ftrace_stub
 #ifdef CONFIG_32BIT
         addiu sp,sp,8
@@ -114,6 +116,7 @@ ftrace_stub:
 #else  /* ! CONFIG_DYNAMIC_FTRACE */
 
 NESTED(_mcount, PT_SIZE, ra)
+EXPORT_SYMBOL(_mcount)
        PTR_LA  t1, ftrace_stub
        PTR_L   t2, ftrace_trace_function /* Prepare t2 for (1) */
        bne     t1, t2, static_trace
index a12904ea9f655c2c64c7381556c6c0a57b76252d..1a0a3b4ecc3efb37ef9db3a23d5acb1dc06a3b8d 100644 (file)
@@ -99,9 +99,10 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
                retval = -ENOMEM;
                goto out_free_new_mask;
        }
-       retval = -EPERM;
-       if (!check_same_owner(p) && !capable(CAP_SYS_NICE))
+       if (!check_same_owner(p) && !capable(CAP_SYS_NICE)) {
+               retval = -EPERM;
                goto out_unlock;
+       }
 
        retval = security_task_setscheduler(p);
        if (retval)
index ef2ca28a028b04b4913d56d1f3a98f75718fd0f4..d8f1cf1ec3703ad56fcea2ac96a0c5c487ccdd67 100644 (file)
@@ -433,8 +433,8 @@ static int multu_func(struct pt_regs *regs, u32 ir)
        rs = regs->regs[MIPSInst_RS(ir)];
        res = (u64)rt * (u64)rs;
        rt = res;
-       regs->lo = (s64)rt;
-       regs->hi = (s64)(res >> 32);
+       regs->lo = (s64)(s32)rt;
+       regs->hi = (s64)(s32)(res >> 32);
 
        MIPS_R2_STATS(muls);
 
@@ -670,9 +670,9 @@ static int maddu_func(struct pt_regs *regs, u32 ir)
        res += ((((s64)rt) << 32) | (u32)rs);
 
        rt = res;
-       regs->lo = (s64)rt;
+       regs->lo = (s64)(s32)rt;
        rs = res >> 32;
-       regs->hi = (s64)rs;
+       regs->hi = (s64)(s32)rs;
 
        MIPS_R2_STATS(dsps);
 
@@ -728,9 +728,9 @@ static int msubu_func(struct pt_regs *regs, u32 ir)
        res = ((((s64)rt) << 32) | (u32)rs) - res;
 
        rt = res;
-       regs->lo = (s64)rt;
+       regs->lo = (s64)(s32)rt;
        rs = res >> 32;
-       regs->hi = (s64)rs;
+       regs->hi = (s64)(s32)rs;
 
        MIPS_R2_STATS(dsps);
 
diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c
deleted file mode 100644 (file)
index 93aeec7..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Export MIPS-specific functions needed for loadable modules.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1996, 97, 98, 99, 2000, 01, 03, 04, 05, 12 by Ralf Baechle
- * Copyright (C) 1999, 2000, 01 Silicon Graphics, Inc.
- */
-#include <linux/interrupt.h>
-#include <linux/export.h>
-#include <asm/checksum.h>
-#include <linux/mm.h>
-#include <linux/uaccess.h>
-#include <asm/ftrace.h>
-#include <asm/fpu.h>
-#include <asm/msa.h>
-
-extern void *__bzero_kernel(void *__s, size_t __count);
-extern void *__bzero(void *__s, size_t __count);
-extern long __strncpy_from_kernel_nocheck_asm(char *__to,
-                                             const char *__from, long __len);
-extern long __strncpy_from_kernel_asm(char *__to, const char *__from,
-                                     long __len);
-extern long __strncpy_from_user_nocheck_asm(char *__to,
-                                           const char *__from, long __len);
-extern long __strncpy_from_user_asm(char *__to, const char *__from,
-                                   long __len);
-extern long __strlen_kernel_asm(const char *s);
-extern long __strlen_user_asm(const char *s);
-extern long __strnlen_kernel_nocheck_asm(const char *s);
-extern long __strnlen_kernel_asm(const char *s);
-extern long __strnlen_user_nocheck_asm(const char *s);
-extern long __strnlen_user_asm(const char *s);
-
-/*
- * Core architecture code
- */
-EXPORT_SYMBOL_GPL(_save_fp);
-#ifdef CONFIG_CPU_HAS_MSA
-EXPORT_SYMBOL_GPL(_save_msa);
-#endif
-
-/*
- * String functions
- */
-EXPORT_SYMBOL(memset);
-EXPORT_SYMBOL(memcpy);
-EXPORT_SYMBOL(memmove);
-
-/*
- * Functions that operate on entire pages.  Mostly used by memory management.
- */
-EXPORT_SYMBOL(clear_page);
-EXPORT_SYMBOL(copy_page);
-
-/*
- * Userspace access stuff.
- */
-EXPORT_SYMBOL(__copy_user);
-EXPORT_SYMBOL(__copy_user_inatomic);
-#ifdef CONFIG_EVA
-EXPORT_SYMBOL(__copy_from_user_eva);
-EXPORT_SYMBOL(__copy_in_user_eva);
-EXPORT_SYMBOL(__copy_to_user_eva);
-EXPORT_SYMBOL(__copy_user_inatomic_eva);
-EXPORT_SYMBOL(__bzero_kernel);
-#endif
-EXPORT_SYMBOL(__bzero);
-EXPORT_SYMBOL(__strncpy_from_kernel_nocheck_asm);
-EXPORT_SYMBOL(__strncpy_from_kernel_asm);
-EXPORT_SYMBOL(__strncpy_from_user_nocheck_asm);
-EXPORT_SYMBOL(__strncpy_from_user_asm);
-EXPORT_SYMBOL(__strlen_kernel_asm);
-EXPORT_SYMBOL(__strlen_user_asm);
-EXPORT_SYMBOL(__strnlen_kernel_nocheck_asm);
-EXPORT_SYMBOL(__strnlen_kernel_asm);
-EXPORT_SYMBOL(__strnlen_user_nocheck_asm);
-EXPORT_SYMBOL(__strnlen_user_asm);
-
-#ifndef CONFIG_CPU_MIPSR6
-EXPORT_SYMBOL(csum_partial);
-EXPORT_SYMBOL(csum_partial_copy_nocheck);
-EXPORT_SYMBOL(__csum_partial_copy_kernel);
-EXPORT_SYMBOL(__csum_partial_copy_to_user);
-EXPORT_SYMBOL(__csum_partial_copy_from_user);
-#endif
-
-EXPORT_SYMBOL(invalid_pte_table);
-#ifdef CONFIG_FUNCTION_TRACER
-/* _mcount is defined in arch/mips/kernel/mcount.S */
-EXPORT_SYMBOL(_mcount);
-#endif
index d3ba9f4105b557d76cf3bf5000d7dcfb074b5ec7..8c35b3152e1eb35cab7f8f605fe48163310b5024 100644 (file)
@@ -101,40 +101,31 @@ struct mips_pmu {
 
 static struct mips_pmu mipspmu;
 
-#define M_PERFCTL_EXL                  (1      <<  0)
-#define M_PERFCTL_KERNEL               (1      <<  1)
-#define M_PERFCTL_SUPERVISOR           (1      <<  2)
-#define M_PERFCTL_USER                 (1      <<  3)
-#define M_PERFCTL_INTERRUPT_ENABLE     (1      <<  4)
-#define M_PERFCTL_EVENT(event)         (((event) & 0x3ff)  << 5)
-#define M_PERFCTL_VPEID(vpe)           ((vpe)    << 16)
+#define M_PERFCTL_EVENT(event)         (((event) << MIPS_PERFCTRL_EVENT_S) & \
+                                        MIPS_PERFCTRL_EVENT)
+#define M_PERFCTL_VPEID(vpe)           ((vpe)    << MIPS_PERFCTRL_VPEID_S)
 
 #ifdef CONFIG_CPU_BMIPS5000
 #define M_PERFCTL_MT_EN(filter)                0
 #else /* !CONFIG_CPU_BMIPS5000 */
-#define M_PERFCTL_MT_EN(filter)                ((filter) << 20)
+#define M_PERFCTL_MT_EN(filter)                (filter)
 #endif /* CONFIG_CPU_BMIPS5000 */
 
-#define           M_TC_EN_ALL                  M_PERFCTL_MT_EN(0)
-#define           M_TC_EN_VPE                  M_PERFCTL_MT_EN(1)
-#define           M_TC_EN_TC                   M_PERFCTL_MT_EN(2)
-#define M_PERFCTL_TCID(tcid)           ((tcid)   << 22)
-#define M_PERFCTL_WIDE                 (1      << 30)
-#define M_PERFCTL_MORE                 (1      << 31)
-#define M_PERFCTL_TC                   (1      << 30)
+#define           M_TC_EN_ALL                  M_PERFCTL_MT_EN(MIPS_PERFCTRL_MT_EN_ALL)
+#define           M_TC_EN_VPE                  M_PERFCTL_MT_EN(MIPS_PERFCTRL_MT_EN_VPE)
+#define           M_TC_EN_TC                   M_PERFCTL_MT_EN(MIPS_PERFCTRL_MT_EN_TC)
 
-#define M_PERFCTL_COUNT_EVENT_WHENEVER (M_PERFCTL_EXL |                \
-                                       M_PERFCTL_KERNEL |              \
-                                       M_PERFCTL_USER |                \
-                                       M_PERFCTL_SUPERVISOR |          \
-                                       M_PERFCTL_INTERRUPT_ENABLE)
+#define M_PERFCTL_COUNT_EVENT_WHENEVER (MIPS_PERFCTRL_EXL |            \
+                                        MIPS_PERFCTRL_K |              \
+                                        MIPS_PERFCTRL_U |              \
+                                        MIPS_PERFCTRL_S |              \
+                                        MIPS_PERFCTRL_IE)
 
 #ifdef CONFIG_MIPS_MT_SMP
 #define M_PERFCTL_CONFIG_MASK          0x3fff801f
 #else
 #define M_PERFCTL_CONFIG_MASK          0x1f
 #endif
-#define M_PERFCTL_EVENT_MASK           0xfe0
 
 
 #ifdef CONFIG_MIPS_PERF_SHARED_TC_COUNTERS
@@ -345,11 +336,11 @@ static void mipsxx_pmu_enable_event(struct hw_perf_event *evt, int idx)
        cpuc->saved_ctrl[idx] = M_PERFCTL_EVENT(evt->event_base & 0xff) |
                (evt->config_base & M_PERFCTL_CONFIG_MASK) |
                /* Make sure interrupt enabled. */
-               M_PERFCTL_INTERRUPT_ENABLE;
+               MIPS_PERFCTRL_IE;
        if (IS_ENABLED(CONFIG_CPU_BMIPS5000))
                /* enable the counter for the calling thread */
                cpuc->saved_ctrl[idx] |=
-                       (1 << (12 + vpe_id())) | M_PERFCTL_TC;
+                       (1 << (12 + vpe_id())) | BRCM_PERFCTRL_TC;
 
        /*
         * We do not actually let the counter run. Leave it until start().
@@ -754,11 +745,11 @@ static int __n_counters(void)
 {
        if (!cpu_has_perf)
                return 0;
-       if (!(read_c0_perfctrl0() & M_PERFCTL_MORE))
+       if (!(read_c0_perfctrl0() & MIPS_PERFCTRL_M))
                return 1;
-       if (!(read_c0_perfctrl1() & M_PERFCTL_MORE))
+       if (!(read_c0_perfctrl1() & MIPS_PERFCTRL_M))
                return 2;
-       if (!(read_c0_perfctrl2() & M_PERFCTL_MORE))
+       if (!(read_c0_perfctrl2() & MIPS_PERFCTRL_M))
                return 3;
 
        return 4;
@@ -1339,7 +1330,7 @@ static int __hw_perf_event_init(struct perf_event *event)
         * We allow max flexibility on how each individual counter shared
         * by the single CPU operates (the mode exclusion and the range).
         */
-       hwc->config_base = M_PERFCTL_INTERRUPT_ENABLE;
+       hwc->config_base = MIPS_PERFCTRL_IE;
 
        /* Calculate range bits and validate it. */
        if (num_possible_cpus() > 1)
@@ -1350,14 +1341,14 @@ static int __hw_perf_event_init(struct perf_event *event)
                mutex_unlock(&raw_event_mutex);
 
        if (!attr->exclude_user)
-               hwc->config_base |= M_PERFCTL_USER;
+               hwc->config_base |= MIPS_PERFCTRL_U;
        if (!attr->exclude_kernel) {
-               hwc->config_base |= M_PERFCTL_KERNEL;
+               hwc->config_base |= MIPS_PERFCTRL_K;
                /* MIPS kernel mode: KSU == 00b || EXL == 1 || ERL == 1 */
-               hwc->config_base |= M_PERFCTL_EXL;
+               hwc->config_base |= MIPS_PERFCTRL_EXL;
        }
        if (!attr->exclude_hv)
-               hwc->config_base |= M_PERFCTL_SUPERVISOR;
+               hwc->config_base |= MIPS_PERFCTRL_S;
 
        hwc->config_base &= M_PERFCTL_CONFIG_MASK;
        /*
@@ -1830,7 +1821,7 @@ init_hw_perf_events(void)
        mipspmu.num_counters = counters;
        mipspmu.irq = irq;
 
-       if (read_c0_perfctrl0() & M_PERFCTL_WIDE) {
+       if (read_c0_perfctrl0() & MIPS_PERFCTRL_W) {
                mipspmu.max_period = (1ULL << 63) - 1;
                mipspmu.valid_count = (1ULL << 63) - 1;
                mipspmu.overflow = 1ULL << 63;
index 5142b1dfe8a70d47c3f99384cd1969a5f95329f5..803e255b6fc3768fdba165d61da9559f6bc079d1 100644 (file)
@@ -33,6 +33,7 @@
 #include <asm/dsemul.h>
 #include <asm/dsp.h>
 #include <asm/fpu.h>
+#include <asm/irq.h>
 #include <asm/msa.h>
 #include <asm/pgtable.h>
 #include <asm/mipsregs.h>
@@ -49,9 +50,7 @@
 #ifdef CONFIG_HOTPLUG_CPU
 void arch_cpu_idle_dead(void)
 {
-       /* What the heck is this check doing ? */
-       if (!cpumask_test_cpu(smp_processor_id(), &cpu_callin_map))
-               play_dead();
+       play_dead();
 }
 #endif
 
@@ -195,11 +194,9 @@ struct mips_frame_info {
 #define J_TARGET(pc,target)    \
                (((unsigned long)(pc) & 0xf0000000) | ((target) << 2))
 
-static inline int is_ra_save_ins(union mips_instruction *ip)
+static inline int is_ra_save_ins(union mips_instruction *ip, int *poff)
 {
 #ifdef CONFIG_CPU_MICROMIPS
-       union mips_instruction mmi;
-
        /*
         * swsp ra,offset
         * swm16 reglist,offset(sp)
@@ -209,29 +206,71 @@ static inline int is_ra_save_ins(union mips_instruction *ip)
         *
         * microMIPS is way more fun...
         */
-       if (mm_insn_16bit(ip->halfword[0])) {
-               mmi.word = (ip->halfword[0] << 16);
-               return (mmi.mm16_r5_format.opcode == mm_swsp16_op &&
-                       mmi.mm16_r5_format.rt == 31) ||
-                      (mmi.mm16_m_format.opcode == mm_pool16c_op &&
-                       mmi.mm16_m_format.func == mm_swm16_op);
+       if (mm_insn_16bit(ip->halfword[1])) {
+               switch (ip->mm16_r5_format.opcode) {
+               case mm_swsp16_op:
+                       if (ip->mm16_r5_format.rt != 31)
+                               return 0;
+
+                       *poff = ip->mm16_r5_format.simmediate;
+                       *poff = (*poff << 2) / sizeof(ulong);
+                       return 1;
+
+               case mm_pool16c_op:
+                       switch (ip->mm16_m_format.func) {
+                       case mm_swm16_op:
+                               *poff = ip->mm16_m_format.imm;
+                               *poff += 1 + ip->mm16_m_format.rlist;
+                               *poff = (*poff << 2) / sizeof(ulong);
+                               return 1;
+
+                       default:
+                               return 0;
+                       }
+
+               default:
+                       return 0;
+               }
        }
-       else {
-               mmi.halfword[0] = ip->halfword[1];
-               mmi.halfword[1] = ip->halfword[0];
-               return (mmi.mm_m_format.opcode == mm_pool32b_op &&
-                       mmi.mm_m_format.rd > 9 &&
-                       mmi.mm_m_format.base == 29 &&
-                       mmi.mm_m_format.func == mm_swm32_func) ||
-                      (mmi.i_format.opcode == mm_sw32_op &&
-                       mmi.i_format.rs == 29 &&
-                       mmi.i_format.rt == 31);
+
+       switch (ip->i_format.opcode) {
+       case mm_sw32_op:
+               if (ip->i_format.rs != 29)
+                       return 0;
+               if (ip->i_format.rt != 31)
+                       return 0;
+
+               *poff = ip->i_format.simmediate / sizeof(ulong);
+               return 1;
+
+       case mm_pool32b_op:
+               switch (ip->mm_m_format.func) {
+               case mm_swm32_func:
+                       if (ip->mm_m_format.rd < 0x10)
+                               return 0;
+                       if (ip->mm_m_format.base != 29)
+                               return 0;
+
+                       *poff = ip->mm_m_format.simmediate;
+                       *poff += (ip->mm_m_format.rd & 0xf) * sizeof(u32);
+                       *poff /= sizeof(ulong);
+                       return 1;
+               default:
+                       return 0;
+               }
+
+       default:
+               return 0;
        }
 #else
        /* sw / sd $ra, offset($sp) */
-       return (ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) &&
-               ip->i_format.rs == 29 &&
-               ip->i_format.rt == 31;
+       if ((ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) &&
+               ip->i_format.rs == 29 && ip->i_format.rt == 31) {
+               *poff = ip->i_format.simmediate / sizeof(ulong);
+               return 1;
+       }
+
+       return 0;
 #endif
 }
 
@@ -246,13 +285,16 @@ static inline int is_jump_ins(union mips_instruction *ip)
         *
         * microMIPS is kind of more fun...
         */
-       union mips_instruction mmi;
-
-       mmi.word = (ip->halfword[0] << 16);
+       if (mm_insn_16bit(ip->halfword[1])) {
+               if ((ip->mm16_r5_format.opcode == mm_pool16c_op &&
+                   (ip->mm16_r5_format.rt & mm_jr16_op) == mm_jr16_op))
+                       return 1;
+               return 0;
+       }
 
-       if ((mmi.mm16_r5_format.opcode == mm_pool16c_op &&
-           (mmi.mm16_r5_format.rt & mm_jr16_op) == mm_jr16_op) ||
-           ip->j_format.opcode == mm_jal32_op)
+       if (ip->j_format.opcode == mm_j32_op)
+               return 1;
+       if (ip->j_format.opcode == mm_jal32_op)
                return 1;
        if (ip->r_format.opcode != mm_pool32a_op ||
                        ip->r_format.func != mm_pool32axf_op)
@@ -280,15 +322,13 @@ static inline int is_sp_move_ins(union mips_instruction *ip)
         *
         * microMIPS is not more fun...
         */
-       if (mm_insn_16bit(ip->halfword[0])) {
-               union mips_instruction mmi;
-
-               mmi.word = (ip->halfword[0] << 16);
-               return (mmi.mm16_r3_format.opcode == mm_pool16d_op &&
-                       mmi.mm16_r3_format.simmediate && mm_addiusp_func) ||
-                      (mmi.mm16_r5_format.opcode == mm_pool16d_op &&
-                       mmi.mm16_r5_format.rt == 29);
+       if (mm_insn_16bit(ip->halfword[1])) {
+               return (ip->mm16_r3_format.opcode == mm_pool16d_op &&
+                       ip->mm16_r3_format.simmediate && mm_addiusp_func) ||
+                      (ip->mm16_r5_format.opcode == mm_pool16d_op &&
+                       ip->mm16_r5_format.rt == 29);
        }
+
        return ip->mm_i_format.opcode == mm_addiu32_op &&
               ip->mm_i_format.rt == 29 && ip->mm_i_format.rs == 29;
 #else
@@ -303,30 +343,36 @@ static inline int is_sp_move_ins(union mips_instruction *ip)
 
 static int get_frame_info(struct mips_frame_info *info)
 {
-#ifdef CONFIG_CPU_MICROMIPS
-       union mips_instruction *ip = (void *) (((char *) info->func) - 1);
-#else
-       union mips_instruction *ip = info->func;
-#endif
-       unsigned max_insns = info->func_size / sizeof(union mips_instruction);
-       unsigned i;
+       bool is_mmips = IS_ENABLED(CONFIG_CPU_MICROMIPS);
+       union mips_instruction insn, *ip, *ip_end;
+       const unsigned int max_insns = 128;
+       unsigned int i;
 
        info->pc_offset = -1;
        info->frame_size = 0;
 
+       ip = (void *)msk_isa16_mode((ulong)info->func);
        if (!ip)
                goto err;
 
-       if (max_insns == 0)
-               max_insns = 128U;       /* unknown function size */
-       max_insns = min(128U, max_insns);
+       ip_end = (void *)ip + info->func_size;
 
-       for (i = 0; i < max_insns; i++, ip++) {
+       for (i = 0; i < max_insns && ip < ip_end; i++, ip++) {
+               if (is_mmips && mm_insn_16bit(ip->halfword[0])) {
+                       insn.halfword[0] = 0;
+                       insn.halfword[1] = ip->halfword[0];
+               } else if (is_mmips) {
+                       insn.halfword[0] = ip->halfword[1];
+                       insn.halfword[1] = ip->halfword[0];
+               } else {
+                       insn.word = ip->word;
+               }
 
-               if (is_jump_ins(ip))
+               if (is_jump_ins(&insn))
                        break;
+
                if (!info->frame_size) {
-                       if (is_sp_move_ins(ip))
+                       if (is_sp_move_ins(&insn))
                        {
 #ifdef CONFIG_CPU_MICROMIPS
                                if (mm_insn_16bit(ip->halfword[0]))
@@ -349,11 +395,9 @@ static int get_frame_info(struct mips_frame_info *info)
                        }
                        continue;
                }
-               if (info->pc_offset == -1 && is_ra_save_ins(ip)) {
-                       info->pc_offset =
-                               ip->i_format.simmediate / sizeof(long);
+               if (info->pc_offset == -1 &&
+                   is_ra_save_ins(&insn, &info->pc_offset))
                        break;
-               }
        }
        if (info->frame_size && info->pc_offset >= 0) /* nested */
                return 0;
@@ -511,7 +555,19 @@ EXPORT_SYMBOL(unwind_stack_by_address);
 unsigned long unwind_stack(struct task_struct *task, unsigned long *sp,
                           unsigned long pc, unsigned long *ra)
 {
-       unsigned long stack_page = (unsigned long)task_stack_page(task);
+       unsigned long stack_page = 0;
+       int cpu;
+
+       for_each_possible_cpu(cpu) {
+               if (on_irq_stack(cpu, *sp)) {
+                       stack_page = (unsigned long)irq_stack[cpu];
+                       break;
+               }
+       }
+
+       if (!stack_page)
+               stack_page = (unsigned long)task_stack_page(task);
+
        return unwind_stack_by_address(stack_page, sp, pc, ra);
 }
 #endif
@@ -673,3 +729,47 @@ int mips_set_process_fp_mode(struct task_struct *task, unsigned int value)
 
        return 0;
 }
+
+#if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32)
+void mips_dump_regs32(u32 *uregs, const struct pt_regs *regs)
+{
+       unsigned int i;
+
+       for (i = MIPS32_EF_R1; i <= MIPS32_EF_R31; i++) {
+               /* k0/k1 are copied as zero. */
+               if (i == MIPS32_EF_R26 || i == MIPS32_EF_R27)
+                       uregs[i] = 0;
+               else
+                       uregs[i] = regs->regs[i - MIPS32_EF_R0];
+       }
+
+       uregs[MIPS32_EF_LO] = regs->lo;
+       uregs[MIPS32_EF_HI] = regs->hi;
+       uregs[MIPS32_EF_CP0_EPC] = regs->cp0_epc;
+       uregs[MIPS32_EF_CP0_BADVADDR] = regs->cp0_badvaddr;
+       uregs[MIPS32_EF_CP0_STATUS] = regs->cp0_status;
+       uregs[MIPS32_EF_CP0_CAUSE] = regs->cp0_cause;
+}
+#endif /* CONFIG_32BIT || CONFIG_MIPS32_O32 */
+
+#ifdef CONFIG_64BIT
+void mips_dump_regs64(u64 *uregs, const struct pt_regs *regs)
+{
+       unsigned int i;
+
+       for (i = MIPS64_EF_R1; i <= MIPS64_EF_R31; i++) {
+               /* k0/k1 are copied as zero. */
+               if (i == MIPS64_EF_R26 || i == MIPS64_EF_R27)
+                       uregs[i] = 0;
+               else
+                       uregs[i] = regs->regs[i - MIPS64_EF_R0];
+       }
+
+       uregs[MIPS64_EF_LO] = regs->lo;
+       uregs[MIPS64_EF_HI] = regs->hi;
+       uregs[MIPS64_EF_CP0_EPC] = regs->cp0_epc;
+       uregs[MIPS64_EF_CP0_BADVADDR] = regs->cp0_badvaddr;
+       uregs[MIPS64_EF_CP0_STATUS] = regs->cp0_status;
+       uregs[MIPS64_EF_CP0_CAUSE] = regs->cp0_cause;
+}
+#endif /* CONFIG_64BIT */
index 5fcec3032f38f6aebdf668af3318997e4f53921f..0dbcd152a1a9be353549b6bc114764c4f0cad381 100644 (file)
@@ -49,6 +49,13 @@ void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
        return __alloc_bootmem(size, align, __pa(MAX_DMA_ADDRESS));
 }
 
+int __init early_init_dt_reserve_memory_arch(phys_addr_t base,
+                                       phys_addr_t size, bool nomap)
+{
+       add_memory_region(base, size, BOOT_MEM_RESERVED);
+       return 0;
+}
+
 void __init __dt_setup_arch(void *bph)
 {
        if (!early_init_dt_scan(bph))
index c8ba2607213298ab0e4a846ca0fa26ee908b253e..fdef26382c376e5de3235108d05e1f107df7035b 100644 (file)
@@ -294,23 +294,8 @@ static int gpr32_get(struct task_struct *target,
 {
        struct pt_regs *regs = task_pt_regs(target);
        u32 uregs[ELF_NGREG] = {};
-       unsigned i;
-
-       for (i = MIPS32_EF_R1; i <= MIPS32_EF_R31; i++) {
-               /* k0/k1 are copied as zero. */
-               if (i == MIPS32_EF_R26 || i == MIPS32_EF_R27)
-                       continue;
-
-               uregs[i] = regs->regs[i - MIPS32_EF_R0];
-       }
-
-       uregs[MIPS32_EF_LO] = regs->lo;
-       uregs[MIPS32_EF_HI] = regs->hi;
-       uregs[MIPS32_EF_CP0_EPC] = regs->cp0_epc;
-       uregs[MIPS32_EF_CP0_BADVADDR] = regs->cp0_badvaddr;
-       uregs[MIPS32_EF_CP0_STATUS] = regs->cp0_status;
-       uregs[MIPS32_EF_CP0_CAUSE] = regs->cp0_cause;
 
+       mips_dump_regs32(uregs, regs);
        return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0,
                                   sizeof(uregs));
 }
@@ -373,23 +358,8 @@ static int gpr64_get(struct task_struct *target,
 {
        struct pt_regs *regs = task_pt_regs(target);
        u64 uregs[ELF_NGREG] = {};
-       unsigned i;
-
-       for (i = MIPS64_EF_R1; i <= MIPS64_EF_R31; i++) {
-               /* k0/k1 are copied as zero. */
-               if (i == MIPS64_EF_R26 || i == MIPS64_EF_R27)
-                       continue;
-
-               uregs[i] = regs->regs[i - MIPS64_EF_R0];
-       }
-
-       uregs[MIPS64_EF_LO] = regs->lo;
-       uregs[MIPS64_EF_HI] = regs->hi;
-       uregs[MIPS64_EF_CP0_EPC] = regs->cp0_epc;
-       uregs[MIPS64_EF_CP0_BADVADDR] = regs->cp0_badvaddr;
-       uregs[MIPS64_EF_CP0_STATUS] = regs->cp0_status;
-       uregs[MIPS64_EF_CP0_CAUSE] = regs->cp0_cause;
 
+       mips_dump_regs64(uregs, regs);
        return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0,
                                   sizeof(uregs));
 }
index ac27ef7d4d0ebd8be86798d8191e32c720263625..1049eeafd97d79ac8198e2666987b69f2deb36ba 100644 (file)
@@ -12,6 +12,7 @@
  */
 #include <asm/asm.h>
 #include <asm/cachectl.h>
+#include <asm/export.h>
 #include <asm/fpregdef.h>
 #include <asm/mipsregs.h>
 #include <asm/asm-offsets.h>
@@ -72,6 +73,7 @@ LEAF(resume)
  * Save a thread's fp context.
  */
 LEAF(_save_fp)
+EXPORT_SYMBOL(_save_fp)
        fpu_save_single a0, t1                  # clobbers t1
        jr      ra
        END(_save_fp)
index 2f0a3b223c97b11276492e4d763a8a5c00a75d0f..758577861523059a3e2e1f83e947121df094877a 100644 (file)
@@ -12,6 +12,7 @@
  */
 #include <asm/asm.h>
 #include <asm/cachectl.h>
+#include <asm/export.h>
 #include <asm/fpregdef.h>
 #include <asm/mipsregs.h>
 #include <asm/asm-offsets.h>
@@ -75,6 +76,7 @@
  * Save a thread's fp context.
  */
 LEAF(_save_fp)
+EXPORT_SYMBOL(_save_fp)
 #if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2) || \
                defined(CONFIG_CPU_MIPS32_R6)
        mfc0    t0, CP0_STATUS
@@ -101,6 +103,7 @@ LEAF(_restore_fp)
  * Save a thread's MSA vector context.
  */
 LEAF(_save_msa)
+EXPORT_SYMBOL(_save_msa)
        msa_save_all    a0
        jr      ra
        END(_save_msa)
index 1958910b75c07aa18926df5d50f93987dbe58406..9103bebc9a8eef76e3d524b63b74aa91936f3663 100644 (file)
@@ -31,6 +31,18 @@ extern u32 _relocation_end[];        /* End relocation table */
 extern long __start___ex_table;        /* Start exception table */
 extern long __stop___ex_table; /* End exception table */
 
+extern void __weak plat_fdt_relocated(void *new_location);
+
+/*
+ * This function may be defined for a platform to perform any post-relocation
+ * fixup necessary.
+ * Return non-zero to abort relocation
+ */
+int __weak plat_post_relocation(long offset)
+{
+       return 0;
+}
+
 static inline u32 __init get_synci_step(void)
 {
        u32 res;
@@ -291,12 +303,14 @@ void *__init relocate_kernel(void)
        int res = 1;
        /* Default to original kernel entry point */
        void *kernel_entry = start_kernel;
+       void *fdt = NULL;
 
        /* Get the command line */
        fw_init_cmdline();
 #if defined(CONFIG_USE_OF)
        /* Deal with the device tree */
-       early_init_dt_scan(plat_get_fdt());
+       fdt = plat_get_fdt();
+       early_init_dt_scan(fdt);
        if (boot_command_line[0]) {
                /* Boot command line was passed in device tree */
                strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
@@ -316,6 +330,29 @@ void *__init relocate_kernel(void)
        arcs_cmdline[0] = '\0';
 
        if (offset) {
+               void (*fdt_relocated_)(void *) = NULL;
+#if defined(CONFIG_USE_OF)
+               unsigned long fdt_phys = virt_to_phys(fdt);
+
+               /*
+                * If built-in dtb is used then it will have been relocated
+                * during kernel _text relocation. If appended DTB is used
+                * then it will not be relocated, but it should remain
+                * intact in the original location. If dtb is loaded by
+                * the bootloader then it may need to be moved if it crosses
+                * the target memory area
+                */
+
+               if (fdt_phys >= virt_to_phys(RELOCATED(&_text)) &&
+                       fdt_phys <= virt_to_phys(RELOCATED(&_end))) {
+                       void *fdt_relocated =
+                               RELOCATED(ALIGN((long)&_end, PAGE_SIZE));
+                       memcpy(fdt_relocated, fdt, fdt_totalsize(fdt));
+                       fdt = fdt_relocated;
+                       fdt_relocated_ = RELOCATED(&plat_fdt_relocated);
+               }
+#endif /* CONFIG_USE_OF */
+
                /* Copy the kernel to it's new location */
                memcpy(loc_new, &_text, kernel_length);
 
@@ -338,6 +375,23 @@ void *__init relocate_kernel(void)
                 */
                memcpy(RELOCATED(&__bss_start), &__bss_start, bss_length);
 
+               /*
+                * If fdt was stored outside of the kernel image and
+                * had to be moved then update platform's state data
+                * with the new fdt location
+                */
+               if (fdt_relocated_)
+                       fdt_relocated_(fdt);
+
+               /*
+                * Last chance for the platform to abort relocation.
+                * This may also be used by the platform to perform any
+                * initialisation required now that the new kernel is
+                * resident in memory and ready to be executed.
+                */
+               if (plat_post_relocation(offset))
+                       goto out;
+
                /* The current thread is now within the relocated image */
                __current_thread_info = RELOCATED(&init_thread_union);
 
index f66e5ce505b23db0e666adb727653df71104c5d1..01d1dbde5fbf1eb2e19c11074fdd5ed7d5a89ec3 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/device.h>
 #include <linux/dma-contiguous.h>
 #include <linux/decompress/generic.h>
+#include <linux/of_fdt.h>
 
 #include <asm/addrspace.h>
 #include <asm/bootinfo.h>
@@ -153,6 +154,35 @@ void __init detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_add
        add_memory_region(start, size, BOOT_MEM_RAM);
 }
 
+bool __init memory_region_available(phys_addr_t start, phys_addr_t size)
+{
+       int i;
+       bool in_ram = false, free = true;
+
+       for (i = 0; i < boot_mem_map.nr_map; i++) {
+               phys_addr_t start_, end_;
+
+               start_ = boot_mem_map.map[i].addr;
+               end_ = boot_mem_map.map[i].addr + boot_mem_map.map[i].size;
+
+               switch (boot_mem_map.map[i].type) {
+               case BOOT_MEM_RAM:
+                       if (start >= start_ && start + size <= end_)
+                               in_ram = true;
+                       break;
+               case BOOT_MEM_RESERVED:
+                       if ((start >= start_ && start < end_) ||
+                           (start < start_ && start + size >= start_))
+                               free = false;
+                       break;
+               default:
+                       continue;
+               }
+       }
+
+       return in_ram && free;
+}
+
 static void __init print_memory_map(void)
 {
        int i;
@@ -332,11 +362,19 @@ static void __init bootmem_init(void)
 
 #else  /* !CONFIG_SGI_IP27 */
 
+static unsigned long __init bootmap_bytes(unsigned long pages)
+{
+       unsigned long bytes = DIV_ROUND_UP(pages, 8);
+
+       return ALIGN(bytes, sizeof(long));
+}
+
 static void __init bootmem_init(void)
 {
        unsigned long reserved_end;
        unsigned long mapstart = ~0UL;
        unsigned long bootmap_size;
+       bool bootmap_valid = false;
        int i;
 
        /*
@@ -430,11 +468,42 @@ static void __init bootmem_init(void)
 #endif
 
        /*
-        * Initialize the boot-time allocator with low memory only.
+        * check that mapstart doesn't overlap with any of
+        * memory regions that have been reserved through eg. DTB
         */
-       bootmap_size = init_bootmem_node(NODE_DATA(0), mapstart,
-                                        min_low_pfn, max_low_pfn);
+       bootmap_size = bootmap_bytes(max_low_pfn - min_low_pfn);
 
+       bootmap_valid = memory_region_available(PFN_PHYS(mapstart),
+                                               bootmap_size);
+       for (i = 0; i < boot_mem_map.nr_map && !bootmap_valid; i++) {
+               unsigned long mapstart_addr;
+
+               switch (boot_mem_map.map[i].type) {
+               case BOOT_MEM_RESERVED:
+                       mapstart_addr = PFN_ALIGN(boot_mem_map.map[i].addr +
+                                               boot_mem_map.map[i].size);
+                       if (PHYS_PFN(mapstart_addr) < mapstart)
+                               break;
+
+                       bootmap_valid = memory_region_available(mapstart_addr,
+                                                               bootmap_size);
+                       if (bootmap_valid)
+                               mapstart = PHYS_PFN(mapstart_addr);
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       if (!bootmap_valid)
+               panic("No memory area to place a bootmap bitmap");
+
+       /*
+        * Initialize the boot-time allocator with low memory only.
+        */
+       if (bootmap_size != init_bootmem_node(NODE_DATA(0), mapstart,
+                                        min_low_pfn, max_low_pfn))
+               panic("Unexpected memory size required for bootmap");
 
        for (i = 0; i < boot_mem_map.nr_map; i++) {
                unsigned long start, end;
@@ -483,6 +552,10 @@ static void __init bootmem_init(void)
                        continue;
                default:
                        /* Not usable memory */
+                       if (start > min_low_pfn && end < max_low_pfn)
+                               reserve_bootmem(boot_mem_map.map[i].addr,
+                                               boot_mem_map.map[i].size,
+                                               BOOTMEM_DEFAULT);
                        continue;
                }
 
@@ -589,6 +662,10 @@ static int __init early_parse_mem(char *p)
                start = memparse(p + 1, &p);
 
        add_memory_region(start, size, BOOT_MEM_RAM);
+
+       if (start && start > PHYS_OFFSET)
+               add_memory_region(PHYS_OFFSET, start - PHYS_OFFSET,
+                               BOOT_MEM_RESERVED);
        return 0;
 }
 early_param("mem", early_parse_mem);
@@ -664,6 +741,11 @@ static void __init mips_parse_crashkernel(void)
        if (ret != 0 || crash_size <= 0)
                return;
 
+       if (!memory_region_available(crash_base, crash_size)) {
+               pr_warn("Invalid memory region reserved for crash kernel\n");
+               return;
+       }
+
        crashk_res.start = crash_base;
        crashk_res.end   = crash_base + crash_size - 1;
 }
@@ -672,6 +754,9 @@ static void __init request_crashkernel(struct resource *res)
 {
        int ret;
 
+       if (crashk_res.start == crashk_res.end)
+               return;
+
        ret = request_resource(res, &crashk_res);
        if (!ret)
                pr_info("Reserving %ldMB of memory at %ldMB for crashkernel\n",
@@ -757,6 +842,9 @@ static void __init arch_mem_init(char **cmdline_p)
                print_memory_map();
        }
 
+       early_init_fdt_reserve_self();
+       early_init_fdt_scan_reserved_mem();
+
        bootmem_init();
 #ifdef CONFIG_PROC_VMCORE
        if (setup_elfcorehdr && setup_elfcorehdr_size) {
index 6d0f1321e0841077531787e07380088b8d6468f0..16e37a28f876cc0af5a6b5889d6ebedf9da02862 100644 (file)
@@ -364,7 +364,7 @@ static int bmips_cpu_disable(void)
 
        set_cpu_online(cpu, false);
        calculate_cpu_foreign_map();
-       cpumask_clear_cpu(cpu, &cpu_callin_map);
+       irq_cpu_offline();
        clear_c0_status(IE_IRQ5);
 
        local_flush_tlb_all();
index 6183ad84cc734501ddad895dbb640d44a34341de..a2544c2394e42331cceee8f0bbf5b538f36e24fb 100644 (file)
@@ -326,7 +326,11 @@ static void cps_boot_secondary(int cpu, struct task_struct *idle)
                        if (cpu_online(remote))
                                break;
                }
-               BUG_ON(remote >= NR_CPUS);
+               if (remote >= NR_CPUS) {
+                       pr_crit("No online CPU in core %u to start CPU%d\n",
+                               core, cpu);
+                       goto out;
+               }
 
                err = smp_call_function_single(remote, remote_vpe_boot,
                                               NULL, 1);
@@ -399,7 +403,6 @@ static int cps_cpu_disable(void)
        smp_mb__after_atomic();
        set_cpu_online(cpu, false);
        calculate_cpu_foreign_map();
-       cpumask_clear_cpu(cpu, &cpu_callin_map);
 
        return 0;
 }
index 7ebb1918e2ac8abb5a2f8bff3b7d0f51cd126ee8..8c60a296294c594cfa03ea12d9913426c803eee2 100644 (file)
@@ -48,8 +48,6 @@
 #include <asm/setup.h>
 #include <asm/maar.h>
 
-cpumask_t cpu_callin_map;              /* Bitmask of started secondaries */
-
 int __cpu_number_map[NR_CPUS];         /* Map physical to logical */
 EXPORT_SYMBOL(__cpu_number_map);
 
@@ -68,6 +66,8 @@ EXPORT_SYMBOL(cpu_sibling_map);
 cpumask_t cpu_core_map[NR_CPUS] __read_mostly;
 EXPORT_SYMBOL(cpu_core_map);
 
+static DECLARE_COMPLETION(cpu_running);
+
 /*
  * A logcal cpu mask containing only one VPE per core to
  * reduce the number of IPIs on large MT systems.
@@ -369,7 +369,7 @@ asmlinkage void start_secondary(void)
        cpumask_set_cpu(cpu, &cpu_coherent_mask);
        notify_cpu_starting(cpu);
 
-       cpumask_set_cpu(cpu, &cpu_callin_map);
+       complete(&cpu_running);
        synchronise_count_slave(cpu);
 
        set_cpu_online(cpu, true);
@@ -430,7 +430,6 @@ void smp_prepare_boot_cpu(void)
 {
        set_cpu_possible(0, true);
        set_cpu_online(0, true);
-       cpumask_set_cpu(0, &cpu_callin_map);
 }
 
 int __cpu_up(unsigned int cpu, struct task_struct *tidle)
@@ -438,11 +437,13 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle)
        mp_ops->boot_secondary(cpu, tidle);
 
        /*
-        * Trust is futile.  We should really have timeouts ...
+        * We must check for timeout here, as the CPU will not be marked
+        * online until the counters are synchronised.
         */
-       while (!cpumask_test_cpu(cpu, &cpu_callin_map)) {
-               udelay(100);
-               schedule();
+       if (!wait_for_completion_timeout(&cpu_running,
+                                        msecs_to_jiffies(1000))) {
+               pr_crit("CPU%u: failed to start\n", cpu);
+               return -EIO;
        }
 
        synchronise_count_master(cpu);
@@ -637,23 +638,6 @@ void flush_tlb_one(unsigned long vaddr)
 EXPORT_SYMBOL(flush_tlb_page);
 EXPORT_SYMBOL(flush_tlb_one);
 
-#if defined(CONFIG_KEXEC)
-void (*dump_ipi_function_ptr)(void *) = NULL;
-void dump_send_ipi(void (*dump_ipi_callback)(void *))
-{
-       int i;
-       int cpu = smp_processor_id();
-
-       dump_ipi_function_ptr = dump_ipi_callback;
-       smp_mb();
-       for_each_online_cpu(i)
-               if (i != cpu)
-                       mp_ops->send_ipi_single(i, SMP_DUMP);
-
-}
-EXPORT_SYMBOL(dump_send_ipi);
-#endif
-
 #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
 
 static DEFINE_PER_CPU(atomic_t, tick_broadcast_count);
index 4472a7f985776ad78a6e032a333cacd5bb2c7415..1df1160b6a47fc69f1af48d15d2e0df3dc7b6793 100644 (file)
@@ -29,7 +29,7 @@ void synchronise_count_master(int cpu)
        int i;
        unsigned long flags;
 
-       printk(KERN_INFO "Synchronize counters for CPU %u: ", cpu);
+       pr_info("Synchronize counters for CPU %u: ", cpu);
 
        local_irq_save(flags);
 
@@ -83,7 +83,7 @@ void synchronise_count_master(int cpu)
         * count registers were almost certainly out of sync
         * so no point in alarming people
         */
-       printk("done.\n");
+       pr_cont("done.\n");
 }
 
 void synchronise_count_slave(int cpu)
index 833f82210528ab9b86a9a79cfc00b433b4bee12a..c86ddbaa4598cdeccc77b778c40ddface2d3a764 100644 (file)
@@ -36,7 +36,6 @@
 #include <asm/sim.h>
 #include <asm/shmparam.h>
 #include <asm/sysmips.h>
-#include <linux/uaccess.h>
 #include <asm/switch_to.h>
 
 /*
@@ -60,16 +59,9 @@ SYSCALL_DEFINE6(mips_mmap, unsigned long, addr, unsigned long, len,
        unsigned long, prot, unsigned long, flags, unsigned long,
        fd, off_t, offset)
 {
-       unsigned long result;
-
-       result = -EINVAL;
        if (offset & ~PAGE_MASK)
-               goto out;
-
-       result = sys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
-
-out:
-       return result;
+               return -EINVAL;
+       return sys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
 }
 
 SYSCALL_DEFINE6(mips_mmap2, unsigned long, addr, unsigned long, len,
index 6c7f9d7e92b3e0dace551122460ff0df8ae89698..cb479be31a500cec8827cbdfaf5e78da070bd416 100644 (file)
@@ -51,6 +51,7 @@
 #include <asm/idle.h>
 #include <asm/mips-cm.h>
 #include <asm/mips-r2-to-r6-emul.h>
+#include <asm/mips-cm.h>
 #include <asm/mipsregs.h>
 #include <asm/mipsmtregs.h>
 #include <asm/module.h>
@@ -1107,7 +1108,6 @@ asmlinkage void do_ri(struct pt_regs *regs)
                switch (status) {
                case 0:
                case SIGEMT:
-                       task_thread_info(current)->r2_emul_return = 1;
                        return;
                case SIGILL:
                        goto no_r2_instr;
@@ -1115,7 +1115,6 @@ asmlinkage void do_ri(struct pt_regs *regs)
                        process_fpemu_return(status,
                                             &current->thread.cp0_baduaddr,
                                             fcr31);
-                       task_thread_info(current)->r2_emul_return = 1;
                        return;
                }
        }
@@ -1644,6 +1643,65 @@ __setup("nol2par", nol2parity);
  */
 static inline void parity_protection_init(void)
 {
+#define ERRCTL_PE      0x80000000
+#define ERRCTL_L2P     0x00800000
+
+       if (mips_cm_revision() >= CM_REV_CM3) {
+               ulong gcr_ectl, cp0_ectl;
+
+               /*
+                * With CM3 systems we need to ensure that the L1 & L2
+                * parity enables are set to the same value, since this
+                * is presumed by the hardware engineers.
+                *
+                * If the user disabled either of L1 or L2 ECC checking,
+                * disable both.
+                */
+               l1parity &= l2parity;
+               l2parity &= l1parity;
+
+               /* Probe L1 ECC support */
+               cp0_ectl = read_c0_ecc();
+               write_c0_ecc(cp0_ectl | ERRCTL_PE);
+               back_to_back_c0_hazard();
+               cp0_ectl = read_c0_ecc();
+
+               /* Probe L2 ECC support */
+               gcr_ectl = read_gcr_err_control();
+
+               if (!(gcr_ectl & CM_GCR_ERR_CONTROL_L2_ECC_SUPPORT_MSK) ||
+                   !(cp0_ectl & ERRCTL_PE)) {
+                       /*
+                        * One of L1 or L2 ECC checking isn't supported,
+                        * so we cannot enable either.
+                        */
+                       l1parity = l2parity = 0;
+               }
+
+               /* Configure L1 ECC checking */
+               if (l1parity)
+                       cp0_ectl |= ERRCTL_PE;
+               else
+                       cp0_ectl &= ~ERRCTL_PE;
+               write_c0_ecc(cp0_ectl);
+               back_to_back_c0_hazard();
+               WARN_ON(!!(read_c0_ecc() & ERRCTL_PE) != l1parity);
+
+               /* Configure L2 ECC checking */
+               if (l2parity)
+                       gcr_ectl |= CM_GCR_ERR_CONTROL_L2_ECC_EN_MSK;
+               else
+                       gcr_ectl &= ~CM_GCR_ERR_CONTROL_L2_ECC_EN_MSK;
+               write_gcr_err_control(gcr_ectl);
+               gcr_ectl = read_gcr_err_control();
+               gcr_ectl &= CM_GCR_ERR_CONTROL_L2_ECC_EN_MSK;
+               WARN_ON(!!gcr_ectl != l2parity);
+
+               pr_info("Cache parity protection %sabled\n",
+                       l1parity ? "en" : "dis");
+               return;
+       }
+
        switch (current_cpu_type()) {
        case CPU_24K:
        case CPU_34K:
@@ -1654,11 +1712,8 @@ static inline void parity_protection_init(void)
        case CPU_PROAPTIV:
        case CPU_P5600:
        case CPU_QEMU_GENERIC:
-       case CPU_I6400:
        case CPU_P6600:
                {
-#define ERRCTL_PE      0x80000000
-#define ERRCTL_L2P     0x00800000
                        unsigned long errctl;
                        unsigned int l1parity_present, l2parity_present;
 
index dbb917403131441369c0ecf1c2a8324644958e85..e99e3fae5326eef924d18f97bcb2f97a745a98c4 100644 (file)
@@ -226,7 +226,7 @@ int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm,
        return uprobe_write_opcode(mm, vaddr, UPROBE_SWBP_INSN);
 }
 
-void __weak arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr,
+void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr,
                                  void *src, unsigned long len)
 {
        unsigned long kaddr, kstart;
index d5de67591735940c86f5e3b8ba2e186a3e94fbaa..f0a0e6d62be38e5bcdb6f8c044f4b026ca940851 100644 (file)
@@ -182,7 +182,7 @@ SECTIONS
         * Force .bss to 64K alignment so that .bss..swapper_pg_dir
         * gets that alignment.  .sbss should be empty, so there will be
         * no holes after __init_end. */
-       BSS_SECTION(0, 0x10000, 0)
+       BSS_SECTION(0, 0x10000, 8)
 
        _end = . ;
 
index 8ac0e5994ed2926548e3da44b158b7a8aff4aa12..0ddf3698b85dac2ebf8bc03e1bf8a089258b8b41 100644 (file)
@@ -269,6 +269,11 @@ static void ltq_hw5_irqdispatch(void)
 DEFINE_HWx_IRQDISPATCH(5)
 #endif
 
+static void ltq_hw_irq_handler(struct irq_desc *desc)
+{
+       ltq_hw_irqdispatch(irq_desc_get_irq(desc) - 2);
+}
+
 #ifdef CONFIG_MIPS_MT_SMP
 void __init arch_init_ipiirq(int irq, struct irqaction *action)
 {
@@ -313,23 +318,19 @@ static struct irqaction irq_call = {
 asmlinkage void plat_irq_dispatch(void)
 {
        unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
-       unsigned int i;
-
-       if ((MIPS_CPU_TIMER_IRQ == 7) && (pending & CAUSEF_IP7)) {
-               do_IRQ(MIPS_CPU_TIMER_IRQ);
-               goto out;
-       } else {
-               for (i = 0; i < MAX_IM; i++) {
-                       if (pending & (CAUSEF_IP2 << i)) {
-                               ltq_hw_irqdispatch(i);
-                               goto out;
-                       }
-               }
+       int irq;
+
+       if (!pending) {
+               spurious_interrupt();
+               return;
        }
-       pr_alert("Spurious IRQ: CAUSE=0x%08x\n", read_c0_status());
 
-out:
-       return;
+       pending >>= CAUSEB_IP;
+       while (pending) {
+               irq = fls(pending) - 1;
+               do_IRQ(MIPS_CPU_IRQ_BASE + irq);
+               pending &= ~BIT(irq);
+       }
 }
 
 static int icu_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
@@ -354,11 +355,6 @@ static const struct irq_domain_ops irq_domain_ops = {
        .map = icu_map,
 };
 
-static struct irqaction cascade = {
-       .handler = no_action,
-       .name = "cascade",
-};
-
 int __init icu_of_init(struct device_node *node, struct device_node *parent)
 {
        struct device_node *eiu_node;
@@ -390,7 +386,7 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent)
        mips_cpu_irq_init();
 
        for (i = 0; i < MAX_IM; i++)
-               setup_irq(i + 2, &cascade);
+               irq_set_chained_handler(i + 2, ltq_hw_irq_handler);
 
        if (cpu_has_vint) {
                pr_info("Setting up vectored interrupts\n");
index 4cbb000e778e3f0fcfcc57942a325d8e318ab343..96773bed8a8a52cdbe33308cd23f9cd6069665bd 100644 (file)
 DEFINE_SPINLOCK(ebu_lock);
 EXPORT_SYMBOL_GPL(ebu_lock);
 
+/*
+ * This is needed by the VPE loader code, just set it to 0 and assume
+ * that the firmware hardcodes this value to something useful.
+ */
+unsigned long physical_memsize = 0L;
+
 /*
  * this struct is filled by the soc specific detection code and holds
  * information about the specific soc type, revision and name
index cef811755123f4749f93b78880f5dffa4bcdc5e1..805b3a6ab2d60c95c8c8a13477cfd21f9bc616e4 100644 (file)
@@ -19,7 +19,8 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/dma-mapping.h>
-#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/spinlock.h>
 #include <linux/clk.h>
 #include <linux/err.h>
 
                                                ltq_dma_membase + (z))
 
 static void __iomem *ltq_dma_membase;
+static DEFINE_SPINLOCK(ltq_dma_lock);
 
 void
 ltq_dma_enable_irq(struct ltq_dma_channel *ch)
 {
        unsigned long flags;
 
-       local_irq_save(flags);
+       spin_lock_irqsave(&ltq_dma_lock, flags);
        ltq_dma_w32(ch->nr, LTQ_DMA_CS);
        ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN);
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&ltq_dma_lock, flags);
 }
 EXPORT_SYMBOL_GPL(ltq_dma_enable_irq);
 
@@ -77,10 +79,10 @@ ltq_dma_disable_irq(struct ltq_dma_channel *ch)
 {
        unsigned long flags;
 
-       local_irq_save(flags);
+       spin_lock_irqsave(&ltq_dma_lock, flags);
        ltq_dma_w32(ch->nr, LTQ_DMA_CS);
        ltq_dma_w32_mask(1 << ch->nr, 0, LTQ_DMA_IRNEN);
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&ltq_dma_lock, flags);
 }
 EXPORT_SYMBOL_GPL(ltq_dma_disable_irq);
 
@@ -89,10 +91,10 @@ ltq_dma_ack_irq(struct ltq_dma_channel *ch)
 {
        unsigned long flags;
 
-       local_irq_save(flags);
+       spin_lock_irqsave(&ltq_dma_lock, flags);
        ltq_dma_w32(ch->nr, LTQ_DMA_CS);
        ltq_dma_w32(DMA_IRQ_ACK, LTQ_DMA_CIS);
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&ltq_dma_lock, flags);
 }
 EXPORT_SYMBOL_GPL(ltq_dma_ack_irq);
 
@@ -101,11 +103,11 @@ ltq_dma_open(struct ltq_dma_channel *ch)
 {
        unsigned long flag;
 
-       local_irq_save(flag);
+       spin_lock_irqsave(&ltq_dma_lock, flag);
        ltq_dma_w32(ch->nr, LTQ_DMA_CS);
        ltq_dma_w32_mask(0, DMA_CHAN_ON, LTQ_DMA_CCTRL);
-       ltq_dma_enable_irq(ch);
-       local_irq_restore(flag);
+       ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN);
+       spin_unlock_irqrestore(&ltq_dma_lock, flag);
 }
 EXPORT_SYMBOL_GPL(ltq_dma_open);
 
@@ -114,11 +116,11 @@ ltq_dma_close(struct ltq_dma_channel *ch)
 {
        unsigned long flag;
 
-       local_irq_save(flag);
+       spin_lock_irqsave(&ltq_dma_lock, flag);
        ltq_dma_w32(ch->nr, LTQ_DMA_CS);
        ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL);
-       ltq_dma_disable_irq(ch);
-       local_irq_restore(flag);
+       ltq_dma_w32_mask(1 << ch->nr, 0, LTQ_DMA_IRNEN);
+       spin_unlock_irqrestore(&ltq_dma_lock, flag);
 }
 EXPORT_SYMBOL_GPL(ltq_dma_close);
 
@@ -133,7 +135,7 @@ ltq_dma_alloc(struct ltq_dma_channel *ch)
                                &ch->phys, GFP_ATOMIC);
        memset(ch->desc_base, 0, LTQ_DESC_NUM * LTQ_DESC_SIZE);
 
-       local_irq_save(flags);
+       spin_lock_irqsave(&ltq_dma_lock, flags);
        ltq_dma_w32(ch->nr, LTQ_DMA_CS);
        ltq_dma_w32(ch->phys, LTQ_DMA_CDBA);
        ltq_dma_w32(LTQ_DESC_NUM, LTQ_DMA_CDLEN);
@@ -142,7 +144,7 @@ ltq_dma_alloc(struct ltq_dma_channel *ch)
        ltq_dma_w32_mask(0, DMA_CHAN_RST, LTQ_DMA_CCTRL);
        while (ltq_dma_r32(LTQ_DMA_CCTRL) & DMA_CHAN_RST)
                ;
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&ltq_dma_lock, flags);
 }
 
 void
@@ -152,11 +154,11 @@ ltq_dma_alloc_tx(struct ltq_dma_channel *ch)
 
        ltq_dma_alloc(ch);
 
-       local_irq_save(flags);
+       spin_lock_irqsave(&ltq_dma_lock, flags);
        ltq_dma_w32(DMA_DESCPT, LTQ_DMA_CIE);
        ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN);
        ltq_dma_w32(DMA_WEIGHT | DMA_TX, LTQ_DMA_CCTRL);
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&ltq_dma_lock, flags);
 }
 EXPORT_SYMBOL_GPL(ltq_dma_alloc_tx);
 
@@ -167,11 +169,11 @@ ltq_dma_alloc_rx(struct ltq_dma_channel *ch)
 
        ltq_dma_alloc(ch);
 
-       local_irq_save(flags);
+       spin_lock_irqsave(&ltq_dma_lock, flags);
        ltq_dma_w32(DMA_DESCPT, LTQ_DMA_CIE);
        ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN);
        ltq_dma_w32(DMA_WEIGHT, LTQ_DMA_CCTRL);
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&ltq_dma_lock, flags);
 }
 EXPORT_SYMBOL_GPL(ltq_dma_alloc_rx);
 
@@ -255,7 +257,6 @@ static const struct of_device_id dma_match[] = {
        { .compatible = "lantiq,dma-xway" },
        {},
 };
-MODULE_DEVICE_TABLE(of, dma_match);
 
 static struct platform_driver dma_driver = {
        .probe = ltq_dma_init,
index 0f1bbea1a816695e1df3e454b26833258b2fea81..e304aabd6678af46ab94dac67bcec2bf85f1a5ae 100644 (file)
@@ -9,7 +9,7 @@
 
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/of_platform.h>
 #include <linux/of_irq.h>
 
@@ -187,7 +187,6 @@ static const struct of_device_id gptu_match[] = {
        { .compatible = "lantiq,gptu-xway" },
        {},
 };
-MODULE_DEVICE_TABLE(of, dma_match);
 
 static struct platform_driver dma_driver = {
        .probe = gptu_probe,
index 236193b5210b0f48e78faaa42bf9fd83bc6e050e..3c3aa05891dd78dd336ca80524870e21df6380ff 100644 (file)
@@ -469,8 +469,8 @@ void __init ltq_soc_init(void)
                        panic("Failed to load xbar nodes from devicetree");
                if (of_address_to_resource(np_pmu, 0, &res_xbar))
                        panic("Failed to get xbar resources");
-               if (request_mem_region(res_xbar.start, resource_size(&res_xbar),
-                       res_xbar.name) < 0)
+               if (!request_mem_region(res_xbar.start, resource_size(&res_xbar),
+                       res_xbar.name))
                        panic("Failed to get xbar resources");
 
                ltq_xbar_membase = ioremap_nocache(res_xbar.start,
@@ -545,7 +545,7 @@ void __init ltq_soc_init(void)
                clkdev_add_pmu("1a800000.pcie", "msi", 1, 1, PMU1_PCIE2_MSI);
                clkdev_add_pmu("1a800000.pcie", "pdi", 1, 1, PMU1_PCIE2_PDI);
                clkdev_add_pmu("1a800000.pcie", "ctl", 1, 1, PMU1_PCIE2_CTL);
-               clkdev_add_pmu("1e108000.eth", NULL, 1, 0, PMU_SWITCH | PMU_PPE_DP);
+               clkdev_add_pmu("1e108000.eth", NULL, 0, 0, PMU_SWITCH | PMU_PPE_DP);
                clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF);
                clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU);
        } else if (of_machine_is_compatible("lantiq,ar10")) {
@@ -553,7 +553,7 @@ void __init ltq_soc_init(void)
                                  ltq_ar10_fpi_hz(), ltq_ar10_pp32_hz());
                clkdev_add_pmu("1e101000.usb", "ctl", 1, 0, PMU_USB0);
                clkdev_add_pmu("1e106000.usb", "ctl", 1, 0, PMU_USB1);
-               clkdev_add_pmu("1e108000.eth", NULL, 1, 0, PMU_SWITCH |
+               clkdev_add_pmu("1e108000.eth", NULL, 0, 0, PMU_SWITCH |
                               PMU_PPE_DP | PMU_PPE_TC);
                clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF);
                clkdev_add_pmu("1f203000.rcu", "gphy", 1, 0, PMU_GPHY);
@@ -575,11 +575,11 @@ void __init ltq_soc_init(void)
                clkdev_add_pmu(NULL, "ahb", 1, 0, PMU_AHBM | PMU_AHBS);
 
                clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF);
-               clkdev_add_pmu("1e108000.eth", NULL, 1, 0,
+               clkdev_add_pmu("1e108000.eth", NULL, 0, 0,
                                PMU_SWITCH | PMU_PPE_DPLUS | PMU_PPE_DPLUM |
                                PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 |
                                PMU_PPE_QSB | PMU_PPE_TOP);
-               clkdev_add_pmu("1f203000.rcu", "gphy", 1, 0, PMU_GPHY);
+               clkdev_add_pmu("1f203000.rcu", "gphy", 0, 0, PMU_GPHY);
                clkdev_add_pmu("1e103000.sdio", NULL, 1, 0, PMU_SDIO);
                clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU);
                clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE);
index 942f32b91d12da6a803e4c9da3edea54a29f3f23..4e272a2622a4332ed783ed52ff25585bfad213aa 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <asm/lasat/lasat.h>
-#include <linux/module.h>
 
 #include "at93c.h"
 
index c710d969938d74b57e7d0b31f1c8a270b546a00f..6f7422400f32aeaca60fc887fcb7d8132b7d9a69 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/types.h>
 #include <asm/lasat/lasat.h>
 
-#include <linux/module.h>
 #include <linux/sysctl.h>
 #include <linux/stddef.h>
 #include <linux/init.h>
index ed88647b57e26710e9a720d9b4cb9aede0def430..2ff84f4b1717aebc3fa61e9bae5d892f30fd6d2c 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/errno.h>
 #include <asm/asm.h>
 #include <asm/asm-offsets.h>
+#include <asm/export.h>
 #include <asm/regdef.h>
 
 #ifdef CONFIG_64BIT
        .set    noreorder
        .align  5
 LEAF(csum_partial)
+EXPORT_SYMBOL(csum_partial)
        move    sum, zero
        move    t7, zero
 
@@ -460,6 +462,7 @@ LEAF(csum_partial)
 #endif
        .if \__nocheck == 1
        FEXPORT(csum_partial_copy_nocheck)
+       EXPORT_SYMBOL(csum_partial_copy_nocheck)
        .endif
        move    sum, zero
        move    odd, zero
@@ -823,9 +826,12 @@ LEAF(csum_partial)
        .endm
 
 LEAF(__csum_partial_copy_kernel)
+EXPORT_SYMBOL(__csum_partial_copy_kernel)
 #ifndef CONFIG_EVA
 FEXPORT(__csum_partial_copy_to_user)
+EXPORT_SYMBOL(__csum_partial_copy_to_user)
 FEXPORT(__csum_partial_copy_from_user)
+EXPORT_SYMBOL(__csum_partial_copy_from_user)
 #endif
 __BUILD_CSUM_PARTIAL_COPY_USER LEGACY_MODE USEROP USEROP 1
 END(__csum_partial_copy_kernel)
index 6c303a94a196a32255269b3395c37d41ed15b464..c3031f18c572ebd529394208e5d51bc33f68e46e 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <asm/asm.h>
 #include <asm/asm-offsets.h>
+#include <asm/export.h>
 #include <asm/regdef.h>
 
 #define dst a0
@@ -622,6 +623,7 @@ SEXC(1)
 
        .align  5
 LEAF(memmove)
+EXPORT_SYMBOL(memmove)
        ADD     t0, a0, a2
        ADD     t1, a1, a2
        sltu    t0, a1, t0                      # dst + len <= src -> memcpy
@@ -674,6 +676,7 @@ LEAF(__rmemcpy)                                     /* a0=dst a1=src a2=len */
  * t6 is used as a flag to note inatomic mode.
  */
 LEAF(__copy_user_inatomic)
+EXPORT_SYMBOL(__copy_user_inatomic)
        b       __copy_user_common
        li      t6, 1
        END(__copy_user_inatomic)
@@ -686,9 +689,11 @@ LEAF(__copy_user_inatomic)
  */
        .align  5
 LEAF(memcpy)                                   /* a0=dst a1=src a2=len */
+EXPORT_SYMBOL(memcpy)
        move    v0, dst                         /* return value */
 .L__memcpy:
 FEXPORT(__copy_user)
+EXPORT_SYMBOL(__copy_user)
        li      t6, 0   /* not inatomic */
 __copy_user_common:
        /* Legacy Mode, user <-> user */
@@ -704,6 +709,7 @@ __copy_user_common:
  */
 
 LEAF(__copy_user_inatomic_eva)
+EXPORT_SYMBOL(__copy_user_inatomic_eva)
        b       __copy_from_user_common
        li      t6, 1
        END(__copy_user_inatomic_eva)
@@ -713,6 +719,7 @@ LEAF(__copy_user_inatomic_eva)
  */
 
 LEAF(__copy_from_user_eva)
+EXPORT_SYMBOL(__copy_from_user_eva)
        li      t6, 0   /* not inatomic */
 __copy_from_user_common:
        __BUILD_COPY_USER EVA_MODE USEROP KERNELOP
@@ -725,6 +732,7 @@ END(__copy_from_user_eva)
  */
 
 LEAF(__copy_to_user_eva)
+EXPORT_SYMBOL(__copy_to_user_eva)
 __BUILD_COPY_USER EVA_MODE KERNELOP USEROP
 END(__copy_to_user_eva)
 
@@ -733,6 +741,7 @@ END(__copy_to_user_eva)
  */
 
 LEAF(__copy_in_user_eva)
+EXPORT_SYMBOL(__copy_in_user_eva)
 __BUILD_COPY_USER EVA_MODE USEROP USEROP
 END(__copy_in_user_eva)
 
index 18a1ccd4d1348c0134ed9d755512b66d1f54779d..a1456664d6c28c9ccc8f837e341fe1a760b3c2d6 100644 (file)
@@ -10,6 +10,7 @@
  */
 #include <asm/asm.h>
 #include <asm/asm-offsets.h>
+#include <asm/export.h>
 #include <asm/regdef.h>
 
 #if LONGSIZE == 4
  */
 
 LEAF(memset)
+EXPORT_SYMBOL(memset)
        beqz            a1, 1f
        move            v0, a0                  /* result */
 
@@ -285,13 +287,16 @@ LEAF(memset)
 1:
 #ifndef CONFIG_EVA
 FEXPORT(__bzero)
+EXPORT_SYMBOL(__bzero)
 #else
 FEXPORT(__bzero_kernel)
+EXPORT_SYMBOL(__bzero_kernel)
 #endif
        __BUILD_BZERO LEGACY_MODE
 
 #ifdef CONFIG_EVA
 LEAF(__bzero)
+EXPORT_SYMBOL(__bzero)
        __BUILD_BZERO EVA_MODE
 END(__bzero)
 #endif
index 929bbacd697e2a8f0bfe5bb46e50233e31a62c92..40be22625bc52552a265d1ebd13807fd9f77fced 100644 (file)
@@ -9,6 +9,7 @@
  */
 #include <asm/asm.h>
 #include <asm/asm-offsets.h>
+#include <asm/export.h>
 #include <asm/regdef.h>
 
 #define EX(insn,reg,addr,handler)                      \
@@ -48,9 +49,11 @@ LEAF(__strlen_\func\()_asm)
        /* Set aliases */
        .global __strlen_user_asm
        .set __strlen_user_asm, __strlen_kernel_asm
+EXPORT_SYMBOL(__strlen_user_asm)
 #endif
 
 __BUILD_STRLEN_ASM kernel
+EXPORT_SYMBOL(__strlen_kernel_asm)
 
 #ifdef CONFIG_EVA
 
@@ -58,4 +61,5 @@ __BUILD_STRLEN_ASM kernel
        .set eva
 __BUILD_STRLEN_ASM user
        .set pop
+EXPORT_SYMBOL(__strlen_user_asm)
 #endif
index 3c32baf8b49447a591e6e552e634eafe5be8d09e..5267ca800b84d05ef98d20da52d5351bca99d0b1 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/errno.h>
 #include <asm/asm.h>
 #include <asm/asm-offsets.h>
+#include <asm/export.h>
 #include <asm/regdef.h>
 
 #define EX(insn,reg,addr,handler)                      \
@@ -72,13 +73,19 @@ FEXPORT(__strncpy_from_\func\()_nocheck_asm)
        .global __strncpy_from_user_nocheck_asm
        .set __strncpy_from_user_asm, __strncpy_from_kernel_asm
        .set __strncpy_from_user_nocheck_asm, __strncpy_from_kernel_nocheck_asm
+EXPORT_SYMBOL(__strncpy_from_user_asm)
+EXPORT_SYMBOL(__strncpy_from_user_nocheck_asm)
 #endif
 
 __BUILD_STRNCPY_ASM kernel
+EXPORT_SYMBOL(__strncpy_from_kernel_asm)
+EXPORT_SYMBOL(__strncpy_from_kernel_nocheck_asm)
 
 #ifdef CONFIG_EVA
        .set push
        .set eva
 __BUILD_STRNCPY_ASM user
        .set pop
+EXPORT_SYMBOL(__strncpy_from_user_asm)
+EXPORT_SYMBOL(__strncpy_from_user_nocheck_asm)
 #endif
index 77e64942f0048c5aac366c0c80a6cf63f0c656d5..860ea99fd70cc46ed393cf77bd5507a61753b6ca 100644 (file)
@@ -8,6 +8,7 @@
  */
 #include <asm/asm.h>
 #include <asm/asm-offsets.h>
+#include <asm/export.h>
 #include <asm/regdef.h>
 
 #define EX(insn,reg,addr,handler)                      \
@@ -70,9 +71,13 @@ FEXPORT(__strnlen_\func\()_nocheck_asm)
        .global __strnlen_user_nocheck_asm
        .set __strnlen_user_asm, __strnlen_kernel_asm
        .set __strnlen_user_nocheck_asm, __strnlen_kernel_nocheck_asm
+EXPORT_SYMBOL(__strnlen_user_asm)
+EXPORT_SYMBOL(__strnlen_user_nocheck_asm)
 #endif
 
 __BUILD_STRNLEN_ASM kernel
+EXPORT_SYMBOL(__strnlen_kernel_asm)
+EXPORT_SYMBOL(__strnlen_kernel_nocheck_asm)
 
 #ifdef CONFIG_EVA
 
@@ -80,4 +85,6 @@ __BUILD_STRNLEN_ASM kernel
        .set eva
 __BUILD_STRNLEN_ASM user
        .set pop
+EXPORT_SYMBOL(__strnlen_user_asm)
+EXPORT_SYMBOL(__strnlen_user_nocheck_asm)
 #endif
index beff0852c6a479ef47911ea69e489c68999256fd..100f23dfa4384495dc4868ee0b921f6963188729 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * Copyright (c) 2011-2016 Zhang, Keguang <keguang.zhang@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
+ * 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 <dma.h>
 #include <nand.h>
 
-#define LS1X_RTC_CTRL  ((void __iomem *)KSEG1ADDR(LS1X_RTC_BASE + 0x40))
-#define RTC_EXTCLK_OK  (BIT(5) | BIT(8))
-#define RTC_EXTCLK_EN  BIT(8)
-
 /* 8250/16550 compatible UART */
 #define LS1X_UART(_id)                                         \
        {                                                       \
@@ -70,19 +66,10 @@ void __init ls1x_serial_set_uartclk(struct platform_device *pdev)
                p->uartclk = clk_get_rate(clk);
 }
 
-void __init ls1x_rtc_set_extclk(struct platform_device *pdev)
-{
-       u32 val;
-
-       val = __raw_readl(LS1X_RTC_CTRL);
-       if (!(val & RTC_EXTCLK_OK))
-               __raw_writel(val | RTC_EXTCLK_EN, LS1X_RTC_CTRL);
-}
-
 /* CPUFreq */
 static struct plat_ls1x_cpufreq ls1x_cpufreq_pdata = {
        .clk_name       = "cpu_clk",
-       .osc_clk_name   = "osc_33m_clk",
+       .osc_clk_name   = "osc_clk",
        .max_freq       = 266 * 1000,
        .min_freq       = 33 * 1000,
 };
@@ -357,7 +344,31 @@ struct platform_device ls1x_ehci_pdev = {
 };
 
 /* Real Time Clock */
+void __init ls1x_rtc_set_extclk(struct platform_device *pdev)
+{
+       u32 val = __raw_readl(LS1X_RTC_CTRL);
+
+       if (!(val & RTC_EXTCLK_OK))
+               __raw_writel(val | RTC_EXTCLK_EN, LS1X_RTC_CTRL);
+}
+
 struct platform_device ls1x_rtc_pdev = {
        .name           = "ls1x-rtc",
        .id             = -1,
 };
+
+/* Watchdog */
+static struct resource ls1x_wdt_resources[] = {
+       {
+               .start  = LS1X_WDT_BASE,
+               .end    = LS1X_WDT_BASE + SZ_16 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+struct platform_device ls1x_wdt_pdev = {
+       .name           = "ls1x-wdt",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(ls1x_wdt_resources),
+       .resource       = ls1x_wdt_resources,
+};
index 38a1d404be1b0268a3700ffbb304897b378668b0..01aceaace314d0f57fd8d82cc453eac499f8ca4f 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * Copyright (c) 2011-2016 Zhang, Keguang <keguang.zhang@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
+ * 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.
  */
 
@@ -72,6 +72,7 @@ static struct platform_device *ls1b_platform_devices[] __initdata = {
        &ls1x_gpio1_pdev,
        &ls1x_nand_pdev,
        &ls1x_rtc_pdev,
+       &ls1x_wdt_pdev,
 };
 
 static int __init ls1b_platform_init(void)
index a96bed5e3ea6025fe704fc951d4844250577ed3b..eb2d913c694fd9562dd2bde2fe8238397cdf3eff 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * Copyright (c) 2016 Yang Ling <gnaygnil@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
+ * 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.
  */
 
@@ -13,6 +13,7 @@ static struct platform_device *ls1c_platform_devices[] __initdata = {
        &ls1x_uart_pdev,
        &ls1x_eth0_pdev,
        &ls1x_rtc_pdev,
+       &ls1x_wdt_pdev,
 };
 
 static int __init ls1c_platform_init(void)
index 9edfa55a0e7828d5f1b7ba10d91bb627650d7d00..b817d6d3a060e8715cc15f5889b2580db3fb5022 100644 (file)
@@ -17,7 +17,7 @@
 
 #include <linux/io.h>
 #include <linux/init.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/jiffies.h>
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
index aab4fd681e1f06b65b7a0f9e8f44f39dd1a85ba1..df7235e334997a2398b4ddf6af96347a5d2be764 100644 (file)
@@ -17,22 +17,14 @@ static void *loongson_dma_alloc_coherent(struct device *dev, size_t size,
        /* ignore region specifiers */
        gfp &= ~(__GFP_DMA | __GFP_DMA32 | __GFP_HIGHMEM);
 
-#ifdef CONFIG_ISA
-       if (dev == NULL)
+       if ((IS_ENABLED(CONFIG_ISA) && dev == NULL) ||
+           (IS_ENABLED(CONFIG_ZONE_DMA) &&
+            dev->coherent_dma_mask < DMA_BIT_MASK(32)))
                gfp |= __GFP_DMA;
-       else
-#endif
-#ifdef CONFIG_ZONE_DMA
-       if (dev->coherent_dma_mask < DMA_BIT_MASK(32))
-               gfp |= __GFP_DMA;
-       else
-#endif
-#ifdef CONFIG_ZONE_DMA32
-       if (dev->coherent_dma_mask < DMA_BIT_MASK(40))
+       else if (IS_ENABLED(CONFIG_ZONE_DMA32) &&
+                dev->coherent_dma_mask < DMA_BIT_MASK(40))
                gfp |= __GFP_DMA32;
-       else
-#endif
-       ;
+
        gfp |= __GFP_NORETRY;
 
        ret = swiotlb_alloc_coherent(dev, size, dma_handle, gfp);
index 57d590ac80045b9bf9848a6e216d22d72cff33d9..6afa2185026703843c9b46a931c4bdb35e11c483 100644 (file)
@@ -17,7 +17,7 @@
  * Free Software Foundation;  either version 2 of the  License, or (at your
  * option) any later version.
  */
-#include <linux/module.h>
+#include <linux/export.h>
 #include <asm/bootinfo.h>
 #include <loongson.h>
 #include <boot_param.h>
index 2dc5122f0e09a454f3ade53a87eaf32f806b12ec..332387678f3e5eada23b80ffc3750207a3f73959 100644 (file)
@@ -7,7 +7,8 @@
  *  Free Software Foundation;  either version 2 of the License, or (at your
  *  option) any later version.
  */
-#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/init.h>
 
 #include <asm/wbflush.h>
 #include <asm/bootinfo.h>
index 9de559d58e1fc6d0aee540185dc22e0c87d8ad2c..d27c41b237a08918e2d6021c40b4322712504759 100644 (file)
@@ -8,7 +8,7 @@
  * option) any later version.
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <asm/bootinfo.h>
 
 #include <loongson.h>
index 2b666d3a3947d5baa81731ab4349a04c54b25023..321822997e768bf4e8e1e76d4324cfc9c06963d8 100644 (file)
@@ -10,7 +10,8 @@
  * (at your option) any later version.
  */
 
-#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/export.h>
 #include <linux/spinlock.h>
 #include <linux/delay.h>
 
index cab5f43e0e29ca7b97bdda99b7b911b24317d362..9e33e45aa17c5d6881d6bc8cd5ca3c90d42098d0 100644 (file)
@@ -8,8 +8,9 @@
  *  option) any later version.
  */
 
+#include <linux/export.h>
+#include <linux/init.h>
 #include <linux/interrupt.h>
-#include <linux/module.h>
 
 #include <asm/irq_cpu.h>
 #include <asm/i8259.h>
index cac4d382ea73f4f9801eec9d9f6a097ddd33e5ba..6859e934862d3a7f0671744c1634e28b8451ca7d 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/interrupt.h>
 #include <linux/pm.h>
 #include <linux/i8042.h>
-#include <linux/module.h>
+#include <linux/export.h>
 
 #include <asm/i8259.h>
 #include <asm/mipsregs.h>
index 8e7649088353d61c103bc5f19857eba2aef281e6..548f759454dce494de9db809a74f56821133efb9 100644 (file)
@@ -1,7 +1,7 @@
 #include <loongson.h>
 #include <irq.h>
 #include <linux/interrupt.h>
-#include <linux/module.h>
+#include <linux/init.h>
 
 #include <asm/irq_cpu.h>
 #include <asm/i8259.h>
index 282c5a8c2fcd4c22649bea11219ec7665f67602f..f17ef520799aef0d827b15b0e0530f65013b9212 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/mmzone.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/nodemask.h>
 #include <linux/swap.h>
 #include <linux/memblock.h>
index 99aab9f859044e01111c2cfba9b97bc186edc38e..cfcf240cedbe26810bc77ffd79bcf297cb6e0f9a 100644 (file)
@@ -418,7 +418,6 @@ static int loongson3_cpu_disable(void)
 
        set_cpu_online(cpu, false);
        calculate_cpu_foreign_map();
-       cpumask_clear_cpu(cpu, &cpu_callin_map);
        local_irq_save(flags);
        fixup_irqs();
        local_irq_restore(flags);
index b4c64bd3f723903296c73d75dba3c3e29b861591..b4cc8811a6642b35901e4bcc9a277b657801d8fb 100644 (file)
@@ -4,7 +4,7 @@
 
 obj-y                          += cache.o dma-default.o extable.o fault.o \
                                   gup.o init.o mmap.o page.o page-funcs.o \
-                                  tlbex.o tlbex-fault.o tlb-funcs.o
+                                  pgtable.o tlbex.o tlbex-fault.o tlb-funcs.o
 
 ifdef CONFIG_CPU_MICROMIPS
 obj-y                          += uasm-micromips.o
index 88cfaf81c958733397a08ccb79d8c4c021f90580..e7f798d55fbcca06eaa0fe07a6822c3aedd18cc8 100644 (file)
@@ -1452,6 +1452,7 @@ static void probe_pcache(void)
        switch (current_cpu_type()) {
        case CPU_20KC:
        case CPU_25KF:
+       case CPU_I6400:
        case CPU_SB1:
        case CPU_SB1A:
        case CPU_XLR:
@@ -1478,7 +1479,6 @@ static void probe_pcache(void)
        case CPU_PROAPTIV:
        case CPU_M5150:
        case CPU_QEMU_GENERIC:
-       case CPU_I6400:
        case CPU_P6600:
        case CPU_M6250:
                if (!(read_c0_config7() & MIPS_CONF7_IAR) &&
@@ -1497,6 +1497,10 @@ static void probe_pcache(void)
                        c->dcache.flags |= MIPS_CACHE_ALIASES;
        }
 
+       /* Physically indexed caches don't suffer from virtual aliasing */
+       if (c->dcache.flags & MIPS_CACHE_PINDEX)
+               c->dcache.flags &= ~MIPS_CACHE_ALIASES;
+
        switch (current_cpu_type()) {
        case CPU_20KC:
                /*
index e86ebcf5c071f8c9d9737b9d1d1e21cd95204212..aa75849c36bcdd79489e4933d334232985d298c5 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/hardirq.h>
 #include <linux/gfp.h>
 #include <linux/kcore.h>
+#include <linux/export.h>
 
 #include <asm/asm-offsets.h>
 #include <asm/bootinfo.h>
@@ -538,5 +539,7 @@ unsigned long pgd_current[NR_CPUS];
 pgd_t swapper_pg_dir[_PTRS_PER_PGD] __section(.bss..swapper_pg_dir);
 #ifndef __PAGETABLE_PMD_FOLDED
 pmd_t invalid_pmd_table[PTRS_PER_PMD] __page_aligned_bss;
+EXPORT_SYMBOL_GPL(invalid_pmd_table);
 #endif
 pte_t invalid_pte_table[PTRS_PER_PTE] __page_aligned_bss;
+EXPORT_SYMBOL(invalid_pte_table);
index d08ea3ff0f53345e7501dd168f32c2177976f6ee..d6d92c02308dd8790f073cc20d64bd2447ec0ae4 100644 (file)
@@ -146,14 +146,14 @@ unsigned long arch_mmap_rnd(void)
 {
        unsigned long rnd;
 
-       rnd = get_random_long();
-       rnd <<= PAGE_SHIFT;
+#ifdef CONFIG_COMPAT
        if (TASK_IS_32BIT_ADDR)
-               rnd &= 0xfffffful;
+               rnd = get_random_long() & ((1UL << mmap_rnd_compat_bits) - 1);
        else
-               rnd &= 0xffffffful;
+#endif /* CONFIG_COMPAT */
+               rnd = get_random_long() & ((1UL << mmap_rnd_bits) - 1);
 
-       return rnd;
+       return rnd << PAGE_SHIFT;
 }
 
 void arch_pick_mmap_layout(struct mm_struct *mm)
index 48a6b38ff13e0a6e5cd7523d431f31b07c9e55d7..43181ac0a1afc6ccf4e7e2d972979da7fce79a0e 100644 (file)
@@ -9,6 +9,7 @@
  * Copyright (C) 2012  Ralf Baechle <ralf@linux-mips.org>
  */
 #include <asm/asm.h>
+#include <asm/export.h>
 #include <asm/regdef.h>
 
 #ifdef CONFIG_SIBYTE_DMA_PAGEOPS
@@ -29,6 +30,7 @@
  */
 EXPORT(__clear_page_start)
 LEAF(cpu_clear_page_function_name)
+EXPORT_SYMBOL(cpu_clear_page_function_name)
 1:     j       1b              /* Dummy, will be replaced. */
        .space 288
 END(cpu_clear_page_function_name)
@@ -44,6 +46,7 @@ EXPORT(__clear_page_end)
  */
 EXPORT(__copy_page_start)
 LEAF(cpu_copy_page_function_name)
+EXPORT_SYMBOL(cpu_copy_page_function_name)
 1:     j       1b              /* Dummy, will be replaced. */
        .space 1344
 END(cpu_copy_page_function_name)
index 6f804f5960abeff77cdbcd2cecf48a1acf989e7c..d5d02993aa21ba99bdd66e2212e9484ed8d8892b 100644 (file)
@@ -661,6 +661,7 @@ void clear_page(void *page)
                ;
        __raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE)));
 }
+EXPORT_SYMBOL(clear_page);
 
 void copy_page(void *to, void *from)
 {
@@ -687,5 +688,6 @@ void copy_page(void *to, void *from)
                ;
        __raw_readq(IOADDR(A_DM_REGISTER(cpu, R_DM_DSCR_BASE)));
 }
+EXPORT_SYMBOL(copy_page);
 
 #endif /* CONFIG_SIBYTE_DMA_PAGEOPS */
index ce4473e7c0d261b04d7bf44fcfc8ddc6414435d9..0ae7b28b4db5d992c11a79e05c76b39cb9a41dcf 100644 (file)
@@ -6,6 +6,7 @@
  * Copyright (C) 1999, 2000 by Silicon Graphics
  * Copyright (C) 2003 by Ralf Baechle
  */
+#include <linux/export.h>
 #include <linux/init.h>
 #include <linux/mm.h>
 #include <asm/fixmap.h>
@@ -60,6 +61,7 @@ void pmd_init(unsigned long addr, unsigned long pagetable)
                p[-1] = pagetable;
        } while (p != end);
 }
+EXPORT_SYMBOL_GPL(pmd_init);
 #endif
 
 pmd_t mk_pmd(struct page *page, pgprot_t prot)
diff --git a/arch/mips/mm/pgtable.c b/arch/mips/mm/pgtable.c
new file mode 100644 (file)
index 0000000..05560b0
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * 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/export.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <asm/pgalloc.h>
+
+pgd_t *pgd_alloc(struct mm_struct *mm)
+{
+       pgd_t *ret, *init;
+
+       ret = (pgd_t *) __get_free_pages(GFP_KERNEL, PGD_ORDER);
+       if (ret) {
+               init = pgd_offset(&init_mm, 0UL);
+               pgd_init((unsigned long)ret);
+               memcpy(ret + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
+                      (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(pgd_alloc);
index 026cb59a914dbc5f52a2c7200ae85f843081441c..f293a97cb885115bcc52685b1015ca1029073158 100644 (file)
@@ -31,26 +31,40 @@ static inline void indy_sc_wipe(unsigned long first, unsigned long last)
        unsigned long tmp;
 
        __asm__ __volatile__(
-       ".set\tpush\t\t\t# indy_sc_wipe\n\t"
-       ".set\tnoreorder\n\t"
-       ".set\tmips3\n\t"
-       ".set\tnoat\n\t"
-       "mfc0\t%2, $12\n\t"
-       "li\t$1, 0x80\t\t\t# Go 64 bit\n\t"
-       "mtc0\t$1, $12\n\t"
-
-       "dli\t$1, 0x9000000080000000\n\t"
-       "or\t%0, $1\t\t\t# first line to flush\n\t"
-       "or\t%1, $1\t\t\t# last line to flush\n\t"
-       ".set\tat\n\t"
-
-       "1:\tsw\t$0, 0(%0)\n\t"
-       "bne\t%0, %1, 1b\n\t"
-       " daddu\t%0, 32\n\t"
-
-       "mtc0\t%2, $12\t\t\t# Back to 32 bit\n\t"
-       "nop; nop; nop; nop;\n\t"
-       ".set\tpop"
+       "       .set    push                    # indy_sc_wipe          \n"
+       "       .set    noreorder                                       \n"
+       "       .set    mips3                                           \n"
+       "       .set    noat                                            \n"
+       "       mfc0    %2, $12                                         \n"
+       "       li      $1, 0x80                # Go 64 bit             \n"
+       "       mtc0    $1, $12                                         \n"
+       "                                                               \n"
+       "       #                                                       \n"
+       "       # Open code a dli $1, 0x9000000080000000                \n"
+       "       #                                                       \n"
+       "       # Required because binutils 2.25 will happily accept    \n"
+       "       # 64 bit instructions in .set mips3 mode but puke on    \n"
+       "       # 64 bit constants when generating 32 bit ELF           \n"
+       "       #                                                       \n"
+       "       lui     $1,0x9000                                       \n"
+       "       dsll    $1,$1,0x10                                      \n"
+       "       ori     $1,$1,0x8000                                    \n"
+       "       dsll    $1,$1,0x10                                      \n"
+       "                                                               \n"
+       "       or      %0, $1                  # first line to flush   \n"
+       "       or      %1, $1                  # last line to flush    \n"
+       "       .set    at                                              \n"
+       "                                                               \n"
+       "1:     sw      $0, 0(%0)                                       \n"
+       "       bne     %0, %1, 1b                                      \n"
+       "        daddu  %0, 32                                          \n"
+       "                                                               \n"
+       "       mtc0    %2, $12                 # Back to 32 bit        \n"
+       "       nop                             # pipeline hazard       \n"
+       "       nop                                                     \n"
+       "       nop                                                     \n"
+       "       nop                                                     \n"
+       "       .set    pop                                             \n"
        : "=r" (first), "=r" (last), "=&r" (tmp)
        : "0" (first), "1" (last));
 }
index 286a4d5a18843c82be783dfde6b12798d191869e..c909c334272945c1c52d812462e78a74c2f1824b 100644 (file)
@@ -181,6 +181,7 @@ static int __init mips_sc_probe_cm3(void)
 
        if (c->scache.linesz) {
                c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT;
+               c->options |= MIPS_CPU_INCLUSIVE_CACHES;
                return 1;
        }
 
index 55ce39606cb8781d23e3c8f3b6df1273b2ee7a5a..9bfee8988eaf11a8618ca4f6ce101a8b70ad2823 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include <linux/bug.h>
+#include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/smp.h>
@@ -34,6 +35,7 @@
 #include <asm/war.h>
 #include <asm/uasm.h>
 #include <asm/setup.h>
+#include <asm/tlbex.h>
 
 static int mips_xpa_disabled;
 
@@ -344,7 +346,8 @@ static int allocate_kscratch(void)
 }
 
 static int scratch_reg;
-static int pgd_reg;
+int pgd_reg;
+EXPORT_SYMBOL_GPL(pgd_reg);
 enum vmalloc64_mode {not_refill, refill_scratch, refill_noscratch};
 
 static struct work_registers build_get_work_registers(u32 **p)
@@ -496,15 +499,9 @@ static void __maybe_unused build_tlb_probe_entry(u32 **p)
        }
 }
 
-/*
- * Write random or indexed TLB entry, and care about the hazards from
- * the preceding mtc0 and for the following eret.
- */
-enum tlb_write_entry { tlb_random, tlb_indexed };
-
-static void build_tlb_write_entry(u32 **p, struct uasm_label **l,
-                                 struct uasm_reloc **r,
-                                 enum tlb_write_entry wmode)
+void build_tlb_write_entry(u32 **p, struct uasm_label **l,
+                          struct uasm_reloc **r,
+                          enum tlb_write_entry wmode)
 {
        void(*tlbw)(u32 **) = NULL;
 
@@ -627,6 +624,7 @@ static void build_tlb_write_entry(u32 **p, struct uasm_label **l,
                break;
        }
 }
+EXPORT_SYMBOL_GPL(build_tlb_write_entry);
 
 static __maybe_unused void build_convert_pte_to_entrylo(u32 **p,
                                                        unsigned int reg)
@@ -781,9 +779,8 @@ static void build_huge_handler_tail(u32 **p, struct uasm_reloc **r,
  * TMP and PTR are scratch.
  * TMP will be clobbered, PTR will hold the pmd entry.
  */
-static void
-build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
-                unsigned int tmp, unsigned int ptr)
+void build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
+                     unsigned int tmp, unsigned int ptr)
 {
 #ifndef CONFIG_MIPS_PGD_C0_CONTEXT
        long pgdc = (long)pgd_current;
@@ -859,6 +856,7 @@ build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
        uasm_i_daddu(p, ptr, ptr, tmp); /* add in pmd offset */
 #endif
 }
+EXPORT_SYMBOL_GPL(build_get_pmde64);
 
 /*
  * BVADDR is the faulting address, PTR is scratch.
@@ -934,8 +932,7 @@ build_get_pgd_vmalloc64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
  * TMP and PTR are scratch.
  * TMP will be clobbered, PTR will hold the pgd entry.
  */
-static void __maybe_unused
-build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr)
+void build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr)
 {
        if (pgd_reg != -1) {
                /* pgd is in pgd_reg */
@@ -960,6 +957,7 @@ build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr)
        uasm_i_sll(p, tmp, tmp, PGD_T_LOG2);
        uasm_i_addu(p, ptr, ptr, tmp); /* add in pgd offset */
 }
+EXPORT_SYMBOL_GPL(build_get_pgde32);
 
 #endif /* !CONFIG_64BIT */
 
@@ -989,7 +987,7 @@ static void build_adjust_context(u32 **p, unsigned int ctx)
        uasm_i_andi(p, ctx, ctx, mask);
 }
 
-static void build_get_ptep(u32 **p, unsigned int tmp, unsigned int ptr)
+void build_get_ptep(u32 **p, unsigned int tmp, unsigned int ptr)
 {
        /*
         * Bug workaround for the Nevada. It seems as if under certain
@@ -1013,8 +1011,9 @@ static void build_get_ptep(u32 **p, unsigned int tmp, unsigned int ptr)
        build_adjust_context(p, tmp);
        UASM_i_ADDU(p, ptr, ptr, tmp); /* add in offset */
 }
+EXPORT_SYMBOL_GPL(build_get_ptep);
 
-static void build_update_entries(u32 **p, unsigned int tmp, unsigned int ptep)
+void build_update_entries(u32 **p, unsigned int tmp, unsigned int ptep)
 {
        int pte_off_even = 0;
        int pte_off_odd = sizeof(pte_t);
@@ -1063,6 +1062,7 @@ static void build_update_entries(u32 **p, unsigned int tmp, unsigned int ptep)
                UASM_i_MTC0(p, 0, C0_ENTRYLO1);
        UASM_i_MTC0(p, ptep, C0_ENTRYLO1); /* load it */
 }
+EXPORT_SYMBOL_GPL(build_update_entries);
 
 struct mips_huge_tlb_info {
        int huge_pte;
@@ -1536,7 +1536,9 @@ static void build_loongson3_tlb_refill_handler(void)
 extern u32 handle_tlbl[], handle_tlbl_end[];
 extern u32 handle_tlbs[], handle_tlbs_end[];
 extern u32 handle_tlbm[], handle_tlbm_end[];
-extern u32 tlbmiss_handler_setup_pgd_start[], tlbmiss_handler_setup_pgd[];
+extern u32 tlbmiss_handler_setup_pgd_start[];
+extern u32 tlbmiss_handler_setup_pgd[];
+EXPORT_SYMBOL_GPL(tlbmiss_handler_setup_pgd);
 extern u32 tlbmiss_handler_setup_pgd_end[];
 
 static void build_setup_pgd(void)
@@ -2041,7 +2043,7 @@ build_r4000_tlbchange_handler_tail(u32 **p, struct uasm_label **l,
 
 static void build_r4000_tlb_load_handler(void)
 {
-       u32 *p = handle_tlbl;
+       u32 *p = (u32 *)msk_isa16_mode((ulong)handle_tlbl);
        const int handle_tlbl_size = handle_tlbl_end - handle_tlbl;
        struct uasm_label *l = labels;
        struct uasm_reloc *r = relocs;
@@ -2224,7 +2226,7 @@ static void build_r4000_tlb_load_handler(void)
 
 static void build_r4000_tlb_store_handler(void)
 {
-       u32 *p = handle_tlbs;
+       u32 *p = (u32 *)msk_isa16_mode((ulong)handle_tlbs);
        const int handle_tlbs_size = handle_tlbs_end - handle_tlbs;
        struct uasm_label *l = labels;
        struct uasm_reloc *r = relocs;
@@ -2279,7 +2281,7 @@ static void build_r4000_tlb_store_handler(void)
 
 static void build_r4000_tlb_modify_handler(void)
 {
-       u32 *p = handle_tlbm;
+       u32 *p = (u32 *)msk_isa16_mode((ulong)handle_tlbm);
        const int handle_tlbm_size = handle_tlbm_end - handle_tlbm;
        struct uasm_label *l = labels;
        struct uasm_reloc *r = relocs;
index 516e1233d771cb3cd87cde8e73ef6f4d296e861b..11e9527c6e441034be9865523678e61d48cbf127 100644 (file)
@@ -23,7 +23,6 @@
  */
 #include <linux/init.h>
 #include <linux/serial_8250.h>
-#include <linux/module.h>
 #include <linux/irq.h>
 #include <linux/platform_device.h>
 #include <asm/mips-boards/maltaint.h>
index 3660dc67d544fbd44c4ff7188fbc0d000fcabf4e..f4961bc9a61d54baad92908ec1660ba534d471a0 100644 (file)
@@ -275,7 +275,7 @@ asmlinkage void plat_irq_dispatch(void)
        do_IRQ(nlm_irq_to_xirq(node, i));
 }
 
-#ifdef CONFIG_OF
+#ifdef CONFIG_CPU_XLP
 static const struct irq_domain_ops xlp_pic_irq_domain_ops = {
        .xlate = irq_domain_xlate_onetwocell,
 };
@@ -348,7 +348,7 @@ void __init arch_init_irq(void)
 #if defined(CONFIG_CPU_XLR)
        nlm_setup_fmn_irq();
 #endif
-#if defined(CONFIG_OF)
+#ifdef CONFIG_CPU_XLP
        of_irq_init(xlp_pic_irq_ids);
 #endif
 }
index f0cc4c9de2bbcdc655b861f189f16bebb9ea7d8b..509c1a7e7c05b1ac7284663031b4d16ed2aad0aa 100644 (file)
@@ -59,8 +59,8 @@ NESTED(xlp_boot_core0_siblings, PT_SIZE, sp)
        sync
        /* find the location to which nlm_boot_siblings was relocated */
        li      t0, CKSEG1ADDR(RESET_VEC_PHYS)
-       dla     t1, nlm_reset_entry
-       dla     t2, nlm_boot_siblings
+       PTR_LA  t1, nlm_reset_entry
+       PTR_LA  t2, nlm_boot_siblings
        dsubu   t2, t1
        daddu   t2, t0
        /* call it */
index 87d7846af2d00fee4c24da23a180d99a834634ea..d61004dd71b4164844d3574fc936874245ed283c 100644 (file)
@@ -197,7 +197,7 @@ static void xlp_enable_secondary_cores(const cpumask_t *wakeup_mask)
        }
 }
 
-void xlp_wakeup_secondary_cpus()
+void xlp_wakeup_secondary_cpus(void)
 {
        /*
         * In case of u-boot, the secondaries are in reset
index 45cb27469fbaa14db9824f9635287b0507498354..c57da6f13929a4e9a52ae6156dd9ddbf38909511 100644 (file)
 
 #include "op_impl.h"
 
-#define M_PERFCTL_EXL                  (1UL      <<  0)
-#define M_PERFCTL_KERNEL               (1UL      <<  1)
-#define M_PERFCTL_SUPERVISOR           (1UL      <<  2)
-#define M_PERFCTL_USER                 (1UL      <<  3)
-#define M_PERFCTL_INTERRUPT_ENABLE     (1UL      <<  4)
-#define M_PERFCTL_EVENT(event)         (((event) & 0x3ff)  << 5)
-#define M_PERFCTL_VPEID(vpe)           ((vpe)    << 16)
-#define M_PERFCTL_MT_EN(filter)                ((filter) << 20)
-#define           M_TC_EN_ALL                  M_PERFCTL_MT_EN(0)
-#define           M_TC_EN_VPE                  M_PERFCTL_MT_EN(1)
-#define           M_TC_EN_TC                   M_PERFCTL_MT_EN(2)
-#define M_PERFCTL_TCID(tcid)           ((tcid)   << 22)
-#define M_PERFCTL_WIDE                 (1UL      << 30)
-#define M_PERFCTL_MORE                 (1UL      << 31)
+#define M_PERFCTL_EVENT(event)         (((event) << MIPS_PERFCTRL_EVENT_S) & \
+                                        MIPS_PERFCTRL_EVENT)
+#define M_PERFCTL_VPEID(vpe)           ((vpe)    << MIPS_PERFCTRL_VPEID_S)
 
 #define M_COUNTER_OVERFLOW             (1UL      << 31)
 
-/* Netlogic XLR specific, count events in all threads in a core */
-#define M_PERFCTL_COUNT_ALL_THREADS    (1UL      << 13)
-
 static int (*save_perf_irq)(void);
 static int perfcount_irq;
 
@@ -51,7 +37,7 @@ static int perfcount_irq;
 
 #ifdef CONFIG_MIPS_MT_SMP
 static int cpu_has_mipsmt_pertccounters;
-#define WHAT           (M_TC_EN_VPE | \
+#define WHAT           (MIPS_PERFCTRL_MT_EN_VPE | \
                         M_PERFCTL_VPEID(cpu_data[smp_processor_id()].vpe_id))
 #define vpe_id()       (cpu_has_mipsmt_pertccounters ? \
                        0 : cpu_data[smp_processor_id()].vpe_id)
@@ -161,15 +147,15 @@ static void mipsxx_reg_setup(struct op_counter_config *ctr)
                        continue;
 
                reg.control[i] = M_PERFCTL_EVENT(ctr[i].event) |
-                                M_PERFCTL_INTERRUPT_ENABLE;
+                                MIPS_PERFCTRL_IE;
                if (ctr[i].kernel)
-                       reg.control[i] |= M_PERFCTL_KERNEL;
+                       reg.control[i] |= MIPS_PERFCTRL_K;
                if (ctr[i].user)
-                       reg.control[i] |= M_PERFCTL_USER;
+                       reg.control[i] |= MIPS_PERFCTRL_U;
                if (ctr[i].exl)
-                       reg.control[i] |= M_PERFCTL_EXL;
+                       reg.control[i] |= MIPS_PERFCTRL_EXL;
                if (boot_cpu_type() == CPU_XLR)
-                       reg.control[i] |= M_PERFCTL_COUNT_ALL_THREADS;
+                       reg.control[i] |= XLR_PERFCTRL_ALLTHREADS;
                reg.counter[i] = 0x80000000 - ctr[i].count;
        }
 }
@@ -254,7 +240,7 @@ static int mipsxx_perfcount_handler(void)
        case n + 1:                                                     \
                control = r_c0_perfctrl ## n();                         \
                counter = r_c0_perfcntr ## n();                         \
-               if ((control & M_PERFCTL_INTERRUPT_ENABLE) &&           \
+               if ((control & MIPS_PERFCTRL_IE) &&                     \
                    (counter & M_COUNTER_OVERFLOW)) {                   \
                        oprofile_add_sample(get_irq_regs(), n);         \
                        w_c0_perfcntr ## n(reg.counter[n]);             \
@@ -273,11 +259,11 @@ static inline int __n_counters(void)
 {
        if (!cpu_has_perf)
                return 0;
-       if (!(read_c0_perfctrl0() & M_PERFCTL_MORE))
+       if (!(read_c0_perfctrl0() & MIPS_PERFCTRL_M))
                return 1;
-       if (!(read_c0_perfctrl1() & M_PERFCTL_MORE))
+       if (!(read_c0_perfctrl1() & MIPS_PERFCTRL_M))
                return 2;
-       if (!(read_c0_perfctrl2() & M_PERFCTL_MORE))
+       if (!(read_c0_perfctrl2() & MIPS_PERFCTRL_M))
                return 3;
 
        return 4;
index a032ae0a533dce2d8afc1d7fe94936037679661e..9b3301d19a63f5b50af2ba1c1df3eeca8aecdf90 100644 (file)
@@ -21,9 +21,9 @@ int __init tx4927_report_pciclk(void)
 {
        int pciclk = 0;
 
-       printk(KERN_INFO "PCIC --%s PCICLK:",
-              (__raw_readq(&tx4927_ccfgptr->ccfg) & TX4927_CCFG_PCI66) ?
-              " PCI66" : "");
+       pr_info("PCIC --%s PCICLK:",
+               (__raw_readq(&tx4927_ccfgptr->ccfg) & TX4927_CCFG_PCI66) ?
+               " PCI66" : "");
        if (__raw_readq(&tx4927_ccfgptr->pcfg) & TX4927_PCFG_PCICLKEN_ALL) {
                u64 ccfg = __raw_readq(&tx4927_ccfgptr->ccfg);
                switch ((unsigned long)ccfg &
@@ -37,14 +37,14 @@ int __init tx4927_report_pciclk(void)
                case TX4927_CCFG_PCIDIVMODE_6:
                        pciclk = txx9_cpu_clock / 6; break;
                }
-               printk("Internal(%u.%uMHz)",
-                      (pciclk + 50000) / 1000000,
-                      ((pciclk + 50000) / 100000) % 10);
+               pr_cont("Internal(%u.%uMHz)",
+                       (pciclk + 50000) / 1000000,
+                       ((pciclk + 50000) / 100000) % 10);
        } else {
-               printk("External");
+               pr_cont("External");
                pciclk = -1;
        }
-       printk("\n");
+       pr_cont("\n");
        return pciclk;
 }
 
@@ -74,8 +74,8 @@ int __init tx4927_pciclk66_setup(void)
                }
                tx4927_ccfg_change(TX4927_CCFG_PCIDIVMODE_MASK,
                                   pcidivmode);
-               printk(KERN_DEBUG "PCICLK: ccfg:%08lx\n",
-                      (unsigned long)__raw_readq(&tx4927_ccfgptr->ccfg));
+               pr_debug("PCICLK: ccfg:%08lx\n",
+                        (unsigned long)__raw_readq(&tx4927_ccfgptr->ccfg));
        } else
                pciclk = -1;
        return pciclk;
@@ -87,5 +87,5 @@ void __init tx4927_setup_pcierr_irq(void)
                        tx4927_pcierr_interrupt,
                        0, "PCI error",
                        (void *)TX4927_PCIC_REG))
-               printk(KERN_WARNING "Failed to request irq for PCIERR\n");
+               pr_warn("Failed to request irq for PCIERR\n");
 }
index 141bba562488d1d37fef412804952c34dff45dd9..000c0e1f9ef869d884d8c9a0cbb286ba87bae97b 100644 (file)
@@ -21,9 +21,9 @@ int __init tx4938_report_pciclk(void)
 {
        int pciclk = 0;
 
-       printk(KERN_INFO "PCIC --%s PCICLK:",
-              (__raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_PCI66) ?
-              " PCI66" : "");
+       pr_info("PCIC --%s PCICLK:",
+               (__raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_PCI66) ?
+               " PCI66" : "");
        if (__raw_readq(&tx4938_ccfgptr->pcfg) & TX4938_PCFG_PCICLKEN_ALL) {
                u64 ccfg = __raw_readq(&tx4938_ccfgptr->ccfg);
                switch ((unsigned long)ccfg &
@@ -45,14 +45,14 @@ int __init tx4938_report_pciclk(void)
                case TX4938_CCFG_PCIDIVMODE_11:
                        pciclk = txx9_cpu_clock / 11; break;
                }
-               printk("Internal(%u.%uMHz)",
-                      (pciclk + 50000) / 1000000,
-                      ((pciclk + 50000) / 100000) % 10);
+               pr_cont("Internal(%u.%uMHz)",
+                       (pciclk + 50000) / 1000000,
+                       ((pciclk + 50000) / 100000) % 10);
        } else {
-               printk("External");
+               pr_cont("External");
                pciclk = -1;
        }
-       printk("\n");
+       pr_cont("\n");
        return pciclk;
 }
 
@@ -62,10 +62,10 @@ void __init tx4938_report_pci1clk(void)
        unsigned int pciclk =
                txx9_gbus_clock / ((ccfg & TX4938_CCFG_PCI1DMD) ? 4 : 2);
 
-       printk(KERN_INFO "PCIC1 -- %sPCICLK:%u.%uMHz\n",
-              (ccfg & TX4938_CCFG_PCI1_66) ? "PCI66 " : "",
-              (pciclk + 50000) / 1000000,
-              ((pciclk + 50000) / 100000) % 10);
+       pr_info("PCIC1 -- %sPCICLK:%u.%uMHz\n",
+               (ccfg & TX4938_CCFG_PCI1_66) ? "PCI66 " : "",
+               (pciclk + 50000) / 1000000,
+               ((pciclk + 50000) / 100000) % 10);
 }
 
 int __init tx4938_pciclk66_setup(void)
@@ -105,8 +105,8 @@ int __init tx4938_pciclk66_setup(void)
                }
                tx4938_ccfg_change(TX4938_CCFG_PCIDIVMODE_MASK,
                                   pcidivmode);
-               printk(KERN_DEBUG "PCICLK: ccfg:%08lx\n",
-                      (unsigned long)__raw_readq(&tx4938_ccfgptr->ccfg));
+               pr_debug("PCICLK: ccfg:%08lx\n",
+                        (unsigned long)__raw_readq(&tx4938_ccfgptr->ccfg));
        } else
                pciclk = -1;
        return pciclk;
@@ -138,5 +138,5 @@ void __init tx4938_setup_pcierr_irq(void)
                        tx4927_pcierr_interrupt,
                        0, "PCI error",
                        (void *)TX4927_PCIC_REG))
-               printk(KERN_WARNING "Failed to request irq for PCIERR\n");
+               pr_warn("Failed to request irq for PCIERR\n");
 }
index cd8ed09c4f5302ffad25822ad3f20a554c6a5dd1..9d6acc00f3489ddbf4558aa1d67568899e7eea9f 100644 (file)
@@ -28,14 +28,14 @@ int __init tx4939_report_pciclk(void)
                pciclk = txx9_master_clock * 20 / 6;
                if (!(__raw_readq(&tx4939_ccfgptr->ccfg) & TX4939_CCFG_PCI66))
                        pciclk /= 2;
-               printk(KERN_CONT "Internal(%u.%uMHz)",
-                      (pciclk + 50000) / 1000000,
-                      ((pciclk + 50000) / 100000) % 10);
+               pr_cont("Internal(%u.%uMHz)",
+                       (pciclk + 50000) / 1000000,
+                       ((pciclk + 50000) / 100000) % 10);
        } else {
-               printk(KERN_CONT "External");
+               pr_cont("External");
                pciclk = -1;
        }
-       printk(KERN_CONT "\n");
+       pr_cont("\n");
        return pciclk;
 }
 
index 4a4c2728c02738e1850aedd3c63a4a0b0b125da9..c28649615c6cb36e8c172663d1f4c56d84c29905 100644 (file)
@@ -2,8 +2,7 @@
 # Joshua Henderson, <joshua.henderson@microchip.com>
 # Copyright (C) 2015 Microchip Technology, Inc.  All rights reserved.
 #
-obj-y                  := init.o time.o config.o
+obj-y                  := config.o early_clk.o init.o time.o
 
 obj-$(CONFIG_EARLY_PRINTK)     += early_console.o      \
-                                  early_pin.o          \
-                                  early_clk.o
+                                  early_pin.o
index ef620a4c82a561da1ceaa18e61631b4832c3c1df..6fdcb3d6fbb596e02b14ef780e52707e3ed99b1d 100644 (file)
@@ -34,7 +34,7 @@
  *  675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/string.h>
index fea917be0ff10d1100f35a237b2ee1d1732b28cf..b4c020a80fd72dd3983dbfcb5bf4c44f5b65f7ac 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/kernel_stat.h>
 #include <linux/sched.h>
 #include <linux/spinlock.h>
-#include <linux/module.h>
 #include <linux/ptrace.h>
 
 #include <asm/cevt-r4k.h>
index 813826a456ca33d30ff84dfb9724a2796871fb4a..9825dee10bc1570c2f9993af83225510afb5e291 100644 (file)
@@ -46,6 +46,7 @@ choice
                select SYS_SUPPORTS_MULTITHREADING
                select SYS_SUPPORTS_SMP
                select SYS_SUPPORTS_MIPS_CPS
+               select SYS_SUPPORTS_HIGHMEM
                select MIPS_GIC
                select COMMON_CLK
                select CLKSRC_MIPS_GIC
index ebaa7cc0e9957b63905f04f5444f81d28f043aa4..df795885eace90301f8f4a9e85df7659f3c88fd6 100644 (file)
@@ -8,7 +8,8 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/export.h>
 #include <linux/clkdev.h>
 #include <linux/clk.h>
 
@@ -62,6 +63,12 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
 }
 EXPORT_SYMBOL_GPL(clk_set_rate);
 
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+       return -1;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
 void __init plat_time_init(void)
 {
        struct clk *clk;
index 4911c1445f1a44549ebfef7beb41a2006c085a85..9b478c95aaf5aab40a0417963eeb2897792f79b9 100644 (file)
@@ -163,8 +163,8 @@ static int __init intc_of_init(struct device_node *node,
        if (of_address_to_resource(node, 0, &res))
                panic("Failed to get intc memory range");
 
-       if (request_mem_region(res.start, resource_size(&res),
-                               res.name) < 0)
+       if (!request_mem_region(res.start, resource_size(&res),
+                               res.name))
                pr_err("Failed to request intc memory");
 
        rt_intc_membase = ioremap_nocache(res.start,
index 3c7c9bf57bf36cac56de4c7d9e8df527f0acac88..094a0ee4af46e913f2cb92f25a8503313dccc26c 100644 (file)
@@ -12,7 +12,6 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/module.h>
 
 #include <asm/mipsregs.h>
 #include <asm/mach-ralink/ralink_regs.h>
@@ -55,7 +54,10 @@ static int dram_type;
 static struct rt2880_pmx_func i2c_grp[] =  { FUNC("i2c", 0, 1, 2) };
 static struct rt2880_pmx_func spi_grp[] = { FUNC("spi", 0, 3, 4) };
 static struct rt2880_pmx_func uartlite_grp[] = { FUNC("uartlite", 0, 15, 2) };
-static struct rt2880_pmx_func mdio_grp[] = { FUNC("mdio", 0, 22, 2) };
+static struct rt2880_pmx_func mdio_grp[] = {
+       FUNC("mdio", MT7620_GPIO_MODE_MDIO, 22, 2),
+       FUNC("refclk", MT7620_GPIO_MODE_MDIO_REFCLK, 22, 2),
+};
 static struct rt2880_pmx_func rgmii1_grp[] = { FUNC("rgmii1", 0, 24, 12) };
 static struct rt2880_pmx_func refclk_grp[] = { FUNC("spi refclk", 0, 37, 3) };
 static struct rt2880_pmx_func ephy_grp[] = { FUNC("ephy", 0, 40, 5) };
@@ -92,7 +94,8 @@ static struct rt2880_pmx_group mt7620a_pinmux_data[] = {
        GRP("uartlite", uartlite_grp, 1, MT7620_GPIO_MODE_UART1),
        GRP_G("wdt", wdt_grp, MT7620_GPIO_MODE_WDT_MASK,
                MT7620_GPIO_MODE_WDT_GPIO, MT7620_GPIO_MODE_WDT_SHIFT),
-       GRP("mdio", mdio_grp, 1, MT7620_GPIO_MODE_MDIO),
+       GRP_G("mdio", mdio_grp, MT7620_GPIO_MODE_MDIO_MASK,
+               MT7620_GPIO_MODE_MDIO_GPIO, MT7620_GPIO_MODE_MDIO_SHIFT),
        GRP("rgmii1", rgmii1_grp, 1, MT7620_GPIO_MODE_RGMII1),
        GRP("spi refclk", refclk_grp, 1, MT7620_GPIO_MODE_SPI_REF_CLK),
        GRP_G("pcie", pcie_rst_grp, MT7620_GPIO_MODE_PCIE_MASK,
@@ -176,7 +179,7 @@ static struct rt2880_pmx_func spi_cs1_grp_mt7628[] = {
 
 static struct rt2880_pmx_func spis_grp_mt7628[] = {
        FUNC("pwm_uart2", 3, 14, 4),
-       FUNC("util", 2, 14, 4),
+       FUNC("utif", 2, 14, 4),
        FUNC("gpio", 1, 14, 4),
        FUNC("spis", 0, 14, 4),
 };
@@ -190,28 +193,28 @@ static struct rt2880_pmx_func gpio_grp_mt7628[] = {
 
 static struct rt2880_pmx_func p4led_kn_grp_mt7628[] = {
        FUNC("jtag", 3, 30, 1),
-       FUNC("util", 2, 30, 1),
+       FUNC("utif", 2, 30, 1),
        FUNC("gpio", 1, 30, 1),
        FUNC("p4led_kn", 0, 30, 1),
 };
 
 static struct rt2880_pmx_func p3led_kn_grp_mt7628[] = {
        FUNC("jtag", 3, 31, 1),
-       FUNC("util", 2, 31, 1),
+       FUNC("utif", 2, 31, 1),
        FUNC("gpio", 1, 31, 1),
        FUNC("p3led_kn", 0, 31, 1),
 };
 
 static struct rt2880_pmx_func p2led_kn_grp_mt7628[] = {
        FUNC("jtag", 3, 32, 1),
-       FUNC("util", 2, 32, 1),
+       FUNC("utif", 2, 32, 1),
        FUNC("gpio", 1, 32, 1),
        FUNC("p2led_kn", 0, 32, 1),
 };
 
 static struct rt2880_pmx_func p1led_kn_grp_mt7628[] = {
        FUNC("jtag", 3, 33, 1),
-       FUNC("util", 2, 33, 1),
+       FUNC("utif", 2, 33, 1),
        FUNC("gpio", 1, 33, 1),
        FUNC("p1led_kn", 0, 33, 1),
 };
@@ -232,28 +235,28 @@ static struct rt2880_pmx_func wled_kn_grp_mt7628[] = {
 
 static struct rt2880_pmx_func p4led_an_grp_mt7628[] = {
        FUNC("jtag", 3, 39, 1),
-       FUNC("util", 2, 39, 1),
+       FUNC("utif", 2, 39, 1),
        FUNC("gpio", 1, 39, 1),
        FUNC("p4led_an", 0, 39, 1),
 };
 
 static struct rt2880_pmx_func p3led_an_grp_mt7628[] = {
        FUNC("jtag", 3, 40, 1),
-       FUNC("util", 2, 40, 1),
+       FUNC("utif", 2, 40, 1),
        FUNC("gpio", 1, 40, 1),
        FUNC("p3led_an", 0, 40, 1),
 };
 
 static struct rt2880_pmx_func p2led_an_grp_mt7628[] = {
        FUNC("jtag", 3, 41, 1),
-       FUNC("util", 2, 41, 1),
+       FUNC("utif", 2, 41, 1),
        FUNC("gpio", 1, 41, 1),
        FUNC("p2led_an", 0, 41, 1),
 };
 
 static struct rt2880_pmx_func p1led_an_grp_mt7628[] = {
        FUNC("jtag", 3, 42, 1),
-       FUNC("util", 2, 42, 1),
+       FUNC("utif", 2, 42, 1),
        FUNC("gpio", 1, 42, 1),
        FUNC("p1led_an", 0, 42, 1),
 };
@@ -509,6 +512,7 @@ void __init ralink_clk_init(void)
        unsigned long sys_rate;
        unsigned long dram_rate;
        unsigned long periph_rate;
+       unsigned long pcmi2s_rate;
 
        xtal_rate = mt7620_get_xtal_rate();
 
@@ -523,6 +527,7 @@ void __init ralink_clk_init(void)
                        cpu_rate = MHZ(575);
                dram_rate = sys_rate = cpu_rate / 3;
                periph_rate = MHZ(40);
+               pcmi2s_rate = MHZ(480);
 
                ralink_clk_add("10000d00.uartlite", periph_rate);
                ralink_clk_add("10000e00.uartlite", periph_rate);
@@ -534,6 +539,7 @@ void __init ralink_clk_init(void)
                dram_rate = mt7620_get_dram_rate(pll_rate);
                sys_rate = mt7620_get_sys_rate(cpu_rate);
                periph_rate = mt7620_get_periph_rate(xtal_rate);
+               pcmi2s_rate = periph_rate;
 
                pr_debug(RFMT("XTAL") RFMT("CPU_PLL") RFMT("PLL"),
                         RINT(xtal_rate), RFRAC(xtal_rate),
@@ -555,6 +561,8 @@ void __init ralink_clk_init(void)
        ralink_clk_add("cpu", cpu_rate);
        ralink_clk_add("10000100.timer", periph_rate);
        ralink_clk_add("10000120.watchdog", periph_rate);
+       ralink_clk_add("10000900.i2c", periph_rate);
+       ralink_clk_add("10000a00.i2s", pcmi2s_rate);
        ralink_clk_add("10000b00.spi", sys_rate);
        ralink_clk_add("10000b40.spi", sys_rate);
        ralink_clk_add("10000c00.uartlite", periph_rate);
index a45bbbe97ac5f69ccd64d8a4a1939dcfc923195a..0695c2d64e49107141091f8614c2689c18e68663 100644 (file)
@@ -9,7 +9,6 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/module.h>
 
 #include <asm/mipsregs.h>
 #include <asm/smp-ops.h>
@@ -181,7 +180,7 @@ void prom_soc_init(struct ralink_soc_info *soc_info)
        } else {
                panic("mt7621: unknown SoC, n0:%08x n1:%08x\n", n0, n1);
        }
-
+       ralink_soc = MT762X_SOC_MT7621AT;
        rev = __raw_readl(sysc + SYSC_REG_CHIP_REV);
 
        snprintf(soc_info->sys_type, RAMIPS_SYS_TYPE_LEN,
index 0aa67a2d0ae6e015f4111793f73b66f6fecce936..1ada8492733b6018766d8a5c1e68cc633133b818 100644 (file)
@@ -40,9 +40,9 @@ __iomem void *plat_of_remap_node(const char *node)
        if (of_address_to_resource(np, 0, &res))
                panic("Failed to get resource for %s", node);
 
-       if ((request_mem_region(res.start,
+       if (!request_mem_region(res.start,
                                resource_size(&res),
-                               res.name) < 0))
+                               res.name))
                panic("Failed to request resources for %s", node);
 
        return ioremap_nocache(res.start, resource_size(&res));
@@ -66,13 +66,21 @@ static int __init early_init_dt_find_memory(unsigned long node,
 
 void __init plat_mem_setup(void)
 {
+       void *dtb = NULL;
+
        set_io_port_base(KSEG1);
 
        /*
         * Load the builtin devicetree. This causes the chosen node to be
-        * parsed resulting in our memory appearing
+        * parsed resulting in our memory appearing. fw_passed_dtb is used
+        * by CONFIG_MIPS_APPENDED_RAW_DTB as well.
         */
-       __dt_setup_arch(__dtb_start);
+       if (fw_passed_dtb)
+               dtb = (void *)fw_passed_dtb;
+       else if (__dtb_start != __dtb_end)
+               dtb = (void *)__dtb_start;
+
+       __dt_setup_arch(dtb);
 
        of_scan_flat_dt(early_init_dt_find_memory, NULL);
        if (memory_dtb)
index 5a73c5e142211d484cc0589cc3ca7f9030953301..23198c9050e5c9a042e23e59d006457f6c0b98b7 100644 (file)
@@ -30,8 +30,10 @@ const char *get_system_type(void)
        return soc_info.sys_type;
 }
 
-static __init void prom_init_cmdline(int argc, char **argv)
+static __init void prom_init_cmdline(void)
 {
+       int argc;
+       char **argv;
        int i;
 
        pr_debug("prom: fw_arg0=%08x fw_arg1=%08x fw_arg2=%08x fw_arg3=%08x\n",
@@ -60,14 +62,11 @@ static __init void prom_init_cmdline(int argc, char **argv)
 
 void __init prom_init(void)
 {
-       int argc;
-       char **argv;
-
        prom_soc_init(&soc_info);
 
        pr_info("SoC Type: %s\n", get_system_type());
 
-       prom_init_cmdline(argc, argv);
+       prom_init_cmdline();
 }
 
 void __init prom_free_prom_memory(void)
index 285796e6d75c2207f3fa45bb48d09622afaada6c..60e44cc8d2c922d21ab8aa8abac095aca207e340 100644 (file)
@@ -12,7 +12,6 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/module.h>
 
 #include <asm/mipsregs.h>
 #include <asm/mach-ralink/ralink_regs.h>
@@ -40,16 +39,6 @@ static struct rt2880_pmx_group rt2880_pinmux_data_act[] = {
        { 0 }
 };
 
-static void rt288x_wdt_reset(void)
-{
-       u32 t;
-
-       /* enable WDT reset output on pin SRAM_CS_N */
-       t = rt_sysc_r32(SYSC_REG_CLKCFG);
-       t |= CLKCFG_SRAM_CS_N_WDT;
-       rt_sysc_w32(t, SYSC_REG_CLKCFG);
-}
-
 void __init ralink_clk_init(void)
 {
        unsigned long cpu_rate, wmac_rate = 40000000;
@@ -75,6 +64,7 @@ void __init ralink_clk_init(void)
        ralink_clk_add("300100.timer", cpu_rate / 2);
        ralink_clk_add("300120.watchdog", cpu_rate / 2);
        ralink_clk_add("300500.uart", cpu_rate / 2);
+       ralink_clk_add("300900.i2c", cpu_rate / 2);
        ralink_clk_add("300c00.uartlite", cpu_rate / 2);
        ralink_clk_add("400000.ethernet", cpu_rate / 2);
        ralink_clk_add("480000.wmac", wmac_rate);
index c8a28c4bf29edc9640bddfba59533b14e904bc11..93d472c60ce467cfc4da3c8d72cef8a7fd9bc45d 100644 (file)
@@ -12,8 +12,9 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/module.h>
+#include <linux/bug.h>
 
+#include <asm/io.h>
 #include <asm/mipsregs.h>
 #include <asm/mach-ralink/ralink_regs.h>
 #include <asm/mach-ralink/rt305x.h>
@@ -89,17 +90,6 @@ static struct rt2880_pmx_group rt5350_pinmux_data[] = {
        { 0 }
 };
 
-static void rt305x_wdt_reset(void)
-{
-       u32 t;
-
-       /* enable WDT reset output on pin SRAM_CS_N */
-       t = rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG);
-       t |= RT305X_SYSCFG_SRAM_CS0_MODE_WDT <<
-               RT305X_SYSCFG_SRAM_CS0_MODE_SHIFT;
-       rt_sysc_w32(t, SYSC_REG_SYSTEM_CONFIG);
-}
-
 static unsigned long rt5350_get_mem_size(void)
 {
        void __iomem *sysc = (void __iomem *) KSEG1ADDR(RT305X_SYSC_BASE);
@@ -200,6 +190,8 @@ void __init ralink_clk_init(void)
 
        ralink_clk_add("cpu", cpu_rate);
        ralink_clk_add("sys", sys_rate);
+       ralink_clk_add("10000900.i2c", uart_rate);
+       ralink_clk_add("10000a00.i2s", uart_rate);
        ralink_clk_add("10000b00.spi", sys_rate);
        ralink_clk_add("10000b40.spi", sys_rate);
        ralink_clk_add("10000100.timer", wdt_rate);
index 4cef9162bd9b8164ca7fab6c4a2f37a5fc48ebee..c4ffd43d3996ac26af1afa42c9c8a876f7fc564c 100644 (file)
@@ -12,7 +12,6 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/module.h>
 
 #include <asm/mipsregs.h>
 #include <asm/mach-ralink/ralink_regs.h>
@@ -63,16 +62,6 @@ static struct rt2880_pmx_group rt3883_pinmux_data[] = {
        { 0 }
 };
 
-static void rt3883_wdt_reset(void)
-{
-       u32 t;
-
-       /* enable WDT reset output on GPIO 2 */
-       t = rt_sysc_r32(RT3883_SYSC_REG_SYSCFG1);
-       t |= RT3883_SYSCFG1_GPIO2_AS_WDT_OUT;
-       rt_sysc_w32(t, RT3883_SYSC_REG_SYSCFG1);
-}
-
 void __init ralink_clk_init(void)
 {
        unsigned long cpu_rate, sys_rate;
@@ -108,6 +97,8 @@ void __init ralink_clk_init(void)
        ralink_clk_add("10000100.timer", sys_rate);
        ralink_clk_add("10000120.watchdog", sys_rate);
        ralink_clk_add("10000500.uart", 40000000);
+       ralink_clk_add("10000900.i2c", 40000000);
+       ralink_clk_add("10000a00.i2s", 40000000);
        ralink_clk_add("10000b00.spi", sys_rate);
        ralink_clk_add("10000b40.spi", sys_rate);
        ralink_clk_add("10000c00.uartlite", 40000000);
@@ -155,5 +146,5 @@ void prom_soc_init(struct ralink_soc_info *soc_info)
 
        rt2880_pinmux_data = rt3883_pinmux_data;
 
-       ralink_soc == RT3883_SOC;
+       ralink_soc = RT3883_SOC;
 }
index 8077ff39bdeabb602680342f0d8e436b5f9bf4cc..d4469b20d176abb675e168d39e7b02bd511533ea 100644 (file)
@@ -71,11 +71,6 @@ static int rt_timer_request(struct rt_timer *rt)
        return err;
 }
 
-static void rt_timer_free(struct rt_timer *rt)
-{
-       free_irq(rt->irq, rt);
-}
-
 static int rt_timer_config(struct rt_timer *rt, unsigned long divisor)
 {
        if (rt->timer_freq < divisor)
@@ -101,15 +96,6 @@ static int rt_timer_enable(struct rt_timer *rt)
        return 0;
 }
 
-static void rt_timer_disable(struct rt_timer *rt)
-{
-       u32 t;
-
-       t = rt_timer_r32(rt, TIMER_REG_TMR0CTL);
-       t &= ~TMR0CTL_ENABLE;
-       rt_timer_w32(rt, TIMER_REG_TMR0CTL, t);
-}
-
 static int rt_timer_probe(struct platform_device *pdev)
 {
        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
index 3a431e802bbc903a57215dfee953a0ae1febfc84..25cc250f2d3488b5a84d21ef4489b718ee9a4e3b 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/kernel_stat.h>
-#include <linux/module.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/types.h>
index 657210e767c29c4329ed67350b68136d27b7611f..6484e4a4597bdf3ac570b475ef3bb8e5b8d57ecc 100644 (file)
@@ -26,7 +26,7 @@
 
 #include <linux/init.h>
 #include <linux/mm.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/string.h>
 #include <linux/console.h>
 #include <linux/bootmem.h>
index b7a4b7e04c387a155242e786e5978382aab9afaa..e8f6b3a42a4833a9c2c5cd1cb0c9c462cba37ed2 100644 (file)
@@ -25,7 +25,7 @@ endif
 # Simplified: what IP22 does at 128MB+ in ksegN, IP28 does at 512MB+ in xkphys
 #
 ifdef CONFIG_SGI_IP28
-  ifeq ($(call cc-option-yn,-mr10k-cache-barrier=store), n)
+  ifeq ($(call cc-option-yn,-march=r10000 -mr10k-cache-barrier=store), n)
       $(error gcc doesn't support needed option -mr10k-cache-barrier=store)
   endif
 endif
index bb70589b5f74ce8c4407fa62c7bc2804f558b707..396956e07307d4c41eedb5f234fc265d46691f38 100644 (file)
@@ -5,8 +5,8 @@
  * Copyright (C) 1998 Ralf Baechle
  */
 
+#include <linux/export.h>
 #include <linux/init.h>
-#include <linux/module.h>
 #include <linux/types.h>
 
 #include <asm/io.h>
index 6b009c45abed4e062c86aecf330ca9c4114d3722..db5a64026443447aab7cffb45dd72d7748a2bf8d 100644 (file)
@@ -8,8 +8,9 @@
  */
 
 #include <linux/init.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/kernel.h>
+#include <linux/spinlock.h>
 
 #include <asm/io.h>
 #include <asm/bootinfo.h>
index e077036a676a506f1fb52cf3678eed2776be94ae..cc6133bb57caa257946a4d12f5911e15f24fe365 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2003 Ladislav Michl (ladis@linux-mips.org)
  */
-#include <linux/module.h>
+#include <linux/export.h>
 
 #include <asm/sgi/hpc3.h>
 #include <asm/sgi/ip22.h>
index 2f45b035702148c03db45de8004e63e4a783483e..a36f6b87548a5a7be7d95173eea1f276060ddd24 100644 (file)
@@ -8,7 +8,6 @@
 #include <linux/linkage.h>
 #include <linux/init.h>
 #include <linux/rtc/ds1286.h>
-#include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
index c7bdfe43df5b312da20dc5b886748caa68d09605..872159970935279315e208535b780bd9b2cd0824 100644 (file)
@@ -8,7 +8,6 @@
 #include <linux/kernel.h>
 #include <linux/kdev_t.h>
 #include <linux/types.h>
-#include <linux/module.h>
 #include <linux/console.h>
 #include <linux/sched.h>
 #include <linux/tty.h>
index 2e0edb385656986f3256e26f21f898c1761fd5a7..f8919b6a24c884f02bf015fda3c87dd6df857607 100644 (file)
@@ -9,11 +9,9 @@
  */
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/signal.h>      /* for SIGBUS */
 #include <linux/sched.h>       /* schow_regs(), force_sig() */
 
-#include <asm/module.h>
 #include <asm/sn/addrs.h>
 #include <asm/sn/arch.h>
 #include <asm/sn/sn0/hub.h>
index 570098bfdf870e7c0af2dacf030bc8f587b361eb..e501c43c02dbb0dbc77215ffec68b904932022c0 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/sched.h>
 #include <linux/smp.h>
 #include <linux/mm.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/cpumask.h>
 #include <asm/cpu.h>
 #include <asm/io.h>
index bda90cf87e8cba2617f6bda905513e45fa058081..2beb03907d0991f970e0aba84f5ff121b36548ef 100644 (file)
@@ -82,7 +82,7 @@ static __init void copy_kernel(nasid_t dest_nasid)
        memcpy((void *)dest_kern_start, (void *)source_start, kern_size);
 }
 
-void __init replicate_kernel_text()
+void __init replicate_kernel_text(void)
 {
        cnodeid_t cnode;
        nasid_t client_nasid;
index f1f88291451ec59adb4a5f28f9d19ea336669932..59133d0abc83626cfb1203ceca417ef1f4215a58 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/memblock.h>
 #include <linux/mm.h>
 #include <linux/mmzone.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/nodemask.h>
 #include <linux/swap.h>
 #include <linux/bootmem.h>
index 563c614ad021f37737fd82c77d98141655b79225..a8e0c776ca6c628faa0b0ef4828de3fb4e9f51a2 100644 (file)
@@ -10,7 +10,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <asm/bootinfo.h>
 #include <asm/io.h>
 #include <asm/mipsregs.h>
index e0c7d9e142fa8c3c8b68f86c5990eae2d07506b5..838d8589a1c0925136749a218f93eaf515925be8 100644 (file)
 #include <asm/ip32/ip32_ints.h>
 
 /* issue a PIO read to make sure no PIO writes are pending */
-static void inline flush_crime_bus(void)
+static inline void flush_crime_bus(void)
 {
        crime->control;
 }
 
-static void inline flush_mace_bus(void)
+static inline void flush_mace_bus(void)
 {
        mace->perif.ctrl.misc;
 }
index 8e2e04f7787068bdd2d3421d14b33ef3cc283867..a05246cbf54cfe852ff288202b9cbec972e4ebbc 100644 (file)
@@ -17,7 +17,7 @@
  */
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/reboot.h>
 #include <linux/string.h>
 
index 9d3c24efdf4a338aeb83fe16566ae5045e506e33..90e43782342b6e0691fd7369186e83e758b68f6f 100644 (file)
@@ -15,8 +15,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
+#include <linux/export.h>
 #include <linux/init.h>
-#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/reboot.h>
 #include <linux/string.h>
index 566c58bd44d073e32dfff5b01eb457faededab99..2203c2548cb47d21c1456f8d37f2982a5d86925b 100644 (file)
@@ -55,8 +55,8 @@ static ssize_t raw_store(struct device *dev,
        return size;
 }
 
-static DEVICE_ATTR(ascii, 0200, NULL, ascii_store);
-static DEVICE_ATTR(raw, 0200, NULL, raw_store);
+static DEVICE_ATTR_WO(ascii);
+static DEVICE_ATTR_WO(raw);
 
 static ssize_t map_seg7_show(struct device *dev,
                             struct device_attribute *attr,
index 285d84e5c7b92cf52785a6aa21393c67a6301c68..0bd2a1e1ff9ab8e0f0d8c56e31872ac08404c7b6 100644 (file)
@@ -55,7 +55,7 @@ int __init txx9_pci66_check(struct pci_controller *hose, int top_bus,
        /* It seems SLC90E66 needs some time after PCI reset... */
        mdelay(80);
 
-       printk(KERN_INFO "PCI: Checking 66MHz capabilities...\n");
+       pr_info("PCI: Checking 66MHz capabilities...\n");
 
        for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) {
                if (PCI_FUNC(pci_devfn))
@@ -74,9 +74,8 @@ int __init txx9_pci66_check(struct pci_controller *hose, int top_bus,
                        early_read_config_word(hose, top_bus, current_bus,
                                               pci_devfn, PCI_STATUS, &stat);
                        if (!(stat & PCI_STATUS_66MHZ)) {
-                               printk(KERN_DEBUG
-                                      "PCI: %02x:%02x not 66MHz capable.\n",
-                                      current_bus, pci_devfn);
+                               pr_debug("PCI: %02x:%02x not 66MHz capable.\n",
+                                        current_bus, pci_devfn);
                                cap66 = 0;
                                break;
                        }
@@ -209,8 +208,8 @@ txx9_alloc_pci_controller(struct pci_controller *pcic,
 
        pcic->mem_offset = 0;   /* busaddr == physaddr */
 
-       printk(KERN_INFO "PCI: IO %pR MEM %pR\n",
-              &pcic->mem_resource[1], &pcic->mem_resource[0]);
+       pr_info("PCI: IO %pR MEM %pR\n", &pcic->mem_resource[1],
+               &pcic->mem_resource[0]);
 
        /* register_pci_controller() will request MEM resource */
        release_resource(&pcic->mem_resource[0]);
@@ -219,7 +218,7 @@ txx9_alloc_pci_controller(struct pci_controller *pcic,
        release_resource(&pcic->mem_resource[0]);
  free_and_exit:
        kfree(new);
-       printk(KERN_ERR "PCI: Failed to allocate resources.\n");
+       pr_err("PCI: Failed to allocate resources.\n");
        return NULL;
 }
 
@@ -260,7 +259,7 @@ static int txx9_i8259_irq_setup(int irq)
        err = request_irq(irq, &i8259_interrupt, IRQF_SHARED,
                          "cascade(i8259)", (void *)(long)irq);
        if (!err)
-               printk(KERN_INFO "PCI-ISA bridge PIC (irq %d)\n", irq);
+               pr_info("PCI-ISA bridge PIC (irq %d)\n", irq);
        return err;
 }
 
@@ -308,13 +307,13 @@ static void quirk_slc90e66_ide(struct pci_dev *dev)
        /* SMSC SLC90E66 IDE uses irq 14, 15 (default) */
        pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 14);
        pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &dat);
-       printk(KERN_INFO "PCI: %s: IRQ %02x", pci_name(dev), dat);
+       pr_info("PCI: %s: IRQ %02x", pci_name(dev), dat);
        /* enable SMSC SLC90E66 IDE */
        for (i = 0; i < ARRAY_SIZE(regs); i++) {
                pci_read_config_byte(dev, regs[i], &dat);
                pci_write_config_byte(dev, regs[i], dat | 0x80);
                pci_read_config_byte(dev, regs[i], &dat);
-               printk(KERN_CONT " IDETIM%d %02x", i, dat);
+               pr_cont(" IDETIM%d %02x", i, dat);
        }
        pci_read_config_byte(dev, 0x5c, &dat);
        /*
@@ -329,8 +328,7 @@ static void quirk_slc90e66_ide(struct pci_dev *dev)
        dat |= 0x01;
        pci_write_config_byte(dev, 0x5c, dat);
        pci_read_config_byte(dev, 0x5c, &dat);
-       printk(KERN_CONT " REG5C %02x", dat);
-       printk(KERN_CONT "\n");
+       pr_cont(" REG5C %02x\n", dat);
 }
 #endif /* CONFIG_TOSHIBA_FPCIB0 */
 
@@ -352,7 +350,7 @@ static void final_fixup(struct pci_dev *dev)
            (bist & PCI_BIST_CAPABLE)) {
                unsigned long timeout;
                pci_set_power_state(dev, PCI_D0);
-               printk(KERN_INFO "PCI: %s BIST...", pci_name(dev));
+               pr_info("PCI: %s BIST...", pci_name(dev));
                pci_write_config_byte(dev, PCI_BIST, PCI_BIST_START);
                timeout = jiffies + HZ * 2;     /* timeout after 2 sec */
                do {
@@ -361,9 +359,9 @@ static void final_fixup(struct pci_dev *dev)
                                break;
                } while (bist & PCI_BIST_START);
                if (bist & (PCI_BIST_CODE_MASK | PCI_BIST_START))
-                       printk(KERN_CONT "failed. (0x%x)\n", bist);
+                       pr_cont("failed. (0x%x)\n", bist);
                else
-                       printk(KERN_CONT "OK.\n");
+                       pr_cont("OK.\n");
        }
 }
 
index a1d98b5c8fd6757683d1e9c23196660676006a54..1791a44ee570a05987d95015cad5854c88ef641b 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/types.h>
 #include <linux/interrupt.h>
 #include <linux/string.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/clk-provider.h>
 #include <linux/clkdev.h>
 #include <linux/err.h>
index d3b83a92cf26c7075939bd23ae0aeb2e083921d2..33f7a7253963ad38f484755766ddaa2ebc089d52 100644 (file)
@@ -67,9 +67,9 @@ void __init tx3927_setup(void)
        /* do reset on watchdog */
        tx3927_ccfgptr->ccfg |= TX3927_CCFG_WR;
 
-       printk(KERN_INFO "TX3927 -- CRIR:%08lx CCFG:%08lx PCFG:%08lx\n",
-              tx3927_ccfgptr->crir,
-              tx3927_ccfgptr->ccfg, tx3927_ccfgptr->pcfg);
+       pr_info("TX3927 -- CRIR:%08lx CCFG:%08lx PCFG:%08lx\n",
+               tx3927_ccfgptr->crir, tx3927_ccfgptr->ccfg,
+               tx3927_ccfgptr->pcfg);
 
        /* TMR */
        for (i = 0; i < TX3927_NR_TMR; i++)
index 8d8011570b1dbe990567a848d52bf513729e18c6..46e9c41013862c960c84e5d26266855c444adb01 100644 (file)
@@ -183,15 +183,14 @@ void __init tx4927_setup(void)
        if (!(____raw_readq(&tx4927_ccfgptr->ccfg) & TX4927_CCFG_PCIARB))
                txx9_clear64(&tx4927_ccfgptr->pcfg, TX4927_PCFG_PCICLKEN_ALL);
 
-       printk(KERN_INFO "%s -- %dMHz(M%dMHz) CRIR:%08x CCFG:%llx PCFG:%llx\n",
-              txx9_pcode_str,
-              (cpuclk + 500000) / 1000000,
-              (txx9_master_clock + 500000) / 1000000,
-              (__u32)____raw_readq(&tx4927_ccfgptr->crir),
-              (unsigned long long)____raw_readq(&tx4927_ccfgptr->ccfg),
-              (unsigned long long)____raw_readq(&tx4927_ccfgptr->pcfg));
+       pr_info("%s -- %dMHz(M%dMHz) CRIR:%08x CCFG:%llx PCFG:%llx\n",
+               txx9_pcode_str, (cpuclk + 500000) / 1000000,
+               (txx9_master_clock + 500000) / 1000000,
+               (__u32)____raw_readq(&tx4927_ccfgptr->crir),
+               ____raw_readq(&tx4927_ccfgptr->ccfg),
+               ____raw_readq(&tx4927_ccfgptr->pcfg));
 
-       printk(KERN_INFO "%s SDRAMC --", txx9_pcode_str);
+       pr_info("%s SDRAMC --", txx9_pcode_str);
        for (i = 0; i < 4; i++) {
                __u64 cr = TX4927_SDRAMC_CR(i);
                unsigned long base, size;
@@ -199,15 +198,14 @@ void __init tx4927_setup(void)
                        continue;       /* disabled */
                base = (unsigned long)(cr >> 49) << 21;
                size = (((unsigned long)(cr >> 33) & 0x7fff) + 1) << 21;
-               printk(" CR%d:%016llx", i, (unsigned long long)cr);
+               pr_cont(" CR%d:%016llx", i, cr);
                tx4927_sdram_resource[i].name = "SDRAM";
                tx4927_sdram_resource[i].start = base;
                tx4927_sdram_resource[i].end = base + size - 1;
                tx4927_sdram_resource[i].flags = IORESOURCE_MEM;
                request_resource(&iomem_resource, &tx4927_sdram_resource[i]);
        }
-       printk(" TR:%09llx\n",
-              (unsigned long long)____raw_readq(&tx4927_sdramcptr->tr));
+       pr_cont(" TR:%09llx\n", ____raw_readq(&tx4927_sdramcptr->tr));
 
        /* TMR */
        /* disable all timers */
index ba265bf1fd06703645cb4a353c3100013741a324..85d1795652da6d09a4fae6d4fcae08c813e83488 100644 (file)
@@ -196,15 +196,14 @@ void __init tx4938_setup(void)
        if (!(____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_PCIARB))
                txx9_clear64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_PCICLKEN_ALL);
 
-       printk(KERN_INFO "%s -- %dMHz(M%dMHz) CRIR:%08x CCFG:%llx PCFG:%llx\n",
-              txx9_pcode_str,
-              (cpuclk + 500000) / 1000000,
-              (txx9_master_clock + 500000) / 1000000,
-              (__u32)____raw_readq(&tx4938_ccfgptr->crir),
-              (unsigned long long)____raw_readq(&tx4938_ccfgptr->ccfg),
-              (unsigned long long)____raw_readq(&tx4938_ccfgptr->pcfg));
-
-       printk(KERN_INFO "%s SDRAMC --", txx9_pcode_str);
+       pr_info("%s -- %dMHz(M%dMHz) CRIR:%08x CCFG:%llx PCFG:%llx\n",
+               txx9_pcode_str, (cpuclk + 500000) / 1000000,
+               (txx9_master_clock + 500000) / 1000000,
+               (__u32)____raw_readq(&tx4938_ccfgptr->crir),
+               ____raw_readq(&tx4938_ccfgptr->ccfg),
+               ____raw_readq(&tx4938_ccfgptr->pcfg));
+
+       pr_info("%s SDRAMC --", txx9_pcode_str);
        for (i = 0; i < 4; i++) {
                __u64 cr = TX4938_SDRAMC_CR(i);
                unsigned long base, size;
@@ -212,15 +211,14 @@ void __init tx4938_setup(void)
                        continue;       /* disabled */
                base = (unsigned long)(cr >> 49) << 21;
                size = (((unsigned long)(cr >> 33) & 0x7fff) + 1) << 21;
-               printk(" CR%d:%016llx", i, (unsigned long long)cr);
+               pr_cont(" CR%d:%016llx", i, cr);
                tx4938_sdram_resource[i].name = "SDRAM";
                tx4938_sdram_resource[i].start = base;
                tx4938_sdram_resource[i].end = base + size - 1;
                tx4938_sdram_resource[i].flags = IORESOURCE_MEM;
                request_resource(&iomem_resource, &tx4938_sdram_resource[i]);
        }
-       printk(" TR:%09llx\n",
-              (unsigned long long)____raw_readq(&tx4938_sdramcptr->tr));
+       pr_cont(" TR:%09llx\n", ____raw_readq(&tx4938_sdramcptr->tr));
 
        /* SRAM */
        if (txx9_pcode == 0x4938 && ____raw_readq(&tx4938_sramcptr->cr) & 1) {
@@ -254,20 +252,20 @@ void __init tx4938_setup(void)
                        txx9_clear64(&tx4938_ccfgptr->clkctr,
                                     TX4938_CLKCTR_PCIC1RST);
                } else {
-                       printk(KERN_INFO "%s: stop PCIC1\n", txx9_pcode_str);
+                       pr_info("%s: stop PCIC1\n", txx9_pcode_str);
                        /* stop PCIC1 */
                        txx9_set64(&tx4938_ccfgptr->clkctr,
                                   TX4938_CLKCTR_PCIC1CKD);
                }
                if (!(pcfg & TX4938_PCFG_ETH0_SEL)) {
-                       printk(KERN_INFO "%s: stop ETH0\n", txx9_pcode_str);
+                       pr_info("%s: stop ETH0\n", txx9_pcode_str);
                        txx9_set64(&tx4938_ccfgptr->clkctr,
                                   TX4938_CLKCTR_ETH0RST);
                        txx9_set64(&tx4938_ccfgptr->clkctr,
                                   TX4938_CLKCTR_ETH0CKD);
                }
                if (!(pcfg & TX4938_PCFG_ETH1_SEL)) {
-                       printk(KERN_INFO "%s: stop ETH1\n", txx9_pcode_str);
+                       pr_info("%s: stop ETH1\n", txx9_pcode_str);
                        txx9_set64(&tx4938_ccfgptr->clkctr,
                                   TX4938_CLKCTR_ETH1RST);
                        txx9_set64(&tx4938_ccfgptr->clkctr,
index 402ac2ec7e83490358f2a945247630e401acd41b..274928987a21a686e1e76a0d8d9f54fa624607e8 100644 (file)
@@ -221,8 +221,8 @@ void __init tx4939_setup(void)
                (txx9_master_clock + 500000) / 1000000,
                (txx9_gbus_clock + 500000) / 1000000,
                (__u32)____raw_readq(&tx4939_ccfgptr->crir),
-               (unsigned long long)____raw_readq(&tx4939_ccfgptr->ccfg),
-               (unsigned long long)____raw_readq(&tx4939_ccfgptr->pcfg));
+               ____raw_readq(&tx4939_ccfgptr->ccfg),
+               ____raw_readq(&tx4939_ccfgptr->pcfg));
 
        pr_info("%s DDRC -- EN:%08x", txx9_pcode_str,
                (__u32)____raw_readq(&tx4939_ddrcptr->winen));
@@ -230,7 +230,7 @@ void __init tx4939_setup(void)
                __u64 win = ____raw_readq(&tx4939_ddrcptr->win[i]);
                if (!((__u32)____raw_readq(&tx4939_ddrcptr->winen) & (1 << i)))
                        continue;       /* disabled */
-               printk(KERN_CONT " #%d:%016llx", i, (unsigned long long)win);
+               pr_cont(" #%d:%016llx", i, win);
                tx4939_sdram_resource[i].name = "DDR SDRAM";
                tx4939_sdram_resource[i].start =
                        (unsigned long)(win >> 48) << 20;
@@ -240,7 +240,7 @@ void __init tx4939_setup(void)
                tx4939_sdram_resource[i].flags = IORESOURCE_MEM;
                request_resource(&iomem_resource, &tx4939_sdram_resource[i]);
        }
-       printk(KERN_CONT "\n");
+       pr_cont("\n");
 
        /* SRAM */
        if (____raw_readq(&tx4939_sramcptr->cr) & 1) {
index f98baa6263d244253d69916644dda4051df10a1b..40f4098d3ae1886651b557a69a52655008f60ff2 100644 (file)
@@ -105,9 +105,8 @@ unsigned long __init smsc_fdc37m81x_init(unsigned long port)
        u8 chip_id;
 
        if (g_smsc_fdc37m81x_base)
-               printk(KERN_WARNING "%s: stepping on old base=0x%0*lx\n",
-                      __func__,
-                      field, g_smsc_fdc37m81x_base);
+               pr_warn("%s: stepping on old base=0x%0*lx\n", __func__, field,
+                       g_smsc_fdc37m81x_base);
 
        g_smsc_fdc37m81x_base = port;
 
@@ -117,8 +116,7 @@ unsigned long __init smsc_fdc37m81x_init(unsigned long port)
        if (chip_id == SMSC_FDC37M81X_CHIP_ID)
                smsc_fdc37m81x_config_end();
        else {
-               printk(KERN_WARNING "%s: unknown chip id 0x%02x\n", __func__,
-                      chip_id);
+               pr_warn("%s: unknown chip id 0x%02x\n", __func__, chip_id);
                g_smsc_fdc37m81x_base = 0;
        }
 
@@ -128,9 +126,8 @@ unsigned long __init smsc_fdc37m81x_init(unsigned long port)
 #ifdef DEBUG
 static void smsc_fdc37m81x_config_dump_one(const char *key, u8 dev, u8 reg)
 {
-       printk(KERN_INFO "%s: dev=0x%02x reg=0x%02x val=0x%02x\n",
-              key, dev, reg,
-              smsc_fdc37m81x_rd(reg));
+       pr_info("%s: dev=0x%02x reg=0x%02x val=0x%02x\n", key, dev, reg,
+               smsc_fdc37m81x_rd(reg));
 }
 
 void smsc_fdc37m81x_config_dump(void)
@@ -142,7 +139,7 @@ void smsc_fdc37m81x_config_dump(void)
 
        orig = smsc_fdc37m81x_rd(SMSC_FDC37M81X_DNUM);
 
-       printk(KERN_INFO "%s: common\n", fname);
+       pr_info("%s: common\n", fname);
        smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_NONE,
                                       SMSC_FDC37M81X_DNUM);
        smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_NONE,
@@ -154,7 +151,7 @@ void smsc_fdc37m81x_config_dump(void)
        smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_NONE,
                                       SMSC_FDC37M81X_PMGT);
 
-       printk(KERN_INFO "%s: keyboard\n", fname);
+       pr_info("%s: keyboard\n", fname);
        smsc_dc37m81x_wr(SMSC_FDC37M81X_DNUM, SMSC_FDC37M81X_KBD);
        smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_KBD,
                                       SMSC_FDC37M81X_ACTIVE);
index c899c0c087a0fa846387061c532f2441adaca599..68a96473c134904fccd8bdeb415724cf923e22ea 100644 (file)
@@ -45,7 +45,7 @@ void __init jmr3927_prom_init(void)
 {
        /* CCFG */
        if ((tx3927_ccfgptr->ccfg & TX3927_CCFG_TLBOFF) == 0)
-               printk(KERN_ERR "TX3927 TLB off\n");
+               pr_err("TX3927 TLB off\n");
 
        add_memory_region(0, JMR3927_SDRAM_SIZE, BOOT_MEM_RAM);
        txx9_sio_putchar_init(TX3927_SIO_REG(1));
index a455166dc6d44fe7418f0b66823e49ce188e690b..613943886e34c5b283c2a7db75303854f197f2e4 100644 (file)
@@ -150,12 +150,11 @@ static void __init jmr3927_board_init(void)
 
        jmr3927_led_set(0);
 
-       printk(KERN_INFO
-              "JMR-TX3927 (Rev %d) --- IOC(Rev %d) DIPSW:%d,%d,%d,%d\n",
-              jmr3927_ioc_reg_in(JMR3927_IOC_BREV_ADDR) & JMR3927_REV_MASK,
-              jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR) & JMR3927_REV_MASK,
-              jmr3927_dipsw1(), jmr3927_dipsw2(),
-              jmr3927_dipsw3(), jmr3927_dipsw4());
+       pr_info("JMR-TX3927 (Rev %d) --- IOC(Rev %d) DIPSW:%d,%d,%d,%d\n",
+               jmr3927_ioc_reg_in(JMR3927_IOC_BREV_ADDR) & JMR3927_REV_MASK,
+               jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR) & JMR3927_REV_MASK,
+               jmr3927_dipsw1(), jmr3927_dipsw2(),
+               jmr3927_dipsw3(), jmr3927_dipsw4());
 }
 
 /* This trick makes rtc-ds1742 driver usable as is. */
index 07939ed6b22fdac50316fbbfe702b8909effc6a0..e68eb2e7ce0cf580cc6a51b6875c0b051a16188b 100644 (file)
@@ -123,15 +123,15 @@ static int __init rbtx4938_ethaddr_init(void)
 
        /* 0-3: "MAC\0", 4-9:eth0, 10-15:eth1, 16:sum */
        if (spi_eeprom_read(SPI_BUSNO, SEEPROM1_CS, 0, dat, sizeof(dat))) {
-               printk(KERN_ERR "seeprom: read error.\n");
+               pr_err("seeprom: read error.\n");
                return -ENODEV;
        } else {
                if (strcmp(dat, "MAC") != 0)
-                       printk(KERN_WARNING "seeprom: bad signature.\n");
+                       pr_warn("seeprom: bad signature.\n");
                for (i = 0, sum = 0; i < sizeof(dat); i++)
                        sum += dat[i];
                if (sum)
-                       printk(KERN_WARNING "seeprom: bad checksum.\n");
+                       pr_warn("seeprom: bad checksum.\n");
        }
        tx4938_ethaddr_init(&dat[4], &dat[4 + 6]);
 #endif /* CONFIG_PCI */
@@ -214,14 +214,14 @@ static void __init rbtx4938_mem_setup(void)
        rbtx4938_fpga_resource.end = CPHYSADDR(RBTX4938_FPGA_REG_ADDR) + 0xffff;
        rbtx4938_fpga_resource.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
        if (request_resource(&txx9_ce_res[2], &rbtx4938_fpga_resource))
-               printk(KERN_ERR "request resource for fpga failed\n");
+               pr_err("request resource for fpga failed\n");
 
        _machine_restart = rbtx4938_machine_restart;
 
        writeb(0xff, rbtx4938_led_addr);
-       printk(KERN_INFO "RBTX4938 --- FPGA(Rev %02x) DIPSW:%02x,%02x\n",
-              readb(rbtx4938_fpga_rev_addr),
-              readb(rbtx4938_dipsw_addr), readb(rbtx4938_bdipsw_addr));
+       pr_info("RBTX4938 --- FPGA(Rev %02x) DIPSW:%02x,%02x\n",
+               readb(rbtx4938_fpga_rev_addr),
+               readb(rbtx4938_dipsw_addr), readb(rbtx4938_bdipsw_addr));
 }
 
 static void __init rbtx4938_ne_init(void)
index c3dc12a8b7d9ddc79f8acf126cdd83bbb91dfee2..b47d2a45dbf497547bd112ab6c9ce60f57e16d8a 100644 (file)
@@ -11,6 +11,7 @@ cflags-vdso := $(ccflags-vdso) \
        $(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \
        -O2 -g -fPIC -fno-strict-aliasing -fno-common -fno-builtin -G 0 \
        -DDISABLE_BRANCH_PROFILING \
+       $(call cc-option, -fno-asynchronous-unwind-tables) \
        $(call cc-option, -fno-stack-protector)
 aflags-vdso := $(ccflags-vdso) \
        -D__ASSEMBLY__ -Wa,-gdwarf-2
@@ -50,6 +51,9 @@ quiet_cmd_vdsold = VDSO    $@
       cmd_vdsold = $(CC) $(c_flags) $(VDSO_LDFLAGS) \
                    -Wl,-T $(filter %.lds,$^) $(filter %.o,$^) -o $@
 
+quiet_cmd_vdsoas_o_S = AS       $@
+      cmd_vdsoas_o_S = $(CC) $(a_flags) -c -o $@ $<
+
 # Strip rule for the raw .so files
 $(obj)/%.so.raw: OBJCOPYFLAGS := -S
 $(obj)/%.so.raw: $(obj)/%.so.dbg.raw FORCE
@@ -110,7 +114,7 @@ $(obj-vdso-o32): KBUILD_CFLAGS := $(cflags-vdso) -mabi=32
 $(obj-vdso-o32): KBUILD_AFLAGS := $(aflags-vdso) -mabi=32
 
 $(obj)/%-o32.o: $(src)/%.S FORCE
-       $(call if_changed_dep,as_o_S)
+       $(call if_changed_dep,vdsoas_o_S)
 
 $(obj)/%-o32.o: $(src)/%.c FORCE
        $(call cmd,force_checksrc)
@@ -150,7 +154,7 @@ $(obj-vdso-n32): KBUILD_CFLAGS := $(cflags-vdso) -mabi=n32
 $(obj-vdso-n32): KBUILD_AFLAGS := $(aflags-vdso) -mabi=n32
 
 $(obj)/%-n32.o: $(src)/%.S FORCE
-       $(call if_changed_dep,as_o_S)
+       $(call if_changed_dep,vdsoas_o_S)
 
 $(obj)/%-n32.o: $(src)/%.c FORCE
        $(call cmd,force_checksrc)
index ff7d1c66cf824f40a61bd23ac2086a963577872e..82906722272d6d8d229752f4282c7eb6ee209582 100644 (file)
  *  Yoichi Yuasa <yuasa@linux-mips.org>
  *  - Added support for NEC VR4133.
  */
+#include <linux/export.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/smp.h>
 #include <linux/types.h>
 
+#include <asm/cpu-type.h>
 #include <asm/cpu.h>
 #include <asm/io.h>
 
index 89bac9885695e7847595016257877c861d2b9a03..1534b354d75da9304431b7258885054b3e053292 100644 (file)
@@ -28,9 +28,9 @@
  *  Yoichi Yuasa <yuasa@linux-mips.org>
  *  - Added support for NEC VR4133.
  */
+#include <linux/export.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
-#include <linux/module.h>
 #include <linux/smp.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
index 41e873bc84747ecd05679585ea9cfdaaf2e9c3c0..745b7b4369618082143eabaf2e3fc0a3a3c0f2f6 100644 (file)
  *  - Coped with INTASSIGN of NEC VR4133.
  */
 #include <linux/errno.h>
+#include <linux/export.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/irq.h>
-#include <linux/module.h>
 #include <linux/smp.h>
 #include <linux/types.h>
 
index ae0e4ee6c61728b7a609451023e28a1302ef7c37..28211f3ee329346e804f2e389d90b860b017244a 100644 (file)
@@ -17,8 +17,8 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
+#include <linux/export.h>
 #include <linux/interrupt.h>
-#include <linux/module.h>
 #include <linux/irq.h>
 
 #include <asm/irq_cpu.h>
index c4d1a716b34757175c73baff932ee6d223a42552..a127cca3ae8cd256272cd894ba2c57152dded569 100644 (file)
 
 #include <linux/of.h>
 #include <linux/of_irq.h>
+#include <linux/irqchip.h>
 
 #include <asm/irq_cpu.h>
 
-static struct of_device_id of_irq_ids[] __initdata = {
-       { .compatible = "mti,cpu-interrupt-controller", .data = mips_cpu_irq_of_init },
-       {},
-};
 
 void __init arch_init_irq(void)
 {
-       of_irq_init(of_irq_ids);
+       irqchip_init();
 }
index 305de461cb8f83395f84a767a774883f9d20ed37..045a903ee6b9486fd56a49232b3e34c0772e816b 100644 (file)
@@ -8,7 +8,7 @@
  * as published by the Free Software Foundation; either version
  * 2 of the Licence, or (at your option) any later version.
  */
-#include <linux/module.h>
+#include <linux/extable.h>
 #include <linux/spinlock.h>
 #include <linux/uaccess.h>
 
index 31d04da85743090e7ac9d6a4d1a6ffe63d12b73d..b39a388825ae33b2627913be7e2e72a2c581658b 100644 (file)
@@ -8,7 +8,7 @@
  * as published by the Free Software Foundation; either version
  * 2 of the Licence, or (at your option) any later version.
  */
-#include <linux/module.h>
+#include <linux/extable.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
index 4d2fc5a589d09492630ddff2a52a7a6a96ab6486..2574dba0407d0ff3732f002586ed91adfd005b01 100644 (file)
@@ -8,7 +8,7 @@
  * for more details.
  */
 
-#include <linux/module.h>
+#include <linux/extable.h>
 #include <linux/uaccess.h>
 
 int fixup_exception(struct pt_regs *regs)
index affc4eb3f89efa7e98bd9cccc3145520f158270e..e7a14e1e0d6b6d3a12293b2f75b96985134c7242 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/ptrace.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
-#include <linux/module.h>
+#include <linux/extable.h>
 #include <linux/uaccess.h>
 #include <linux/ptrace.h>
 
index a4574cb4b0fb88cc783066cf48d4a35ecd4ead1e..d29c41bfbffaab232cf21d781aed6893fde12c06 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/extable.h>
 #include <linux/kmod.h>
 #include <linux/string.h>
 #include <linux/errno.h>
index b1a7435e786afd590f53e2ec286c15886f0e0dbb..53592a639744f44dbbe9a2b0fd300d6593be2485 100644 (file)
@@ -17,7 +17,7 @@
 
 #include <linux/mm.h>
 #include <linux/interrupt.h>
-#include <linux/module.h>
+#include <linux/extable.h>
 #include <linux/sched.h>
 
 #include <linux/uaccess.h>
index 3ce91a3df27f175286d0c70b71e9254fbcc1196a..1d2d69dd6409036565b4d1e9bfbb0a81f37da7e9 100644 (file)
@@ -62,7 +62,6 @@ CONFIG_MPC8610_HPCD=y
 CONFIG_GEF_SBC610=y
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_STAT=m
-CONFIG_CPU_FREQ_STAT_DETAILS=y
 CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
 CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=m
index d948a6818961d05906a001a1de34e068061d1684..2b22bcf02c27e8559adc3aee6e7c61bb770a6109 100644 (file)
@@ -23,7 +23,7 @@
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#include <linux/module.h>
+#include <linux/extable.h>
 #include <linux/sched.h>
 
 #include <asm/cacheflush.h>
index 01ff6445171cdd91cdf8c8e9eed125f18862737e..ec871355fc2d60498cee6b245c44476f0dc59604 100644 (file)
@@ -23,7 +23,7 @@
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#include <linux/module.h>
+#include <linux/extable.h>
 
 int fixup_exception(struct pt_regs *regs)
 {
index 995b71e4db4bafe3100ca5f4d62c9c2aff2af136..b85fad4f08740b853bc730ca10ffe78086f94c96 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
-#include <linux/module.h>
+#include <linux/extable.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/string.h>
index 16b122510c84f430d48f7257788205ab825bcfba..6595b6b45bf152ae1dc3b57ee22f53b3b8cd2013 100644 (file)
@@ -9,7 +9,6 @@
  */
 
 #include <linux/mmc/sh_mmcif.h>
-#include <linux/mmc/boot.h>
 #include <mach/romimage.h>
 
 #define MMCIF_BASE      (void __iomem *)0xa4ca0000
 #define HIZCRC         0xa405015c
 #define DRVCRA         0xa405018a
 
+enum {
+       MMCIF_PROGRESS_ENTER,
+       MMCIF_PROGRESS_INIT,
+       MMCIF_PROGRESS_LOAD,
+       MMCIF_PROGRESS_DONE
+};
+
 /* SH7724 specific MMCIF loader
  *
  * loads the romImage from an MMC card starting from block 512
@@ -30,7 +36,7 @@
  */
 asmlinkage void mmcif_loader(unsigned char *buf, unsigned long no_bytes)
 {
-       mmcif_update_progress(MMC_PROGRESS_ENTER);
+       mmcif_update_progress(MMCIF_PROGRESS_ENTER);
 
        /* enable clock to the MMCIF hardware block */
        __raw_writel(__raw_readl(MSTPCR2) & ~0x20000000, MSTPCR2);
@@ -53,12 +59,12 @@ asmlinkage void mmcif_loader(unsigned char *buf, unsigned long no_bytes)
        /* high drive capability for MMC pins */
        __raw_writew(__raw_readw(DRVCRA) | 0x3000, DRVCRA);
 
-       mmcif_update_progress(MMC_PROGRESS_INIT);
+       mmcif_update_progress(MMCIF_PROGRESS_INIT);
 
        /* setup MMCIF hardware */
        sh_mmcif_boot_init(MMCIF_BASE);
 
-       mmcif_update_progress(MMC_PROGRESS_LOAD);
+       mmcif_update_progress(MMCIF_PROGRESS_LOAD);
 
        /* load kernel via MMCIF interface */
        sh_mmcif_boot_do_read(MMCIF_BASE, 512,
@@ -68,5 +74,5 @@ asmlinkage void mmcif_loader(unsigned char *buf, unsigned long no_bytes)
        /* disable clock to the MMCIF hardware block */
        __raw_writel(__raw_readl(MSTPCR2) | 0x20000000, MSTPCR2);
 
-       mmcif_update_progress(MMC_PROGRESS_DONE);
+       mmcif_update_progress(MMCIF_PROGRESS_DONE);
 }
index 9bdcf72ec06adea46e83da8952d0d70be19f61be..2fce54d9c388496e8c3de442e6c3ddb835acddaf 100644 (file)
@@ -25,7 +25,7 @@ CONFIG_SH_SH7785LCR=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPU_FREQ_STAT=y
 CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
 CONFIG_SH_CPU_FREQ=y
 CONFIG_HEARTBEAT=y
index a38d0c7b818fe317a8e223a4531288c64fe73dba..c4f0fee812c3592b741d27e986faea9e89219bb0 100644 (file)
@@ -192,7 +192,6 @@ struct exception_table_entry {
 #endif
 
 int fixup_exception(struct pt_regs *regs);
-const struct exception_table_entry *search_exception_tables(unsigned long addr);
 
 extern void *set_exception_table_vec(unsigned int vec, void *handler);
 
index 1653ff64b1037ed131513a8509dc03d8861cdefb..52a5e11247d192b30c777a26cd3db6f75b50cf40 100644 (file)
@@ -9,7 +9,7 @@
  * for more details.
  */
 #include <linux/kprobes.h>
-#include <linux/module.h>
+#include <linux/extable.h>
 #include <linux/ptrace.h>
 #include <linux/preempt.h>
 #include <linux/kdebug.h>
index dfdad72c61caf2847cddac6c37c344c1a635b6cb..9513fa7840aa998a9151235481c24a220da75a63 100644 (file)
@@ -8,7 +8,8 @@
 #include <linux/hardirq.h>
 #include <linux/kernel.h>
 #include <linux/kexec.h>
-#include <linux/module.h>
+#include <linux/extable.h>
+#include <linux/module.h>      /* print_modules */
 #include <asm/unwinder.h>
 #include <asm/traps.h>
 
index 9cfcbb5848e45201bd42c44672f80cae51c68693..24a75d315dcbba0f2a7cd6cf0690b428c1f2c2d4 100644 (file)
@@ -4,7 +4,7 @@
  *   linux/arch/i386/mm/extable.c
  */
 
-#include <linux/module.h>
+#include <linux/extable.h>
 #include <linux/uaccess.h>
 
 int fixup_exception(struct pt_regs *regs)
index 96edaff8c98329d4f6fbffbe506d79e602df8d2f..b90cdfad2c78db5103d04fdd4d53d52975c5e651 100644 (file)
@@ -11,7 +11,7 @@
  * for more details.
  */
 #include <linux/rwsem.h>
-#include <linux/module.h>
+#include <linux/extable.h>
 #include <linux/uaccess.h>
 
 extern unsigned long copy_user_memcpy, copy_user_memcpy_end;
index 768a11e6bd4fa083a34c8b2ef2bd62aa2bbd1553..db214e9931d9260cca320ff3212c66da7d44d742 100644 (file)
@@ -3,6 +3,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/extable.h>
 #include <linux/uaccess.h>
 
 void sort_extable(struct exception_table_entry *start,
index 6564180eb285908fa594da57bc427f24503e105d..c562046947ba5d50d8d36e72b1228fb63cec595b 100644 (file)
@@ -9,7 +9,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#include <linux/module.h>
+#include <linux/extable.h>
 #include <linux/uaccess.h>
 
 int fixup_exception(struct pt_regs *regs)
index 6c7f70bcaae3263b1b9a229c87739c1bd25b68e1..b656d216a8a85d83c0ef1f2505e8145d13e32a3b 100644 (file)
@@ -9,7 +9,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#include <linux/module.h>
+#include <linux/extable.h>
 #include <linux/signal.h>
 #include <linux/mm.h>
 #include <linux/hardirq.h>
index a12a047184ee4789d8fd041493862c543fa692ac..f6d20f6cca12cabc2d186e4bf282e2aef61a0eee 100644 (file)
@@ -472,6 +472,13 @@ HYPERVISOR_xenpmu_op(unsigned int op, void *arg)
        return _hypercall2(int, xenpmu_op, op, arg);
 }
 
+static inline int
+HYPERVISOR_dm_op(
+       domid_t dom, unsigned int nr_bufs, void *bufs)
+{
+       return _hypercall3(int, dm_op, dom, nr_bufs, bufs);
+}
+
 static inline void
 MULTI_fpu_taskswitch(struct multicall_entry *mcl, int set)
 {
index 7ff007ed899d1731c97eba25fc40ccac38a90309..ae32838cac5fd2251e1ffa0bbb8b8c629e399a84 100644 (file)
@@ -724,11 +724,12 @@ int acpi_map_cpu2node(acpi_handle handle, int cpu, int physid)
        return 0;
 }
 
-int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, int *pcpu)
+int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 acpi_id,
+                int *pcpu)
 {
        int cpu;
 
-       cpu = acpi_register_lapic(physid, U32_MAX, ACPI_MADT_ENABLED);
+       cpu = acpi_register_lapic(physid, acpi_id, ACPI_MADT_ENABLED);
        if (cpu < 0) {
                pr_info(PREFIX "Unable to map lapic to logical cpu number\n");
                return cpu;
index af15f4444330b6c69fe20fc71a993070a9f26a5d..8233a630280f52052ffb9a5f7c89f273cedf0425 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/sched.h>
 
 #include <acpi/processor.h>
-#include <asm/acpi.h>
 #include <asm/mwait.h>
 #include <asm/special_insns.h>
 
@@ -89,7 +88,8 @@ static long acpi_processor_ffh_cstate_probe_cpu(void *_cx)
        retval = 0;
        /* If the HW does not support any sub-states in this C-state */
        if (num_cstate_subtype == 0) {
-               pr_warn(FW_BUG "ACPI MWAIT C-state 0x%x not supported by HW (0x%x)\n", cx->address, edx_part);
+               pr_warn(FW_BUG "ACPI MWAIT C-state 0x%x not supported by HW (0x%x)\n",
+                               cx->address, edx_part);
                retval = -1;
                goto out;
        }
@@ -104,8 +104,8 @@ static long acpi_processor_ffh_cstate_probe_cpu(void *_cx)
        if (!mwait_supported[cstate_type]) {
                mwait_supported[cstate_type] = 1;
                printk(KERN_DEBUG
-                       "Monitor-Mwait will be used to enter C-%d "
-                       "state\n", cx->type);
+                       "Monitor-Mwait will be used to enter C-%d state\n",
+                       cx->type);
        }
        snprintf(cx->desc,
                        ACPI_CX_DESC_LEN, "ACPI FFH INTEL MWAIT 0x%x",
@@ -166,6 +166,7 @@ EXPORT_SYMBOL_GPL(acpi_processor_ffh_cstate_enter);
 static int __init ffh_cstate_init(void)
 {
        struct cpuinfo_x86 *c = &boot_cpu_data;
+
        if (c->x86_vendor != X86_VENDOR_INTEL)
                return -1;
 
index c7b15f3e2cf37096f1041169aa544f706394a886..76b6dbd627df2564ca0a65b5c5633ec03f6599d7 100644 (file)
@@ -53,5 +53,5 @@ config XEN_DEBUG_FS
 
 config XEN_PVH
        bool "Support for running as a PVH guest"
-       depends on X86_64 && XEN && XEN_PVHVM
+       depends on XEN && XEN_PVHVM && ACPI
        def_bool n
index e47e52787d32eb9e4b9c7b6cb50b7a11f57dc586..cb0164aee156266cd0e02bf2ed466a49102cfa44 100644 (file)
@@ -23,3 +23,4 @@ obj-$(CONFIG_XEN_DEBUG_FS)    += debugfs.o
 obj-$(CONFIG_XEN_DOM0)         += vga.o
 obj-$(CONFIG_SWIOTLB_XEN)      += pci-swiotlb-xen.o
 obj-$(CONFIG_XEN_EFI)          += efi.o
+obj-$(CONFIG_XEN_PVH)          += xen-pvh.o
index 44c88ad1841a3696a7225965f16760820bea938a..bcea81f36fc5fdb7e0abae26be7e1d90f57af594 100644 (file)
@@ -145,7 +145,7 @@ static void xen_silent_inquire(int apicid)
 static int xen_cpu_present_to_apicid(int cpu)
 {
        if (cpu_present(cpu))
-               return xen_get_apic_id(xen_apic_read(APIC_ID));
+               return cpu_data(cpu).apicid;
        else
                return BAD_APICID;
 }
index 51ef952327257cb2a787b6743805e4cb677ecafc..ec1d5c46e58f7cd0719c84686b627e10b7b18dcd 100644 (file)
@@ -45,6 +45,7 @@
 #include <xen/interface/memory.h>
 #include <xen/interface/nmi.h>
 #include <xen/interface/xen-mca.h>
+#include <xen/interface/hvm/start_info.h>
 #include <xen/features.h>
 #include <xen/page.h>
 #include <xen/hvm.h>
@@ -176,6 +177,20 @@ struct tls_descs {
  */
 static DEFINE_PER_CPU(struct tls_descs, shadow_tls_desc);
 
+#ifdef CONFIG_XEN_PVH
+/*
+ * PVH variables.
+ *
+ * xen_pvh and pvh_bootparams need to live in data segment since they
+ * are used after startup_{32|64}, which clear .bss, are invoked.
+ */
+bool xen_pvh __attribute__((section(".data"))) = 0;
+struct boot_params pvh_bootparams __attribute__((section(".data")));
+
+struct hvm_start_info pvh_start_info;
+unsigned int pvh_start_info_sz = sizeof(pvh_start_info);
+#endif
+
 static void clamp_max_cpus(void)
 {
 #ifdef CONFIG_SMP
@@ -1138,10 +1153,11 @@ void xen_setup_vcpu_info_placement(void)
                xen_vcpu_setup(cpu);
        }
 
-       /* xen_vcpu_setup managed to place the vcpu_info within the
-        * percpu area for all cpus, so make use of it. Note that for
-        * PVH we want to use native IRQ mechanism. */
-       if (have_vcpu_info_placement && !xen_pvh_domain()) {
+       /*
+        * xen_vcpu_setup managed to place the vcpu_info within the
+        * percpu area for all cpus, so make use of it.
+        */
+       if (have_vcpu_info_placement) {
                pv_irq_ops.save_fl = __PV_IS_CALLEE_SAVE(xen_save_fl_direct);
                pv_irq_ops.restore_fl = __PV_IS_CALLEE_SAVE(xen_restore_fl_direct);
                pv_irq_ops.irq_disable = __PV_IS_CALLEE_SAVE(xen_irq_disable_direct);
@@ -1413,49 +1429,9 @@ static void __init xen_boot_params_init_edd(void)
  * Set up the GDT and segment registers for -fstack-protector.  Until
  * we do this, we have to be careful not to call any stack-protected
  * function, which is most of the kernel.
- *
- * Note, that it is __ref because the only caller of this after init
- * is PVH which is not going to use xen_load_gdt_boot or other
- * __init functions.
  */
-static void __ref xen_setup_gdt(int cpu)
+static void xen_setup_gdt(int cpu)
 {
-       if (xen_feature(XENFEAT_auto_translated_physmap)) {
-#ifdef CONFIG_X86_64
-               unsigned long dummy;
-
-               load_percpu_segment(cpu); /* We need to access per-cpu area */
-               switch_to_new_gdt(cpu); /* GDT and GS set */
-
-               /* We are switching of the Xen provided GDT to our HVM mode
-                * GDT. The new GDT has  __KERNEL_CS with CS.L = 1
-                * and we are jumping to reload it.
-                */
-               asm volatile ("pushq %0\n"
-                             "leaq 1f(%%rip),%0\n"
-                             "pushq %0\n"
-                             "lretq\n"
-                             "1:\n"
-                             : "=&r" (dummy) : "0" (__KERNEL_CS));
-
-               /*
-                * While not needed, we also set the %es, %ds, and %fs
-                * to zero. We don't care about %ss as it is NULL.
-                * Strictly speaking this is not needed as Xen zeros those
-                * out (and also MSR_FS_BASE, MSR_GS_BASE, MSR_KERNEL_GS_BASE)
-                *
-                * Linux zeros them in cpu_init() and in secondary_startup_64
-                * (for BSP).
-                */
-               loadsegment(es, 0);
-               loadsegment(ds, 0);
-               loadsegment(fs, 0);
-#else
-               /* PVH: TODO Implement. */
-               BUG();
-#endif
-               return; /* PVH does not need any PV GDT ops. */
-       }
        pv_cpu_ops.write_gdt_entry = xen_write_gdt_entry_boot;
        pv_cpu_ops.load_gdt = xen_load_gdt_boot;
 
@@ -1466,59 +1442,6 @@ static void __ref xen_setup_gdt(int cpu)
        pv_cpu_ops.load_gdt = xen_load_gdt;
 }
 
-#ifdef CONFIG_XEN_PVH
-/*
- * A PV guest starts with default flags that are not set for PVH, set them
- * here asap.
- */
-static void xen_pvh_set_cr_flags(int cpu)
-{
-
-       /* Some of these are setup in 'secondary_startup_64'. The others:
-        * X86_CR0_TS, X86_CR0_PE, X86_CR0_ET are set by Xen for HVM guests
-        * (which PVH shared codepaths), while X86_CR0_PG is for PVH. */
-       write_cr0(read_cr0() | X86_CR0_MP | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM);
-
-       if (!cpu)
-               return;
-       /*
-        * For BSP, PSE PGE are set in probe_page_size_mask(), for APs
-        * set them here. For all, OSFXSR OSXMMEXCPT are set in fpu__init_cpu().
-       */
-       if (boot_cpu_has(X86_FEATURE_PSE))
-               cr4_set_bits_and_update_boot(X86_CR4_PSE);
-
-       if (boot_cpu_has(X86_FEATURE_PGE))
-               cr4_set_bits_and_update_boot(X86_CR4_PGE);
-}
-
-/*
- * Note, that it is ref - because the only caller of this after init
- * is PVH which is not going to use xen_load_gdt_boot or other
- * __init functions.
- */
-void __ref xen_pvh_secondary_vcpu_init(int cpu)
-{
-       xen_setup_gdt(cpu);
-       xen_pvh_set_cr_flags(cpu);
-}
-
-static void __init xen_pvh_early_guest_init(void)
-{
-       if (!xen_feature(XENFEAT_auto_translated_physmap))
-               return;
-
-       BUG_ON(!xen_feature(XENFEAT_hvm_callback_vector));
-
-       xen_pvh_early_cpu_init(0, false);
-       xen_pvh_set_cr_flags(0);
-
-#ifdef CONFIG_X86_32
-       BUG(); /* PVH: Implement proper support. */
-#endif
-}
-#endif    /* CONFIG_XEN_PVH */
-
 static void __init xen_dom0_set_legacy_features(void)
 {
        x86_platform.legacy.rtc = 1;
@@ -1555,24 +1478,17 @@ asmlinkage __visible void __init xen_start_kernel(void)
        xen_domain_type = XEN_PV_DOMAIN;
 
        xen_setup_features();
-#ifdef CONFIG_XEN_PVH
-       xen_pvh_early_guest_init();
-#endif
+
        xen_setup_machphys_mapping();
 
        /* Install Xen paravirt ops */
        pv_info = xen_info;
        pv_init_ops = xen_init_ops;
-       if (!xen_pvh_domain()) {
-               pv_cpu_ops = xen_cpu_ops;
+       pv_cpu_ops = xen_cpu_ops;
 
-               x86_platform.get_nmi_reason = xen_get_nmi_reason;
-       }
+       x86_platform.get_nmi_reason = xen_get_nmi_reason;
 
-       if (xen_feature(XENFEAT_auto_translated_physmap))
-               x86_init.resources.memory_setup = xen_auto_xlated_memory_setup;
-       else
-               x86_init.resources.memory_setup = xen_memory_setup;
+       x86_init.resources.memory_setup = xen_memory_setup;
        x86_init.oem.arch_setup = xen_arch_setup;
        x86_init.oem.banner = xen_banner;
 
@@ -1665,18 +1581,15 @@ asmlinkage __visible void __init xen_start_kernel(void)
        /* set the limit of our address space */
        xen_reserve_top();
 
-       /* PVH: runs at default kernel iopl of 0 */
-       if (!xen_pvh_domain()) {
-               /*
-                * We used to do this in xen_arch_setup, but that is too late
-                * on AMD were early_cpu_init (run before ->arch_setup()) calls
-                * early_amd_init which pokes 0xcf8 port.
-                */
-               set_iopl.iopl = 1;
-               rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
-               if (rc != 0)
-                       xen_raw_printk("physdev_op failed %d\n", rc);
-       }
+       /*
+        * We used to do this in xen_arch_setup, but that is too late
+        * on AMD were early_cpu_init (run before ->arch_setup()) calls
+        * early_amd_init which pokes 0xcf8 port.
+        */
+       set_iopl.iopl = 1;
+       rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
+       if (rc != 0)
+               xen_raw_printk("physdev_op failed %d\n", rc);
 
 #ifdef CONFIG_X86_32
        /* set up basic CPUID stuff */
@@ -1758,6 +1671,102 @@ asmlinkage __visible void __init xen_start_kernel(void)
 #endif
 }
 
+#ifdef CONFIG_XEN_PVH
+
+static void xen_pvh_arch_setup(void)
+{
+#ifdef CONFIG_ACPI
+       /* Make sure we don't fall back to (default) ACPI_IRQ_MODEL_PIC. */
+       if (nr_ioapics == 0)
+               acpi_irq_model = ACPI_IRQ_MODEL_PLATFORM;
+#endif
+}
+
+static void __init init_pvh_bootparams(void)
+{
+       struct xen_memory_map memmap;
+       unsigned int i;
+       int rc;
+
+       memset(&pvh_bootparams, 0, sizeof(pvh_bootparams));
+
+       memmap.nr_entries = ARRAY_SIZE(pvh_bootparams.e820_map);
+       set_xen_guest_handle(memmap.buffer, pvh_bootparams.e820_map);
+       rc = HYPERVISOR_memory_op(XENMEM_memory_map, &memmap);
+       if (rc) {
+               xen_raw_printk("XENMEM_memory_map failed (%d)\n", rc);
+               BUG();
+       }
+
+       if (memmap.nr_entries < E820MAX - 1) {
+               pvh_bootparams.e820_map[memmap.nr_entries].addr =
+                       ISA_START_ADDRESS;
+               pvh_bootparams.e820_map[memmap.nr_entries].size =
+                       ISA_END_ADDRESS - ISA_START_ADDRESS;
+               pvh_bootparams.e820_map[memmap.nr_entries].type =
+                       E820_RESERVED;
+               memmap.nr_entries++;
+       } else
+               xen_raw_printk("Warning: Can fit ISA range into e820\n");
+
+       sanitize_e820_map(pvh_bootparams.e820_map,
+                         ARRAY_SIZE(pvh_bootparams.e820_map),
+                         &memmap.nr_entries);
+
+       pvh_bootparams.e820_entries = memmap.nr_entries;
+       for (i = 0; i < pvh_bootparams.e820_entries; i++)
+               e820_add_region(pvh_bootparams.e820_map[i].addr,
+                               pvh_bootparams.e820_map[i].size,
+                               pvh_bootparams.e820_map[i].type);
+
+       pvh_bootparams.hdr.cmd_line_ptr =
+               pvh_start_info.cmdline_paddr;
+
+       /* The first module is always ramdisk. */
+       if (pvh_start_info.nr_modules) {
+               struct hvm_modlist_entry *modaddr =
+                       __va(pvh_start_info.modlist_paddr);
+               pvh_bootparams.hdr.ramdisk_image = modaddr->paddr;
+               pvh_bootparams.hdr.ramdisk_size = modaddr->size;
+       }
+
+       /*
+        * See Documentation/x86/boot.txt.
+        *
+        * Version 2.12 supports Xen entry point but we will use default x86/PC
+        * environment (i.e. hardware_subarch 0).
+        */
+       pvh_bootparams.hdr.version = 0x212;
+       pvh_bootparams.hdr.type_of_loader = (9 << 4) | 0; /* Xen loader */
+}
+
+/*
+ * This routine (and those that it might call) should not use
+ * anything that lives in .bss since that segment will be cleared later.
+ */
+void __init xen_prepare_pvh(void)
+{
+       u32 msr;
+       u64 pfn;
+
+       if (pvh_start_info.magic != XEN_HVM_START_MAGIC_VALUE) {
+               xen_raw_printk("Error: Unexpected magic value (0x%08x)\n",
+                               pvh_start_info.magic);
+               BUG();
+       }
+
+       xen_pvh = 1;
+
+       msr = cpuid_ebx(xen_cpuid_base() + 2);
+       pfn = __pa(hypercall_page);
+       wrmsr_safe(msr, (u32)pfn, (u32)(pfn >> 32));
+
+       init_pvh_bootparams();
+
+       x86_init.oem.arch_setup = xen_pvh_arch_setup;
+}
+#endif
+
 void __ref xen_hvm_init_shared_info(void)
 {
        int cpu;
@@ -1797,20 +1806,29 @@ void __ref xen_hvm_init_shared_info(void)
 static void __init init_hvm_pv_info(void)
 {
        int major, minor;
-       uint32_t eax, ebx, ecx, edx, pages, msr, base;
-       u64 pfn;
+       uint32_t eax, ebx, ecx, edx, base;
 
        base = xen_cpuid_base();
-       cpuid(base + 1, &eax, &ebx, &ecx, &edx);
+       eax = cpuid_eax(base + 1);
 
        major = eax >> 16;
        minor = eax & 0xffff;
        printk(KERN_INFO "Xen version %d.%d.\n", major, minor);
 
-       cpuid(base + 2, &pages, &msr, &ecx, &edx);
+       xen_domain_type = XEN_HVM_DOMAIN;
 
-       pfn = __pa(hypercall_page);
-       wrmsr_safe(msr, (u32)pfn, (u32)(pfn >> 32));
+       /* PVH set up hypercall page in xen_prepare_pvh(). */
+       if (xen_pvh_domain())
+               pv_info.name = "Xen PVH";
+       else {
+               u64 pfn;
+               uint32_t msr;
+
+               pv_info.name = "Xen HVM";
+               msr = cpuid_ebx(base + 2);
+               pfn = __pa(hypercall_page);
+               wrmsr_safe(msr, (u32)pfn, (u32)(pfn >> 32));
+       }
 
        xen_setup_features();
 
@@ -1819,10 +1837,6 @@ static void __init init_hvm_pv_info(void)
                this_cpu_write(xen_vcpu_id, ebx);
        else
                this_cpu_write(xen_vcpu_id, smp_processor_id());
-
-       pv_info.name = "Xen HVM";
-
-       xen_domain_type = XEN_HVM_DOMAIN;
 }
 #endif
 
@@ -1910,6 +1924,9 @@ static void __init xen_hvm_guest_init(void)
        x86_init.irqs.intr_init = xen_init_IRQ;
        xen_hvm_init_time_ops();
        xen_hvm_init_mmu_ops();
+
+       if (xen_pvh_domain())
+               machine_ops.emergency_restart = xen_emergency_restart;
 #ifdef CONFIG_KEXEC_CORE
        machine_ops.shutdown = xen_hvm_shutdown;
        machine_ops.crash_shutdown = xen_hvm_crash_shutdown;
index 7d5afdb417cc5e47a590f8f650e3fdcb96d544ac..f6740b5b173808a6e9b8b5bff44802b28ed7f8cb 100644 (file)
@@ -1792,10 +1792,6 @@ static void __init set_page_prot_flags(void *addr, pgprot_t prot,
        unsigned long pfn = __pa(addr) >> PAGE_SHIFT;
        pte_t pte = pfn_pte(pfn, prot);
 
-       /* For PVH no need to set R/O or R/W to pin them or unpin them. */
-       if (xen_feature(XENFEAT_auto_translated_physmap))
-               return;
-
        if (HYPERVISOR_update_va_mapping((unsigned long)addr, pte, flags))
                BUG();
 }
@@ -1902,8 +1898,7 @@ static void __init check_pt_base(unsigned long *pt_base, unsigned long *pt_end,
  * level2_ident_pgt, and level2_kernel_pgt.  This means that only the
  * kernel has a physical mapping to start with - but that's enough to
  * get __va working.  We need to fill in the rest of the physical
- * mapping once some sort of allocator has been set up.  NOTE: for
- * PVH, the page tables are native.
+ * mapping once some sort of allocator has been set up.
  */
 void __init xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn)
 {
@@ -2812,16 +2807,6 @@ static int do_remap_gfn(struct vm_area_struct *vma,
 
        BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_IO)) == (VM_PFNMAP | VM_IO)));
 
-       if (xen_feature(XENFEAT_auto_translated_physmap)) {
-#ifdef CONFIG_XEN_PVH
-               /* We need to update the local page tables and the xen HAP */
-               return xen_xlate_remap_gfn_array(vma, addr, gfn, nr, err_ptr,
-                                                prot, domid, pages);
-#else
-               return -EINVAL;
-#endif
-        }
-
        rmd.mfn = gfn;
        rmd.prot = prot;
        /* We use the err_ptr to indicate if there we are doing a contiguous
@@ -2915,10 +2900,6 @@ int xen_unmap_domain_gfn_range(struct vm_area_struct *vma,
        if (!pages || !xen_feature(XENFEAT_auto_translated_physmap))
                return 0;
 
-#ifdef CONFIG_XEN_PVH
-       return xen_xlate_unmap_gfn_range(vma, numpgs, pages);
-#else
        return -EINVAL;
-#endif
 }
 EXPORT_SYMBOL_GPL(xen_unmap_domain_gfn_range);
index 90d1b83cf35f2ae72f7bde1b63fcbb2c9fb219ec..33a783c77d969ecb5c76b841e13aa2ac19ad0da5 100644 (file)
@@ -73,8 +73,8 @@ bool xen_has_pv_devices(void)
        if (!xen_domain())
                return false;
 
-       /* PV domains always have them. */
-       if (xen_pv_domain())
+       /* PV and PVH domains always have them. */
+       if (xen_pv_domain() || xen_pvh_domain())
                return true;
 
        /* And user has xen_platform_pci=0 set in guest config as
index f3f7b41116f7afcd3a37880d6e814b67cac0f005..a8c306cf88683e6c19e32f483e50dfcc0ca681ac 100644 (file)
@@ -914,39 +914,6 @@ char * __init xen_memory_setup(void)
        return "Xen";
 }
 
-/*
- * Machine specific memory setup for auto-translated guests.
- */
-char * __init xen_auto_xlated_memory_setup(void)
-{
-       struct xen_memory_map memmap;
-       int i;
-       int rc;
-
-       memmap.nr_entries = ARRAY_SIZE(xen_e820_map);
-       set_xen_guest_handle(memmap.buffer, xen_e820_map);
-
-       rc = HYPERVISOR_memory_op(XENMEM_memory_map, &memmap);
-       if (rc < 0)
-               panic("No memory map (%d)\n", rc);
-
-       xen_e820_map_entries = memmap.nr_entries;
-
-       sanitize_e820_map(xen_e820_map, ARRAY_SIZE(xen_e820_map),
-                         &xen_e820_map_entries);
-
-       for (i = 0; i < xen_e820_map_entries; i++)
-               e820_add_region(xen_e820_map[i].addr, xen_e820_map[i].size,
-                               xen_e820_map[i].type);
-
-       /* Remove p2m info, it is not needed. */
-       xen_start_info->mfn_list = 0;
-       xen_start_info->first_p2m_pfn = 0;
-       xen_start_info->nr_p2m_frames = 0;
-
-       return "Xen";
-}
-
 /*
  * Set the bit indicating "nosegneg" library variants should be used.
  * We only need to bother in pure 32-bit mode; compat 32-bit processes
@@ -1032,8 +999,8 @@ void __init xen_pvmmu_arch_setup(void)
 void __init xen_arch_setup(void)
 {
        xen_panic_handler_init();
-       if (!xen_feature(XENFEAT_auto_translated_physmap))
-               xen_pvmmu_arch_setup();
+
+       xen_pvmmu_arch_setup();
 
 #ifdef CONFIG_ACPI
        if (!(xen_start_info->flags & SIF_INITDOMAIN)) {
index 311acad7dad2abdc8501c70866674ed4f5858495..0dee6f59ea8268147d755faaf3490fd4242e317c 100644 (file)
@@ -99,18 +99,8 @@ static void cpu_bringup(void)
        local_irq_enable();
 }
 
-/*
- * Note: cpu parameter is only relevant for PVH. The reason for passing it
- * is we can't do smp_processor_id until the percpu segments are loaded, for
- * which we need the cpu number! So we pass it in rdi as first parameter.
- */
-asmlinkage __visible void cpu_bringup_and_idle(int cpu)
+asmlinkage __visible void cpu_bringup_and_idle(void)
 {
-#ifdef CONFIG_XEN_PVH
-       if (xen_feature(XENFEAT_auto_translated_physmap) &&
-           xen_feature(XENFEAT_supervisor_mode_kernel))
-               xen_pvh_secondary_vcpu_init(cpu);
-#endif
        cpu_bringup();
        cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
 }
@@ -404,61 +394,47 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle)
        gdt = get_cpu_gdt_table(cpu);
 
 #ifdef CONFIG_X86_32
-       /* Note: PVH is not yet supported on x86_32. */
        ctxt->user_regs.fs = __KERNEL_PERCPU;
        ctxt->user_regs.gs = __KERNEL_STACK_CANARY;
 #endif
        memset(&ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt));
 
-       if (!xen_feature(XENFEAT_auto_translated_physmap)) {
-               ctxt->user_regs.eip = (unsigned long)cpu_bringup_and_idle;
-               ctxt->flags = VGCF_IN_KERNEL;
-               ctxt->user_regs.eflags = 0x1000; /* IOPL_RING1 */
-               ctxt->user_regs.ds = __USER_DS;
-               ctxt->user_regs.es = __USER_DS;
-               ctxt->user_regs.ss = __KERNEL_DS;
+       ctxt->user_regs.eip = (unsigned long)cpu_bringup_and_idle;
+       ctxt->flags = VGCF_IN_KERNEL;
+       ctxt->user_regs.eflags = 0x1000; /* IOPL_RING1 */
+       ctxt->user_regs.ds = __USER_DS;
+       ctxt->user_regs.es = __USER_DS;
+       ctxt->user_regs.ss = __KERNEL_DS;
 
-               xen_copy_trap_info(ctxt->trap_ctxt);
+       xen_copy_trap_info(ctxt->trap_ctxt);
 
-               ctxt->ldt_ents = 0;
+       ctxt->ldt_ents = 0;
 
-               BUG_ON((unsigned long)gdt & ~PAGE_MASK);
+       BUG_ON((unsigned long)gdt & ~PAGE_MASK);
 
-               gdt_mfn = arbitrary_virt_to_mfn(gdt);
-               make_lowmem_page_readonly(gdt);
-               make_lowmem_page_readonly(mfn_to_virt(gdt_mfn));
+       gdt_mfn = arbitrary_virt_to_mfn(gdt);
+       make_lowmem_page_readonly(gdt);
+       make_lowmem_page_readonly(mfn_to_virt(gdt_mfn));
 
-               ctxt->gdt_frames[0] = gdt_mfn;
-               ctxt->gdt_ents      = GDT_ENTRIES;
+       ctxt->gdt_frames[0] = gdt_mfn;
+       ctxt->gdt_ents      = GDT_ENTRIES;
 
-               ctxt->kernel_ss = __KERNEL_DS;
-               ctxt->kernel_sp = idle->thread.sp0;
+       ctxt->kernel_ss = __KERNEL_DS;
+       ctxt->kernel_sp = idle->thread.sp0;
 
 #ifdef CONFIG_X86_32
-               ctxt->event_callback_cs     = __KERNEL_CS;
-               ctxt->failsafe_callback_cs  = __KERNEL_CS;
+       ctxt->event_callback_cs     = __KERNEL_CS;
+       ctxt->failsafe_callback_cs  = __KERNEL_CS;
 #else
-               ctxt->gs_base_kernel = per_cpu_offset(cpu);
-#endif
-               ctxt->event_callback_eip    =
-                                       (unsigned long)xen_hypervisor_callback;
-               ctxt->failsafe_callback_eip =
-                                       (unsigned long)xen_failsafe_callback;
-               ctxt->user_regs.cs = __KERNEL_CS;
-               per_cpu(xen_cr3, cpu) = __pa(swapper_pg_dir);
-       }
-#ifdef CONFIG_XEN_PVH
-       else {
-               /*
-                * The vcpu comes on kernel page tables which have the NX pte
-                * bit set. This means before DS/SS is touched, NX in
-                * EFER must be set. Hence the following assembly glue code.
-                */
-               ctxt->user_regs.eip = (unsigned long)xen_pvh_early_cpu_init;
-               ctxt->user_regs.rdi = cpu;
-               ctxt->user_regs.rsi = true;  /* entry == true */
-       }
+       ctxt->gs_base_kernel = per_cpu_offset(cpu);
 #endif
+       ctxt->event_callback_eip    =
+               (unsigned long)xen_hypervisor_callback;
+       ctxt->failsafe_callback_eip =
+               (unsigned long)xen_failsafe_callback;
+       ctxt->user_regs.cs = __KERNEL_CS;
+       per_cpu(xen_cr3, cpu) = __pa(swapper_pg_dir);
+
        ctxt->user_regs.esp = idle->thread.sp0 - sizeof(struct pt_regs);
        ctxt->ctrlreg[3] = xen_pfn_to_cr3(virt_to_gfn(swapper_pg_dir));
        if (HYPERVISOR_vcpu_op(VCPUOP_initialise, xen_vcpu_nr(cpu), ctxt))
index c5c16dc4f694e832ca2f680fb4fb0a9e646fb2ef..9beef333584abee258d704af97c8af8dd226d33a 100644 (file)
@@ -21,12 +21,4 @@ static inline int xen_smp_intr_init(unsigned int cpu)
 static inline void xen_smp_intr_free(unsigned int cpu) {}
 #endif /* CONFIG_SMP */
 
-#ifdef CONFIG_XEN_PVH
-extern void xen_pvh_early_cpu_init(int cpu, bool entry);
-#else
-static inline void xen_pvh_early_cpu_init(int cpu, bool entry)
-{
-}
-#endif
-
 #endif
index 7f8d8abf4c1ab8b1ea114fee0365f1505b81aeea..37794e42b67dcfc3e5afb25d53cfa0afb2fcbf77 100644 (file)
 #include <xen/interface/xen-mca.h>
 #include <asm/xen/interface.h>
 
-#ifdef CONFIG_XEN_PVH
-#define PVH_FEATURES_STR  "|writable_descriptor_tables|auto_translated_physmap|supervisor_mode_kernel"
-/* Note the lack of 'hvm_callback_vector'. Older hypervisor will
- * balk at this being part of XEN_ELFNOTE_FEATURES, so we put it in
- * XEN_ELFNOTE_SUPPORTED_FEATURES which older hypervisors will ignore.
- */
-#define PVH_FEATURES ((1 << XENFEAT_writable_page_tables) | \
-                     (1 << XENFEAT_auto_translated_physmap) | \
-                     (1 << XENFEAT_supervisor_mode_kernel) | \
-                     (1 << XENFEAT_hvm_callback_vector))
-/* The XENFEAT_writable_page_tables is not stricly necessary as we set that
- * up regardless whether this CONFIG option is enabled or not, but it
- * clarifies what the right flags need to be.
- */
-#else
-#define PVH_FEATURES_STR  ""
-#define PVH_FEATURES (0)
-#endif
-
        __INIT
 ENTRY(startup_xen)
        cld
@@ -54,41 +35,6 @@ ENTRY(startup_xen)
 
        __FINIT
 
-#ifdef CONFIG_XEN_PVH
-/*
- * xen_pvh_early_cpu_init() - early PVH VCPU initialization
- * @cpu:   this cpu number (%rdi)
- * @entry: true if this is a secondary vcpu coming up on this entry
- *         point, false if this is the boot CPU being initialized for
- *         the first time (%rsi)
- *
- * Note: This is called as a function on the boot CPU, and is the entry point
- *       on the secondary CPU.
- */
-ENTRY(xen_pvh_early_cpu_init)
-       mov     %rsi, %r11
-
-       /* Gather features to see if NX implemented. */
-       mov     $0x80000001, %eax
-       cpuid
-       mov     %edx, %esi
-
-       mov     $MSR_EFER, %ecx
-       rdmsr
-       bts     $_EFER_SCE, %eax
-
-       bt      $20, %esi
-       jnc     1f              /* No NX, skip setting it */
-       bts     $_EFER_NX, %eax
-1:     wrmsr
-#ifdef CONFIG_SMP
-       cmp     $0, %r11b
-       jne     cpu_bringup_and_idle
-#endif
-       ret
-
-#endif /* CONFIG_XEN_PVH */
-
 .pushsection .text
        .balign PAGE_SIZE
 ENTRY(hypercall_page)
@@ -114,10 +60,10 @@ ENTRY(hypercall_page)
 #endif
        ELFNOTE(Xen, XEN_ELFNOTE_ENTRY,          _ASM_PTR startup_xen)
        ELFNOTE(Xen, XEN_ELFNOTE_HYPERCALL_PAGE, _ASM_PTR hypercall_page)
-       ELFNOTE(Xen, XEN_ELFNOTE_FEATURES,       .ascii "!writable_page_tables|pae_pgdir_above_4gb"; .asciz PVH_FEATURES_STR)
-       ELFNOTE(Xen, XEN_ELFNOTE_SUPPORTED_FEATURES, .long (PVH_FEATURES) |
-                                               (1 << XENFEAT_writable_page_tables) |
-                                               (1 << XENFEAT_dom0))
+       ELFNOTE(Xen, XEN_ELFNOTE_FEATURES,
+               .ascii "!writable_page_tables|pae_pgdir_above_4gb")
+       ELFNOTE(Xen, XEN_ELFNOTE_SUPPORTED_FEATURES,
+               .long (1 << XENFEAT_writable_page_tables) | (1 << XENFEAT_dom0))
        ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE,       .asciz "yes")
        ELFNOTE(Xen, XEN_ELFNOTE_LOADER,         .asciz "generic")
        ELFNOTE(Xen, XEN_ELFNOTE_L1_MFN_VALID,
index ac0a2b0f9e626088fd44670c1709e0bf2da2900f..f6a41c41ebc7d1b3f1d251ff7144c4d071c82fdd 100644 (file)
@@ -146,5 +146,4 @@ __visible void xen_adjust_exception_frame(void);
 
 extern int xen_panic_handler_init(void);
 
-void xen_pvh_secondary_vcpu_init(int cpu);
 #endif /* XEN_OPS_H */
diff --git a/arch/x86/xen/xen-pvh.S b/arch/x86/xen/xen-pvh.S
new file mode 100644 (file)
index 0000000..5e24671
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Copyright C 2016, Oracle and/or its affiliates. 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/>.
+ */
+
+       .code32
+       .text
+#define _pa(x)          ((x) - __START_KERNEL_map)
+
+#include <linux/elfnote.h>
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/asm.h>
+#include <asm/boot.h>
+#include <asm/processor-flags.h>
+#include <asm/msr.h>
+#include <xen/interface/elfnote.h>
+
+       __HEAD
+
+/*
+ * Entry point for PVH guests.
+ *
+ * Xen ABI specifies the following register state when we come here:
+ *
+ * - `ebx`: contains the physical memory address where the loader has placed
+ *          the boot start info structure.
+ * - `cr0`: bit 0 (PE) must be set. All the other writeable bits are cleared.
+ * - `cr4`: all bits are cleared.
+ * - `cs `: must be a 32-bit read/execute code segment with a base of â€˜0’
+ *          and a limit of â€˜0xFFFFFFFF’. The selector value is unspecified.
+ * - `ds`, `es`: must be a 32-bit read/write data segment with a base of
+ *               â€˜0’ and a limit of â€˜0xFFFFFFFF’. The selector values are all
+ *               unspecified.
+ * - `tr`: must be a 32-bit TSS (active) with a base of '0' and a limit
+ *         of '0x67'.
+ * - `eflags`: bit 17 (VM) must be cleared. Bit 9 (IF) must be cleared.
+ *             Bit 8 (TF) must be cleared. Other bits are all unspecified.
+ *
+ * All other processor registers and flag bits are unspecified. The OS is in
+ * charge of setting up it's own stack, GDT and IDT.
+ */
+
+ENTRY(pvh_start_xen)
+       cld
+
+       lgdt (_pa(gdt))
+
+       mov $(__BOOT_DS),%eax
+       mov %eax,%ds
+       mov %eax,%es
+       mov %eax,%ss
+
+       /* Stash hvm_start_info. */
+       mov $_pa(pvh_start_info), %edi
+       mov %ebx, %esi
+       mov _pa(pvh_start_info_sz), %ecx
+       shr $2,%ecx
+       rep
+       movsl
+
+       mov $_pa(early_stack_end), %esp
+
+       /* Enable PAE mode. */
+       mov %cr4, %eax
+       orl $X86_CR4_PAE, %eax
+       mov %eax, %cr4
+
+#ifdef CONFIG_X86_64
+       /* Enable Long mode. */
+       mov $MSR_EFER, %ecx
+       rdmsr
+       btsl $_EFER_LME, %eax
+       wrmsr
+
+       /* Enable pre-constructed page tables. */
+       mov $_pa(init_level4_pgt), %eax
+       mov %eax, %cr3
+       mov $(X86_CR0_PG | X86_CR0_PE), %eax
+       mov %eax, %cr0
+
+       /* Jump to 64-bit mode. */
+       ljmp $__KERNEL_CS, $_pa(1f)
+
+       /* 64-bit entry point. */
+       .code64
+1:
+       call xen_prepare_pvh
+
+       /* startup_64 expects boot_params in %rsi. */
+       mov $_pa(pvh_bootparams), %rsi
+       mov $_pa(startup_64), %rax
+       jmp *%rax
+
+#else /* CONFIG_X86_64 */
+
+       call mk_early_pgtbl_32
+
+       mov $_pa(initial_page_table), %eax
+       mov %eax, %cr3
+
+       mov %cr0, %eax
+       or $(X86_CR0_PG | X86_CR0_PE), %eax
+       mov %eax, %cr0
+
+       ljmp $__BOOT_CS, $1f
+1:
+       call xen_prepare_pvh
+       mov $_pa(pvh_bootparams), %esi
+
+       /* startup_32 doesn't expect paging and PAE to be on. */
+       ljmp $__BOOT_CS, $_pa(2f)
+2:
+       mov %cr0, %eax
+       and $~X86_CR0_PG, %eax
+       mov %eax, %cr0
+       mov %cr4, %eax
+       and $~X86_CR4_PAE, %eax
+       mov %eax, %cr4
+
+       ljmp $__BOOT_CS, $_pa(startup_32)
+#endif
+END(pvh_start_xen)
+
+       .section ".init.data","aw"
+       .balign 8
+gdt:
+       .word gdt_end - gdt_start
+       .long _pa(gdt_start)
+       .word 0
+gdt_start:
+       .quad 0x0000000000000000            /* NULL descriptor */
+       .quad 0x0000000000000000            /* reserved */
+#ifdef CONFIG_X86_64
+       .quad GDT_ENTRY(0xa09a, 0, 0xfffff) /* __KERNEL_CS */
+#else
+       .quad GDT_ENTRY(0xc09a, 0, 0xfffff) /* __KERNEL_CS */
+#endif
+       .quad GDT_ENTRY(0xc092, 0, 0xfffff) /* __KERNEL_DS */
+gdt_end:
+
+       .balign 4
+early_stack:
+       .fill 256, 1, 0
+early_stack_end:
+
+       ELFNOTE(Xen, XEN_ELFNOTE_PHYS32_ENTRY,
+                    _ASM_PTR (pvh_start_xen - __START_KERNEL_map))
index 2725e08ef353798956d4378085d55ae00eeba303..a14df5aa98c898f641812eef88fc6969d06ad172 100644 (file)
@@ -13,7 +13,7 @@
  */
 
 #include <linux/mm.h>
-#include <linux/module.h>
+#include <linux/extable.h>
 #include <linux/hardirq.h>
 #include <linux/perf_event.h>
 #include <linux/uaccess.h>
index 8bf114a3858acd94622831cd720d0e22c83dfdb4..a2a92e57a87db6cb886d967d190c1d489e06d88d 100644 (file)
@@ -49,9 +49,13 @@ config LBDAF
 
          If unsure, say Y.
 
+config BLK_SCSI_REQUEST
+       bool
+
 config BLK_DEV_BSG
        bool "Block layer SG support v4"
        default y
+       select BLK_SCSI_REQUEST
        help
          Saying Y here will enable generic SG (SCSI generic) v4 support
          for any block device.
@@ -71,6 +75,7 @@ config BLK_DEV_BSGLIB
        bool "Block layer SG support v4 helper lib"
        default n
        select BLK_DEV_BSG
+       select BLK_SCSI_REQUEST
        help
          Subsystems will normally enable this if needed. Users will not
          normally need to manually enable this.
@@ -147,6 +152,25 @@ config BLK_WBT_MQ
        Multiqueue currently doesn't have support for IO scheduling,
        enabling this option is recommended.
 
+config BLK_DEBUG_FS
+       bool "Block layer debugging information in debugfs"
+       default y
+       depends on DEBUG_FS
+       ---help---
+       Include block layer debugging information in debugfs. This information
+       is mostly useful for kernel developers, but it doesn't incur any cost
+       at runtime.
+
+       Unless you are building a kernel for a tiny system, you should
+       say Y here.
+
+config BLK_SED_OPAL
+       bool "Logic for interfacing with Opal enabled SEDs"
+       ---help---
+       Builds Logic for interfacing with Opal enabled controllers.
+       Enabling this option enables users to setup/unlock/lock
+       Locking ranges for SED devices using the Opal protocol.
+
 menu "Partition Types"
 
 source "block/partitions/Kconfig"
index 421bef9c4c48d26c035792716064e9f273253c6e..0715ce93daef42001407f690912a1b2a437e5a6e 100644 (file)
@@ -63,6 +63,56 @@ config DEFAULT_IOSCHED
        default "cfq" if DEFAULT_CFQ
        default "noop" if DEFAULT_NOOP
 
+config MQ_IOSCHED_DEADLINE
+       tristate "MQ deadline I/O scheduler"
+       default y
+       ---help---
+         MQ version of the deadline IO scheduler.
+
+config MQ_IOSCHED_NONE
+       bool
+       default y
+
+choice
+       prompt "Default single-queue blk-mq I/O scheduler"
+       default DEFAULT_SQ_NONE
+       help
+         Select the I/O scheduler which will be used by default for blk-mq
+         managed block devices with a single queue.
+
+       config DEFAULT_SQ_DEADLINE
+               bool "MQ Deadline" if MQ_IOSCHED_DEADLINE=y
+
+       config DEFAULT_SQ_NONE
+               bool "None"
+
+endchoice
+
+config DEFAULT_SQ_IOSCHED
+       string
+       default "mq-deadline" if DEFAULT_SQ_DEADLINE
+       default "none" if DEFAULT_SQ_NONE
+
+choice
+       prompt "Default multi-queue blk-mq I/O scheduler"
+       default DEFAULT_MQ_NONE
+       help
+         Select the I/O scheduler which will be used by default for blk-mq
+         managed block devices with multiple queues.
+
+       config DEFAULT_MQ_DEADLINE
+               bool "MQ Deadline" if MQ_IOSCHED_DEADLINE=y
+
+       config DEFAULT_MQ_NONE
+               bool "None"
+
+endchoice
+
+config DEFAULT_MQ_IOSCHED
+       string
+       default "mq-deadline" if DEFAULT_MQ_DEADLINE
+       default "none" if DEFAULT_MQ_NONE
+
 endmenu
 
 endif
index a827f988c4e67435a90513bd65d498eebcf8ff6f..2ad7c304e3f5075d943e6c57450437c610f1364f 100644 (file)
@@ -6,11 +6,12 @@ obj-$(CONFIG_BLOCK) := bio.o elevator.o blk-core.o blk-tag.o blk-sysfs.o \
                        blk-flush.o blk-settings.o blk-ioc.o blk-map.o \
                        blk-exec.o blk-merge.o blk-softirq.o blk-timeout.o \
                        blk-lib.o blk-mq.o blk-mq-tag.o blk-stat.o \
-                       blk-mq-sysfs.o blk-mq-cpumap.o ioctl.o \
-                       genhd.o scsi_ioctl.o partition-generic.o ioprio.o \
+                       blk-mq-sysfs.o blk-mq-cpumap.o blk-mq-sched.o ioctl.o \
+                       genhd.o partition-generic.o ioprio.o \
                        badblocks.o partitions/
 
-obj-$(CONFIG_BOUNCE)   += bounce.o
+obj-$(CONFIG_BOUNCE)           += bounce.o
+obj-$(CONFIG_BLK_SCSI_REQUEST) += scsi_ioctl.o
 obj-$(CONFIG_BLK_DEV_BSG)      += bsg.o
 obj-$(CONFIG_BLK_DEV_BSGLIB)   += bsg-lib.o
 obj-$(CONFIG_BLK_CGROUP)       += blk-cgroup.o
@@ -18,6 +19,7 @@ obj-$(CONFIG_BLK_DEV_THROTTLING)      += blk-throttle.o
 obj-$(CONFIG_IOSCHED_NOOP)     += noop-iosched.o
 obj-$(CONFIG_IOSCHED_DEADLINE) += deadline-iosched.o
 obj-$(CONFIG_IOSCHED_CFQ)      += cfq-iosched.o
+obj-$(CONFIG_MQ_IOSCHED_DEADLINE)      += mq-deadline.o
 
 obj-$(CONFIG_BLOCK_COMPAT)     += compat_ioctl.o
 obj-$(CONFIG_BLK_CMDLINE_PARSER)       += cmdline-parser.o
@@ -25,3 +27,5 @@ obj-$(CONFIG_BLK_DEV_INTEGRITY) += bio-integrity.o blk-integrity.o t10-pi.o
 obj-$(CONFIG_BLK_MQ_PCI)       += blk-mq-pci.o
 obj-$(CONFIG_BLK_DEV_ZONED)    += blk-zoned.o
 obj-$(CONFIG_BLK_WBT)          += blk-wbt.o
+obj-$(CONFIG_BLK_DEBUG_FS)     += blk-mq-debugfs.o
+obj-$(CONFIG_BLK_SED_OPAL)     += sed-opal.o
index 2b375020fc49bab0bfcabda4fc3d16118b5f1512..4b564d0c3e29a4c15becf545a996794b296ae622 100644 (file)
@@ -1227,9 +1227,6 @@ struct bio *bio_copy_user_iov(struct request_queue *q,
        if (!bio)
                goto out_bmd;
 
-       if (iter->type & WRITE)
-               bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
-
        ret = 0;
 
        if (map_data) {
@@ -1394,16 +1391,10 @@ struct bio *bio_map_user_iov(struct request_queue *q,
 
        kfree(pages);
 
-       /*
-        * set data direction, and check if mapped pages need bouncing
-        */
-       if (iter->type & WRITE)
-               bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
-
        bio_set_flag(bio, BIO_USER_MAPPED);
 
        /*
-        * subtle -- if __bio_map_user() ended up bouncing a bio,
+        * subtle -- if bio_map_user_iov() ended up bouncing a bio,
         * it would normally disappear when its bi_end_io is run.
         * however, we need it for the unmap, so grab an extra
         * reference to it
@@ -1445,8 +1436,8 @@ static void __bio_unmap_user(struct bio *bio)
  *     bio_unmap_user  -       unmap a bio
  *     @bio:           the bio being unmapped
  *
- *     Unmap a bio previously mapped by bio_map_user(). Must be called with
- *     process context.
+ *     Unmap a bio previously mapped by bio_map_user_iov(). Must be called from
+ *     process context.
  *
  *     bio_unmap_user() may sleep.
  */
@@ -1590,7 +1581,6 @@ struct bio *bio_copy_kern(struct request_queue *q, void *data, unsigned int len,
                bio->bi_private = data;
        } else {
                bio->bi_end_io = bio_copy_kern_endio;
-               bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
        }
 
        return bio;
index 8ba0af780e880e1c6ed72d772ba77dea5a79f436..295e98c2c8ccdf7c86515306157d620c83052119 100644 (file)
@@ -184,7 +184,7 @@ static struct blkcg_gq *blkg_create(struct blkcg *blkcg,
                goto err_free_blkg;
        }
 
-       wb_congested = wb_congested_get_create(&q->backing_dev_info,
+       wb_congested = wb_congested_get_create(q->backing_dev_info,
                                               blkcg->css.id,
                                               GFP_NOWAIT | __GFP_NOWARN);
        if (!wb_congested) {
@@ -469,8 +469,8 @@ static int blkcg_reset_stats(struct cgroup_subsys_state *css,
 const char *blkg_dev_name(struct blkcg_gq *blkg)
 {
        /* some drivers (floppy) instantiate a queue w/o disk registered */
-       if (blkg->q->backing_dev_info.dev)
-               return dev_name(blkg->q->backing_dev_info.dev);
+       if (blkg->q->backing_dev_info->dev)
+               return dev_name(blkg->q->backing_dev_info->dev);
        return NULL;
 }
 EXPORT_SYMBOL_GPL(blkg_dev_name);
@@ -1079,10 +1079,8 @@ int blkcg_init_queue(struct request_queue *q)
        if (preloaded)
                radix_tree_preload_end();
 
-       if (IS_ERR(blkg)) {
-               blkg_free(new_blkg);
+       if (IS_ERR(blkg))
                return PTR_ERR(blkg);
-       }
 
        q->root_blkg = blkg;
        q->root_rl.blkg = blkg;
@@ -1223,7 +1221,10 @@ int blkcg_activate_policy(struct request_queue *q,
        if (blkcg_policy_enabled(q, pol))
                return 0;
 
-       blk_queue_bypass_start(q);
+       if (q->mq_ops)
+               blk_mq_freeze_queue(q);
+       else
+               blk_queue_bypass_start(q);
 pd_prealloc:
        if (!pd_prealloc) {
                pd_prealloc = pol->pd_alloc_fn(GFP_KERNEL, q->node);
@@ -1261,7 +1262,10 @@ pd_prealloc:
 
        spin_unlock_irq(q->queue_lock);
 out_bypass_end:
-       blk_queue_bypass_end(q);
+       if (q->mq_ops)
+               blk_mq_unfreeze_queue(q);
+       else
+               blk_queue_bypass_end(q);
        if (pd_prealloc)
                pol->pd_free_fn(pd_prealloc);
        return ret;
@@ -1284,7 +1288,11 @@ void blkcg_deactivate_policy(struct request_queue *q,
        if (!blkcg_policy_enabled(q, pol))
                return;
 
-       blk_queue_bypass_start(q);
+       if (q->mq_ops)
+               blk_mq_freeze_queue(q);
+       else
+               blk_queue_bypass_start(q);
+
        spin_lock_irq(q->queue_lock);
 
        __clear_bit(pol->plid, q->blkcg_pols);
@@ -1304,7 +1312,11 @@ void blkcg_deactivate_policy(struct request_queue *q,
        }
 
        spin_unlock_irq(q->queue_lock);
-       blk_queue_bypass_end(q);
+
+       if (q->mq_ops)
+               blk_mq_unfreeze_queue(q);
+       else
+               blk_queue_bypass_end(q);
 }
 EXPORT_SYMBOL_GPL(blkcg_deactivate_policy);
 
index 61ba08c58b649b54fdfbc4e06c7e1b11b015512a..b9e857f4afe85fcc1b19d00064e62e743c1c977f 100644 (file)
 #include <linux/ratelimit.h>
 #include <linux/pm_runtime.h>
 #include <linux/blk-cgroup.h>
+#include <linux/debugfs.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/block.h>
 
 #include "blk.h"
 #include "blk-mq.h"
+#include "blk-mq-sched.h"
 #include "blk-wbt.h"
 
+#ifdef CONFIG_DEBUG_FS
+struct dentry *blk_debugfs_root;
+#endif
+
 EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_remap);
 EXPORT_TRACEPOINT_SYMBOL_GPL(block_rq_remap);
 EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_complete);
@@ -74,7 +80,7 @@ static void blk_clear_congested(struct request_list *rl, int sync)
         * flip its congestion state for events on other blkcgs.
         */
        if (rl == &rl->q->root_rl)
-               clear_wb_congested(rl->q->backing_dev_info.wb.congested, sync);
+               clear_wb_congested(rl->q->backing_dev_info->wb.congested, sync);
 #endif
 }
 
@@ -85,7 +91,7 @@ static void blk_set_congested(struct request_list *rl, int sync)
 #else
        /* see blk_clear_congested() */
        if (rl == &rl->q->root_rl)
-               set_wb_congested(rl->q->backing_dev_info.wb.congested, sync);
+               set_wb_congested(rl->q->backing_dev_info->wb.congested, sync);
 #endif
 }
 
@@ -104,22 +110,6 @@ void blk_queue_congestion_threshold(struct request_queue *q)
        q->nr_congestion_off = nr;
 }
 
-/**
- * blk_get_backing_dev_info - get the address of a queue's backing_dev_info
- * @bdev:      device
- *
- * Locates the passed device's request queue and returns the address of its
- * backing_dev_info.  This function can only be called if @bdev is opened
- * and the return value is never NULL.
- */
-struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev)
-{
-       struct request_queue *q = bdev_get_queue(bdev);
-
-       return &q->backing_dev_info;
-}
-EXPORT_SYMBOL(blk_get_backing_dev_info);
-
 void blk_rq_init(struct request_queue *q, struct request *rq)
 {
        memset(rq, 0, sizeof(*rq));
@@ -131,9 +121,8 @@ void blk_rq_init(struct request_queue *q, struct request *rq)
        rq->__sector = (sector_t) -1;
        INIT_HLIST_NODE(&rq->hash);
        RB_CLEAR_NODE(&rq->rb_node);
-       rq->cmd = rq->__cmd;
-       rq->cmd_len = BLK_MAX_CDB;
        rq->tag = -1;
+       rq->internal_tag = -1;
        rq->start_time = jiffies;
        set_start_time_ns(rq);
        rq->part = NULL;
@@ -158,10 +147,8 @@ static void req_bio_endio(struct request *rq, struct bio *bio,
 
 void blk_dump_rq_flags(struct request *rq, char *msg)
 {
-       int bit;
-
-       printk(KERN_INFO "%s: dev %s: type=%x, flags=%llx\n", msg,
-               rq->rq_disk ? rq->rq_disk->disk_name : "?", rq->cmd_type,
+       printk(KERN_INFO "%s: dev %s: flags=%llx\n", msg,
+               rq->rq_disk ? rq->rq_disk->disk_name : "?",
                (unsigned long long) rq->cmd_flags);
 
        printk(KERN_INFO "  sector %llu, nr/cnr %u/%u\n",
@@ -169,13 +156,6 @@ void blk_dump_rq_flags(struct request *rq, char *msg)
               blk_rq_sectors(rq), blk_rq_cur_sectors(rq));
        printk(KERN_INFO "  bio %p, biotail %p, len %u\n",
               rq->bio, rq->biotail, blk_rq_bytes(rq));
-
-       if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
-               printk(KERN_INFO "  cdb: ");
-               for (bit = 0; bit < BLK_MAX_CDB; bit++)
-                       printk("%02x ", rq->cmd[bit]);
-               printk("\n");
-       }
 }
 EXPORT_SYMBOL(blk_dump_rq_flags);
 
@@ -525,12 +505,14 @@ void blk_set_queue_dying(struct request_queue *q)
        else {
                struct request_list *rl;
 
+               spin_lock_irq(q->queue_lock);
                blk_queue_for_each_rl(rl, q) {
                        if (rl->rq_pool) {
                                wake_up(&rl->wait[BLK_RW_SYNC]);
                                wake_up(&rl->wait[BLK_RW_ASYNC]);
                        }
                }
+               spin_unlock_irq(q->queue_lock);
        }
 }
 EXPORT_SYMBOL_GPL(blk_set_queue_dying);
@@ -584,7 +566,7 @@ void blk_cleanup_queue(struct request_queue *q)
        blk_flush_integrity();
 
        /* @q won't process any more request, flush async actions */
-       del_timer_sync(&q->backing_dev_info.laptop_mode_wb_timer);
+       del_timer_sync(&q->backing_dev_info->laptop_mode_wb_timer);
        blk_sync_queue(q);
 
        if (q->mq_ops)
@@ -596,7 +578,8 @@ void blk_cleanup_queue(struct request_queue *q)
                q->queue_lock = &q->__queue_lock;
        spin_unlock_irq(lock);
 
-       bdi_unregister(&q->backing_dev_info);
+       bdi_unregister(q->backing_dev_info);
+       put_disk_devt(q->disk_devt);
 
        /* @q is and will stay empty, shutdown and put */
        blk_put_queue(q);
@@ -604,17 +587,41 @@ void blk_cleanup_queue(struct request_queue *q)
 EXPORT_SYMBOL(blk_cleanup_queue);
 
 /* Allocate memory local to the request queue */
-static void *alloc_request_struct(gfp_t gfp_mask, void *data)
+static void *alloc_request_simple(gfp_t gfp_mask, void *data)
 {
-       int nid = (int)(long)data;
-       return kmem_cache_alloc_node(request_cachep, gfp_mask, nid);
+       struct request_queue *q = data;
+
+       return kmem_cache_alloc_node(request_cachep, gfp_mask, q->node);
 }
 
-static void free_request_struct(void *element, void *unused)
+static void free_request_simple(void *element, void *data)
 {
        kmem_cache_free(request_cachep, element);
 }
 
+static void *alloc_request_size(gfp_t gfp_mask, void *data)
+{
+       struct request_queue *q = data;
+       struct request *rq;
+
+       rq = kmalloc_node(sizeof(struct request) + q->cmd_size, gfp_mask,
+                       q->node);
+       if (rq && q->init_rq_fn && q->init_rq_fn(q, rq, gfp_mask) < 0) {
+               kfree(rq);
+               rq = NULL;
+       }
+       return rq;
+}
+
+static void free_request_size(void *element, void *data)
+{
+       struct request_queue *q = data;
+
+       if (q->exit_rq_fn)
+               q->exit_rq_fn(q, element);
+       kfree(element);
+}
+
 int blk_init_rl(struct request_list *rl, struct request_queue *q,
                gfp_t gfp_mask)
 {
@@ -627,10 +634,15 @@ int blk_init_rl(struct request_list *rl, struct request_queue *q,
        init_waitqueue_head(&rl->wait[BLK_RW_SYNC]);
        init_waitqueue_head(&rl->wait[BLK_RW_ASYNC]);
 
-       rl->rq_pool = mempool_create_node(BLKDEV_MIN_RQ, alloc_request_struct,
-                                         free_request_struct,
-                                         (void *)(long)q->node, gfp_mask,
-                                         q->node);
+       if (q->cmd_size) {
+               rl->rq_pool = mempool_create_node(BLKDEV_MIN_RQ,
+                               alloc_request_size, free_request_size,
+                               q, gfp_mask, q->node);
+       } else {
+               rl->rq_pool = mempool_create_node(BLKDEV_MIN_RQ,
+                               alloc_request_simple, free_request_simple,
+                               q, gfp_mask, q->node);
+       }
        if (!rl->rq_pool)
                return -ENOMEM;
 
@@ -693,7 +705,6 @@ static void blk_rq_timed_out_timer(unsigned long data)
 struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
 {
        struct request_queue *q;
-       int err;
 
        q = kmem_cache_alloc_node(blk_requestq_cachep,
                                gfp_mask | __GFP_ZERO, node_id);
@@ -708,17 +719,17 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
        if (!q->bio_split)
                goto fail_id;
 
-       q->backing_dev_info.ra_pages =
+       q->backing_dev_info = bdi_alloc_node(gfp_mask, node_id);
+       if (!q->backing_dev_info)
+               goto fail_split;
+
+       q->backing_dev_info->ra_pages =
                        (VM_MAX_READAHEAD * 1024) / PAGE_SIZE;
-       q->backing_dev_info.capabilities = BDI_CAP_CGROUP_WRITEBACK;
-       q->backing_dev_info.name = "block";
+       q->backing_dev_info->capabilities = BDI_CAP_CGROUP_WRITEBACK;
+       q->backing_dev_info->name = "block";
        q->node = node_id;
 
-       err = bdi_init(&q->backing_dev_info);
-       if (err)
-               goto fail_split;
-
-       setup_timer(&q->backing_dev_info.laptop_mode_wb_timer,
+       setup_timer(&q->backing_dev_info->laptop_mode_wb_timer,
                    laptop_mode_timer_fn, (unsigned long) q);
        setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q);
        INIT_LIST_HEAD(&q->queue_head);
@@ -768,7 +779,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
 fail_ref:
        percpu_ref_exit(&q->q_usage_counter);
 fail_bdi:
-       bdi_destroy(&q->backing_dev_info);
+       bdi_put(q->backing_dev_info);
 fail_split:
        bioset_free(q->bio_split);
 fail_id:
@@ -821,15 +832,19 @@ EXPORT_SYMBOL(blk_init_queue);
 struct request_queue *
 blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id)
 {
-       struct request_queue *uninit_q, *q;
+       struct request_queue *q;
 
-       uninit_q = blk_alloc_queue_node(GFP_KERNEL, node_id);
-       if (!uninit_q)
+       q = blk_alloc_queue_node(GFP_KERNEL, node_id);
+       if (!q)
                return NULL;
 
-       q = blk_init_allocated_queue(uninit_q, rfn, lock);
-       if (!q)
-               blk_cleanup_queue(uninit_q);
+       q->request_fn = rfn;
+       if (lock)
+               q->queue_lock = lock;
+       if (blk_init_allocated_queue(q) < 0) {
+               blk_cleanup_queue(q);
+               return NULL;
+       }
 
        return q;
 }
@@ -837,30 +852,22 @@ EXPORT_SYMBOL(blk_init_queue_node);
 
 static blk_qc_t blk_queue_bio(struct request_queue *q, struct bio *bio);
 
-struct request_queue *
-blk_init_allocated_queue(struct request_queue *q, request_fn_proc *rfn,
-                        spinlock_t *lock)
-{
-       if (!q)
-               return NULL;
 
-       q->fq = blk_alloc_flush_queue(q, NUMA_NO_NODE, 0);
+int blk_init_allocated_queue(struct request_queue *q)
+{
+       q->fq = blk_alloc_flush_queue(q, NUMA_NO_NODE, q->cmd_size);
        if (!q->fq)
-               return NULL;
+               return -ENOMEM;
+
+       if (q->init_rq_fn && q->init_rq_fn(q, q->fq->flush_rq, GFP_KERNEL))
+               goto out_free_flush_queue;
 
        if (blk_init_rl(&q->root_rl, q, GFP_KERNEL))
-               goto fail;
+               goto out_exit_flush_rq;
 
        INIT_WORK(&q->timeout_work, blk_timeout_work);
-       q->request_fn           = rfn;
-       q->prep_rq_fn           = NULL;
-       q->unprep_rq_fn         = NULL;
        q->queue_flags          |= QUEUE_FLAG_DEFAULT;
 
-       /* Override internal queue lock with supplied lock pointer */
-       if (lock)
-               q->queue_lock           = lock;
-
        /*
         * This also sets hw/phys segments, boundary and size
         */
@@ -874,17 +881,19 @@ blk_init_allocated_queue(struct request_queue *q, request_fn_proc *rfn,
        /* init elevator */
        if (elevator_init(q, NULL)) {
                mutex_unlock(&q->sysfs_lock);
-               goto fail;
+               goto out_exit_flush_rq;
        }
 
        mutex_unlock(&q->sysfs_lock);
+       return 0;
 
-       return q;
-
-fail:
+out_exit_flush_rq:
+       if (q->exit_rq_fn)
+               q->exit_rq_fn(q, q->fq->flush_rq);
+out_free_flush_queue:
        blk_free_flush_queue(q->fq);
        wbt_exit(q);
-       return NULL;
+       return -ENOMEM;
 }
 EXPORT_SYMBOL(blk_init_allocated_queue);
 
@@ -1020,41 +1029,6 @@ int blk_update_nr_requests(struct request_queue *q, unsigned int nr)
        return 0;
 }
 
-/*
- * Determine if elevator data should be initialized when allocating the
- * request associated with @bio.
- */
-static bool blk_rq_should_init_elevator(struct bio *bio)
-{
-       if (!bio)
-               return true;
-
-       /*
-        * Flush requests do not use the elevator so skip initialization.
-        * This allows a request to share the flush and elevator data.
-        */
-       if (bio->bi_opf & (REQ_PREFLUSH | REQ_FUA))
-               return false;
-
-       return true;
-}
-
-/**
- * rq_ioc - determine io_context for request allocation
- * @bio: request being allocated is for this bio (can be %NULL)
- *
- * Determine io_context to use for request allocation for @bio.  May return
- * %NULL if %current->io_context doesn't exist.
- */
-static struct io_context *rq_ioc(struct bio *bio)
-{
-#ifdef CONFIG_BLK_CGROUP
-       if (bio && bio->bi_ioc)
-               return bio->bi_ioc;
-#endif
-       return current->io_context;
-}
-
 /**
  * __get_request - get a free request
  * @rl: request list to allocate from
@@ -1133,10 +1107,13 @@ static struct request *__get_request(struct request_list *rl, unsigned int op,
         * request is freed.  This guarantees icq's won't be destroyed and
         * makes creating new ones safe.
         *
+        * Flush requests do not use the elevator so skip initialization.
+        * This allows a request to share the flush and elevator data.
+        *
         * Also, lookup icq while holding queue_lock.  If it doesn't exist,
         * it will be created after releasing queue_lock.
         */
-       if (blk_rq_should_init_elevator(bio) && !blk_queue_bypass(q)) {
+       if (!op_is_flush(op) && !blk_queue_bypass(q)) {
                rq_flags |= RQF_ELVPRIV;
                q->nr_rqs_elvpriv++;
                if (et->icq_cache && ioc)
@@ -1196,7 +1173,7 @@ fail_elvpriv:
         * disturb iosched and blkcg but weird is bettern than dead.
         */
        printk_ratelimited(KERN_WARNING "%s: dev %s: request aux data allocation failed, iosched may be disturbed\n",
-                          __func__, dev_name(q->backing_dev_info.dev));
+                          __func__, dev_name(q->backing_dev_info->dev));
 
        rq->rq_flags &= ~RQF_ELVPRIV;
        rq->elv.icq = NULL;
@@ -1290,8 +1267,6 @@ static struct request *blk_old_get_request(struct request_queue *q, int rw,
 {
        struct request *rq;
 
-       BUG_ON(rw != READ && rw != WRITE);
-
        /* create ioc upfront */
        create_io_context(gfp_mask, q->node);
 
@@ -1320,18 +1295,6 @@ struct request *blk_get_request(struct request_queue *q, int rw, gfp_t gfp_mask)
 }
 EXPORT_SYMBOL(blk_get_request);
 
-/**
- * blk_rq_set_block_pc - initialize a request to type BLOCK_PC
- * @rq:                request to be initialized
- *
- */
-void blk_rq_set_block_pc(struct request *rq)
-{
-       rq->cmd_type = REQ_TYPE_BLOCK_PC;
-       memset(rq->__cmd, 0, sizeof(rq->__cmd));
-}
-EXPORT_SYMBOL(blk_rq_set_block_pc);
-
 /**
  * blk_requeue_request - put a request back on queue
  * @q:         request queue where request should be inserted
@@ -1522,6 +1485,30 @@ bool bio_attempt_front_merge(struct request_queue *q, struct request *req,
        return true;
 }
 
+bool bio_attempt_discard_merge(struct request_queue *q, struct request *req,
+               struct bio *bio)
+{
+       unsigned short segments = blk_rq_nr_discard_segments(req);
+
+       if (segments >= queue_max_discard_segments(q))
+               goto no_merge;
+       if (blk_rq_sectors(req) + bio_sectors(bio) >
+           blk_rq_get_max_sectors(req, blk_rq_pos(req)))
+               goto no_merge;
+
+       req->biotail->bi_next = bio;
+       req->biotail = bio;
+       req->__data_len += bio->bi_iter.bi_size;
+       req->ioprio = ioprio_best(req->ioprio, bio_prio(bio));
+       req->nr_phys_segments = segments + 1;
+
+       blk_account_io_start(req, false);
+       return true;
+no_merge:
+       req_set_nomerge(q, req);
+       return false;
+}
+
 /**
  * blk_attempt_plug_merge - try to merge with %current's plugged list
  * @q: request_queue new bio is being queued at
@@ -1550,12 +1537,11 @@ bool blk_attempt_plug_merge(struct request_queue *q, struct bio *bio,
 {
        struct blk_plug *plug;
        struct request *rq;
-       bool ret = false;
        struct list_head *plug_list;
 
        plug = current->plug;
        if (!plug)
-               goto out;
+               return false;
        *request_count = 0;
 
        if (q->mq_ops)
@@ -1564,7 +1550,7 @@ bool blk_attempt_plug_merge(struct request_queue *q, struct bio *bio,
                plug_list = &plug->list;
 
        list_for_each_entry_reverse(rq, plug_list, queuelist) {
-               int el_ret;
+               bool merged = false;
 
                if (rq->q == q) {
                        (*request_count)++;
@@ -1580,19 +1566,25 @@ bool blk_attempt_plug_merge(struct request_queue *q, struct bio *bio,
                if (rq->q != q || !blk_rq_merge_ok(rq, bio))
                        continue;
 
-               el_ret = blk_try_merge(rq, bio);
-               if (el_ret == ELEVATOR_BACK_MERGE) {
-                       ret = bio_attempt_back_merge(q, rq, bio);
-                       if (ret)
-                               break;
-               } else if (el_ret == ELEVATOR_FRONT_MERGE) {
-                       ret = bio_attempt_front_merge(q, rq, bio);
-                       if (ret)
-                               break;
+               switch (blk_try_merge(rq, bio)) {
+               case ELEVATOR_BACK_MERGE:
+                       merged = bio_attempt_back_merge(q, rq, bio);
+                       break;
+               case ELEVATOR_FRONT_MERGE:
+                       merged = bio_attempt_front_merge(q, rq, bio);
+                       break;
+               case ELEVATOR_DISCARD_MERGE:
+                       merged = bio_attempt_discard_merge(q, rq, bio);
+                       break;
+               default:
+                       break;
                }
+
+               if (merged)
+                       return true;
        }
-out:
-       return ret;
+
+       return false;
 }
 
 unsigned int blk_plug_queued_count(struct request_queue *q)
@@ -1621,7 +1613,6 @@ out:
 
 void init_request_from_bio(struct request *req, struct bio *bio)
 {
-       req->cmd_type = REQ_TYPE_FS;
        if (bio->bi_opf & REQ_RAHEAD)
                req->cmd_flags |= REQ_FAILFAST_MASK;
 
@@ -1635,8 +1626,8 @@ void init_request_from_bio(struct request *req, struct bio *bio)
 static blk_qc_t blk_queue_bio(struct request_queue *q, struct bio *bio)
 {
        struct blk_plug *plug;
-       int el_ret, where = ELEVATOR_INSERT_SORT;
-       struct request *req;
+       int where = ELEVATOR_INSERT_SORT;
+       struct request *req, *free;
        unsigned int request_count = 0;
        unsigned int wb_acct;
 
@@ -1655,7 +1646,7 @@ static blk_qc_t blk_queue_bio(struct request_queue *q, struct bio *bio)
                return BLK_QC_T_NONE;
        }
 
-       if (bio->bi_opf & (REQ_PREFLUSH | REQ_FUA)) {
+       if (op_is_flush(bio->bi_opf)) {
                spin_lock_irq(q->queue_lock);
                where = ELEVATOR_INSERT_FLUSH;
                goto get_rq;
@@ -1673,21 +1664,29 @@ static blk_qc_t blk_queue_bio(struct request_queue *q, struct bio *bio)
 
        spin_lock_irq(q->queue_lock);
 
-       el_ret = elv_merge(q, &req, bio);
-       if (el_ret == ELEVATOR_BACK_MERGE) {
-               if (bio_attempt_back_merge(q, req, bio)) {
-                       elv_bio_merged(q, req, bio);
-                       if (!attempt_back_merge(q, req))
-                               elv_merged_request(q, req, el_ret);
-                       goto out_unlock;
-               }
-       } else if (el_ret == ELEVATOR_FRONT_MERGE) {
-               if (bio_attempt_front_merge(q, req, bio)) {
-                       elv_bio_merged(q, req, bio);
-                       if (!attempt_front_merge(q, req))
-                               elv_merged_request(q, req, el_ret);
-                       goto out_unlock;
-               }
+       switch (elv_merge(q, &req, bio)) {
+       case ELEVATOR_BACK_MERGE:
+               if (!bio_attempt_back_merge(q, req, bio))
+                       break;
+               elv_bio_merged(q, req, bio);
+               free = attempt_back_merge(q, req);
+               if (free)
+                       __blk_put_request(q, free);
+               else
+                       elv_merged_request(q, req, ELEVATOR_BACK_MERGE);
+               goto out_unlock;
+       case ELEVATOR_FRONT_MERGE:
+               if (!bio_attempt_front_merge(q, req, bio))
+                       break;
+               elv_bio_merged(q, req, bio);
+               free = attempt_front_merge(q, req);
+               if (free)
+                       __blk_put_request(q, free);
+               else
+                       elv_merged_request(q, req, ELEVATOR_FRONT_MERGE);
+               goto out_unlock;
+       default:
+               break;
        }
 
 get_rq:
@@ -1894,7 +1893,7 @@ generic_make_request_checks(struct bio *bio)
         * drivers without flush support don't have to worry
         * about them.
         */
-       if ((bio->bi_opf & (REQ_PREFLUSH | REQ_FUA)) &&
+       if (op_is_flush(bio->bi_opf) &&
            !test_bit(QUEUE_FLAG_WC, &q->queue_flags)) {
                bio->bi_opf &= ~(REQ_PREFLUSH | REQ_FUA);
                if (!nr_sectors) {
@@ -2143,7 +2142,7 @@ int blk_insert_cloned_request(struct request_queue *q, struct request *rq)
        if (q->mq_ops) {
                if (blk_queue_io_stat(q))
                        blk_account_io_start(rq, true);
-               blk_mq_insert_request(rq, false, true, false);
+               blk_mq_sched_insert_request(rq, false, true, false, false);
                return 0;
        }
 
@@ -2159,7 +2158,7 @@ int blk_insert_cloned_request(struct request_queue *q, struct request *rq)
         */
        BUG_ON(blk_queued_rq(rq));
 
-       if (rq->cmd_flags & (REQ_PREFLUSH | REQ_FUA))
+       if (op_is_flush(rq->cmd_flags))
                where = ELEVATOR_INSERT_FLUSH;
 
        add_acct_request(q, rq, where);
@@ -2464,14 +2463,6 @@ void blk_start_request(struct request *req)
                wbt_issue(req->q->rq_wb, &req->issue_stat);
        }
 
-       /*
-        * We are now handing the request to the hardware, initialize
-        * resid_len to full count and add the timeout handler.
-        */
-       req->resid_len = blk_rq_bytes(req);
-       if (unlikely(blk_bidi_rq(req)))
-               req->next_rq->resid_len = blk_rq_bytes(req->next_rq);
-
        BUG_ON(test_bit(REQ_ATOM_COMPLETE, &req->atomic_flags));
        blk_add_timer(req);
 }
@@ -2542,10 +2533,10 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes)
         * TODO: tj: This is too subtle.  It would be better to let
         * low level drivers do what they see fit.
         */
-       if (req->cmd_type == REQ_TYPE_FS)
+       if (!blk_rq_is_passthrough(req))
                req->errors = 0;
 
-       if (error && req->cmd_type == REQ_TYPE_FS &&
+       if (error && !blk_rq_is_passthrough(req) &&
            !(req->rq_flags & RQF_QUIET)) {
                char *error_type;
 
@@ -2617,7 +2608,7 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes)
        req->__data_len -= total_bytes;
 
        /* update sector only for requests with clear definition of sector */
-       if (req->cmd_type == REQ_TYPE_FS)
+       if (!blk_rq_is_passthrough(req))
                req->__sector += total_bytes >> 9;
 
        /* mixed attributes always follow the first bio */
@@ -2695,8 +2686,8 @@ void blk_finish_request(struct request *req, int error)
 
        BUG_ON(blk_queued_rq(req));
 
-       if (unlikely(laptop_mode) && req->cmd_type == REQ_TYPE_FS)
-               laptop_io_completion(&req->q->backing_dev_info);
+       if (unlikely(laptop_mode) && !blk_rq_is_passthrough(req))
+               laptop_io_completion(req->q->backing_dev_info);
 
        blk_delete_timer(req);
 
@@ -3019,8 +3010,6 @@ EXPORT_SYMBOL_GPL(blk_rq_unprep_clone);
 static void __blk_rq_prep_clone(struct request *dst, struct request *src)
 {
        dst->cpu = src->cpu;
-       dst->cmd_flags = src->cmd_flags | REQ_NOMERGE;
-       dst->cmd_type = src->cmd_type;
        dst->__sector = blk_rq_pos(src);
        dst->__data_len = blk_rq_bytes(src);
        dst->nr_phys_segments = src->nr_phys_segments;
@@ -3270,7 +3259,7 @@ void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule)
                /*
                 * rq is already accounted, so use raw insert
                 */
-               if (rq->cmd_flags & (REQ_PREFLUSH | REQ_FUA))
+               if (op_is_flush(rq->cmd_flags))
                        __elv_add_request(q, rq, ELEVATOR_INSERT_FLUSH);
                else
                        __elv_add_request(q, rq, ELEVATOR_INSERT_SORT_MERGE);
@@ -3496,5 +3485,9 @@ int __init blk_dev_init(void)
        blk_requestq_cachep = kmem_cache_create("request_queue",
                        sizeof(struct request_queue), 0, SLAB_PANIC, NULL);
 
+#ifdef CONFIG_DEBUG_FS
+       blk_debugfs_root = debugfs_create_dir("block", NULL);
+#endif
+
        return 0;
 }
index 3ecb00a6cf45dd5463331a18dd124128a7eec94d..8cd0e9bc8dc89b7bde4e4ab56aa7752677618f72 100644 (file)
@@ -9,11 +9,7 @@
 #include <linux/sched/sysctl.h>
 
 #include "blk.h"
-
-/*
- * for max sense size
- */
-#include <scsi/scsi_cmnd.h>
+#include "blk-mq-sched.h"
 
 /**
  * blk_end_sync_rq - executes a completion event on a request
@@ -55,7 +51,7 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
        int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK;
 
        WARN_ON(irqs_disabled());
-       WARN_ON(rq->cmd_type == REQ_TYPE_FS);
+       WARN_ON(!blk_rq_is_passthrough(rq));
 
        rq->rq_disk = bd_disk;
        rq->end_io = done;
@@ -65,7 +61,7 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
         * be reused after dying flag is set
         */
        if (q->mq_ops) {
-               blk_mq_insert_request(rq, at_head, true, false);
+               blk_mq_sched_insert_request(rq, at_head, true, false, false);
                return;
        }
 
@@ -100,16 +96,9 @@ int blk_execute_rq(struct request_queue *q, struct gendisk *bd_disk,
                   struct request *rq, int at_head)
 {
        DECLARE_COMPLETION_ONSTACK(wait);
-       char sense[SCSI_SENSE_BUFFERSIZE];
        int err = 0;
        unsigned long hang_check;
 
-       if (!rq->sense) {
-               memset(sense, 0, sizeof(sense));
-               rq->sense = sense;
-               rq->sense_len = 0;
-       }
-
        rq->end_io_data = &wait;
        blk_execute_rq_nowait(q, bd_disk, rq, at_head, blk_end_sync_rq);
 
@@ -123,11 +112,6 @@ int blk_execute_rq(struct request_queue *q, struct gendisk *bd_disk,
        if (rq->errors)
                err = -EIO;
 
-       if (rq->sense == sense) {
-               rq->sense = NULL;
-               rq->sense_len = 0;
-       }
-
        return err;
 }
 EXPORT_SYMBOL(blk_execute_rq);
index 20b7c7a02f1cbdfe5a63c5918d3abd356bd4265b..0d5a9c1da1fc71db5706926e69e2a22b7491eea9 100644 (file)
@@ -74,6 +74,7 @@
 #include "blk.h"
 #include "blk-mq.h"
 #include "blk-mq-tag.h"
+#include "blk-mq-sched.h"
 
 /* FLUSH/FUA sequences */
 enum {
@@ -296,8 +297,14 @@ static bool blk_kick_flush(struct request_queue *q, struct blk_flush_queue *fq)
        if (fq->flush_pending_idx != fq->flush_running_idx || list_empty(pending))
                return false;
 
-       /* C2 and C3 */
+       /* C2 and C3
+        *
+        * For blk-mq + scheduling, we can risk having all driver tags
+        * assigned to empty flushes, and we deadlock if we are expecting
+        * other requests to make progress. Don't defer for that case.
+        */
        if (!list_empty(&fq->flush_data_in_flight) &&
+           !(q->mq_ops && q->elevator) &&
            time_before(jiffies,
                        fq->flush_pending_since + FLUSH_PENDING_TIMEOUT))
                return false;
@@ -326,7 +333,6 @@ static bool blk_kick_flush(struct request_queue *q, struct blk_flush_queue *fq)
                blk_mq_tag_set_rq(hctx, first_rq->tag, flush_rq);
        }
 
-       flush_rq->cmd_type = REQ_TYPE_FS;
        flush_rq->cmd_flags = REQ_OP_FLUSH | REQ_PREFLUSH;
        flush_rq->rq_flags |= RQF_FLUSH_SEQ;
        flush_rq->rq_disk = first_rq->rq_disk;
@@ -391,9 +397,10 @@ static void mq_flush_data_end_io(struct request *rq, int error)
         * the comment in flush_end_io().
         */
        spin_lock_irqsave(&fq->mq_flush_lock, flags);
-       if (blk_flush_complete_seq(rq, fq, REQ_FSEQ_DATA, error))
-               blk_mq_run_hw_queue(hctx, true);
+       blk_flush_complete_seq(rq, fq, REQ_FSEQ_DATA, error);
        spin_unlock_irqrestore(&fq->mq_flush_lock, flags);
+
+       blk_mq_run_hw_queue(hctx, true);
 }
 
 /**
@@ -453,9 +460,9 @@ void blk_insert_flush(struct request *rq)
         */
        if ((policy & REQ_FSEQ_DATA) &&
            !(policy & (REQ_FSEQ_PREFLUSH | REQ_FSEQ_POSTFLUSH))) {
-               if (q->mq_ops) {
-                       blk_mq_insert_request(rq, false, true, false);
-               else
+               if (q->mq_ops)
+                       blk_mq_sched_insert_request(rq, false, true, false, false);
+               else
                        list_add_tail(&rq->queuelist, &q->queue_head);
                return;
        }
@@ -545,11 +552,10 @@ struct blk_flush_queue *blk_alloc_flush_queue(struct request_queue *q,
        if (!fq)
                goto fail;
 
-       if (q->mq_ops) {
+       if (q->mq_ops)
                spin_lock_init(&fq->mq_flush_lock);
-               rq_sz = round_up(rq_sz + cmd_size, cache_line_size());
-       }
 
+       rq_sz = round_up(rq_sz + cmd_size, cache_line_size());
        fq->flush_rq = kzalloc_node(rq_sz, GFP_KERNEL, node);
        if (!fq->flush_rq)
                goto fail_rq;
index d69c5c79f98e71059827265531aba75a63458f74..9f0ff5ba4f84d606ff49e96711d4cc78c3922c0d 100644 (file)
@@ -443,10 +443,10 @@ void blk_integrity_revalidate(struct gendisk *disk)
                return;
 
        if (bi->profile)
-               disk->queue->backing_dev_info.capabilities |=
+               disk->queue->backing_dev_info->capabilities |=
                        BDI_CAP_STABLE_WRITES;
        else
-               disk->queue->backing_dev_info.capabilities &=
+               disk->queue->backing_dev_info->capabilities &=
                        ~BDI_CAP_STABLE_WRITES;
 }
 
index 381cb50a673c33ed86f6f5d597331137f2881ce3..b12f9c87b4c31cd76310dc56f8ec95c23086c7e0 100644 (file)
@@ -35,7 +35,10 @@ static void icq_free_icq_rcu(struct rcu_head *head)
        kmem_cache_free(icq->__rcu_icq_cache, icq);
 }
 
-/* Exit an icq. Called with both ioc and q locked. */
+/*
+ * Exit an icq. Called with both ioc and q locked for sq, only ioc locked for
+ * mq.
+ */
 static void ioc_exit_icq(struct io_cq *icq)
 {
        struct elevator_type *et = icq->q->elevator->type;
@@ -43,8 +46,10 @@ static void ioc_exit_icq(struct io_cq *icq)
        if (icq->flags & ICQ_EXITED)
                return;
 
-       if (et->ops.elevator_exit_icq_fn)
-               et->ops.elevator_exit_icq_fn(icq);
+       if (et->uses_mq && et->ops.mq.exit_icq)
+               et->ops.mq.exit_icq(icq);
+       else if (!et->uses_mq && et->ops.sq.elevator_exit_icq_fn)
+               et->ops.sq.elevator_exit_icq_fn(icq);
 
        icq->flags |= ICQ_EXITED;
 }
@@ -164,6 +169,7 @@ EXPORT_SYMBOL(put_io_context);
  */
 void put_io_context_active(struct io_context *ioc)
 {
+       struct elevator_type *et;
        unsigned long flags;
        struct io_cq *icq;
 
@@ -182,13 +188,19 @@ retry:
        hlist_for_each_entry(icq, &ioc->icq_list, ioc_node) {
                if (icq->flags & ICQ_EXITED)
                        continue;
-               if (spin_trylock(icq->q->queue_lock)) {
+
+               et = icq->q->elevator->type;
+               if (et->uses_mq) {
                        ioc_exit_icq(icq);
-                       spin_unlock(icq->q->queue_lock);
                } else {
-                       spin_unlock_irqrestore(&ioc->lock, flags);
-                       cpu_relax();
-                       goto retry;
+                       if (spin_trylock(icq->q->queue_lock)) {
+                               ioc_exit_icq(icq);
+                               spin_unlock(icq->q->queue_lock);
+                       } else {
+                               spin_unlock_irqrestore(&ioc->lock, flags);
+                               cpu_relax();
+                               goto retry;
+                       }
                }
        }
        spin_unlock_irqrestore(&ioc->lock, flags);
@@ -383,8 +395,10 @@ struct io_cq *ioc_create_icq(struct io_context *ioc, struct request_queue *q,
        if (likely(!radix_tree_insert(&ioc->icq_tree, q->id, icq))) {
                hlist_add_head(&icq->ioc_node, &ioc->icq_list);
                list_add(&icq->q_node, &q->icq_list);
-               if (et->ops.elevator_init_icq_fn)
-                       et->ops.elevator_init_icq_fn(icq);
+               if (et->uses_mq && et->ops.mq.init_icq)
+                       et->ops.mq.init_icq(icq);
+               else if (!et->uses_mq && et->ops.sq.elevator_init_icq_fn)
+                       et->ops.sq.elevator_init_icq_fn(icq);
        } else {
                kmem_cache_free(et->icq_cache, icq);
                icq = ioc_lookup_icq(ioc, q);
index 0acb6640ead708ef8450a32cb7ff6b0aee350515..2f18c2a0be1b22680472972c03f93b598dc7cb12 100644 (file)
@@ -16,8 +16,6 @@
 int blk_rq_append_bio(struct request *rq, struct bio *bio)
 {
        if (!rq->bio) {
-               rq->cmd_flags &= REQ_OP_MASK;
-               rq->cmd_flags |= (bio->bi_opf & REQ_OP_MASK);
                blk_rq_bio_prep(rq->q, rq, bio);
        } else {
                if (!ll_back_merge_fn(rq->q, rq, bio))
@@ -62,6 +60,9 @@ static int __blk_rq_map_user_iov(struct request *rq,
        if (IS_ERR(bio))
                return PTR_ERR(bio);
 
+       bio->bi_opf &= ~REQ_OP_MASK;
+       bio->bi_opf |= req_op(rq);
+
        if (map_data && map_data->null_mapped)
                bio_set_flag(bio, BIO_NULL_MAPPED);
 
@@ -90,7 +91,7 @@ static int __blk_rq_map_user_iov(struct request *rq,
 }
 
 /**
- * blk_rq_map_user_iov - map user data to a request, for REQ_TYPE_BLOCK_PC usage
+ * blk_rq_map_user_iov - map user data to a request, for passthrough requests
  * @q:         request queue where request should be inserted
  * @rq:                request to map data to
  * @map_data:   pointer to the rq_map_data holding pages (if necessary)
@@ -199,7 +200,7 @@ int blk_rq_unmap_user(struct bio *bio)
 EXPORT_SYMBOL(blk_rq_unmap_user);
 
 /**
- * blk_rq_map_kern - map kernel data to a request, for REQ_TYPE_BLOCK_PC usage
+ * blk_rq_map_kern - map kernel data to a request, for passthrough requests
  * @q:         request queue where request should be inserted
  * @rq:                request to fill
  * @kbuf:      the kernel buffer
@@ -234,8 +235,8 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf,
        if (IS_ERR(bio))
                return PTR_ERR(bio);
 
-       if (!reading)
-               bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
+       bio->bi_opf &= ~REQ_OP_MASK;
+       bio->bi_opf |= req_op(rq);
 
        if (do_copy)
                rq->rq_flags |= RQF_COPY_USER;
index 182398cb152490d96b7e48c4fd74f11657c8e665..2afa262425d102e5c1500912f3b6d77525754566 100644 (file)
@@ -482,13 +482,6 @@ int blk_rq_map_sg(struct request_queue *q, struct request *rq,
 }
 EXPORT_SYMBOL(blk_rq_map_sg);
 
-static void req_set_nomerge(struct request_queue *q, struct request *req)
-{
-       req->cmd_flags |= REQ_NOMERGE;
-       if (req == q->last_merge)
-               q->last_merge = NULL;
-}
-
 static inline int ll_new_hw_segment(struct request_queue *q,
                                    struct request *req,
                                    struct bio *bio)
@@ -659,31 +652,32 @@ static void blk_account_io_merge(struct request *req)
 }
 
 /*
- * Has to be called with the request spinlock acquired
+ * For non-mq, this has to be called with the request spinlock acquired.
+ * For mq with scheduling, the appropriate queue wide lock should be held.
  */
-static int attempt_merge(struct request_queue *q, struct request *req,
-                         struct request *next)
+static struct request *attempt_merge(struct request_queue *q,
+                                    struct request *req, struct request *next)
 {
        if (!rq_mergeable(req) || !rq_mergeable(next))
-               return 0;
+               return NULL;
 
        if (req_op(req) != req_op(next))
-               return 0;
+               return NULL;
 
        /*
         * not contiguous
         */
        if (blk_rq_pos(req) + blk_rq_sectors(req) != blk_rq_pos(next))
-               return 0;
+               return NULL;
 
        if (rq_data_dir(req) != rq_data_dir(next)
            || req->rq_disk != next->rq_disk
            || req_no_special_merge(next))
-               return 0;
+               return NULL;
 
        if (req_op(req) == REQ_OP_WRITE_SAME &&
            !blk_write_same_mergeable(req->bio, next->bio))
-               return 0;
+               return NULL;
 
        /*
         * If we are allowed to merge, then append bio list
@@ -692,7 +686,7 @@ static int attempt_merge(struct request_queue *q, struct request *req,
         * counts here.
         */
        if (!ll_merge_requests_fn(q, req, next))
-               return 0;
+               return NULL;
 
        /*
         * If failfast settings disagree or any of the two is already
@@ -732,42 +726,51 @@ static int attempt_merge(struct request_queue *q, struct request *req,
        if (blk_rq_cpu_valid(next))
                req->cpu = next->cpu;
 
-       /* owner-ship of bio passed from next to req */
+       /*
+        * ownership of bio passed from next to req, return 'next' for
+        * the caller to free
+        */
        next->bio = NULL;
-       __blk_put_request(q, next);
-       return 1;
+       return next;
 }
 
-int attempt_back_merge(struct request_queue *q, struct request *rq)
+struct request *attempt_back_merge(struct request_queue *q, struct request *rq)
 {
        struct request *next = elv_latter_request(q, rq);
 
        if (next)
                return attempt_merge(q, rq, next);
 
-       return 0;
+       return NULL;
 }
 
-int attempt_front_merge(struct request_queue *q, struct request *rq)
+struct request *attempt_front_merge(struct request_queue *q, struct request *rq)
 {
        struct request *prev = elv_former_request(q, rq);
 
        if (prev)
                return attempt_merge(q, prev, rq);
 
-       return 0;
+       return NULL;
 }
 
 int blk_attempt_req_merge(struct request_queue *q, struct request *rq,
                          struct request *next)
 {
        struct elevator_queue *e = q->elevator;
+       struct request *free;
 
-       if (e->type->ops.elevator_allow_rq_merge_fn)
-               if (!e->type->ops.elevator_allow_rq_merge_fn(q, rq, next))
+       if (!e->uses_mq && e->type->ops.sq.elevator_allow_rq_merge_fn)
+               if (!e->type->ops.sq.elevator_allow_rq_merge_fn(q, rq, next))
                        return 0;
 
-       return attempt_merge(q, rq, next);
+       free = attempt_merge(q, rq, next);
+       if (free) {
+               __blk_put_request(q, free);
+               return 1;
+       }
+
+       return 0;
 }
 
 bool blk_rq_merge_ok(struct request *rq, struct bio *bio)
@@ -798,9 +801,12 @@ bool blk_rq_merge_ok(struct request *rq, struct bio *bio)
        return true;
 }
 
-int blk_try_merge(struct request *rq, struct bio *bio)
+enum elv_merge blk_try_merge(struct request *rq, struct bio *bio)
 {
-       if (blk_rq_pos(rq) + blk_rq_sectors(rq) == bio->bi_iter.bi_sector)
+       if (req_op(rq) == REQ_OP_DISCARD &&
+           queue_max_discard_segments(rq->q) > 1)
+               return ELEVATOR_DISCARD_MERGE;
+       else if (blk_rq_pos(rq) + blk_rq_sectors(rq) == bio->bi_iter.bi_sector)
                return ELEVATOR_BACK_MERGE;
        else if (blk_rq_pos(rq) - bio_sectors(bio) == bio->bi_iter.bi_sector)
                return ELEVATOR_FRONT_MERGE;
diff --git a/block/blk-mq-debugfs.c b/block/blk-mq-debugfs.c
new file mode 100644 (file)
index 0000000..f6d9179
--- /dev/null
@@ -0,0 +1,772 @@
+/*
+ * Copyright (C) 2017 Facebook
+ *
+ * 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, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/blkdev.h>
+#include <linux/debugfs.h>
+
+#include <linux/blk-mq.h>
+#include "blk.h"
+#include "blk-mq.h"
+#include "blk-mq-tag.h"
+
+struct blk_mq_debugfs_attr {
+       const char *name;
+       umode_t mode;
+       const struct file_operations *fops;
+};
+
+static int blk_mq_debugfs_seq_open(struct inode *inode, struct file *file,
+                                  const struct seq_operations *ops)
+{
+       struct seq_file *m;
+       int ret;
+
+       ret = seq_open(file, ops);
+       if (!ret) {
+               m = file->private_data;
+               m->private = inode->i_private;
+       }
+       return ret;
+}
+
+static int hctx_state_show(struct seq_file *m, void *v)
+{
+       struct blk_mq_hw_ctx *hctx = m->private;
+
+       seq_printf(m, "0x%lx\n", hctx->state);
+       return 0;
+}
+
+static int hctx_state_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, hctx_state_show, inode->i_private);
+}
+
+static const struct file_operations hctx_state_fops = {
+       .open           = hctx_state_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int hctx_flags_show(struct seq_file *m, void *v)
+{
+       struct blk_mq_hw_ctx *hctx = m->private;
+
+       seq_printf(m, "0x%lx\n", hctx->flags);
+       return 0;
+}
+
+static int hctx_flags_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, hctx_flags_show, inode->i_private);
+}
+
+static const struct file_operations hctx_flags_fops = {
+       .open           = hctx_flags_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int blk_mq_debugfs_rq_show(struct seq_file *m, void *v)
+{
+       struct request *rq = list_entry_rq(v);
+
+       seq_printf(m, "%p {.cmd_flags=0x%x, .rq_flags=0x%x, .tag=%d, .internal_tag=%d}\n",
+                  rq, rq->cmd_flags, (__force unsigned int)rq->rq_flags,
+                  rq->tag, rq->internal_tag);
+       return 0;
+}
+
+static void *hctx_dispatch_start(struct seq_file *m, loff_t *pos)
+       __acquires(&hctx->lock)
+{
+       struct blk_mq_hw_ctx *hctx = m->private;
+
+       spin_lock(&hctx->lock);
+       return seq_list_start(&hctx->dispatch, *pos);
+}
+
+static void *hctx_dispatch_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       struct blk_mq_hw_ctx *hctx = m->private;
+
+       return seq_list_next(v, &hctx->dispatch, pos);
+}
+
+static void hctx_dispatch_stop(struct seq_file *m, void *v)
+       __releases(&hctx->lock)
+{
+       struct blk_mq_hw_ctx *hctx = m->private;
+
+       spin_unlock(&hctx->lock);
+}
+
+static const struct seq_operations hctx_dispatch_seq_ops = {
+       .start  = hctx_dispatch_start,
+       .next   = hctx_dispatch_next,
+       .stop   = hctx_dispatch_stop,
+       .show   = blk_mq_debugfs_rq_show,
+};
+
+static int hctx_dispatch_open(struct inode *inode, struct file *file)
+{
+       return blk_mq_debugfs_seq_open(inode, file, &hctx_dispatch_seq_ops);
+}
+
+static const struct file_operations hctx_dispatch_fops = {
+       .open           = hctx_dispatch_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
+static int hctx_ctx_map_show(struct seq_file *m, void *v)
+{
+       struct blk_mq_hw_ctx *hctx = m->private;
+
+       sbitmap_bitmap_show(&hctx->ctx_map, m);
+       return 0;
+}
+
+static int hctx_ctx_map_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, hctx_ctx_map_show, inode->i_private);
+}
+
+static const struct file_operations hctx_ctx_map_fops = {
+       .open           = hctx_ctx_map_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static void blk_mq_debugfs_tags_show(struct seq_file *m,
+                                    struct blk_mq_tags *tags)
+{
+       seq_printf(m, "nr_tags=%u\n", tags->nr_tags);
+       seq_printf(m, "nr_reserved_tags=%u\n", tags->nr_reserved_tags);
+       seq_printf(m, "active_queues=%d\n",
+                  atomic_read(&tags->active_queues));
+
+       seq_puts(m, "\nbitmap_tags:\n");
+       sbitmap_queue_show(&tags->bitmap_tags, m);
+
+       if (tags->nr_reserved_tags) {
+               seq_puts(m, "\nbreserved_tags:\n");
+               sbitmap_queue_show(&tags->breserved_tags, m);
+       }
+}
+
+static int hctx_tags_show(struct seq_file *m, void *v)
+{
+       struct blk_mq_hw_ctx *hctx = m->private;
+       struct request_queue *q = hctx->queue;
+       int res;
+
+       res = mutex_lock_interruptible(&q->sysfs_lock);
+       if (res)
+               goto out;
+       if (hctx->tags)
+               blk_mq_debugfs_tags_show(m, hctx->tags);
+       mutex_unlock(&q->sysfs_lock);
+
+out:
+       return res;
+}
+
+static int hctx_tags_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, hctx_tags_show, inode->i_private);
+}
+
+static const struct file_operations hctx_tags_fops = {
+       .open           = hctx_tags_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int hctx_tags_bitmap_show(struct seq_file *m, void *v)
+{
+       struct blk_mq_hw_ctx *hctx = m->private;
+       struct request_queue *q = hctx->queue;
+       int res;
+
+       res = mutex_lock_interruptible(&q->sysfs_lock);
+       if (res)
+               goto out;
+       if (hctx->tags)
+               sbitmap_bitmap_show(&hctx->tags->bitmap_tags.sb, m);
+       mutex_unlock(&q->sysfs_lock);
+
+out:
+       return res;
+}
+
+static int hctx_tags_bitmap_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, hctx_tags_bitmap_show, inode->i_private);
+}
+
+static const struct file_operations hctx_tags_bitmap_fops = {
+       .open           = hctx_tags_bitmap_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int hctx_sched_tags_show(struct seq_file *m, void *v)
+{
+       struct blk_mq_hw_ctx *hctx = m->private;
+       struct request_queue *q = hctx->queue;
+       int res;
+
+       res = mutex_lock_interruptible(&q->sysfs_lock);
+       if (res)
+               goto out;
+       if (hctx->sched_tags)
+               blk_mq_debugfs_tags_show(m, hctx->sched_tags);
+       mutex_unlock(&q->sysfs_lock);
+
+out:
+       return res;
+}
+
+static int hctx_sched_tags_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, hctx_sched_tags_show, inode->i_private);
+}
+
+static const struct file_operations hctx_sched_tags_fops = {
+       .open           = hctx_sched_tags_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int hctx_sched_tags_bitmap_show(struct seq_file *m, void *v)
+{
+       struct blk_mq_hw_ctx *hctx = m->private;
+       struct request_queue *q = hctx->queue;
+       int res;
+
+       res = mutex_lock_interruptible(&q->sysfs_lock);
+       if (res)
+               goto out;
+       if (hctx->sched_tags)
+               sbitmap_bitmap_show(&hctx->sched_tags->bitmap_tags.sb, m);
+       mutex_unlock(&q->sysfs_lock);
+
+out:
+       return res;
+}
+
+static int hctx_sched_tags_bitmap_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, hctx_sched_tags_bitmap_show, inode->i_private);
+}
+
+static const struct file_operations hctx_sched_tags_bitmap_fops = {
+       .open           = hctx_sched_tags_bitmap_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int hctx_io_poll_show(struct seq_file *m, void *v)
+{
+       struct blk_mq_hw_ctx *hctx = m->private;
+
+       seq_printf(m, "considered=%lu\n", hctx->poll_considered);
+       seq_printf(m, "invoked=%lu\n", hctx->poll_invoked);
+       seq_printf(m, "success=%lu\n", hctx->poll_success);
+       return 0;
+}
+
+static int hctx_io_poll_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, hctx_io_poll_show, inode->i_private);
+}
+
+static ssize_t hctx_io_poll_write(struct file *file, const char __user *buf,
+                                 size_t count, loff_t *ppos)
+{
+       struct seq_file *m = file->private_data;
+       struct blk_mq_hw_ctx *hctx = m->private;
+
+       hctx->poll_considered = hctx->poll_invoked = hctx->poll_success = 0;
+       return count;
+}
+
+static const struct file_operations hctx_io_poll_fops = {
+       .open           = hctx_io_poll_open,
+       .read           = seq_read,
+       .write          = hctx_io_poll_write,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static void print_stat(struct seq_file *m, struct blk_rq_stat *stat)
+{
+       seq_printf(m, "samples=%d, mean=%lld, min=%llu, max=%llu",
+                  stat->nr_samples, stat->mean, stat->min, stat->max);
+}
+
+static int hctx_stats_show(struct seq_file *m, void *v)
+{
+       struct blk_mq_hw_ctx *hctx = m->private;
+       struct blk_rq_stat stat[2];
+
+       blk_stat_init(&stat[BLK_STAT_READ]);
+       blk_stat_init(&stat[BLK_STAT_WRITE]);
+
+       blk_hctx_stat_get(hctx, stat);
+
+       seq_puts(m, "read: ");
+       print_stat(m, &stat[BLK_STAT_READ]);
+       seq_puts(m, "\n");
+
+       seq_puts(m, "write: ");
+       print_stat(m, &stat[BLK_STAT_WRITE]);
+       seq_puts(m, "\n");
+       return 0;
+}
+
+static int hctx_stats_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, hctx_stats_show, inode->i_private);
+}
+
+static ssize_t hctx_stats_write(struct file *file, const char __user *buf,
+                               size_t count, loff_t *ppos)
+{
+       struct seq_file *m = file->private_data;
+       struct blk_mq_hw_ctx *hctx = m->private;
+       struct blk_mq_ctx *ctx;
+       int i;
+
+       hctx_for_each_ctx(hctx, ctx, i) {
+               blk_stat_init(&ctx->stat[BLK_STAT_READ]);
+               blk_stat_init(&ctx->stat[BLK_STAT_WRITE]);
+       }
+       return count;
+}
+
+static const struct file_operations hctx_stats_fops = {
+       .open           = hctx_stats_open,
+       .read           = seq_read,
+       .write          = hctx_stats_write,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int hctx_dispatched_show(struct seq_file *m, void *v)
+{
+       struct blk_mq_hw_ctx *hctx = m->private;
+       int i;
+
+       seq_printf(m, "%8u\t%lu\n", 0U, hctx->dispatched[0]);
+
+       for (i = 1; i < BLK_MQ_MAX_DISPATCH_ORDER - 1; i++) {
+               unsigned int d = 1U << (i - 1);
+
+               seq_printf(m, "%8u\t%lu\n", d, hctx->dispatched[i]);
+       }
+
+       seq_printf(m, "%8u+\t%lu\n", 1U << (i - 1), hctx->dispatched[i]);
+       return 0;
+}
+
+static int hctx_dispatched_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, hctx_dispatched_show, inode->i_private);
+}
+
+static ssize_t hctx_dispatched_write(struct file *file, const char __user *buf,
+                                    size_t count, loff_t *ppos)
+{
+       struct seq_file *m = file->private_data;
+       struct blk_mq_hw_ctx *hctx = m->private;
+       int i;
+
+       for (i = 0; i < BLK_MQ_MAX_DISPATCH_ORDER; i++)
+               hctx->dispatched[i] = 0;
+       return count;
+}
+
+static const struct file_operations hctx_dispatched_fops = {
+       .open           = hctx_dispatched_open,
+       .read           = seq_read,
+       .write          = hctx_dispatched_write,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int hctx_queued_show(struct seq_file *m, void *v)
+{
+       struct blk_mq_hw_ctx *hctx = m->private;
+
+       seq_printf(m, "%lu\n", hctx->queued);
+       return 0;
+}
+
+static int hctx_queued_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, hctx_queued_show, inode->i_private);
+}
+
+static ssize_t hctx_queued_write(struct file *file, const char __user *buf,
+                                size_t count, loff_t *ppos)
+{
+       struct seq_file *m = file->private_data;
+       struct blk_mq_hw_ctx *hctx = m->private;
+
+       hctx->queued = 0;
+       return count;
+}
+
+static const struct file_operations hctx_queued_fops = {
+       .open           = hctx_queued_open,
+       .read           = seq_read,
+       .write          = hctx_queued_write,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int hctx_run_show(struct seq_file *m, void *v)
+{
+       struct blk_mq_hw_ctx *hctx = m->private;
+
+       seq_printf(m, "%lu\n", hctx->run);
+       return 0;
+}
+
+static int hctx_run_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, hctx_run_show, inode->i_private);
+}
+
+static ssize_t hctx_run_write(struct file *file, const char __user *buf,
+                                size_t count, loff_t *ppos)
+{
+       struct seq_file *m = file->private_data;
+       struct blk_mq_hw_ctx *hctx = m->private;
+
+       hctx->run = 0;
+       return count;
+}
+
+static const struct file_operations hctx_run_fops = {
+       .open           = hctx_run_open,
+       .read           = seq_read,
+       .write          = hctx_run_write,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int hctx_active_show(struct seq_file *m, void *v)
+{
+       struct blk_mq_hw_ctx *hctx = m->private;
+
+       seq_printf(m, "%d\n", atomic_read(&hctx->nr_active));
+       return 0;
+}
+
+static int hctx_active_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, hctx_active_show, inode->i_private);
+}
+
+static const struct file_operations hctx_active_fops = {
+       .open           = hctx_active_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static void *ctx_rq_list_start(struct seq_file *m, loff_t *pos)
+       __acquires(&ctx->lock)
+{
+       struct blk_mq_ctx *ctx = m->private;
+
+       spin_lock(&ctx->lock);
+       return seq_list_start(&ctx->rq_list, *pos);
+}
+
+static void *ctx_rq_list_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       struct blk_mq_ctx *ctx = m->private;
+
+       return seq_list_next(v, &ctx->rq_list, pos);
+}
+
+static void ctx_rq_list_stop(struct seq_file *m, void *v)
+       __releases(&ctx->lock)
+{
+       struct blk_mq_ctx *ctx = m->private;
+
+       spin_unlock(&ctx->lock);
+}
+
+static const struct seq_operations ctx_rq_list_seq_ops = {
+       .start  = ctx_rq_list_start,
+       .next   = ctx_rq_list_next,
+       .stop   = ctx_rq_list_stop,
+       .show   = blk_mq_debugfs_rq_show,
+};
+
+static int ctx_rq_list_open(struct inode *inode, struct file *file)
+{
+       return blk_mq_debugfs_seq_open(inode, file, &ctx_rq_list_seq_ops);
+}
+
+static const struct file_operations ctx_rq_list_fops = {
+       .open           = ctx_rq_list_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
+static int ctx_dispatched_show(struct seq_file *m, void *v)
+{
+       struct blk_mq_ctx *ctx = m->private;
+
+       seq_printf(m, "%lu %lu\n", ctx->rq_dispatched[1], ctx->rq_dispatched[0]);
+       return 0;
+}
+
+static int ctx_dispatched_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ctx_dispatched_show, inode->i_private);
+}
+
+static ssize_t ctx_dispatched_write(struct file *file, const char __user *buf,
+                                   size_t count, loff_t *ppos)
+{
+       struct seq_file *m = file->private_data;
+       struct blk_mq_ctx *ctx = m->private;
+
+       ctx->rq_dispatched[0] = ctx->rq_dispatched[1] = 0;
+       return count;
+}
+
+static const struct file_operations ctx_dispatched_fops = {
+       .open           = ctx_dispatched_open,
+       .read           = seq_read,
+       .write          = ctx_dispatched_write,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int ctx_merged_show(struct seq_file *m, void *v)
+{
+       struct blk_mq_ctx *ctx = m->private;
+
+       seq_printf(m, "%lu\n", ctx->rq_merged);
+       return 0;
+}
+
+static int ctx_merged_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ctx_merged_show, inode->i_private);
+}
+
+static ssize_t ctx_merged_write(struct file *file, const char __user *buf,
+                                   size_t count, loff_t *ppos)
+{
+       struct seq_file *m = file->private_data;
+       struct blk_mq_ctx *ctx = m->private;
+
+       ctx->rq_merged = 0;
+       return count;
+}
+
+static const struct file_operations ctx_merged_fops = {
+       .open           = ctx_merged_open,
+       .read           = seq_read,
+       .write          = ctx_merged_write,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int ctx_completed_show(struct seq_file *m, void *v)
+{
+       struct blk_mq_ctx *ctx = m->private;
+
+       seq_printf(m, "%lu %lu\n", ctx->rq_completed[1], ctx->rq_completed[0]);
+       return 0;
+}
+
+static int ctx_completed_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ctx_completed_show, inode->i_private);
+}
+
+static ssize_t ctx_completed_write(struct file *file, const char __user *buf,
+                                  size_t count, loff_t *ppos)
+{
+       struct seq_file *m = file->private_data;
+       struct blk_mq_ctx *ctx = m->private;
+
+       ctx->rq_completed[0] = ctx->rq_completed[1] = 0;
+       return count;
+}
+
+static const struct file_operations ctx_completed_fops = {
+       .open           = ctx_completed_open,
+       .read           = seq_read,
+       .write          = ctx_completed_write,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static const struct blk_mq_debugfs_attr blk_mq_debugfs_hctx_attrs[] = {
+       {"state", 0400, &hctx_state_fops},
+       {"flags", 0400, &hctx_flags_fops},
+       {"dispatch", 0400, &hctx_dispatch_fops},
+       {"ctx_map", 0400, &hctx_ctx_map_fops},
+       {"tags", 0400, &hctx_tags_fops},
+       {"tags_bitmap", 0400, &hctx_tags_bitmap_fops},
+       {"sched_tags", 0400, &hctx_sched_tags_fops},
+       {"sched_tags_bitmap", 0400, &hctx_sched_tags_bitmap_fops},
+       {"io_poll", 0600, &hctx_io_poll_fops},
+       {"stats", 0600, &hctx_stats_fops},
+       {"dispatched", 0600, &hctx_dispatched_fops},
+       {"queued", 0600, &hctx_queued_fops},
+       {"run", 0600, &hctx_run_fops},
+       {"active", 0400, &hctx_active_fops},
+       {},
+};
+
+static const struct blk_mq_debugfs_attr blk_mq_debugfs_ctx_attrs[] = {
+       {"rq_list", 0400, &ctx_rq_list_fops},
+       {"dispatched", 0600, &ctx_dispatched_fops},
+       {"merged", 0600, &ctx_merged_fops},
+       {"completed", 0600, &ctx_completed_fops},
+       {},
+};
+
+int blk_mq_debugfs_register(struct request_queue *q, const char *name)
+{
+       if (!blk_debugfs_root)
+               return -ENOENT;
+
+       q->debugfs_dir = debugfs_create_dir(name, blk_debugfs_root);
+       if (!q->debugfs_dir)
+               goto err;
+
+       if (blk_mq_debugfs_register_hctxs(q))
+               goto err;
+
+       return 0;
+
+err:
+       blk_mq_debugfs_unregister(q);
+       return -ENOMEM;
+}
+
+void blk_mq_debugfs_unregister(struct request_queue *q)
+{
+       debugfs_remove_recursive(q->debugfs_dir);
+       q->mq_debugfs_dir = NULL;
+       q->debugfs_dir = NULL;
+}
+
+static bool debugfs_create_files(struct dentry *parent, void *data,
+                               const struct blk_mq_debugfs_attr *attr)
+{
+       for (; attr->name; attr++) {
+               if (!debugfs_create_file(attr->name, attr->mode, parent,
+                                        data, attr->fops))
+                       return false;
+       }
+       return true;
+}
+
+static int blk_mq_debugfs_register_ctx(struct request_queue *q,
+                                      struct blk_mq_ctx *ctx,
+                                      struct dentry *hctx_dir)
+{
+       struct dentry *ctx_dir;
+       char name[20];
+
+       snprintf(name, sizeof(name), "cpu%u", ctx->cpu);
+       ctx_dir = debugfs_create_dir(name, hctx_dir);
+       if (!ctx_dir)
+               return -ENOMEM;
+
+       if (!debugfs_create_files(ctx_dir, ctx, blk_mq_debugfs_ctx_attrs))
+               return -ENOMEM;
+
+       return 0;
+}
+
+static int blk_mq_debugfs_register_hctx(struct request_queue *q,
+                                       struct blk_mq_hw_ctx *hctx)
+{
+       struct blk_mq_ctx *ctx;
+       struct dentry *hctx_dir;
+       char name[20];
+       int i;
+
+       snprintf(name, sizeof(name), "%u", hctx->queue_num);
+       hctx_dir = debugfs_create_dir(name, q->mq_debugfs_dir);
+       if (!hctx_dir)
+               return -ENOMEM;
+
+       if (!debugfs_create_files(hctx_dir, hctx, blk_mq_debugfs_hctx_attrs))
+               return -ENOMEM;
+
+       hctx_for_each_ctx(hctx, ctx, i) {
+               if (blk_mq_debugfs_register_ctx(q, ctx, hctx_dir))
+                       return -ENOMEM;
+       }
+
+       return 0;
+}
+
+int blk_mq_debugfs_register_hctxs(struct request_queue *q)
+{
+       struct blk_mq_hw_ctx *hctx;
+       int i;
+
+       if (!q->debugfs_dir)
+               return -ENOENT;
+
+       q->mq_debugfs_dir = debugfs_create_dir("mq", q->debugfs_dir);
+       if (!q->mq_debugfs_dir)
+               goto err;
+
+       queue_for_each_hw_ctx(q, hctx, i) {
+               if (blk_mq_debugfs_register_hctx(q, hctx))
+                       goto err;
+       }
+
+       return 0;
+
+err:
+       blk_mq_debugfs_unregister_hctxs(q);
+       return -ENOMEM;
+}
+
+void blk_mq_debugfs_unregister_hctxs(struct request_queue *q)
+{
+       debugfs_remove_recursive(q->mq_debugfs_dir);
+       q->mq_debugfs_dir = NULL;
+}
diff --git a/block/blk-mq-sched.c b/block/blk-mq-sched.c
new file mode 100644 (file)
index 0000000..9e8d679
--- /dev/null
@@ -0,0 +1,515 @@
+/*
+ * blk-mq scheduling framework
+ *
+ * Copyright (C) 2016 Jens Axboe
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/blk-mq.h>
+
+#include <trace/events/block.h>
+
+#include "blk.h"
+#include "blk-mq.h"
+#include "blk-mq-sched.h"
+#include "blk-mq-tag.h"
+#include "blk-wbt.h"
+
+void blk_mq_sched_free_hctx_data(struct request_queue *q,
+                                void (*exit)(struct blk_mq_hw_ctx *))
+{
+       struct blk_mq_hw_ctx *hctx;
+       int i;
+
+       queue_for_each_hw_ctx(q, hctx, i) {
+               if (exit && hctx->sched_data)
+                       exit(hctx);
+               kfree(hctx->sched_data);
+               hctx->sched_data = NULL;
+       }
+}
+EXPORT_SYMBOL_GPL(blk_mq_sched_free_hctx_data);
+
+int blk_mq_sched_init_hctx_data(struct request_queue *q, size_t size,
+                               int (*init)(struct blk_mq_hw_ctx *),
+                               void (*exit)(struct blk_mq_hw_ctx *))
+{
+       struct blk_mq_hw_ctx *hctx;
+       int ret;
+       int i;
+
+       queue_for_each_hw_ctx(q, hctx, i) {
+               hctx->sched_data = kmalloc_node(size, GFP_KERNEL, hctx->numa_node);
+               if (!hctx->sched_data) {
+                       ret = -ENOMEM;
+                       goto error;
+               }
+
+               if (init) {
+                       ret = init(hctx);
+                       if (ret) {
+                               /*
+                                * We don't want to give exit() a partially
+                                * initialized sched_data. init() must clean up
+                                * if it fails.
+                                */
+                               kfree(hctx->sched_data);
+                               hctx->sched_data = NULL;
+                               goto error;
+                       }
+               }
+       }
+
+       return 0;
+error:
+       blk_mq_sched_free_hctx_data(q, exit);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(blk_mq_sched_init_hctx_data);
+
+static void __blk_mq_sched_assign_ioc(struct request_queue *q,
+                                     struct request *rq,
+                                     struct bio *bio,
+                                     struct io_context *ioc)
+{
+       struct io_cq *icq;
+
+       spin_lock_irq(q->queue_lock);
+       icq = ioc_lookup_icq(ioc, q);
+       spin_unlock_irq(q->queue_lock);
+
+       if (!icq) {
+               icq = ioc_create_icq(ioc, q, GFP_ATOMIC);
+               if (!icq)
+                       return;
+       }
+
+       rq->elv.icq = icq;
+       if (!blk_mq_sched_get_rq_priv(q, rq, bio)) {
+               rq->rq_flags |= RQF_ELVPRIV;
+               get_io_context(icq->ioc);
+               return;
+       }
+
+       rq->elv.icq = NULL;
+}
+
+static void blk_mq_sched_assign_ioc(struct request_queue *q,
+                                   struct request *rq, struct bio *bio)
+{
+       struct io_context *ioc;
+
+       ioc = rq_ioc(bio);
+       if (ioc)
+               __blk_mq_sched_assign_ioc(q, rq, bio, ioc);
+}
+
+struct request *blk_mq_sched_get_request(struct request_queue *q,
+                                        struct bio *bio,
+                                        unsigned int op,
+                                        struct blk_mq_alloc_data *data)
+{
+       struct elevator_queue *e = q->elevator;
+       struct blk_mq_hw_ctx *hctx;
+       struct blk_mq_ctx *ctx;
+       struct request *rq;
+
+       blk_queue_enter_live(q);
+       ctx = blk_mq_get_ctx(q);
+       hctx = blk_mq_map_queue(q, ctx->cpu);
+
+       blk_mq_set_alloc_data(data, q, data->flags, ctx, hctx);
+
+       if (e) {
+               data->flags |= BLK_MQ_REQ_INTERNAL;
+
+               /*
+                * Flush requests are special and go directly to the
+                * dispatch list.
+                */
+               if (!op_is_flush(op) && e->type->ops.mq.get_request) {
+                       rq = e->type->ops.mq.get_request(q, op, data);
+                       if (rq)
+                               rq->rq_flags |= RQF_QUEUED;
+               } else
+                       rq = __blk_mq_alloc_request(data, op);
+       } else {
+               rq = __blk_mq_alloc_request(data, op);
+               if (rq)
+                       data->hctx->tags->rqs[rq->tag] = rq;
+       }
+
+       if (rq) {
+               if (!op_is_flush(op)) {
+                       rq->elv.icq = NULL;
+                       if (e && e->type->icq_cache)
+                               blk_mq_sched_assign_ioc(q, rq, bio);
+               }
+               data->hctx->queued++;
+               return rq;
+       }
+
+       blk_queue_exit(q);
+       return NULL;
+}
+
+void blk_mq_sched_put_request(struct request *rq)
+{
+       struct request_queue *q = rq->q;
+       struct elevator_queue *e = q->elevator;
+
+       if (rq->rq_flags & RQF_ELVPRIV) {
+               blk_mq_sched_put_rq_priv(rq->q, rq);
+               if (rq->elv.icq) {
+                       put_io_context(rq->elv.icq->ioc);
+                       rq->elv.icq = NULL;
+               }
+       }
+
+       if ((rq->rq_flags & RQF_QUEUED) && e && e->type->ops.mq.put_request)
+               e->type->ops.mq.put_request(rq);
+       else
+               blk_mq_finish_request(rq);
+}
+
+void blk_mq_sched_dispatch_requests(struct blk_mq_hw_ctx *hctx)
+{
+       struct elevator_queue *e = hctx->queue->elevator;
+       const bool has_sched_dispatch = e && e->type->ops.mq.dispatch_request;
+       bool did_work = false;
+       LIST_HEAD(rq_list);
+
+       if (unlikely(blk_mq_hctx_stopped(hctx)))
+               return;
+
+       hctx->run++;
+
+       /*
+        * If we have previous entries on our dispatch list, grab them first for
+        * more fair dispatch.
+        */
+       if (!list_empty_careful(&hctx->dispatch)) {
+               spin_lock(&hctx->lock);
+               if (!list_empty(&hctx->dispatch))
+                       list_splice_init(&hctx->dispatch, &rq_list);
+               spin_unlock(&hctx->lock);
+       }
+
+       /*
+        * Only ask the scheduler for requests, if we didn't have residual
+        * requests from the dispatch list. This is to avoid the case where
+        * we only ever dispatch a fraction of the requests available because
+        * of low device queue depth. Once we pull requests out of the IO
+        * scheduler, we can no longer merge or sort them. So it's best to
+        * leave them there for as long as we can. Mark the hw queue as
+        * needing a restart in that case.
+        */
+       if (!list_empty(&rq_list)) {
+               blk_mq_sched_mark_restart(hctx);
+               did_work = blk_mq_dispatch_rq_list(hctx, &rq_list);
+       } else if (!has_sched_dispatch) {
+               blk_mq_flush_busy_ctxs(hctx, &rq_list);
+               blk_mq_dispatch_rq_list(hctx, &rq_list);
+       }
+
+       /*
+        * We want to dispatch from the scheduler if we had no work left
+        * on the dispatch list, OR if we did have work but weren't able
+        * to make progress.
+        */
+       if (!did_work && has_sched_dispatch) {
+               do {
+                       struct request *rq;
+
+                       rq = e->type->ops.mq.dispatch_request(hctx);
+                       if (!rq)
+                               break;
+                       list_add(&rq->queuelist, &rq_list);
+               } while (blk_mq_dispatch_rq_list(hctx, &rq_list));
+       }
+}
+
+void blk_mq_sched_move_to_dispatch(struct blk_mq_hw_ctx *hctx,
+                                  struct list_head *rq_list,
+                                  struct request *(*get_rq)(struct blk_mq_hw_ctx *))
+{
+       do {
+               struct request *rq;
+
+               rq = get_rq(hctx);
+               if (!rq)
+                       break;
+
+               list_add_tail(&rq->queuelist, rq_list);
+       } while (1);
+}
+EXPORT_SYMBOL_GPL(blk_mq_sched_move_to_dispatch);
+
+bool blk_mq_sched_try_merge(struct request_queue *q, struct bio *bio,
+                           struct request **merged_request)
+{
+       struct request *rq;
+
+       switch (elv_merge(q, &rq, bio)) {
+       case ELEVATOR_BACK_MERGE:
+               if (!blk_mq_sched_allow_merge(q, rq, bio))
+                       return false;
+               if (!bio_attempt_back_merge(q, rq, bio))
+                       return false;
+               *merged_request = attempt_back_merge(q, rq);
+               if (!*merged_request)
+                       elv_merged_request(q, rq, ELEVATOR_BACK_MERGE);
+               return true;
+       case ELEVATOR_FRONT_MERGE:
+               if (!blk_mq_sched_allow_merge(q, rq, bio))
+                       return false;
+               if (!bio_attempt_front_merge(q, rq, bio))
+                       return false;
+               *merged_request = attempt_front_merge(q, rq);
+               if (!*merged_request)
+                       elv_merged_request(q, rq, ELEVATOR_FRONT_MERGE);
+               return true;
+       default:
+               return false;
+       }
+}
+EXPORT_SYMBOL_GPL(blk_mq_sched_try_merge);
+
+bool __blk_mq_sched_bio_merge(struct request_queue *q, struct bio *bio)
+{
+       struct elevator_queue *e = q->elevator;
+
+       if (e->type->ops.mq.bio_merge) {
+               struct blk_mq_ctx *ctx = blk_mq_get_ctx(q);
+               struct blk_mq_hw_ctx *hctx = blk_mq_map_queue(q, ctx->cpu);
+
+               blk_mq_put_ctx(ctx);
+               return e->type->ops.mq.bio_merge(hctx, bio);
+       }
+
+       return false;
+}
+
+bool blk_mq_sched_try_insert_merge(struct request_queue *q, struct request *rq)
+{
+       return rq_mergeable(rq) && elv_attempt_insert_merge(q, rq);
+}
+EXPORT_SYMBOL_GPL(blk_mq_sched_try_insert_merge);
+
+void blk_mq_sched_request_inserted(struct request *rq)
+{
+       trace_block_rq_insert(rq->q, rq);
+}
+EXPORT_SYMBOL_GPL(blk_mq_sched_request_inserted);
+
+static bool blk_mq_sched_bypass_insert(struct blk_mq_hw_ctx *hctx,
+                                      struct request *rq)
+{
+       if (rq->tag == -1) {
+               rq->rq_flags |= RQF_SORTED;
+               return false;
+       }
+
+       /*
+        * If we already have a real request tag, send directly to
+        * the dispatch list.
+        */
+       spin_lock(&hctx->lock);
+       list_add(&rq->queuelist, &hctx->dispatch);
+       spin_unlock(&hctx->lock);
+       return true;
+}
+
+static void blk_mq_sched_restart_hctx(struct blk_mq_hw_ctx *hctx)
+{
+       if (test_bit(BLK_MQ_S_SCHED_RESTART, &hctx->state)) {
+               clear_bit(BLK_MQ_S_SCHED_RESTART, &hctx->state);
+               if (blk_mq_hctx_has_pending(hctx))
+                       blk_mq_run_hw_queue(hctx, true);
+       }
+}
+
+void blk_mq_sched_restart_queues(struct blk_mq_hw_ctx *hctx)
+{
+       unsigned int i;
+
+       if (!(hctx->flags & BLK_MQ_F_TAG_SHARED))
+               blk_mq_sched_restart_hctx(hctx);
+       else {
+               struct request_queue *q = hctx->queue;
+
+               if (!test_bit(QUEUE_FLAG_RESTART, &q->queue_flags))
+                       return;
+
+               clear_bit(QUEUE_FLAG_RESTART, &q->queue_flags);
+
+               queue_for_each_hw_ctx(q, hctx, i)
+                       blk_mq_sched_restart_hctx(hctx);
+       }
+}
+
+/*
+ * Add flush/fua to the queue. If we fail getting a driver tag, then
+ * punt to the requeue list. Requeue will re-invoke us from a context
+ * that's safe to block from.
+ */
+static void blk_mq_sched_insert_flush(struct blk_mq_hw_ctx *hctx,
+                                     struct request *rq, bool can_block)
+{
+       if (blk_mq_get_driver_tag(rq, &hctx, can_block)) {
+               blk_insert_flush(rq);
+               blk_mq_run_hw_queue(hctx, true);
+       } else
+               blk_mq_add_to_requeue_list(rq, false, true);
+}
+
+void blk_mq_sched_insert_request(struct request *rq, bool at_head,
+                                bool run_queue, bool async, bool can_block)
+{
+       struct request_queue *q = rq->q;
+       struct elevator_queue *e = q->elevator;
+       struct blk_mq_ctx *ctx = rq->mq_ctx;
+       struct blk_mq_hw_ctx *hctx = blk_mq_map_queue(q, ctx->cpu);
+
+       if (rq->tag == -1 && op_is_flush(rq->cmd_flags)) {
+               blk_mq_sched_insert_flush(hctx, rq, can_block);
+               return;
+       }
+
+       if (e && blk_mq_sched_bypass_insert(hctx, rq))
+               goto run;
+
+       if (e && e->type->ops.mq.insert_requests) {
+               LIST_HEAD(list);
+
+               list_add(&rq->queuelist, &list);
+               e->type->ops.mq.insert_requests(hctx, &list, at_head);
+       } else {
+               spin_lock(&ctx->lock);
+               __blk_mq_insert_request(hctx, rq, at_head);
+               spin_unlock(&ctx->lock);
+       }
+
+run:
+       if (run_queue)
+               blk_mq_run_hw_queue(hctx, async);
+}
+
+void blk_mq_sched_insert_requests(struct request_queue *q,
+                                 struct blk_mq_ctx *ctx,
+                                 struct list_head *list, bool run_queue_async)
+{
+       struct blk_mq_hw_ctx *hctx = blk_mq_map_queue(q, ctx->cpu);
+       struct elevator_queue *e = hctx->queue->elevator;
+
+       if (e) {
+               struct request *rq, *next;
+
+               /*
+                * We bypass requests that already have a driver tag assigned,
+                * which should only be flushes. Flushes are only ever inserted
+                * as single requests, so we shouldn't ever hit the
+                * WARN_ON_ONCE() below (but let's handle it just in case).
+                */
+               list_for_each_entry_safe(rq, next, list, queuelist) {
+                       if (WARN_ON_ONCE(rq->tag != -1)) {
+                               list_del_init(&rq->queuelist);
+                               blk_mq_sched_bypass_insert(hctx, rq);
+                       }
+               }
+       }
+
+       if (e && e->type->ops.mq.insert_requests)
+               e->type->ops.mq.insert_requests(hctx, list, false);
+       else
+               blk_mq_insert_requests(hctx, ctx, list);
+
+       blk_mq_run_hw_queue(hctx, run_queue_async);
+}
+
+static void blk_mq_sched_free_tags(struct blk_mq_tag_set *set,
+                                  struct blk_mq_hw_ctx *hctx,
+                                  unsigned int hctx_idx)
+{
+       if (hctx->sched_tags) {
+               blk_mq_free_rqs(set, hctx->sched_tags, hctx_idx);
+               blk_mq_free_rq_map(hctx->sched_tags);
+               hctx->sched_tags = NULL;
+       }
+}
+
+int blk_mq_sched_setup(struct request_queue *q)
+{
+       struct blk_mq_tag_set *set = q->tag_set;
+       struct blk_mq_hw_ctx *hctx;
+       int ret, i;
+
+       /*
+        * Default to 256, since we don't split into sync/async like the
+        * old code did. Additionally, this is a per-hw queue depth.
+        */
+       q->nr_requests = 2 * BLKDEV_MAX_RQ;
+
+       /*
+        * We're switching to using an IO scheduler, so setup the hctx
+        * scheduler tags and switch the request map from the regular
+        * tags to scheduler tags. First allocate what we need, so we
+        * can safely fail and fallback, if needed.
+        */
+       ret = 0;
+       queue_for_each_hw_ctx(q, hctx, i) {
+               hctx->sched_tags = blk_mq_alloc_rq_map(set, i, q->nr_requests, 0);
+               if (!hctx->sched_tags) {
+                       ret = -ENOMEM;
+                       break;
+               }
+               ret = blk_mq_alloc_rqs(set, hctx->sched_tags, i, q->nr_requests);
+               if (ret)
+                       break;
+       }
+
+       /*
+        * If we failed, free what we did allocate
+        */
+       if (ret) {
+               queue_for_each_hw_ctx(q, hctx, i) {
+                       if (!hctx->sched_tags)
+                               continue;
+                       blk_mq_sched_free_tags(set, hctx, i);
+               }
+
+               return ret;
+       }
+
+       return 0;
+}
+
+void blk_mq_sched_teardown(struct request_queue *q)
+{
+       struct blk_mq_tag_set *set = q->tag_set;
+       struct blk_mq_hw_ctx *hctx;
+       int i;
+
+       queue_for_each_hw_ctx(q, hctx, i)
+               blk_mq_sched_free_tags(set, hctx, i);
+}
+
+int blk_mq_sched_init(struct request_queue *q)
+{
+       int ret;
+
+#if defined(CONFIG_DEFAULT_SQ_NONE)
+       if (q->nr_hw_queues == 1)
+               return 0;
+#endif
+#if defined(CONFIG_DEFAULT_MQ_NONE)
+       if (q->nr_hw_queues > 1)
+               return 0;
+#endif
+
+       mutex_lock(&q->sysfs_lock);
+       ret = elevator_init(q, NULL);
+       mutex_unlock(&q->sysfs_lock);
+
+       return ret;
+}
diff --git a/block/blk-mq-sched.h b/block/blk-mq-sched.h
new file mode 100644 (file)
index 0000000..7b5f3b9
--- /dev/null
@@ -0,0 +1,143 @@
+#ifndef BLK_MQ_SCHED_H
+#define BLK_MQ_SCHED_H
+
+#include "blk-mq.h"
+#include "blk-mq-tag.h"
+
+int blk_mq_sched_init_hctx_data(struct request_queue *q, size_t size,
+                               int (*init)(struct blk_mq_hw_ctx *),
+                               void (*exit)(struct blk_mq_hw_ctx *));
+
+void blk_mq_sched_free_hctx_data(struct request_queue *q,
+                                void (*exit)(struct blk_mq_hw_ctx *));
+
+struct request *blk_mq_sched_get_request(struct request_queue *q, struct bio *bio, unsigned int op, struct blk_mq_alloc_data *data);
+void blk_mq_sched_put_request(struct request *rq);
+
+void blk_mq_sched_request_inserted(struct request *rq);
+bool blk_mq_sched_try_merge(struct request_queue *q, struct bio *bio,
+                               struct request **merged_request);
+bool __blk_mq_sched_bio_merge(struct request_queue *q, struct bio *bio);
+bool blk_mq_sched_try_insert_merge(struct request_queue *q, struct request *rq);
+void blk_mq_sched_restart_queues(struct blk_mq_hw_ctx *hctx);
+
+void blk_mq_sched_insert_request(struct request *rq, bool at_head,
+                                bool run_queue, bool async, bool can_block);
+void blk_mq_sched_insert_requests(struct request_queue *q,
+                                 struct blk_mq_ctx *ctx,
+                                 struct list_head *list, bool run_queue_async);
+
+void blk_mq_sched_dispatch_requests(struct blk_mq_hw_ctx *hctx);
+void blk_mq_sched_move_to_dispatch(struct blk_mq_hw_ctx *hctx,
+                       struct list_head *rq_list,
+                       struct request *(*get_rq)(struct blk_mq_hw_ctx *));
+
+int blk_mq_sched_setup(struct request_queue *q);
+void blk_mq_sched_teardown(struct request_queue *q);
+
+int blk_mq_sched_init(struct request_queue *q);
+
+static inline bool
+blk_mq_sched_bio_merge(struct request_queue *q, struct bio *bio)
+{
+       struct elevator_queue *e = q->elevator;
+
+       if (!e || blk_queue_nomerges(q) || !bio_mergeable(bio))
+               return false;
+
+       return __blk_mq_sched_bio_merge(q, bio);
+}
+
+static inline int blk_mq_sched_get_rq_priv(struct request_queue *q,
+                                          struct request *rq,
+                                          struct bio *bio)
+{
+       struct elevator_queue *e = q->elevator;
+
+       if (e && e->type->ops.mq.get_rq_priv)
+               return e->type->ops.mq.get_rq_priv(q, rq, bio);
+
+       return 0;
+}
+
+static inline void blk_mq_sched_put_rq_priv(struct request_queue *q,
+                                           struct request *rq)
+{
+       struct elevator_queue *e = q->elevator;
+
+       if (e && e->type->ops.mq.put_rq_priv)
+               e->type->ops.mq.put_rq_priv(q, rq);
+}
+
+static inline bool
+blk_mq_sched_allow_merge(struct request_queue *q, struct request *rq,
+                        struct bio *bio)
+{
+       struct elevator_queue *e = q->elevator;
+
+       if (e && e->type->ops.mq.allow_merge)
+               return e->type->ops.mq.allow_merge(q, rq, bio);
+
+       return true;
+}
+
+static inline void
+blk_mq_sched_completed_request(struct blk_mq_hw_ctx *hctx, struct request *rq)
+{
+       struct elevator_queue *e = hctx->queue->elevator;
+
+       if (e && e->type->ops.mq.completed_request)
+               e->type->ops.mq.completed_request(hctx, rq);
+
+       BUG_ON(rq->internal_tag == -1);
+
+       blk_mq_put_tag(hctx, hctx->sched_tags, rq->mq_ctx, rq->internal_tag);
+}
+
+static inline void blk_mq_sched_started_request(struct request *rq)
+{
+       struct request_queue *q = rq->q;
+       struct elevator_queue *e = q->elevator;
+
+       if (e && e->type->ops.mq.started_request)
+               e->type->ops.mq.started_request(rq);
+}
+
+static inline void blk_mq_sched_requeue_request(struct request *rq)
+{
+       struct request_queue *q = rq->q;
+       struct elevator_queue *e = q->elevator;
+
+       if (e && e->type->ops.mq.requeue_request)
+               e->type->ops.mq.requeue_request(rq);
+}
+
+static inline bool blk_mq_sched_has_work(struct blk_mq_hw_ctx *hctx)
+{
+       struct elevator_queue *e = hctx->queue->elevator;
+
+       if (e && e->type->ops.mq.has_work)
+               return e->type->ops.mq.has_work(hctx);
+
+       return false;
+}
+
+static inline void blk_mq_sched_mark_restart(struct blk_mq_hw_ctx *hctx)
+{
+       if (!test_bit(BLK_MQ_S_SCHED_RESTART, &hctx->state)) {
+               set_bit(BLK_MQ_S_SCHED_RESTART, &hctx->state);
+               if (hctx->flags & BLK_MQ_F_TAG_SHARED) {
+                       struct request_queue *q = hctx->queue;
+
+                       if (!test_bit(QUEUE_FLAG_RESTART, &q->queue_flags))
+                               set_bit(QUEUE_FLAG_RESTART, &q->queue_flags);
+               }
+       }
+}
+
+static inline bool blk_mq_sched_needs_restart(struct blk_mq_hw_ctx *hctx)
+{
+       return test_bit(BLK_MQ_S_SCHED_RESTART, &hctx->state);
+}
+
+#endif
index eacd3af72099018c82e0a41fb9460b670d3e2845..295e69670c39343d058cbf7f67fc076f7249e94e 100644 (file)
@@ -122,123 +122,16 @@ static ssize_t blk_mq_hw_sysfs_store(struct kobject *kobj,
        return res;
 }
 
-static ssize_t blk_mq_sysfs_dispatched_show(struct blk_mq_ctx *ctx, char *page)
-{
-       return sprintf(page, "%lu %lu\n", ctx->rq_dispatched[1],
-                               ctx->rq_dispatched[0]);
-}
-
-static ssize_t blk_mq_sysfs_merged_show(struct blk_mq_ctx *ctx, char *page)
-{
-       return sprintf(page, "%lu\n", ctx->rq_merged);
-}
-
-static ssize_t blk_mq_sysfs_completed_show(struct blk_mq_ctx *ctx, char *page)
-{
-       return sprintf(page, "%lu %lu\n", ctx->rq_completed[1],
-                               ctx->rq_completed[0]);
-}
-
-static ssize_t sysfs_list_show(char *page, struct list_head *list, char *msg)
-{
-       struct request *rq;
-       int len = snprintf(page, PAGE_SIZE - 1, "%s:\n", msg);
-
-       list_for_each_entry(rq, list, queuelist) {
-               const int rq_len = 2 * sizeof(rq) + 2;
-
-               /* if the output will be truncated */
-               if (PAGE_SIZE - 1 < len + rq_len) {
-                       /* backspacing if it can't hold '\t...\n' */
-                       if (PAGE_SIZE - 1 < len + 5)
-                               len -= rq_len;
-                       len += snprintf(page + len, PAGE_SIZE - 1 - len,
-                                       "\t...\n");
-                       break;
-               }
-               len += snprintf(page + len, PAGE_SIZE - 1 - len,
-                               "\t%p\n", rq);
-       }
-
-       return len;
-}
-
-static ssize_t blk_mq_sysfs_rq_list_show(struct blk_mq_ctx *ctx, char *page)
-{
-       ssize_t ret;
-
-       spin_lock(&ctx->lock);
-       ret = sysfs_list_show(page, &ctx->rq_list, "CTX pending");
-       spin_unlock(&ctx->lock);
-
-       return ret;
-}
-
-static ssize_t blk_mq_hw_sysfs_poll_show(struct blk_mq_hw_ctx *hctx, char *page)
-{
-       return sprintf(page, "considered=%lu, invoked=%lu, success=%lu\n",
-                      hctx->poll_considered, hctx->poll_invoked,
-                      hctx->poll_success);
-}
-
-static ssize_t blk_mq_hw_sysfs_poll_store(struct blk_mq_hw_ctx *hctx,
-                                         const char *page, size_t size)
-{
-       hctx->poll_considered = hctx->poll_invoked = hctx->poll_success = 0;
-
-       return size;
-}
-
-static ssize_t blk_mq_hw_sysfs_queued_show(struct blk_mq_hw_ctx *hctx,
-                                          char *page)
-{
-       return sprintf(page, "%lu\n", hctx->queued);
-}
-
-static ssize_t blk_mq_hw_sysfs_run_show(struct blk_mq_hw_ctx *hctx, char *page)
-{
-       return sprintf(page, "%lu\n", hctx->run);
-}
-
-static ssize_t blk_mq_hw_sysfs_dispatched_show(struct blk_mq_hw_ctx *hctx,
-                                              char *page)
-{
-       char *start_page = page;
-       int i;
-
-       page += sprintf(page, "%8u\t%lu\n", 0U, hctx->dispatched[0]);
-
-       for (i = 1; i < BLK_MQ_MAX_DISPATCH_ORDER - 1; i++) {
-               unsigned int d = 1U << (i - 1);
-
-               page += sprintf(page, "%8u\t%lu\n", d, hctx->dispatched[i]);
-       }
-
-       page += sprintf(page, "%8u+\t%lu\n", 1U << (i - 1),
-                                               hctx->dispatched[i]);
-       return page - start_page;
-}
-
-static ssize_t blk_mq_hw_sysfs_rq_list_show(struct blk_mq_hw_ctx *hctx,
+static ssize_t blk_mq_hw_sysfs_nr_tags_show(struct blk_mq_hw_ctx *hctx,
                                            char *page)
 {
-       ssize_t ret;
-
-       spin_lock(&hctx->lock);
-       ret = sysfs_list_show(page, &hctx->dispatch, "HCTX pending");
-       spin_unlock(&hctx->lock);
-
-       return ret;
+       return sprintf(page, "%u\n", hctx->tags->nr_tags);
 }
 
-static ssize_t blk_mq_hw_sysfs_tags_show(struct blk_mq_hw_ctx *hctx, char *page)
+static ssize_t blk_mq_hw_sysfs_nr_reserved_tags_show(struct blk_mq_hw_ctx *hctx,
+                                                    char *page)
 {
-       return blk_mq_tag_sysfs_show(hctx->tags, page);
-}
-
-static ssize_t blk_mq_hw_sysfs_active_show(struct blk_mq_hw_ctx *hctx, char *page)
-{
-       return sprintf(page, "%u\n", atomic_read(&hctx->nr_active));
+       return sprintf(page, "%u\n", hctx->tags->nr_reserved_tags);
 }
 
 static ssize_t blk_mq_hw_sysfs_cpus_show(struct blk_mq_hw_ctx *hctx, char *page)
@@ -259,121 +152,27 @@ static ssize_t blk_mq_hw_sysfs_cpus_show(struct blk_mq_hw_ctx *hctx, char *page)
        return ret;
 }
 
-static void blk_mq_stat_clear(struct blk_mq_hw_ctx *hctx)
-{
-       struct blk_mq_ctx *ctx;
-       unsigned int i;
-
-       hctx_for_each_ctx(hctx, ctx, i) {
-               blk_stat_init(&ctx->stat[BLK_STAT_READ]);
-               blk_stat_init(&ctx->stat[BLK_STAT_WRITE]);
-       }
-}
-
-static ssize_t blk_mq_hw_sysfs_stat_store(struct blk_mq_hw_ctx *hctx,
-                                         const char *page, size_t count)
-{
-       blk_mq_stat_clear(hctx);
-       return count;
-}
-
-static ssize_t print_stat(char *page, struct blk_rq_stat *stat, const char *pre)
-{
-       return sprintf(page, "%s samples=%llu, mean=%lld, min=%lld, max=%lld\n",
-                       pre, (long long) stat->nr_samples,
-                       (long long) stat->mean, (long long) stat->min,
-                       (long long) stat->max);
-}
-
-static ssize_t blk_mq_hw_sysfs_stat_show(struct blk_mq_hw_ctx *hctx, char *page)
-{
-       struct blk_rq_stat stat[2];
-       ssize_t ret;
-
-       blk_stat_init(&stat[BLK_STAT_READ]);
-       blk_stat_init(&stat[BLK_STAT_WRITE]);
-
-       blk_hctx_stat_get(hctx, stat);
-
-       ret = print_stat(page, &stat[BLK_STAT_READ], "read :");
-       ret += print_stat(page + ret, &stat[BLK_STAT_WRITE], "write:");
-       return ret;
-}
-
-static struct blk_mq_ctx_sysfs_entry blk_mq_sysfs_dispatched = {
-       .attr = {.name = "dispatched", .mode = S_IRUGO },
-       .show = blk_mq_sysfs_dispatched_show,
-};
-static struct blk_mq_ctx_sysfs_entry blk_mq_sysfs_merged = {
-       .attr = {.name = "merged", .mode = S_IRUGO },
-       .show = blk_mq_sysfs_merged_show,
-};
-static struct blk_mq_ctx_sysfs_entry blk_mq_sysfs_completed = {
-       .attr = {.name = "completed", .mode = S_IRUGO },
-       .show = blk_mq_sysfs_completed_show,
-};
-static struct blk_mq_ctx_sysfs_entry blk_mq_sysfs_rq_list = {
-       .attr = {.name = "rq_list", .mode = S_IRUGO },
-       .show = blk_mq_sysfs_rq_list_show,
-};
-
 static struct attribute *default_ctx_attrs[] = {
-       &blk_mq_sysfs_dispatched.attr,
-       &blk_mq_sysfs_merged.attr,
-       &blk_mq_sysfs_completed.attr,
-       &blk_mq_sysfs_rq_list.attr,
        NULL,
 };
 
-static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_queued = {
-       .attr = {.name = "queued", .mode = S_IRUGO },
-       .show = blk_mq_hw_sysfs_queued_show,
+static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_nr_tags = {
+       .attr = {.name = "nr_tags", .mode = S_IRUGO },
+       .show = blk_mq_hw_sysfs_nr_tags_show,
 };
-static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_run = {
-       .attr = {.name = "run", .mode = S_IRUGO },
-       .show = blk_mq_hw_sysfs_run_show,
-};
-static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_dispatched = {
-       .attr = {.name = "dispatched", .mode = S_IRUGO },
-       .show = blk_mq_hw_sysfs_dispatched_show,
-};
-static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_active = {
-       .attr = {.name = "active", .mode = S_IRUGO },
-       .show = blk_mq_hw_sysfs_active_show,
-};
-static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_pending = {
-       .attr = {.name = "pending", .mode = S_IRUGO },
-       .show = blk_mq_hw_sysfs_rq_list_show,
-};
-static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_tags = {
-       .attr = {.name = "tags", .mode = S_IRUGO },
-       .show = blk_mq_hw_sysfs_tags_show,
+static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_nr_reserved_tags = {
+       .attr = {.name = "nr_reserved_tags", .mode = S_IRUGO },
+       .show = blk_mq_hw_sysfs_nr_reserved_tags_show,
 };
 static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_cpus = {
        .attr = {.name = "cpu_list", .mode = S_IRUGO },
        .show = blk_mq_hw_sysfs_cpus_show,
 };
-static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_poll = {
-       .attr = {.name = "io_poll", .mode = S_IWUSR | S_IRUGO },
-       .show = blk_mq_hw_sysfs_poll_show,
-       .store = blk_mq_hw_sysfs_poll_store,
-};
-static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_stat = {
-       .attr = {.name = "stats", .mode = S_IRUGO | S_IWUSR },
-       .show = blk_mq_hw_sysfs_stat_show,
-       .store = blk_mq_hw_sysfs_stat_store,
-};
 
 static struct attribute *default_hw_ctx_attrs[] = {
-       &blk_mq_hw_sysfs_queued.attr,
-       &blk_mq_hw_sysfs_run.attr,
-       &blk_mq_hw_sysfs_dispatched.attr,
-       &blk_mq_hw_sysfs_pending.attr,
-       &blk_mq_hw_sysfs_tags.attr,
+       &blk_mq_hw_sysfs_nr_tags.attr,
+       &blk_mq_hw_sysfs_nr_reserved_tags.attr,
        &blk_mq_hw_sysfs_cpus.attr,
-       &blk_mq_hw_sysfs_active.attr,
-       &blk_mq_hw_sysfs_poll.attr,
-       &blk_mq_hw_sysfs_stat.attr,
        NULL,
 };
 
@@ -455,6 +254,8 @@ static void __blk_mq_unregister_dev(struct device *dev, struct request_queue *q)
                kobject_put(&hctx->kobj);
        }
 
+       blk_mq_debugfs_unregister_hctxs(q);
+
        kobject_uevent(&q->mq_kobj, KOBJ_REMOVE);
        kobject_del(&q->mq_kobj);
        kobject_put(&q->mq_kobj);
@@ -504,6 +305,8 @@ int blk_mq_register_dev(struct device *dev, struct request_queue *q)
 
        kobject_uevent(&q->mq_kobj, KOBJ_ADD);
 
+       blk_mq_debugfs_register(q, kobject_name(&dev->kobj));
+
        queue_for_each_hw_ctx(q, hctx, i) {
                ret = blk_mq_register_hctx(hctx);
                if (ret)
@@ -529,6 +332,8 @@ void blk_mq_sysfs_unregister(struct request_queue *q)
        if (!q->mq_sysfs_init_done)
                return;
 
+       blk_mq_debugfs_unregister_hctxs(q);
+
        queue_for_each_hw_ctx(q, hctx, i)
                blk_mq_unregister_hctx(hctx);
 }
@@ -541,6 +346,8 @@ int blk_mq_sysfs_register(struct request_queue *q)
        if (!q->mq_sysfs_init_done)
                return ret;
 
+       blk_mq_debugfs_register_hctxs(q);
+
        queue_for_each_hw_ctx(q, hctx, i) {
                ret = blk_mq_register_hctx(hctx);
                if (ret)
index dcf5ce3ba4bff3068486d8596c5941e9f382d228..54c84363c1b2385899472d77cb4fc93c81a59643 100644 (file)
@@ -90,113 +90,97 @@ static inline bool hctx_may_queue(struct blk_mq_hw_ctx *hctx,
        return atomic_read(&hctx->nr_active) < depth;
 }
 
-static int __bt_get(struct blk_mq_hw_ctx *hctx, struct sbitmap_queue *bt)
+static int __blk_mq_get_tag(struct blk_mq_alloc_data *data,
+                           struct sbitmap_queue *bt)
 {
-       if (!hctx_may_queue(hctx, bt))
+       if (!(data->flags & BLK_MQ_REQ_INTERNAL) &&
+           !hctx_may_queue(data->hctx, bt))
                return -1;
        return __sbitmap_queue_get(bt);
 }
 
-static int bt_get(struct blk_mq_alloc_data *data, struct sbitmap_queue *bt,
-                 struct blk_mq_hw_ctx *hctx, struct blk_mq_tags *tags)
+unsigned int blk_mq_get_tag(struct blk_mq_alloc_data *data)
 {
+       struct blk_mq_tags *tags = blk_mq_tags_from_data(data);
+       struct sbitmap_queue *bt;
        struct sbq_wait_state *ws;
        DEFINE_WAIT(wait);
+       unsigned int tag_offset;
+       bool drop_ctx;
        int tag;
 
-       tag = __bt_get(hctx, bt);
+       if (data->flags & BLK_MQ_REQ_RESERVED) {
+               if (unlikely(!tags->nr_reserved_tags)) {
+                       WARN_ON_ONCE(1);
+                       return BLK_MQ_TAG_FAIL;
+               }
+               bt = &tags->breserved_tags;
+               tag_offset = 0;
+       } else {
+               bt = &tags->bitmap_tags;
+               tag_offset = tags->nr_reserved_tags;
+       }
+
+       tag = __blk_mq_get_tag(data, bt);
        if (tag != -1)
-               return tag;
+               goto found_tag;
 
        if (data->flags & BLK_MQ_REQ_NOWAIT)
-               return -1;
+               return BLK_MQ_TAG_FAIL;
 
-       ws = bt_wait_ptr(bt, hctx);
+       ws = bt_wait_ptr(bt, data->hctx);
+       drop_ctx = data->ctx == NULL;
        do {
                prepare_to_wait(&ws->wait, &wait, TASK_UNINTERRUPTIBLE);
 
-               tag = __bt_get(hctx, bt);
+               tag = __blk_mq_get_tag(data, bt);
                if (tag != -1)
                        break;
 
                /*
                 * We're out of tags on this hardware queue, kick any
                 * pending IO submits before going to sleep waiting for
-                * some to complete. Note that hctx can be NULL here for
-                * reserved tag allocation.
+                * some to complete.
                 */
-               if (hctx)
-                       blk_mq_run_hw_queue(hctx, false);
+               blk_mq_run_hw_queue(data->hctx, false);
 
                /*
                 * Retry tag allocation after running the hardware queue,
                 * as running the queue may also have found completions.
                 */
-               tag = __bt_get(hctx, bt);
+               tag = __blk_mq_get_tag(data, bt);
                if (tag != -1)
                        break;
 
-               blk_mq_put_ctx(data->ctx);
+               if (data->ctx)
+                       blk_mq_put_ctx(data->ctx);
 
                io_schedule();
 
                data->ctx = blk_mq_get_ctx(data->q);
                data->hctx = blk_mq_map_queue(data->q, data->ctx->cpu);
-               if (data->flags & BLK_MQ_REQ_RESERVED) {
-                       bt = &data->hctx->tags->breserved_tags;
-               } else {
-                       hctx = data->hctx;
-                       bt = &hctx->tags->bitmap_tags;
-               }
+               tags = blk_mq_tags_from_data(data);
+               if (data->flags & BLK_MQ_REQ_RESERVED)
+                       bt = &tags->breserved_tags;
+               else
+                       bt = &tags->bitmap_tags;
+
                finish_wait(&ws->wait, &wait);
-               ws = bt_wait_ptr(bt, hctx);
+               ws = bt_wait_ptr(bt, data->hctx);
        } while (1);
 
-       finish_wait(&ws->wait, &wait);
-       return tag;
-}
-
-static unsigned int __blk_mq_get_tag(struct blk_mq_alloc_data *data)
-{
-       int tag;
-
-       tag = bt_get(data, &data->hctx->tags->bitmap_tags, data->hctx,
-                    data->hctx->tags);
-       if (tag >= 0)
-               return tag + data->hctx->tags->nr_reserved_tags;
-
-       return BLK_MQ_TAG_FAIL;
-}
-
-static unsigned int __blk_mq_get_reserved_tag(struct blk_mq_alloc_data *data)
-{
-       int tag;
-
-       if (unlikely(!data->hctx->tags->nr_reserved_tags)) {
-               WARN_ON_ONCE(1);
-               return BLK_MQ_TAG_FAIL;
-       }
-
-       tag = bt_get(data, &data->hctx->tags->breserved_tags, NULL,
-                    data->hctx->tags);
-       if (tag < 0)
-               return BLK_MQ_TAG_FAIL;
+       if (drop_ctx && data->ctx)
+               blk_mq_put_ctx(data->ctx);
 
-       return tag;
-}
+       finish_wait(&ws->wait, &wait);
 
-unsigned int blk_mq_get_tag(struct blk_mq_alloc_data *data)
-{
-       if (data->flags & BLK_MQ_REQ_RESERVED)
-               return __blk_mq_get_reserved_tag(data);
-       return __blk_mq_get_tag(data);
+found_tag:
+       return tag + tag_offset;
 }
 
-void blk_mq_put_tag(struct blk_mq_hw_ctx *hctx, struct blk_mq_ctx *ctx,
-                   unsigned int tag)
+void blk_mq_put_tag(struct blk_mq_hw_ctx *hctx, struct blk_mq_tags *tags,
+                   struct blk_mq_ctx *ctx, unsigned int tag)
 {
-       struct blk_mq_tags *tags = hctx->tags;
-
        if (tag >= tags->nr_reserved_tags) {
                const int real_tag = tag - tags->nr_reserved_tags;
 
@@ -312,11 +296,11 @@ int blk_mq_reinit_tagset(struct blk_mq_tag_set *set)
                struct blk_mq_tags *tags = set->tags[i];
 
                for (j = 0; j < tags->nr_tags; j++) {
-                       if (!tags->rqs[j])
+                       if (!tags->static_rqs[j])
                                continue;
 
                        ret = set->ops->reinit_request(set->driver_data,
-                                               tags->rqs[j]);
+                                               tags->static_rqs[j]);
                        if (ret)
                                goto out;
                }
@@ -351,11 +335,6 @@ void blk_mq_queue_tag_busy_iter(struct request_queue *q, busy_iter_fn *fn,
 
 }
 
-static unsigned int bt_unused_tags(const struct sbitmap_queue *bt)
-{
-       return bt->sb.depth - sbitmap_weight(&bt->sb);
-}
-
 static int bt_alloc(struct sbitmap_queue *bt, unsigned int depth,
                    bool round_robin, int node)
 {
@@ -411,19 +390,56 @@ void blk_mq_free_tags(struct blk_mq_tags *tags)
        kfree(tags);
 }
 
-int blk_mq_tag_update_depth(struct blk_mq_tags *tags, unsigned int tdepth)
+int blk_mq_tag_update_depth(struct blk_mq_hw_ctx *hctx,
+                           struct blk_mq_tags **tagsptr, unsigned int tdepth,
+                           bool can_grow)
 {
-       tdepth -= tags->nr_reserved_tags;
-       if (tdepth > tags->nr_tags)
+       struct blk_mq_tags *tags = *tagsptr;
+
+       if (tdepth <= tags->nr_reserved_tags)
                return -EINVAL;
 
+       tdepth -= tags->nr_reserved_tags;
+
        /*
-        * Don't need (or can't) update reserved tags here, they remain
-        * static and should never need resizing.
+        * If we are allowed to grow beyond the original size, allocate
+        * a new set of tags before freeing the old one.
         */
-       sbitmap_queue_resize(&tags->bitmap_tags, tdepth);
+       if (tdepth > tags->nr_tags) {
+               struct blk_mq_tag_set *set = hctx->queue->tag_set;
+               struct blk_mq_tags *new;
+               bool ret;
+
+               if (!can_grow)
+                       return -EINVAL;
+
+               /*
+                * We need some sort of upper limit, set it high enough that
+                * no valid use cases should require more.
+                */
+               if (tdepth > 16 * BLKDEV_MAX_RQ)
+                       return -EINVAL;
+
+               new = blk_mq_alloc_rq_map(set, hctx->queue_num, tdepth, 0);
+               if (!new)
+                       return -ENOMEM;
+               ret = blk_mq_alloc_rqs(set, new, hctx->queue_num, tdepth);
+               if (ret) {
+                       blk_mq_free_rq_map(new);
+                       return -ENOMEM;
+               }
+
+               blk_mq_free_rqs(set, *tagsptr, hctx->queue_num);
+               blk_mq_free_rq_map(*tagsptr);
+               *tagsptr = new;
+       } else {
+               /*
+                * Don't need (or can't) update reserved tags here, they
+                * remain static and should never need resizing.
+                */
+               sbitmap_queue_resize(&tags->bitmap_tags, tdepth);
+       }
 
-       blk_mq_tag_wakeup_all(tags, false);
        return 0;
 }
 
@@ -454,25 +470,3 @@ u32 blk_mq_unique_tag(struct request *rq)
                (rq->tag & BLK_MQ_UNIQUE_TAG_MASK);
 }
 EXPORT_SYMBOL(blk_mq_unique_tag);
-
-ssize_t blk_mq_tag_sysfs_show(struct blk_mq_tags *tags, char *page)
-{
-       char *orig_page = page;
-       unsigned int free, res;
-
-       if (!tags)
-               return 0;
-
-       page += sprintf(page, "nr_tags=%u, reserved_tags=%u, "
-                       "bits_per_word=%u\n",
-                       tags->nr_tags, tags->nr_reserved_tags,
-                       1U << tags->bitmap_tags.sb.shift);
-
-       free = bt_unused_tags(&tags->bitmap_tags);
-       res = bt_unused_tags(&tags->breserved_tags);
-
-       page += sprintf(page, "nr_free=%u, nr_reserved=%u\n", free, res);
-       page += sprintf(page, "active_queues=%u\n", atomic_read(&tags->active_queues));
-
-       return page - orig_page;
-}
index d1662734dc539d866f9edcd48f155e2465f63942..63497423c5cd32fb50542cf626590693c5f929e7 100644 (file)
@@ -16,6 +16,7 @@ struct blk_mq_tags {
        struct sbitmap_queue breserved_tags;
 
        struct request **rqs;
+       struct request **static_rqs;
        struct list_head page_list;
 };
 
@@ -24,11 +25,12 @@ extern struct blk_mq_tags *blk_mq_init_tags(unsigned int nr_tags, unsigned int r
 extern void blk_mq_free_tags(struct blk_mq_tags *tags);
 
 extern unsigned int blk_mq_get_tag(struct blk_mq_alloc_data *data);
-extern void blk_mq_put_tag(struct blk_mq_hw_ctx *hctx, struct blk_mq_ctx *ctx,
-                          unsigned int tag);
+extern void blk_mq_put_tag(struct blk_mq_hw_ctx *hctx, struct blk_mq_tags *tags,
+                          struct blk_mq_ctx *ctx, unsigned int tag);
 extern bool blk_mq_has_free_tags(struct blk_mq_tags *tags);
-extern ssize_t blk_mq_tag_sysfs_show(struct blk_mq_tags *tags, char *page);
-extern int blk_mq_tag_update_depth(struct blk_mq_tags *tags, unsigned int depth);
+extern int blk_mq_tag_update_depth(struct blk_mq_hw_ctx *hctx,
+                                       struct blk_mq_tags **tags,
+                                       unsigned int depth, bool can_grow);
 extern void blk_mq_tag_wakeup_all(struct blk_mq_tags *tags, bool);
 void blk_mq_queue_tag_busy_iter(struct request_queue *q, busy_iter_fn *fn,
                void *priv);
index c3400b5444a7da9842622cb4b0c94b2f1b5ddd64..b29e7dc7b309e4cf939cd2c011b26b38dfd4df73 100644 (file)
@@ -32,6 +32,7 @@
 #include "blk-mq-tag.h"
 #include "blk-stat.h"
 #include "blk-wbt.h"
+#include "blk-mq-sched.h"
 
 static DEFINE_MUTEX(all_q_mutex);
 static LIST_HEAD(all_q_list);
@@ -39,9 +40,11 @@ static LIST_HEAD(all_q_list);
 /*
  * Check if any of the ctx's have pending work in this hardware queue
  */
-static bool blk_mq_hctx_has_pending(struct blk_mq_hw_ctx *hctx)
+bool blk_mq_hctx_has_pending(struct blk_mq_hw_ctx *hctx)
 {
-       return sbitmap_any_bit_set(&hctx->ctx_map);
+       return sbitmap_any_bit_set(&hctx->ctx_map) ||
+                       !list_empty_careful(&hctx->dispatch) ||
+                       blk_mq_sched_has_work(hctx);
 }
 
 /*
@@ -167,8 +170,8 @@ bool blk_mq_can_queue(struct blk_mq_hw_ctx *hctx)
 }
 EXPORT_SYMBOL(blk_mq_can_queue);
 
-static void blk_mq_rq_ctx_init(struct request_queue *q, struct blk_mq_ctx *ctx,
-                              struct request *rq, unsigned int op)
+void blk_mq_rq_ctx_init(struct request_queue *q, struct blk_mq_ctx *ctx,
+                       struct request *rq, unsigned int op)
 {
        INIT_LIST_HEAD(&rq->queuelist);
        /* csd/requeue_work/fifo_time is initialized before use */
@@ -196,13 +199,7 @@ static void blk_mq_rq_ctx_init(struct request_queue *q, struct blk_mq_ctx *ctx,
        rq->special = NULL;
        /* tag was already set */
        rq->errors = 0;
-
-       rq->cmd = rq->__cmd;
-
        rq->extra_len = 0;
-       rq->sense_len = 0;
-       rq->resid_len = 0;
-       rq->sense = NULL;
 
        INIT_LIST_HEAD(&rq->timeout_list);
        rq->timeout = 0;
@@ -213,53 +210,58 @@ static void blk_mq_rq_ctx_init(struct request_queue *q, struct blk_mq_ctx *ctx,
 
        ctx->rq_dispatched[op_is_sync(op)]++;
 }
+EXPORT_SYMBOL_GPL(blk_mq_rq_ctx_init);
 
-static struct request *
-__blk_mq_alloc_request(struct blk_mq_alloc_data *data, unsigned int op)
+struct request *__blk_mq_alloc_request(struct blk_mq_alloc_data *data,
+                                      unsigned int op)
 {
        struct request *rq;
        unsigned int tag;
 
        tag = blk_mq_get_tag(data);
        if (tag != BLK_MQ_TAG_FAIL) {
-               rq = data->hctx->tags->rqs[tag];
+               struct blk_mq_tags *tags = blk_mq_tags_from_data(data);
 
-               if (blk_mq_tag_busy(data->hctx)) {
-                       rq->rq_flags = RQF_MQ_INFLIGHT;
-                       atomic_inc(&data->hctx->nr_active);
+               rq = tags->static_rqs[tag];
+
+               if (data->flags & BLK_MQ_REQ_INTERNAL) {
+                       rq->tag = -1;
+                       rq->internal_tag = tag;
+               } else {
+                       if (blk_mq_tag_busy(data->hctx)) {
+                               rq->rq_flags = RQF_MQ_INFLIGHT;
+                               atomic_inc(&data->hctx->nr_active);
+                       }
+                       rq->tag = tag;
+                       rq->internal_tag = -1;
                }
 
-               rq->tag = tag;
                blk_mq_rq_ctx_init(data->q, data->ctx, rq, op);
                return rq;
        }
 
        return NULL;
 }
+EXPORT_SYMBOL_GPL(__blk_mq_alloc_request);
 
 struct request *blk_mq_alloc_request(struct request_queue *q, int rw,
                unsigned int flags)
 {
-       struct blk_mq_ctx *ctx;
-       struct blk_mq_hw_ctx *hctx;
+       struct blk_mq_alloc_data alloc_data = { .flags = flags };
        struct request *rq;
-       struct blk_mq_alloc_data alloc_data;
        int ret;
 
        ret = blk_queue_enter(q, flags & BLK_MQ_REQ_NOWAIT);
        if (ret)
                return ERR_PTR(ret);
 
-       ctx = blk_mq_get_ctx(q);
-       hctx = blk_mq_map_queue(q, ctx->cpu);
-       blk_mq_set_alloc_data(&alloc_data, q, flags, ctx, hctx);
-       rq = __blk_mq_alloc_request(&alloc_data, rw);
-       blk_mq_put_ctx(ctx);
+       rq = blk_mq_sched_get_request(q, NULL, rw, &alloc_data);
 
-       if (!rq) {
-               blk_queue_exit(q);
+       blk_mq_put_ctx(alloc_data.ctx);
+       blk_queue_exit(q);
+
+       if (!rq)
                return ERR_PTR(-EWOULDBLOCK);
-       }
 
        rq->__data_len = 0;
        rq->__sector = (sector_t) -1;
@@ -319,10 +321,10 @@ out_queue_exit:
 }
 EXPORT_SYMBOL_GPL(blk_mq_alloc_request_hctx);
 
-static void __blk_mq_free_request(struct blk_mq_hw_ctx *hctx,
-                                 struct blk_mq_ctx *ctx, struct request *rq)
+void __blk_mq_finish_request(struct blk_mq_hw_ctx *hctx, struct blk_mq_ctx *ctx,
+                            struct request *rq)
 {
-       const int tag = rq->tag;
+       const int sched_tag = rq->internal_tag;
        struct request_queue *q = rq->q;
 
        if (rq->rq_flags & RQF_MQ_INFLIGHT)
@@ -333,23 +335,31 @@ static void __blk_mq_free_request(struct blk_mq_hw_ctx *hctx,
 
        clear_bit(REQ_ATOM_STARTED, &rq->atomic_flags);
        clear_bit(REQ_ATOM_POLL_SLEPT, &rq->atomic_flags);
-       blk_mq_put_tag(hctx, ctx, tag);
+       if (rq->tag != -1)
+               blk_mq_put_tag(hctx, hctx->tags, ctx, rq->tag);
+       if (sched_tag != -1)
+               blk_mq_sched_completed_request(hctx, rq);
+       blk_mq_sched_restart_queues(hctx);
        blk_queue_exit(q);
 }
 
-void blk_mq_free_hctx_request(struct blk_mq_hw_ctx *hctx, struct request *rq)
+static void blk_mq_finish_hctx_request(struct blk_mq_hw_ctx *hctx,
+                                    struct request *rq)
 {
        struct blk_mq_ctx *ctx = rq->mq_ctx;
 
        ctx->rq_completed[rq_is_sync(rq)]++;
-       __blk_mq_free_request(hctx, ctx, rq);
+       __blk_mq_finish_request(hctx, ctx, rq);
+}
 
+void blk_mq_finish_request(struct request *rq)
+{
+       blk_mq_finish_hctx_request(blk_mq_map_queue(rq->q, rq->mq_ctx->cpu), rq);
 }
-EXPORT_SYMBOL_GPL(blk_mq_free_hctx_request);
 
 void blk_mq_free_request(struct request *rq)
 {
-       blk_mq_free_hctx_request(blk_mq_map_queue(rq->q, rq->mq_ctx->cpu), rq);
+       blk_mq_sched_put_request(rq);
 }
 EXPORT_SYMBOL_GPL(blk_mq_free_request);
 
@@ -467,11 +477,9 @@ void blk_mq_start_request(struct request *rq)
 {
        struct request_queue *q = rq->q;
 
-       trace_block_rq_issue(q, rq);
+       blk_mq_sched_started_request(rq);
 
-       rq->resid_len = blk_rq_bytes(rq);
-       if (unlikely(blk_bidi_rq(rq)))
-               rq->next_rq->resid_len = blk_rq_bytes(rq->next_rq);
+       trace_block_rq_issue(q, rq);
 
        if (test_bit(QUEUE_FLAG_STATS, &q->queue_flags)) {
                blk_stat_set_issue_time(&rq->issue_stat);
@@ -515,6 +523,7 @@ static void __blk_mq_requeue_request(struct request *rq)
 
        trace_block_rq_requeue(q, rq);
        wbt_requeue(q->rq_wb, &rq->issue_stat);
+       blk_mq_sched_requeue_request(rq);
 
        if (test_and_clear_bit(REQ_ATOM_STARTED, &rq->atomic_flags)) {
                if (q->dma_drain_size && blk_rq_bytes(rq))
@@ -549,13 +558,13 @@ static void blk_mq_requeue_work(struct work_struct *work)
 
                rq->rq_flags &= ~RQF_SOFTBARRIER;
                list_del_init(&rq->queuelist);
-               blk_mq_insert_request(rq, true, false, false);
+               blk_mq_sched_insert_request(rq, true, false, false, true);
        }
 
        while (!list_empty(&rq_list)) {
                rq = list_entry(rq_list.next, struct request, queuelist);
                list_del_init(&rq->queuelist);
-               blk_mq_insert_request(rq, false, false, false);
+               blk_mq_sched_insert_request(rq, false, false, false, true);
        }
 
        blk_mq_run_hw_queues(q, false);
@@ -639,7 +648,7 @@ struct blk_mq_timeout_data {
 
 void blk_mq_rq_timed_out(struct request *req, bool reserved)
 {
-       struct blk_mq_ops *ops = req->q->mq_ops;
+       const struct blk_mq_ops *ops = req->q->mq_ops;
        enum blk_eh_timer_return ret = BLK_EH_RESET_TIMER;
 
        /*
@@ -754,7 +763,7 @@ static bool blk_mq_attempt_merge(struct request_queue *q,
        int checked = 8;
 
        list_for_each_entry_reverse(rq, &ctx->rq_list, queuelist) {
-               int el_ret;
+               bool merged = false;
 
                if (!checked--)
                        break;
@@ -762,20 +771,25 @@ static bool blk_mq_attempt_merge(struct request_queue *q,
                if (!blk_rq_merge_ok(rq, bio))
                        continue;
 
-               el_ret = blk_try_merge(rq, bio);
-               if (el_ret == ELEVATOR_BACK_MERGE) {
-                       if (bio_attempt_back_merge(q, rq, bio)) {
-                               ctx->rq_merged++;
-                               return true;
-                       }
+               switch (blk_try_merge(rq, bio)) {
+               case ELEVATOR_BACK_MERGE:
+                       if (blk_mq_sched_allow_merge(q, rq, bio))
+                               merged = bio_attempt_back_merge(q, rq, bio);
                        break;
-               } else if (el_ret == ELEVATOR_FRONT_MERGE) {
-                       if (bio_attempt_front_merge(q, rq, bio)) {
-                               ctx->rq_merged++;
-                               return true;
-                       }
+               case ELEVATOR_FRONT_MERGE:
+                       if (blk_mq_sched_allow_merge(q, rq, bio))
+                               merged = bio_attempt_front_merge(q, rq, bio);
+                       break;
+               case ELEVATOR_DISCARD_MERGE:
+                       merged = bio_attempt_discard_merge(q, rq, bio);
                        break;
+               default:
+                       continue;
                }
+
+               if (merged)
+                       ctx->rq_merged++;
+               return merged;
        }
 
        return false;
@@ -803,7 +817,7 @@ static bool flush_busy_ctx(struct sbitmap *sb, unsigned int bitnr, void *data)
  * Process software queues that have been marked busy, splicing them
  * to the for-dispatch
  */
-static void flush_busy_ctxs(struct blk_mq_hw_ctx *hctx, struct list_head *list)
+void blk_mq_flush_busy_ctxs(struct blk_mq_hw_ctx *hctx, struct list_head *list)
 {
        struct flush_busy_ctx_data data = {
                .hctx = hctx,
@@ -812,6 +826,7 @@ static void flush_busy_ctxs(struct blk_mq_hw_ctx *hctx, struct list_head *list)
 
        sbitmap_for_each_set(&hctx->ctx_map, flush_busy_ctx, &data);
 }
+EXPORT_SYMBOL_GPL(blk_mq_flush_busy_ctxs);
 
 static inline unsigned int queued_to_index(unsigned int queued)
 {
@@ -821,6 +836,74 @@ static inline unsigned int queued_to_index(unsigned int queued)
        return min(BLK_MQ_MAX_DISPATCH_ORDER - 1, ilog2(queued) + 1);
 }
 
+bool blk_mq_get_driver_tag(struct request *rq, struct blk_mq_hw_ctx **hctx,
+                          bool wait)
+{
+       struct blk_mq_alloc_data data = {
+               .q = rq->q,
+               .hctx = blk_mq_map_queue(rq->q, rq->mq_ctx->cpu),
+               .flags = wait ? 0 : BLK_MQ_REQ_NOWAIT,
+       };
+
+       if (rq->tag != -1) {
+done:
+               if (hctx)
+                       *hctx = data.hctx;
+               return true;
+       }
+
+       rq->tag = blk_mq_get_tag(&data);
+       if (rq->tag >= 0) {
+               if (blk_mq_tag_busy(data.hctx)) {
+                       rq->rq_flags |= RQF_MQ_INFLIGHT;
+                       atomic_inc(&data.hctx->nr_active);
+               }
+               data.hctx->tags->rqs[rq->tag] = rq;
+               goto done;
+       }
+
+       return false;
+}
+
+static void blk_mq_put_driver_tag(struct blk_mq_hw_ctx *hctx,
+                                 struct request *rq)
+{
+       if (rq->tag == -1 || rq->internal_tag == -1)
+               return;
+
+       blk_mq_put_tag(hctx, hctx->tags, rq->mq_ctx, rq->tag);
+       rq->tag = -1;
+
+       if (rq->rq_flags & RQF_MQ_INFLIGHT) {
+               rq->rq_flags &= ~RQF_MQ_INFLIGHT;
+               atomic_dec(&hctx->nr_active);
+       }
+}
+
+/*
+ * If we fail getting a driver tag because all the driver tags are already
+ * assigned and on the dispatch list, BUT the first entry does not have a
+ * tag, then we could deadlock. For that case, move entries with assigned
+ * driver tags to the front, leaving the set of tagged requests in the
+ * same order, and the untagged set in the same order.
+ */
+static bool reorder_tags_to_front(struct list_head *list)
+{
+       struct request *rq, *tmp, *first = NULL;
+
+       list_for_each_entry_safe_reverse(rq, tmp, list, queuelist) {
+               if (rq == first)
+                       break;
+               if (rq->tag != -1) {
+                       list_move(&rq->queuelist, list);
+                       if (!first)
+                               first = rq;
+               }
+       }
+
+       return first != NULL;
+}
+
 bool blk_mq_dispatch_rq_list(struct blk_mq_hw_ctx *hctx, struct list_head *list)
 {
        struct request_queue *q = hctx->queue;
@@ -843,6 +926,20 @@ bool blk_mq_dispatch_rq_list(struct blk_mq_hw_ctx *hctx, struct list_head *list)
                struct blk_mq_queue_data bd;
 
                rq = list_first_entry(list, struct request, queuelist);
+               if (!blk_mq_get_driver_tag(rq, &hctx, false)) {
+                       if (!queued && reorder_tags_to_front(list))
+                               continue;
+
+                       /*
+                        * We failed getting a driver tag. Mark the queue(s)
+                        * as needing a restart. Retry getting a tag again,
+                        * in case the needed IO completed right before we
+                        * marked the queue as needing a restart.
+                        */
+                       blk_mq_sched_mark_restart(hctx);
+                       if (!blk_mq_get_driver_tag(rq, &hctx, false))
+                               break;
+               }
                list_del_init(&rq->queuelist);
 
                bd.rq = rq;
@@ -855,6 +952,7 @@ bool blk_mq_dispatch_rq_list(struct blk_mq_hw_ctx *hctx, struct list_head *list)
                        queued++;
                        break;
                case BLK_MQ_RQ_QUEUE_BUSY:
+                       blk_mq_put_driver_tag(hctx, rq);
                        list_add(&rq->queuelist, list);
                        __blk_mq_requeue_request(rq);
                        break;
@@ -885,7 +983,7 @@ bool blk_mq_dispatch_rq_list(struct blk_mq_hw_ctx *hctx, struct list_head *list)
         */
        if (!list_empty(list)) {
                spin_lock(&hctx->lock);
-               list_splice(list, &hctx->dispatch);
+               list_splice_init(list, &hctx->dispatch);
                spin_unlock(&hctx->lock);
 
                /*
@@ -896,45 +994,15 @@ bool blk_mq_dispatch_rq_list(struct blk_mq_hw_ctx *hctx, struct list_head *list)
                 * the requests in rq_list might get lost.
                 *
                 * blk_mq_run_hw_queue() already checks the STOPPED bit
-                **/
-               blk_mq_run_hw_queue(hctx, true);
-       }
-
-       return ret != BLK_MQ_RQ_QUEUE_BUSY;
-}
-
-/*
- * Run this hardware queue, pulling any software queues mapped to it in.
- * Note that this function currently has various problems around ordering
- * of IO. In particular, we'd like FIFO behaviour on handling existing
- * items on the hctx->dispatch list. Ignore that for now.
- */
-static void blk_mq_process_rq_list(struct blk_mq_hw_ctx *hctx)
-{
-       LIST_HEAD(rq_list);
-
-       if (unlikely(blk_mq_hctx_stopped(hctx)))
-               return;
-
-       hctx->run++;
-
-       /*
-        * Touch any software queue that has pending entries.
-        */
-       flush_busy_ctxs(hctx, &rq_list);
-
-       /*
-        * If we have previous entries on our dispatch list, grab them
-        * and stuff them at the front for more fair dispatch.
-        */
-       if (!list_empty_careful(&hctx->dispatch)) {
-               spin_lock(&hctx->lock);
-               if (!list_empty(&hctx->dispatch))
-                       list_splice_init(&hctx->dispatch, &rq_list);
-               spin_unlock(&hctx->lock);
+                *
+                * If RESTART is set, then let completion restart the queue
+                * instead of potentially looping here.
+                */
+               if (!blk_mq_sched_needs_restart(hctx))
+                       blk_mq_run_hw_queue(hctx, true);
        }
 
-       blk_mq_dispatch_rq_list(hctx, &rq_list);
+       return queued != 0;
 }
 
 static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx)
@@ -946,11 +1014,11 @@ static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx)
 
        if (!(hctx->flags & BLK_MQ_F_BLOCKING)) {
                rcu_read_lock();
-               blk_mq_process_rq_list(hctx);
+               blk_mq_sched_dispatch_requests(hctx);
                rcu_read_unlock();
        } else {
                srcu_idx = srcu_read_lock(&hctx->queue_rq_srcu);
-               blk_mq_process_rq_list(hctx);
+               blk_mq_sched_dispatch_requests(hctx);
                srcu_read_unlock(&hctx->queue_rq_srcu, srcu_idx);
        }
 }
@@ -1006,8 +1074,7 @@ void blk_mq_run_hw_queues(struct request_queue *q, bool async)
        int i;
 
        queue_for_each_hw_ctx(q, hctx, i) {
-               if ((!blk_mq_hctx_has_pending(hctx) &&
-                   list_empty_careful(&hctx->dispatch)) ||
+               if (!blk_mq_hctx_has_pending(hctx) ||
                    blk_mq_hctx_stopped(hctx))
                        continue;
 
@@ -1116,6 +1183,7 @@ void blk_mq_delay_queue(struct blk_mq_hw_ctx *hctx, unsigned long msecs)
        if (unlikely(!blk_mq_hw_queue_mapped(hctx)))
                return;
 
+       blk_mq_stop_hw_queue(hctx);
        kblockd_schedule_delayed_work_on(blk_mq_hctx_next_cpu(hctx),
                        &hctx->delay_work, msecs_to_jiffies(msecs));
 }
@@ -1135,8 +1203,8 @@ static inline void __blk_mq_insert_req_list(struct blk_mq_hw_ctx *hctx,
                list_add_tail(&rq->queuelist, &ctx->rq_list);
 }
 
-static void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx,
-                                   struct request *rq, bool at_head)
+void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq,
+                            bool at_head)
 {
        struct blk_mq_ctx *ctx = rq->mq_ctx;
 
@@ -1144,32 +1212,10 @@ static void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx,
        blk_mq_hctx_mark_pending(hctx, ctx);
 }
 
-void blk_mq_insert_request(struct request *rq, bool at_head, bool run_queue,
-                          bool async)
-{
-       struct blk_mq_ctx *ctx = rq->mq_ctx;
-       struct request_queue *q = rq->q;
-       struct blk_mq_hw_ctx *hctx = blk_mq_map_queue(q, ctx->cpu);
-
-       spin_lock(&ctx->lock);
-       __blk_mq_insert_request(hctx, rq, at_head);
-       spin_unlock(&ctx->lock);
-
-       if (run_queue)
-               blk_mq_run_hw_queue(hctx, async);
-}
-
-static void blk_mq_insert_requests(struct request_queue *q,
-                                    struct blk_mq_ctx *ctx,
-                                    struct list_head *list,
-                                    int depth,
-                                    bool from_schedule)
+void blk_mq_insert_requests(struct blk_mq_hw_ctx *hctx, struct blk_mq_ctx *ctx,
+                           struct list_head *list)
 
 {
-       struct blk_mq_hw_ctx *hctx = blk_mq_map_queue(q, ctx->cpu);
-
-       trace_block_unplug(q, depth, !from_schedule);
-
        /*
         * preemption doesn't flush plug list, so it's possible ctx->cpu is
         * offline now
@@ -1185,8 +1231,6 @@ static void blk_mq_insert_requests(struct request_queue *q,
        }
        blk_mq_hctx_mark_pending(hctx, ctx);
        spin_unlock(&ctx->lock);
-
-       blk_mq_run_hw_queue(hctx, from_schedule);
 }
 
 static int plug_ctx_cmp(void *priv, struct list_head *a, struct list_head *b)
@@ -1222,9 +1266,10 @@ void blk_mq_flush_plug_list(struct blk_plug *plug, bool from_schedule)
                BUG_ON(!rq->q);
                if (rq->mq_ctx != this_ctx) {
                        if (this_ctx) {
-                               blk_mq_insert_requests(this_q, this_ctx,
-                                                       &ctx_list, depth,
-                                                       from_schedule);
+                               trace_block_unplug(this_q, depth, from_schedule);
+                               blk_mq_sched_insert_requests(this_q, this_ctx,
+                                                               &ctx_list,
+                                                               from_schedule);
                        }
 
                        this_ctx = rq->mq_ctx;
@@ -1241,8 +1286,9 @@ void blk_mq_flush_plug_list(struct blk_plug *plug, bool from_schedule)
         * on 'ctx_list'. Do those.
         */
        if (this_ctx) {
-               blk_mq_insert_requests(this_q, this_ctx, &ctx_list, depth,
-                                      from_schedule);
+               trace_block_unplug(this_q, depth, from_schedule);
+               blk_mq_sched_insert_requests(this_q, this_ctx, &ctx_list,
+                                               from_schedule);
        }
 }
 
@@ -1280,46 +1326,39 @@ insert_rq:
                }
 
                spin_unlock(&ctx->lock);
-               __blk_mq_free_request(hctx, ctx, rq);
+               __blk_mq_finish_request(hctx, ctx, rq);
                return true;
        }
 }
 
-static struct request *blk_mq_map_request(struct request_queue *q,
-                                         struct bio *bio,
-                                         struct blk_mq_alloc_data *data)
+static blk_qc_t request_to_qc_t(struct blk_mq_hw_ctx *hctx, struct request *rq)
 {
-       struct blk_mq_hw_ctx *hctx;
-       struct blk_mq_ctx *ctx;
-       struct request *rq;
+       if (rq->tag != -1)
+               return blk_tag_to_qc_t(rq->tag, hctx->queue_num, false);
 
-       blk_queue_enter_live(q);
-       ctx = blk_mq_get_ctx(q);
-       hctx = blk_mq_map_queue(q, ctx->cpu);
-
-       trace_block_getrq(q, bio, bio->bi_opf);
-       blk_mq_set_alloc_data(data, q, 0, ctx, hctx);
-       rq = __blk_mq_alloc_request(data, bio->bi_opf);
-
-       data->hctx->queued++;
-       return rq;
+       return blk_tag_to_qc_t(rq->internal_tag, hctx->queue_num, true);
 }
 
 static void blk_mq_try_issue_directly(struct request *rq, blk_qc_t *cookie)
 {
-       int ret;
        struct request_queue *q = rq->q;
-       struct blk_mq_hw_ctx *hctx = blk_mq_map_queue(q, rq->mq_ctx->cpu);
        struct blk_mq_queue_data bd = {
                .rq = rq,
                .list = NULL,
                .last = 1
        };
-       blk_qc_t new_cookie = blk_tag_to_qc_t(rq->tag, hctx->queue_num);
+       struct blk_mq_hw_ctx *hctx;
+       blk_qc_t new_cookie;
+       int ret;
 
-       if (blk_mq_hctx_stopped(hctx))
+       if (q->elevator)
                goto insert;
 
+       if (!blk_mq_get_driver_tag(rq, &hctx, false))
+               goto insert;
+
+       new_cookie = request_to_qc_t(hctx, rq);
+
        /*
         * For OK queue, we are done. For error, kill it. Any other
         * error (busy), just add it to our list as we previously
@@ -1341,7 +1380,7 @@ static void blk_mq_try_issue_directly(struct request *rq, blk_qc_t *cookie)
        }
 
 insert:
-       blk_mq_insert_request(rq, false, true, true);
+       blk_mq_sched_insert_request(rq, false, true, true, false);
 }
 
 /*
@@ -1352,8 +1391,8 @@ insert:
 static blk_qc_t blk_mq_make_request(struct request_queue *q, struct bio *bio)
 {
        const int is_sync = op_is_sync(bio->bi_opf);
-       const int is_flush_fua = bio->bi_opf & (REQ_PREFLUSH | REQ_FUA);
-       struct blk_mq_alloc_data data;
+       const int is_flush_fua = op_is_flush(bio->bi_opf);
+       struct blk_mq_alloc_data data = { .flags = 0 };
        struct request *rq;
        unsigned int request_count = 0, srcu_idx;
        struct blk_plug *plug;
@@ -1374,9 +1413,14 @@ static blk_qc_t blk_mq_make_request(struct request_queue *q, struct bio *bio)
            blk_attempt_plug_merge(q, bio, &request_count, &same_queue_rq))
                return BLK_QC_T_NONE;
 
+       if (blk_mq_sched_bio_merge(q, bio))
+               return BLK_QC_T_NONE;
+
        wb_acct = wbt_wait(q->rq_wb, bio, NULL);
 
-       rq = blk_mq_map_request(q, bio, &data);
+       trace_block_getrq(q, bio, bio->bi_opf);
+
+       rq = blk_mq_sched_get_request(q, bio, bio->bi_opf, &data);
        if (unlikely(!rq)) {
                __wbt_done(q->rq_wb, wb_acct);
                return BLK_QC_T_NONE;
@@ -1384,9 +1428,11 @@ static blk_qc_t blk_mq_make_request(struct request_queue *q, struct bio *bio)
 
        wbt_track(&rq->issue_stat, wb_acct);
 
-       cookie = blk_tag_to_qc_t(rq->tag, data.hctx->queue_num);
+       cookie = request_to_qc_t(data.hctx, rq);
 
        if (unlikely(is_flush_fua)) {
+               if (q->elevator)
+                       goto elv_insert;
                blk_mq_bio_to_request(rq, bio);
                blk_insert_flush(rq);
                goto run_queue;
@@ -1438,6 +1484,14 @@ static blk_qc_t blk_mq_make_request(struct request_queue *q, struct bio *bio)
                goto done;
        }
 
+       if (q->elevator) {
+elv_insert:
+               blk_mq_put_ctx(data.ctx);
+               blk_mq_bio_to_request(rq, bio);
+               blk_mq_sched_insert_request(rq, false, true,
+                                               !is_sync || is_flush_fua, true);
+               goto done;
+       }
        if (!blk_mq_merge_queue_io(data.hctx, data.ctx, rq, bio)) {
                /*
                 * For a SYNC request, send it to the hardware immediately. For
@@ -1460,10 +1514,10 @@ done:
 static blk_qc_t blk_sq_make_request(struct request_queue *q, struct bio *bio)
 {
        const int is_sync = op_is_sync(bio->bi_opf);
-       const int is_flush_fua = bio->bi_opf & (REQ_PREFLUSH | REQ_FUA);
+       const int is_flush_fua = op_is_flush(bio->bi_opf);
        struct blk_plug *plug;
        unsigned int request_count = 0;
-       struct blk_mq_alloc_data data;
+       struct blk_mq_alloc_data data = { .flags = 0 };
        struct request *rq;
        blk_qc_t cookie;
        unsigned int wb_acct;
@@ -1483,9 +1537,14 @@ static blk_qc_t blk_sq_make_request(struct request_queue *q, struct bio *bio)
        } else
                request_count = blk_plug_queued_count(q);
 
+       if (blk_mq_sched_bio_merge(q, bio))
+               return BLK_QC_T_NONE;
+
        wb_acct = wbt_wait(q->rq_wb, bio, NULL);
 
-       rq = blk_mq_map_request(q, bio, &data);
+       trace_block_getrq(q, bio, bio->bi_opf);
+
+       rq = blk_mq_sched_get_request(q, bio, bio->bi_opf, &data);
        if (unlikely(!rq)) {
                __wbt_done(q->rq_wb, wb_acct);
                return BLK_QC_T_NONE;
@@ -1493,9 +1552,11 @@ static blk_qc_t blk_sq_make_request(struct request_queue *q, struct bio *bio)
 
        wbt_track(&rq->issue_stat, wb_acct);
 
-       cookie = blk_tag_to_qc_t(rq->tag, data.hctx->queue_num);
+       cookie = request_to_qc_t(data.hctx, rq);
 
        if (unlikely(is_flush_fua)) {
+               if (q->elevator)
+                       goto elv_insert;
                blk_mq_bio_to_request(rq, bio);
                blk_insert_flush(rq);
                goto run_queue;
@@ -1535,6 +1596,14 @@ static blk_qc_t blk_sq_make_request(struct request_queue *q, struct bio *bio)
                return cookie;
        }
 
+       if (q->elevator) {
+elv_insert:
+               blk_mq_put_ctx(data.ctx);
+               blk_mq_bio_to_request(rq, bio);
+               blk_mq_sched_insert_request(rq, false, true,
+                                               !is_sync || is_flush_fua, true);
+               goto done;
+       }
        if (!blk_mq_merge_queue_io(data.hctx, data.ctx, rq, bio)) {
                /*
                 * For a SYNC request, send it to the hardware immediately. For
@@ -1547,11 +1616,12 @@ run_queue:
        }
 
        blk_mq_put_ctx(data.ctx);
+done:
        return cookie;
 }
 
-static void blk_mq_free_rq_map(struct blk_mq_tag_set *set,
-               struct blk_mq_tags *tags, unsigned int hctx_idx)
+void blk_mq_free_rqs(struct blk_mq_tag_set *set, struct blk_mq_tags *tags,
+                    unsigned int hctx_idx)
 {
        struct page *page;
 
@@ -1559,11 +1629,13 @@ static void blk_mq_free_rq_map(struct blk_mq_tag_set *set,
                int i;
 
                for (i = 0; i < tags->nr_tags; i++) {
-                       if (!tags->rqs[i])
+                       struct request *rq = tags->static_rqs[i];
+
+                       if (!rq)
                                continue;
-                       set->ops->exit_request(set->driver_data, tags->rqs[i],
+                       set->ops->exit_request(set->driver_data, rq,
                                                hctx_idx, i);
-                       tags->rqs[i] = NULL;
+                       tags->static_rqs[i] = NULL;
                }
        }
 
@@ -1577,33 +1649,32 @@ static void blk_mq_free_rq_map(struct blk_mq_tag_set *set,
                kmemleak_free(page_address(page));
                __free_pages(page, page->private);
        }
+}
 
+void blk_mq_free_rq_map(struct blk_mq_tags *tags)
+{
        kfree(tags->rqs);
+       tags->rqs = NULL;
+       kfree(tags->static_rqs);
+       tags->static_rqs = NULL;
 
        blk_mq_free_tags(tags);
 }
 
-static size_t order_to_size(unsigned int order)
-{
-       return (size_t)PAGE_SIZE << order;
-}
-
-static struct blk_mq_tags *blk_mq_init_rq_map(struct blk_mq_tag_set *set,
-               unsigned int hctx_idx)
+struct blk_mq_tags *blk_mq_alloc_rq_map(struct blk_mq_tag_set *set,
+                                       unsigned int hctx_idx,
+                                       unsigned int nr_tags,
+                                       unsigned int reserved_tags)
 {
        struct blk_mq_tags *tags;
-       unsigned int i, j, entries_per_page, max_order = 4;
-       size_t rq_size, left;
 
-       tags = blk_mq_init_tags(set->queue_depth, set->reserved_tags,
+       tags = blk_mq_init_tags(nr_tags, reserved_tags,
                                set->numa_node,
                                BLK_MQ_FLAG_TO_ALLOC_POLICY(set->flags));
        if (!tags)
                return NULL;
 
-       INIT_LIST_HEAD(&tags->page_list);
-
-       tags->rqs = kzalloc_node(set->queue_depth * sizeof(struct request *),
+       tags->rqs = kzalloc_node(nr_tags * sizeof(struct request *),
                                 GFP_NOIO | __GFP_NOWARN | __GFP_NORETRY,
                                 set->numa_node);
        if (!tags->rqs) {
@@ -1611,15 +1682,40 @@ static struct blk_mq_tags *blk_mq_init_rq_map(struct blk_mq_tag_set *set,
                return NULL;
        }
 
+       tags->static_rqs = kzalloc_node(nr_tags * sizeof(struct request *),
+                                GFP_NOIO | __GFP_NOWARN | __GFP_NORETRY,
+                                set->numa_node);
+       if (!tags->static_rqs) {
+               kfree(tags->rqs);
+               blk_mq_free_tags(tags);
+               return NULL;
+       }
+
+       return tags;
+}
+
+static size_t order_to_size(unsigned int order)
+{
+       return (size_t)PAGE_SIZE << order;
+}
+
+int blk_mq_alloc_rqs(struct blk_mq_tag_set *set, struct blk_mq_tags *tags,
+                    unsigned int hctx_idx, unsigned int depth)
+{
+       unsigned int i, j, entries_per_page, max_order = 4;
+       size_t rq_size, left;
+
+       INIT_LIST_HEAD(&tags->page_list);
+
        /*
         * rq_size is the size of the request plus driver payload, rounded
         * to the cacheline size
         */
        rq_size = round_up(sizeof(struct request) + set->cmd_size,
                                cache_line_size());
-       left = rq_size * set->queue_depth;
+       left = rq_size * depth;
 
-       for (i = 0; i < set->queue_depth; ) {
+       for (i = 0; i < depth; ) {
                int this_order = max_order;
                struct page *page;
                int to_do;
@@ -1653,15 +1749,17 @@ static struct blk_mq_tags *blk_mq_init_rq_map(struct blk_mq_tag_set *set,
                 */
                kmemleak_alloc(p, order_to_size(this_order), 1, GFP_NOIO);
                entries_per_page = order_to_size(this_order) / rq_size;
-               to_do = min(entries_per_page, set->queue_depth - i);
+               to_do = min(entries_per_page, depth - i);
                left -= to_do * rq_size;
                for (j = 0; j < to_do; j++) {
-                       tags->rqs[i] = p;
+                       struct request *rq = p;
+
+                       tags->static_rqs[i] = rq;
                        if (set->ops->init_request) {
                                if (set->ops->init_request(set->driver_data,
-                                               tags->rqs[i], hctx_idx, i,
+                                               rq, hctx_idx, i,
                                                set->numa_node)) {
-                                       tags->rqs[i] = NULL;
+                                       tags->static_rqs[i] = NULL;
                                        goto fail;
                                }
                        }
@@ -1670,11 +1768,11 @@ static struct blk_mq_tags *blk_mq_init_rq_map(struct blk_mq_tag_set *set,
                        i++;
                }
        }
-       return tags;
+       return 0;
 
 fail:
-       blk_mq_free_rq_map(set, tags, hctx_idx);
-       return NULL;
+       blk_mq_free_rqs(set, tags, hctx_idx);
+       return -ENOMEM;
 }
 
 /*
@@ -1866,6 +1964,35 @@ static void blk_mq_init_cpu_queues(struct request_queue *q,
        }
 }
 
+static bool __blk_mq_alloc_rq_map(struct blk_mq_tag_set *set, int hctx_idx)
+{
+       int ret = 0;
+
+       set->tags[hctx_idx] = blk_mq_alloc_rq_map(set, hctx_idx,
+                                       set->queue_depth, set->reserved_tags);
+       if (!set->tags[hctx_idx])
+               return false;
+
+       ret = blk_mq_alloc_rqs(set, set->tags[hctx_idx], hctx_idx,
+                               set->queue_depth);
+       if (!ret)
+               return true;
+
+       blk_mq_free_rq_map(set->tags[hctx_idx]);
+       set->tags[hctx_idx] = NULL;
+       return false;
+}
+
+static void blk_mq_free_map_and_requests(struct blk_mq_tag_set *set,
+                                        unsigned int hctx_idx)
+{
+       if (set->tags[hctx_idx]) {
+               blk_mq_free_rqs(set, set->tags[hctx_idx], hctx_idx);
+               blk_mq_free_rq_map(set->tags[hctx_idx]);
+               set->tags[hctx_idx] = NULL;
+       }
+}
+
 static void blk_mq_map_swqueue(struct request_queue *q,
                               const struct cpumask *online_mask)
 {
@@ -1894,17 +2021,15 @@ static void blk_mq_map_swqueue(struct request_queue *q,
 
                hctx_idx = q->mq_map[i];
                /* unmapped hw queue can be remapped after CPU topo changed */
-               if (!set->tags[hctx_idx]) {
-                       set->tags[hctx_idx] = blk_mq_init_rq_map(set, hctx_idx);
-
+               if (!set->tags[hctx_idx] &&
+                   !__blk_mq_alloc_rq_map(set, hctx_idx)) {
                        /*
                         * If tags initialization fail for some hctx,
                         * that hctx won't be brought online.  In this
                         * case, remap the current ctx to hctx[0] which
                         * is guaranteed to always have tags allocated
                         */
-                       if (!set->tags[hctx_idx])
-                               q->mq_map[i] = 0;
+                       q->mq_map[i] = 0;
                }
 
                ctx = per_cpu_ptr(q->queue_ctx, i);
@@ -1927,10 +2052,9 @@ static void blk_mq_map_swqueue(struct request_queue *q,
                         * fallback in case of a new remap fails
                         * allocation
                         */
-                       if (i && set->tags[i]) {
-                               blk_mq_free_rq_map(set, set->tags[i], i);
-                               set->tags[i] = NULL;
-                       }
+                       if (i && set->tags[i])
+                               blk_mq_free_map_and_requests(set, i);
+
                        hctx->tags = NULL;
                        continue;
                }
@@ -2023,6 +2147,8 @@ void blk_mq_release(struct request_queue *q)
        struct blk_mq_hw_ctx *hctx;
        unsigned int i;
 
+       blk_mq_sched_teardown(q);
+
        /* hctx kobj stays in hctx */
        queue_for_each_hw_ctx(q, hctx, i) {
                if (!hctx)
@@ -2097,10 +2223,8 @@ static void blk_mq_realloc_hw_ctxs(struct blk_mq_tag_set *set,
                struct blk_mq_hw_ctx *hctx = hctxs[j];
 
                if (hctx) {
-                       if (hctx->tags) {
-                               blk_mq_free_rq_map(set, hctx->tags, j);
-                               set->tags[j] = NULL;
-                       }
+                       if (hctx->tags)
+                               blk_mq_free_map_and_requests(set, j);
                        blk_mq_exit_hctx(q, set, hctx, j);
                        free_cpumask_var(hctx->cpumask);
                        kobject_put(&hctx->kobj);
@@ -2181,6 +2305,14 @@ struct request_queue *blk_mq_init_allocated_queue(struct blk_mq_tag_set *set,
        mutex_unlock(&all_q_mutex);
        put_online_cpus();
 
+       if (!(set->flags & BLK_MQ_F_NO_SCHED)) {
+               int ret;
+
+               ret = blk_mq_sched_init(q);
+               if (ret)
+                       return ERR_PTR(ret);
+       }
+
        return q;
 
 err_hctxs:
@@ -2279,10 +2411,10 @@ static int blk_mq_queue_reinit_dead(unsigned int cpu)
  * Now CPU1 is just onlined and a request is inserted into ctx1->rq_list
  * and set bit0 in pending bitmap as ctx1->index_hw is still zero.
  *
- * And then while running hw queue, flush_busy_ctxs() finds bit0 is set in
- * pending bitmap and tries to retrieve requests in hctx->ctxs[0]->rq_list.
- * But htx->ctxs[0] is a pointer to ctx0, so the request in ctx1->rq_list
- * is ignored.
+ * And then while running hw queue, blk_mq_flush_busy_ctxs() finds bit0 is set
+ * in pending bitmap and tries to retrieve requests in hctx->ctxs[0]->rq_list.
+ * But htx->ctxs[0] is a pointer to ctx0, so the request in ctx1->rq_list is
+ * ignored.
  */
 static int blk_mq_queue_reinit_prepare(unsigned int cpu)
 {
@@ -2296,17 +2428,15 @@ static int __blk_mq_alloc_rq_maps(struct blk_mq_tag_set *set)
 {
        int i;
 
-       for (i = 0; i < set->nr_hw_queues; i++) {
-               set->tags[i] = blk_mq_init_rq_map(set, i);
-               if (!set->tags[i])
+       for (i = 0; i < set->nr_hw_queues; i++)
+               if (!__blk_mq_alloc_rq_map(set, i))
                        goto out_unwind;
-       }
 
        return 0;
 
 out_unwind:
        while (--i >= 0)
-               blk_mq_free_rq_map(set, set->tags[i], i);
+               blk_mq_free_rq_map(set->tags[i]);
 
        return -ENOMEM;
 }
@@ -2430,10 +2560,8 @@ void blk_mq_free_tag_set(struct blk_mq_tag_set *set)
 {
        int i;
 
-       for (i = 0; i < nr_cpu_ids; i++) {
-               if (set->tags[i])
-                       blk_mq_free_rq_map(set, set->tags[i], i);
-       }
+       for (i = 0; i < nr_cpu_ids; i++)
+               blk_mq_free_map_and_requests(set, i);
 
        kfree(set->mq_map);
        set->mq_map = NULL;
@@ -2449,14 +2577,28 @@ int blk_mq_update_nr_requests(struct request_queue *q, unsigned int nr)
        struct blk_mq_hw_ctx *hctx;
        int i, ret;
 
-       if (!set || nr > set->queue_depth)
+       if (!set)
                return -EINVAL;
 
+       blk_mq_freeze_queue(q);
+       blk_mq_quiesce_queue(q);
+
        ret = 0;
        queue_for_each_hw_ctx(q, hctx, i) {
                if (!hctx->tags)
                        continue;
-               ret = blk_mq_tag_update_depth(hctx->tags, nr);
+               /*
+                * If we're using an MQ scheduler, just update the scheduler
+                * queue depth. This is similar to what the old code would do.
+                */
+               if (!hctx->sched_tags) {
+                       ret = blk_mq_tag_update_depth(hctx, &hctx->tags,
+                                                       min(nr, set->queue_depth),
+                                                       false);
+               } else {
+                       ret = blk_mq_tag_update_depth(hctx, &hctx->sched_tags,
+                                                       nr, true);
+               }
                if (ret)
                        break;
        }
@@ -2464,6 +2606,9 @@ int blk_mq_update_nr_requests(struct request_queue *q, unsigned int nr)
        if (!ret)
                q->nr_requests = nr;
 
+       blk_mq_unfreeze_queue(q);
+       blk_mq_start_stopped_hw_queues(q, true);
+
        return ret;
 }
 
@@ -2483,10 +2628,14 @@ void blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set, int nr_hw_queues)
        list_for_each_entry(q, &set->tag_list, tag_set_list) {
                blk_mq_realloc_hw_ctxs(set, q);
 
+               /*
+                * Manually set the make_request_fn as blk_queue_make_request
+                * resets a lot of the queue settings.
+                */
                if (q->nr_hw_queues > 1)
-                       blk_queue_make_request(q, blk_mq_make_request);
+                       q->make_request_fn = blk_mq_make_request;
                else
-                       blk_queue_make_request(q, blk_sq_make_request);
+                       q->make_request_fn = blk_sq_make_request;
 
                blk_mq_queue_reinit(q, cpu_online_mask);
        }
@@ -2649,7 +2798,10 @@ bool blk_mq_poll(struct request_queue *q, blk_qc_t cookie)
                blk_flush_plug_list(plug, false);
 
        hctx = q->queue_hw_ctx[blk_qc_t_to_queue_num(cookie)];
-       rq = blk_mq_tag_to_rq(hctx->tags, blk_qc_t_to_tag(cookie));
+       if (!blk_qc_t_is_internal(cookie))
+               rq = blk_mq_tag_to_rq(hctx->tags, blk_qc_t_to_tag(cookie));
+       else
+               rq = blk_mq_tag_to_rq(hctx->sched_tags, blk_qc_t_to_tag(cookie));
 
        return __blk_mq_poll(hctx, rq);
 }
index 63e9116cddbd575c9ed85d716df0e4252f89d261..24b2256186f33fc38f7ffe9b36b6624ec0c9dd8f 100644 (file)
@@ -32,7 +32,31 @@ void blk_mq_free_queue(struct request_queue *q);
 int blk_mq_update_nr_requests(struct request_queue *q, unsigned int nr);
 void blk_mq_wake_waiters(struct request_queue *q);
 bool blk_mq_dispatch_rq_list(struct blk_mq_hw_ctx *, struct list_head *);
+void blk_mq_flush_busy_ctxs(struct blk_mq_hw_ctx *hctx, struct list_head *list);
+bool blk_mq_hctx_has_pending(struct blk_mq_hw_ctx *hctx);
+bool blk_mq_get_driver_tag(struct request *rq, struct blk_mq_hw_ctx **hctx,
+                               bool wait);
 
+/*
+ * Internal helpers for allocating/freeing the request map
+ */
+void blk_mq_free_rqs(struct blk_mq_tag_set *set, struct blk_mq_tags *tags,
+                    unsigned int hctx_idx);
+void blk_mq_free_rq_map(struct blk_mq_tags *tags);
+struct blk_mq_tags *blk_mq_alloc_rq_map(struct blk_mq_tag_set *set,
+                                       unsigned int hctx_idx,
+                                       unsigned int nr_tags,
+                                       unsigned int reserved_tags);
+int blk_mq_alloc_rqs(struct blk_mq_tag_set *set, struct blk_mq_tags *tags,
+                    unsigned int hctx_idx, unsigned int depth);
+
+/*
+ * Internal helpers for request insertion into sw queues
+ */
+void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq,
+                               bool at_head);
+void blk_mq_insert_requests(struct blk_mq_hw_ctx *hctx, struct blk_mq_ctx *ctx,
+                               struct list_head *list);
 /*
  * CPU hotplug helpers
  */
@@ -57,6 +81,35 @@ extern int blk_mq_sysfs_register(struct request_queue *q);
 extern void blk_mq_sysfs_unregister(struct request_queue *q);
 extern void blk_mq_hctx_kobj_init(struct blk_mq_hw_ctx *hctx);
 
+/*
+ * debugfs helpers
+ */
+#ifdef CONFIG_BLK_DEBUG_FS
+int blk_mq_debugfs_register(struct request_queue *q, const char *name);
+void blk_mq_debugfs_unregister(struct request_queue *q);
+int blk_mq_debugfs_register_hctxs(struct request_queue *q);
+void blk_mq_debugfs_unregister_hctxs(struct request_queue *q);
+#else
+static inline int blk_mq_debugfs_register(struct request_queue *q,
+                                         const char *name)
+{
+       return 0;
+}
+
+static inline void blk_mq_debugfs_unregister(struct request_queue *q)
+{
+}
+
+static inline int blk_mq_debugfs_register_hctxs(struct request_queue *q)
+{
+       return 0;
+}
+
+static inline void blk_mq_debugfs_unregister_hctxs(struct request_queue *q)
+{
+}
+#endif
+
 extern void blk_mq_rq_timed_out(struct request *req, bool reserved);
 
 void blk_mq_release(struct request_queue *q);
@@ -103,6 +156,25 @@ static inline void blk_mq_set_alloc_data(struct blk_mq_alloc_data *data,
        data->hctx = hctx;
 }
 
+static inline struct blk_mq_tags *blk_mq_tags_from_data(struct blk_mq_alloc_data *data)
+{
+       if (data->flags & BLK_MQ_REQ_INTERNAL)
+               return data->hctx->sched_tags;
+
+       return data->hctx->tags;
+}
+
+/*
+ * Internal helpers for request allocation/init/free
+ */
+void blk_mq_rq_ctx_init(struct request_queue *q, struct blk_mq_ctx *ctx,
+                       struct request *rq, unsigned int op);
+void __blk_mq_finish_request(struct blk_mq_hw_ctx *hctx, struct blk_mq_ctx *ctx,
+                               struct request *rq);
+void blk_mq_finish_request(struct request *rq);
+struct request *__blk_mq_alloc_request(struct blk_mq_alloc_data *data,
+                                       unsigned int op);
+
 static inline bool blk_mq_hctx_stopped(struct blk_mq_hw_ctx *hctx)
 {
        return test_bit(BLK_MQ_S_STOPPED, &hctx->state);
index 529e55f52a03d7126fbbb77d0eef771e3d7ebe2d..1e7174ffc9d49d0757cf7cb7da1ffe822f7fbbd6 100644 (file)
@@ -88,6 +88,7 @@ EXPORT_SYMBOL_GPL(blk_queue_lld_busy);
 void blk_set_default_limits(struct queue_limits *lim)
 {
        lim->max_segments = BLK_MAX_SEGMENTS;
+       lim->max_discard_segments = 1;
        lim->max_integrity_segments = 0;
        lim->seg_boundary_mask = BLK_SEG_BOUNDARY_MASK;
        lim->virt_boundary_mask = 0;
@@ -128,6 +129,7 @@ void blk_set_stacking_limits(struct queue_limits *lim)
        /* Inherit limits from component devices */
        lim->discard_zeroes_data = 1;
        lim->max_segments = USHRT_MAX;
+       lim->max_discard_segments = 1;
        lim->max_hw_sectors = UINT_MAX;
        lim->max_segment_size = UINT_MAX;
        lim->max_sectors = UINT_MAX;
@@ -253,7 +255,7 @@ void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_hw_secto
        max_sectors = min_not_zero(max_hw_sectors, limits->max_dev_sectors);
        max_sectors = min_t(unsigned int, max_sectors, BLK_DEF_MAX_SECTORS);
        limits->max_sectors = max_sectors;
-       q->backing_dev_info.io_pages = max_sectors >> (PAGE_SHIFT - 9);
+       q->backing_dev_info->io_pages = max_sectors >> (PAGE_SHIFT - 9);
 }
 EXPORT_SYMBOL(blk_queue_max_hw_sectors);
 
@@ -336,6 +338,22 @@ void blk_queue_max_segments(struct request_queue *q, unsigned short max_segments
 }
 EXPORT_SYMBOL(blk_queue_max_segments);
 
+/**
+ * blk_queue_max_discard_segments - set max segments for discard requests
+ * @q:  the request queue for the device
+ * @max_segments:  max number of segments
+ *
+ * Description:
+ *    Enables a low level driver to set an upper limit on the number of
+ *    segments in a discard request.
+ **/
+void blk_queue_max_discard_segments(struct request_queue *q,
+               unsigned short max_segments)
+{
+       q->limits.max_discard_segments = max_segments;
+}
+EXPORT_SYMBOL_GPL(blk_queue_max_discard_segments);
+
 /**
  * blk_queue_max_segment_size - set max segment size for blk_rq_map_sg
  * @q:  the request queue for the device
@@ -553,6 +571,8 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
                                            b->virt_boundary_mask);
 
        t->max_segments = min_not_zero(t->max_segments, b->max_segments);
+       t->max_discard_segments = min_not_zero(t->max_discard_segments,
+                                              b->max_discard_segments);
        t->max_integrity_segments = min_not_zero(t->max_integrity_segments,
                                                 b->max_integrity_segments);
 
index 1dbce057592d3bacf9709718799c270d3f7827b5..002af836aa87d8444e5682921570ea6dba23fa13 100644 (file)
@@ -89,7 +89,7 @@ queue_requests_store(struct request_queue *q, const char *page, size_t count)
 
 static ssize_t queue_ra_show(struct request_queue *q, char *page)
 {
-       unsigned long ra_kb = q->backing_dev_info.ra_pages <<
+       unsigned long ra_kb = q->backing_dev_info->ra_pages <<
                                        (PAGE_SHIFT - 10);
 
        return queue_var_show(ra_kb, (page));
@@ -104,7 +104,7 @@ queue_ra_store(struct request_queue *q, const char *page, size_t count)
        if (ret < 0)
                return ret;
 
-       q->backing_dev_info.ra_pages = ra_kb >> (PAGE_SHIFT - 10);
+       q->backing_dev_info->ra_pages = ra_kb >> (PAGE_SHIFT - 10);
 
        return ret;
 }
@@ -121,6 +121,12 @@ static ssize_t queue_max_segments_show(struct request_queue *q, char *page)
        return queue_var_show(queue_max_segments(q), (page));
 }
 
+static ssize_t queue_max_discard_segments_show(struct request_queue *q,
+               char *page)
+{
+       return queue_var_show(queue_max_discard_segments(q), (page));
+}
+
 static ssize_t queue_max_integrity_segments_show(struct request_queue *q, char *page)
 {
        return queue_var_show(q->limits.max_integrity_segments, (page));
@@ -236,7 +242,7 @@ queue_max_sectors_store(struct request_queue *q, const char *page, size_t count)
 
        spin_lock_irq(q->queue_lock);
        q->limits.max_sectors = max_sectors_kb << 1;
-       q->backing_dev_info.io_pages = max_sectors_kb >> (PAGE_SHIFT - 10);
+       q->backing_dev_info->io_pages = max_sectors_kb >> (PAGE_SHIFT - 10);
        spin_unlock_irq(q->queue_lock);
 
        return ret;
@@ -545,6 +551,11 @@ static struct queue_sysfs_entry queue_max_segments_entry = {
        .show = queue_max_segments_show,
 };
 
+static struct queue_sysfs_entry queue_max_discard_segments_entry = {
+       .attr = {.name = "max_discard_segments", .mode = S_IRUGO },
+       .show = queue_max_discard_segments_show,
+};
+
 static struct queue_sysfs_entry queue_max_integrity_segments_entry = {
        .attr = {.name = "max_integrity_segments", .mode = S_IRUGO },
        .show = queue_max_integrity_segments_show,
@@ -697,6 +708,7 @@ static struct attribute *default_attrs[] = {
        &queue_max_hw_sectors_entry.attr,
        &queue_max_sectors_entry.attr,
        &queue_max_segments_entry.attr,
+       &queue_max_discard_segments_entry.attr,
        &queue_max_integrity_segments_entry.attr,
        &queue_max_segment_size_entry.attr,
        &queue_iosched_entry.attr,
@@ -799,7 +811,7 @@ static void blk_release_queue(struct kobject *kobj)
                container_of(kobj, struct request_queue, kobj);
 
        wbt_exit(q);
-       bdi_exit(&q->backing_dev_info);
+       bdi_put(q->backing_dev_info);
        blkcg_exit_queue(q);
 
        if (q->elevator) {
@@ -814,13 +826,19 @@ static void blk_release_queue(struct kobject *kobj)
        if (q->queue_tags)
                __blk_queue_free_tags(q);
 
-       if (!q->mq_ops)
+       if (!q->mq_ops) {
+               if (q->exit_rq_fn)
+                       q->exit_rq_fn(q, q->fq->flush_rq);
                blk_free_flush_queue(q->fq);
-       else
+       } else {
                blk_mq_release(q);
+       }
 
        blk_trace_shutdown(q);
 
+       if (q->mq_ops)
+               blk_mq_debugfs_unregister(q);
+
        if (q->bio_split)
                bioset_free(q->bio_split);
 
@@ -884,32 +902,36 @@ int blk_register_queue(struct gendisk *disk)
        if (ret)
                return ret;
 
+       if (q->mq_ops)
+               blk_mq_register_dev(dev, q);
+
+       /* Prevent changes through sysfs until registration is completed. */
+       mutex_lock(&q->sysfs_lock);
+
        ret = kobject_add(&q->kobj, kobject_get(&dev->kobj), "%s", "queue");
        if (ret < 0) {
                blk_trace_remove_sysfs(dev);
-               return ret;
+               goto unlock;
        }
 
        kobject_uevent(&q->kobj, KOBJ_ADD);
 
-       if (q->mq_ops)
-               blk_mq_register_dev(dev, q);
-
        blk_wb_init(q);
 
-       if (!q->request_fn)
-               return 0;
-
-       ret = elv_register_queue(q);
-       if (ret) {
-               kobject_uevent(&q->kobj, KOBJ_REMOVE);
-               kobject_del(&q->kobj);
-               blk_trace_remove_sysfs(dev);
-               kobject_put(&dev->kobj);
-               return ret;
+       if (q->request_fn || (q->mq_ops && q->elevator)) {
+               ret = elv_register_queue(q);
+               if (ret) {
+                       kobject_uevent(&q->kobj, KOBJ_REMOVE);
+                       kobject_del(&q->kobj);
+                       blk_trace_remove_sysfs(dev);
+                       kobject_put(&dev->kobj);
+                       goto unlock;
+               }
        }
-
-       return 0;
+       ret = 0;
+unlock:
+       mutex_unlock(&q->sysfs_lock);
+       return ret;
 }
 
 void blk_unregister_queue(struct gendisk *disk)
@@ -922,7 +944,7 @@ void blk_unregister_queue(struct gendisk *disk)
        if (q->mq_ops)
                blk_mq_unregister_dev(disk_to_dev(disk), q);
 
-       if (q->request_fn)
+       if (q->request_fn || (q->mq_ops && q->elevator))
                elv_unregister_queue(q);
 
        kobject_uevent(&q->kobj, KOBJ_REMOVE);
index bae1decb6ec39c7c9032ee9379aad43464e75edf..07cc329fa4b0aa9f01fc32b4f56211df8dff7107 100644 (file)
@@ -272,6 +272,7 @@ void blk_queue_end_tag(struct request_queue *q, struct request *rq)
        list_del_init(&rq->queuelist);
        rq->rq_flags &= ~RQF_QUEUED;
        rq->tag = -1;
+       rq->internal_tag = -1;
 
        if (unlikely(bqt->tag_index[tag] == NULL))
                printk(KERN_ERR "%s: tag %d is missing\n",
index a6bb4fe326c39b2a996fe4330bc15933451d6503..82fd0cc394ebd9d6ad3a0e02b9d5556baccc14c4 100644 (file)
@@ -866,10 +866,12 @@ static void tg_update_disptime(struct throtl_grp *tg)
        unsigned long read_wait = -1, write_wait = -1, min_wait = -1, disptime;
        struct bio *bio;
 
-       if ((bio = throtl_peek_queued(&sq->queued[READ])))
+       bio = throtl_peek_queued(&sq->queued[READ]);
+       if (bio)
                tg_may_dispatch(tg, bio, &read_wait);
 
-       if ((bio = throtl_peek_queued(&sq->queued[WRITE])))
+       bio = throtl_peek_queued(&sq->queued[WRITE]);
+       if (bio)
                tg_may_dispatch(tg, bio, &write_wait);
 
        min_wait = min(read_wait, write_wait);
index f0a9c07b4c7a5ef9e96985a89c5c000d62a78cd0..1aedb1f7ee0c7fde717d7701d3ee74cc90c21d17 100644 (file)
@@ -96,7 +96,7 @@ static void wb_timestamp(struct rq_wb *rwb, unsigned long *var)
  */
 static bool wb_recent_wait(struct rq_wb *rwb)
 {
-       struct bdi_writeback *wb = &rwb->queue->backing_dev_info.wb;
+       struct bdi_writeback *wb = &rwb->queue->backing_dev_info->wb;
 
        return time_before(jiffies, wb->dirty_sleep + HZ);
 }
@@ -279,7 +279,7 @@ enum {
 
 static int __latency_exceeded(struct rq_wb *rwb, struct blk_rq_stat *stat)
 {
-       struct backing_dev_info *bdi = &rwb->queue->backing_dev_info;
+       struct backing_dev_info *bdi = rwb->queue->backing_dev_info;
        u64 thislat;
 
        /*
@@ -339,7 +339,7 @@ static int latency_exceeded(struct rq_wb *rwb)
 
 static void rwb_trace_step(struct rq_wb *rwb, const char *msg)
 {
-       struct backing_dev_info *bdi = &rwb->queue->backing_dev_info;
+       struct backing_dev_info *bdi = rwb->queue->backing_dev_info;
 
        trace_wbt_step(bdi, msg, rwb->scale_step, rwb->cur_win_nsec,
                        rwb->wb_background, rwb->wb_normal, rwb->wb_max);
@@ -423,7 +423,7 @@ static void wb_timer_fn(unsigned long data)
 
        status = latency_exceeded(rwb);
 
-       trace_wbt_timer(&rwb->queue->backing_dev_info, status, rwb->scale_step,
+       trace_wbt_timer(rwb->queue->backing_dev_info, status, rwb->scale_step,
                        inflight);
 
        /*
index 041185e5f12994dc146528db2627707e42a700ee..d1ea4bd9b9a3f8f24eba17f4e35fbddaebd23c7d 100644 (file)
 /* Max future timer expiry for timeouts */
 #define BLK_MAX_TIMEOUT                (5 * HZ)
 
+#ifdef CONFIG_DEBUG_FS
+extern struct dentry *blk_debugfs_root;
+#endif
+
 struct blk_flush_queue {
        unsigned int            flush_queue_delayed:1;
        unsigned int            flush_pending_idx:1;
@@ -96,6 +100,8 @@ bool bio_attempt_front_merge(struct request_queue *q, struct request *req,
                             struct bio *bio);
 bool bio_attempt_back_merge(struct request_queue *q, struct request *req,
                            struct bio *bio);
+bool bio_attempt_discard_merge(struct request_queue *q, struct request *req,
+               struct bio *bio);
 bool blk_attempt_plug_merge(struct request_queue *q, struct bio *bio,
                            unsigned int *request_count,
                            struct request **same_queue_rq);
@@ -167,7 +173,7 @@ static inline struct request *__elv_next_request(struct request_queue *q)
                        return NULL;
                }
                if (unlikely(blk_queue_bypass(q)) ||
-                   !q->elevator->type->ops.elevator_dispatch_fn(q, 0))
+                   !q->elevator->type->ops.sq.elevator_dispatch_fn(q, 0))
                        return NULL;
        }
 }
@@ -176,16 +182,16 @@ static inline void elv_activate_rq(struct request_queue *q, struct request *rq)
 {
        struct elevator_queue *e = q->elevator;
 
-       if (e->type->ops.elevator_activate_req_fn)
-               e->type->ops.elevator_activate_req_fn(q, rq);
+       if (e->type->ops.sq.elevator_activate_req_fn)
+               e->type->ops.sq.elevator_activate_req_fn(q, rq);
 }
 
 static inline void elv_deactivate_rq(struct request_queue *q, struct request *rq)
 {
        struct elevator_queue *e = q->elevator;
 
-       if (e->type->ops.elevator_deactivate_req_fn)
-               e->type->ops.elevator_deactivate_req_fn(q, rq);
+       if (e->type->ops.sq.elevator_deactivate_req_fn)
+               e->type->ops.sq.elevator_deactivate_req_fn(q, rq);
 }
 
 #ifdef CONFIG_FAIL_IO_TIMEOUT
@@ -204,14 +210,14 @@ int ll_back_merge_fn(struct request_queue *q, struct request *req,
                     struct bio *bio);
 int ll_front_merge_fn(struct request_queue *q, struct request *req, 
                      struct bio *bio);
-int attempt_back_merge(struct request_queue *q, struct request *rq);
-int attempt_front_merge(struct request_queue *q, struct request *rq);
+struct request *attempt_back_merge(struct request_queue *q, struct request *rq);
+struct request *attempt_front_merge(struct request_queue *q, struct request *rq);
 int blk_attempt_req_merge(struct request_queue *q, struct request *rq,
                                struct request *next);
 void blk_recalc_rq_segments(struct request *rq);
 void blk_rq_set_mixed_merge(struct request *rq);
 bool blk_rq_merge_ok(struct request *rq, struct bio *bio);
-int blk_try_merge(struct request *rq, struct bio *bio);
+enum elv_merge blk_try_merge(struct request *rq, struct bio *bio);
 
 void blk_queue_congestion_threshold(struct request_queue *q);
 
@@ -249,7 +255,14 @@ static inline int blk_do_io_stat(struct request *rq)
 {
        return rq->rq_disk &&
               (rq->rq_flags & RQF_IO_STAT) &&
-               (rq->cmd_type == REQ_TYPE_FS);
+               !blk_rq_is_passthrough(rq);
+}
+
+static inline void req_set_nomerge(struct request_queue *q, struct request *req)
+{
+       req->cmd_flags |= REQ_NOMERGE;
+       if (req == q->last_merge)
+               q->last_merge = NULL;
 }
 
 /*
@@ -263,6 +276,22 @@ void ioc_clear_queue(struct request_queue *q);
 
 int create_task_io_context(struct task_struct *task, gfp_t gfp_mask, int node);
 
+/**
+ * rq_ioc - determine io_context for request allocation
+ * @bio: request being allocated is for this bio (can be %NULL)
+ *
+ * Determine io_context to use for request allocation for @bio.  May return
+ * %NULL if %current->io_context doesn't exist.
+ */
+static inline struct io_context *rq_ioc(struct bio *bio)
+{
+#ifdef CONFIG_BLK_CGROUP
+       if (bio && bio->bi_ioc)
+               return bio->bi_ioc;
+#endif
+       return current->io_context;
+}
+
 /**
  * create_io_context - try to create task->io_context
  * @gfp_mask: allocation mask
index 9d652a99231615b3f959a8407f866d3d22c51a6a..cd15f9dbb1474ad5aeb7b387420f9a6dbd021f95 100644 (file)
@@ -71,22 +71,24 @@ void bsg_job_done(struct bsg_job *job, int result,
 {
        struct request *req = job->req;
        struct request *rsp = req->next_rq;
+       struct scsi_request *rq = scsi_req(req);
        int err;
 
        err = job->req->errors = result;
        if (err < 0)
                /* we're only returning the result field in the reply */
-               job->req->sense_len = sizeof(u32);
+               rq->sense_len = sizeof(u32);
        else
-               job->req->sense_len = job->reply_len;
+               rq->sense_len = job->reply_len;
        /* we assume all request payload was transferred, residual == 0 */
-       req->resid_len = 0;
+       rq->resid_len = 0;
 
        if (rsp) {
-               WARN_ON(reply_payload_rcv_len > rsp->resid_len);
+               WARN_ON(reply_payload_rcv_len > scsi_req(rsp)->resid_len);
 
                /* set reply (bidi) residual */
-               rsp->resid_len -= min(reply_payload_rcv_len, rsp->resid_len);
+               scsi_req(rsp)->resid_len -=
+                       min(reply_payload_rcv_len, scsi_req(rsp)->resid_len);
        }
        blk_complete_request(req);
 }
@@ -113,6 +115,7 @@ static int bsg_map_buffer(struct bsg_buffer *buf, struct request *req)
        if (!buf->sg_list)
                return -ENOMEM;
        sg_init_table(buf->sg_list, req->nr_phys_segments);
+       scsi_req(req)->resid_len = blk_rq_bytes(req);
        buf->sg_cnt = blk_rq_map_sg(req->q, req, buf->sg_list);
        buf->payload_len = blk_rq_bytes(req);
        return 0;
@@ -127,6 +130,7 @@ static int bsg_create_job(struct device *dev, struct request *req)
 {
        struct request *rsp = req->next_rq;
        struct request_queue *q = req->q;
+       struct scsi_request *rq = scsi_req(req);
        struct bsg_job *job;
        int ret;
 
@@ -140,9 +144,9 @@ static int bsg_create_job(struct device *dev, struct request *req)
        job->req = req;
        if (q->bsg_job_size)
                job->dd_data = (void *)&job[1];
-       job->request = req->cmd;
-       job->request_len = req->cmd_len;
-       job->reply = req->sense;
+       job->request = rq->cmd;
+       job->request_len = rq->cmd_len;
+       job->reply = rq->sense;
        job->reply_len = SCSI_SENSE_BUFFERSIZE; /* Size of sense buffer
                                                 * allocated */
        if (req->bio) {
@@ -177,7 +181,7 @@ failjob_rls_job:
  *
  * Drivers/subsys should pass this to the queue init function.
  */
-void bsg_request_fn(struct request_queue *q)
+static void bsg_request_fn(struct request_queue *q)
        __releases(q->queue_lock)
        __acquires(q->queue_lock)
 {
@@ -214,24 +218,30 @@ void bsg_request_fn(struct request_queue *q)
        put_device(dev);
        spin_lock_irq(q->queue_lock);
 }
-EXPORT_SYMBOL_GPL(bsg_request_fn);
 
 /**
  * bsg_setup_queue - Create and add the bsg hooks so we can receive requests
  * @dev: device to attach bsg device to
- * @q: request queue setup by caller
  * @name: device to give bsg device
  * @job_fn: bsg job handler
  * @dd_job_size: size of LLD data needed for each job
- *
- * The caller should have setup the reuqest queue with bsg_request_fn
- * as the request_fn.
  */
-int bsg_setup_queue(struct device *dev, struct request_queue *q,
-                   char *name, bsg_job_fn *job_fn, int dd_job_size)
+struct request_queue *bsg_setup_queue(struct device *dev, char *name,
+               bsg_job_fn *job_fn, int dd_job_size)
 {
+       struct request_queue *q;
        int ret;
 
+       q = blk_alloc_queue(GFP_KERNEL);
+       if (!q)
+               return ERR_PTR(-ENOMEM);
+       q->cmd_size = sizeof(struct scsi_request);
+       q->request_fn = bsg_request_fn;
+
+       ret = blk_init_allocated_queue(q);
+       if (ret)
+               goto out_cleanup_queue;
+
        q->queuedata = dev;
        q->bsg_job_size = dd_job_size;
        q->bsg_job_fn = job_fn;
@@ -243,9 +253,12 @@ int bsg_setup_queue(struct device *dev, struct request_queue *q,
        if (ret) {
                printk(KERN_ERR "%s: bsg interface failed to "
                       "initialize - register queue\n", dev->kobj.name);
-               return ret;
+               goto out_cleanup_queue;
        }
 
-       return 0;
+       return q;
+out_cleanup_queue:
+       blk_cleanup_queue(q);
+       return ERR_PTR(ret);
 }
 EXPORT_SYMBOL_GPL(bsg_setup_queue);
index a57046de2f07f00eae78aaabe9b5e43c1ecc178f..a9a8b8e0446f4434616a4f4d7f5513bd3a8936c9 100644 (file)
@@ -85,7 +85,6 @@ struct bsg_command {
        struct bio *bidi_bio;
        int err;
        struct sg_io_v4 hdr;
-       char sense[SCSI_SENSE_BUFFERSIZE];
 };
 
 static void bsg_free_command(struct bsg_command *bc)
@@ -140,18 +139,20 @@ static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq,
                                struct sg_io_v4 *hdr, struct bsg_device *bd,
                                fmode_t has_write_perm)
 {
+       struct scsi_request *req = scsi_req(rq);
+
        if (hdr->request_len > BLK_MAX_CDB) {
-               rq->cmd = kzalloc(hdr->request_len, GFP_KERNEL);
-               if (!rq->cmd)
+               req->cmd = kzalloc(hdr->request_len, GFP_KERNEL);
+               if (!req->cmd)
                        return -ENOMEM;
        }
 
-       if (copy_from_user(rq->cmd, (void __user *)(unsigned long)hdr->request,
+       if (copy_from_user(req->cmd, (void __user *)(unsigned long)hdr->request,
                           hdr->request_len))
                return -EFAULT;
 
        if (hdr->subprotocol == BSG_SUB_PROTOCOL_SCSI_CMD) {
-               if (blk_verify_command(rq->cmd, has_write_perm))
+               if (blk_verify_command(req->cmd, has_write_perm))
                        return -EPERM;
        } else if (!capable(CAP_SYS_RAWIO))
                return -EPERM;
@@ -159,7 +160,7 @@ static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq,
        /*
         * fill in request structure
         */
-       rq->cmd_len = hdr->request_len;
+       req->cmd_len = hdr->request_len;
 
        rq->timeout = msecs_to_jiffies(hdr->timeout);
        if (!rq->timeout)
@@ -176,7 +177,7 @@ static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq,
  * Check if sg_io_v4 from user is allowed and valid
  */
 static int
-bsg_validate_sgv4_hdr(struct sg_io_v4 *hdr, int *rw)
+bsg_validate_sgv4_hdr(struct sg_io_v4 *hdr, int *op)
 {
        int ret = 0;
 
@@ -197,7 +198,7 @@ bsg_validate_sgv4_hdr(struct sg_io_v4 *hdr, int *rw)
                ret = -EINVAL;
        }
 
-       *rw = hdr->dout_xfer_len ? WRITE : READ;
+       *op = hdr->dout_xfer_len ? REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN;
        return ret;
 }
 
@@ -205,13 +206,12 @@ bsg_validate_sgv4_hdr(struct sg_io_v4 *hdr, int *rw)
  * map sg_io_v4 to a request.
  */
 static struct request *
-bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, fmode_t has_write_perm,
-           u8 *sense)
+bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, fmode_t has_write_perm)
 {
        struct request_queue *q = bd->queue;
        struct request *rq, *next_rq = NULL;
-       int ret, rw;
-       unsigned int dxfer_len;
+       int ret;
+       unsigned int op, dxfer_len;
        void __user *dxferp = NULL;
        struct bsg_class_device *bcd = &q->bsg_dev;
 
@@ -226,36 +226,35 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, fmode_t has_write_perm,
                hdr->dout_xfer_len, (unsigned long long) hdr->din_xferp,
                hdr->din_xfer_len);
 
-       ret = bsg_validate_sgv4_hdr(hdr, &rw);
+       ret = bsg_validate_sgv4_hdr(hdr, &op);
        if (ret)
                return ERR_PTR(ret);
 
        /*
         * map scatter-gather elements separately and string them to request
         */
-       rq = blk_get_request(q, rw, GFP_KERNEL);
+       rq = blk_get_request(q, op, GFP_KERNEL);
        if (IS_ERR(rq))
                return rq;
-       blk_rq_set_block_pc(rq);
+       scsi_req_init(rq);
 
        ret = blk_fill_sgv4_hdr_rq(q, rq, hdr, bd, has_write_perm);
        if (ret)
                goto out;
 
-       if (rw == WRITE && hdr->din_xfer_len) {
+       if (op == REQ_OP_SCSI_OUT && hdr->din_xfer_len) {
                if (!test_bit(QUEUE_FLAG_BIDI, &q->queue_flags)) {
                        ret = -EOPNOTSUPP;
                        goto out;
                }
 
-               next_rq = blk_get_request(q, READ, GFP_KERNEL);
+               next_rq = blk_get_request(q, REQ_OP_SCSI_IN, GFP_KERNEL);
                if (IS_ERR(next_rq)) {
                        ret = PTR_ERR(next_rq);
                        next_rq = NULL;
                        goto out;
                }
                rq->next_rq = next_rq;
-               next_rq->cmd_type = rq->cmd_type;
 
                dxferp = (void __user *)(unsigned long)hdr->din_xferp;
                ret =  blk_rq_map_user(q, next_rq, NULL, dxferp,
@@ -280,13 +279,9 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, fmode_t has_write_perm,
                        goto out;
        }
 
-       rq->sense = sense;
-       rq->sense_len = 0;
-
        return rq;
 out:
-       if (rq->cmd != rq->__cmd)
-               kfree(rq->cmd);
+       scsi_req_free_cmd(scsi_req(rq));
        blk_put_request(rq);
        if (next_rq) {
                blk_rq_unmap_user(next_rq->bio);
@@ -393,6 +388,7 @@ static struct bsg_command *bsg_get_done_cmd(struct bsg_device *bd)
 static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr,
                                    struct bio *bio, struct bio *bidi_bio)
 {
+       struct scsi_request *req = scsi_req(rq);
        int ret = 0;
 
        dprintk("rq %p bio %p 0x%x\n", rq, bio, rq->errors);
@@ -407,12 +403,12 @@ static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr,
                hdr->info |= SG_INFO_CHECK;
        hdr->response_len = 0;
 
-       if (rq->sense_len && hdr->response) {
+       if (req->sense_len && hdr->response) {
                int len = min_t(unsigned int, hdr->max_response_len,
-                                       rq->sense_len);
+                                       req->sense_len);
 
                ret = copy_to_user((void __user *)(unsigned long)hdr->response,
-                                  rq->sense, len);
+                                  req->sense, len);
                if (!ret)
                        hdr->response_len = len;
                else
@@ -420,14 +416,14 @@ static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr,
        }
 
        if (rq->next_rq) {
-               hdr->dout_resid = rq->resid_len;
-               hdr->din_resid = rq->next_rq->resid_len;
+               hdr->dout_resid = req->resid_len;
+               hdr->din_resid = scsi_req(rq->next_rq)->resid_len;
                blk_rq_unmap_user(bidi_bio);
                blk_put_request(rq->next_rq);
        } else if (rq_data_dir(rq) == READ)
-               hdr->din_resid = rq->resid_len;
+               hdr->din_resid = req->resid_len;
        else
-               hdr->dout_resid = rq->resid_len;
+               hdr->dout_resid = req->resid_len;
 
        /*
         * If the request generated a negative error number, return it
@@ -439,8 +435,7 @@ static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr,
                ret = rq->errors;
 
        blk_rq_unmap_user(bio);
-       if (rq->cmd != rq->__cmd)
-               kfree(rq->cmd);
+       scsi_req_free_cmd(req);
        blk_put_request(rq);
 
        return ret;
@@ -625,7 +620,7 @@ static int __bsg_write(struct bsg_device *bd, const char __user *buf,
                /*
                 * get a request, fill in the blanks, and add to request queue
                 */
-               rq = bsg_map_hdr(bd, &bc->hdr, has_write_perm, bc->sense);
+               rq = bsg_map_hdr(bd, &bc->hdr, has_write_perm);
                if (IS_ERR(rq)) {
                        ret = PTR_ERR(rq);
                        rq = NULL;
@@ -911,12 +906,11 @@ static long bsg_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                struct bio *bio, *bidi_bio = NULL;
                struct sg_io_v4 hdr;
                int at_head;
-               u8 sense[SCSI_SENSE_BUFFERSIZE];
 
                if (copy_from_user(&hdr, uarg, sizeof(hdr)))
                        return -EFAULT;
 
-               rq = bsg_map_hdr(bd, &hdr, file->f_mode & FMODE_WRITE, sense);
+               rq = bsg_map_hdr(bd, &hdr, file->f_mode & FMODE_WRITE);
                if (IS_ERR(rq))
                        return PTR_ERR(rq);
 
index 838f07e2b64a207c0f4d46477a4ffb81d0e4a60b..13794477785985f21b68daeccb328af3702e3d24 100644 (file)
@@ -2528,7 +2528,7 @@ static void cfq_remove_request(struct request *rq)
        }
 }
 
-static int cfq_merge(struct request_queue *q, struct request **req,
+static enum elv_merge cfq_merge(struct request_queue *q, struct request **req,
                     struct bio *bio)
 {
        struct cfq_data *cfqd = q->elevator->elevator_data;
@@ -2544,7 +2544,7 @@ static int cfq_merge(struct request_queue *q, struct request **req,
 }
 
 static void cfq_merged_request(struct request_queue *q, struct request *req,
-                              int type)
+                              enum elv_merge type)
 {
        if (type == ELEVATOR_FRONT_MERGE) {
                struct cfq_queue *cfqq = RQ_CFQQ(req);
@@ -2749,9 +2749,11 @@ static struct cfq_queue *cfq_get_next_queue_forced(struct cfq_data *cfqd)
        if (!cfqg)
                return NULL;
 
-       for_each_cfqg_st(cfqg, i, j, st)
-               if ((cfqq = cfq_rb_first(st)) != NULL)
+       for_each_cfqg_st(cfqg, i, j, st) {
+               cfqq = cfq_rb_first(st);
+               if (cfqq)
                        return cfqq;
+       }
        return NULL;
 }
 
@@ -3860,6 +3862,8 @@ cfq_get_queue(struct cfq_data *cfqd, bool is_sync, struct cfq_io_cq *cic,
                goto out;
        }
 
+       /* cfq_init_cfqq() assumes cfqq->ioprio_class is initialized. */
+       cfqq->ioprio_class = IOPRIO_CLASS_NONE;
        cfq_init_cfqq(cfqd, cfqq, current->pid, is_sync);
        cfq_init_prio_data(cfqq, cic);
        cfq_link_cfqq_cfqg(cfqq, cfqg);
@@ -4838,7 +4842,7 @@ static struct elv_fs_entry cfq_attrs[] = {
 };
 
 static struct elevator_type iosched_cfq = {
-       .ops = {
+       .ops.sq = {
                .elevator_merge_fn =            cfq_merge,
                .elevator_merged_fn =           cfq_merged_request,
                .elevator_merge_req_fn =        cfq_merged_requests,
index 556826ac7cb4837c44d15d9f5576469d578055b3..570021a0dc1ca5b903c990c1ae26d5913e71cd47 100644 (file)
@@ -661,7 +661,6 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
        struct block_device *bdev = inode->i_bdev;
        struct gendisk *disk = bdev->bd_disk;
        fmode_t mode = file->f_mode;
-       struct backing_dev_info *bdi;
        loff_t size;
        unsigned int max_sectors;
 
@@ -708,9 +707,8 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
        case BLKFRAGET:
                if (!arg)
                        return -EINVAL;
-               bdi = blk_get_backing_dev_info(bdev);
                return compat_put_long(arg,
-                                      (bdi->ra_pages * PAGE_SIZE) / 512);
+                              (bdev->bd_bdi->ra_pages * PAGE_SIZE) / 512);
        case BLKROGET: /* compatible */
                return compat_put_int(arg, bdev_read_only(bdev) != 0);
        case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */
@@ -728,8 +726,7 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
        case BLKFRASET:
                if (!capable(CAP_SYS_ADMIN))
                        return -EACCES;
-               bdi = blk_get_backing_dev_info(bdev);
-               bdi->ra_pages = (arg * 512) / PAGE_SIZE;
+               bdev->bd_bdi->ra_pages = (arg * 512) / PAGE_SIZE;
                return 0;
        case BLKGETSIZE:
                size = i_size_read(bdev->bd_inode);
index 55e0bb6d7da796e3b526a16832914ca88fcb879f..c68f6bbc0dcdc25fb8de64d5df658d87feae214b 100644 (file)
@@ -120,12 +120,11 @@ static void deadline_remove_request(struct request_queue *q, struct request *rq)
        deadline_del_rq_rb(dd, rq);
 }
 
-static int
+static enum elv_merge
 deadline_merge(struct request_queue *q, struct request **req, struct bio *bio)
 {
        struct deadline_data *dd = q->elevator->elevator_data;
        struct request *__rq;
-       int ret;
 
        /*
         * check for front merge
@@ -138,20 +137,17 @@ deadline_merge(struct request_queue *q, struct request **req, struct bio *bio)
                        BUG_ON(sector != blk_rq_pos(__rq));
 
                        if (elv_bio_merge_ok(__rq, bio)) {
-                               ret = ELEVATOR_FRONT_MERGE;
-                               goto out;
+                               *req = __rq;
+                               return ELEVATOR_FRONT_MERGE;
                        }
                }
        }
 
        return ELEVATOR_NO_MERGE;
-out:
-       *req = __rq;
-       return ret;
 }
 
 static void deadline_merged_request(struct request_queue *q,
-                                   struct request *req, int type)
+                                   struct request *req, enum elv_merge type)
 {
        struct deadline_data *dd = q->elevator->elevator_data;
 
@@ -439,7 +435,7 @@ static struct elv_fs_entry deadline_attrs[] = {
 };
 
 static struct elevator_type iosched_deadline = {
-       .ops = {
+       .ops.sq = {
                .elevator_merge_fn =            deadline_merge,
                .elevator_merged_fn =           deadline_merged_request,
                .elevator_merge_req_fn =        deadline_merged_requests,
index 40f0c04e5ad3d076ee24d34f3424b9e42194d454..699d10f71a2cac3f871bb6879f68f1fc5fafe714 100644 (file)
@@ -40,6 +40,7 @@
 #include <trace/events/block.h>
 
 #include "blk.h"
+#include "blk-mq-sched.h"
 
 static DEFINE_SPINLOCK(elv_list_lock);
 static LIST_HEAD(elv_list);
@@ -58,8 +59,10 @@ static int elv_iosched_allow_bio_merge(struct request *rq, struct bio *bio)
        struct request_queue *q = rq->q;
        struct elevator_queue *e = q->elevator;
 
-       if (e->type->ops.elevator_allow_bio_merge_fn)
-               return e->type->ops.elevator_allow_bio_merge_fn(q, rq, bio);
+       if (e->uses_mq && e->type->ops.mq.allow_merge)
+               return e->type->ops.mq.allow_merge(q, rq, bio);
+       else if (!e->uses_mq && e->type->ops.sq.elevator_allow_bio_merge_fn)
+               return e->type->ops.sq.elevator_allow_bio_merge_fn(q, rq, bio);
 
        return 1;
 }
@@ -163,6 +166,7 @@ struct elevator_queue *elevator_alloc(struct request_queue *q,
        kobject_init(&eq->kobj, &elv_ktype);
        mutex_init(&eq->sysfs_lock);
        hash_init(eq->hash);
+       eq->uses_mq = e->uses_mq;
 
        return eq;
 }
@@ -203,11 +207,12 @@ int elevator_init(struct request_queue *q, char *name)
        }
 
        /*
-        * Use the default elevator specified by config boot param or
-        * config option.  Don't try to load modules as we could be running
-        * off async and request_module() isn't allowed from async.
+        * Use the default elevator specified by config boot param for
+        * non-mq devices, or by config option. Don't try to load modules
+        * as we could be running off async and request_module() isn't
+        * allowed from async.
         */
-       if (!e && *chosen_elevator) {
+       if (!e && !q->mq_ops && *chosen_elevator) {
                e = elevator_get(chosen_elevator, false);
                if (!e)
                        printk(KERN_ERR "I/O scheduler %s not found\n",
@@ -215,18 +220,32 @@ int elevator_init(struct request_queue *q, char *name)
        }
 
        if (!e) {
-               e = elevator_get(CONFIG_DEFAULT_IOSCHED, false);
+               if (q->mq_ops && q->nr_hw_queues == 1)
+                       e = elevator_get(CONFIG_DEFAULT_SQ_IOSCHED, false);
+               else if (q->mq_ops)
+                       e = elevator_get(CONFIG_DEFAULT_MQ_IOSCHED, false);
+               else
+                       e = elevator_get(CONFIG_DEFAULT_IOSCHED, false);
+
                if (!e) {
                        printk(KERN_ERR
                                "Default I/O scheduler not found. " \
-                               "Using noop.\n");
+                               "Using noop/none.\n");
                        e = elevator_get("noop", false);
                }
        }
 
-       err = e->ops.elevator_init_fn(q, e);
-       if (err)
+       if (e->uses_mq) {
+               err = blk_mq_sched_setup(q);
+               if (!err)
+                       err = e->ops.mq.init_sched(q, e);
+       } else
+               err = e->ops.sq.elevator_init_fn(q, e);
+       if (err) {
+               if (e->uses_mq)
+                       blk_mq_sched_teardown(q);
                elevator_put(e);
+       }
        return err;
 }
 EXPORT_SYMBOL(elevator_init);
@@ -234,8 +253,10 @@ EXPORT_SYMBOL(elevator_init);
 void elevator_exit(struct elevator_queue *e)
 {
        mutex_lock(&e->sysfs_lock);
-       if (e->type->ops.elevator_exit_fn)
-               e->type->ops.elevator_exit_fn(e);
+       if (e->uses_mq && e->type->ops.mq.exit_sched)
+               e->type->ops.mq.exit_sched(e);
+       else if (!e->uses_mq && e->type->ops.sq.elevator_exit_fn)
+               e->type->ops.sq.elevator_exit_fn(e);
        mutex_unlock(&e->sysfs_lock);
 
        kobject_put(&e->kobj);
@@ -253,6 +274,7 @@ void elv_rqhash_del(struct request_queue *q, struct request *rq)
        if (ELV_ON_HASH(rq))
                __elv_rqhash_del(rq);
 }
+EXPORT_SYMBOL_GPL(elv_rqhash_del);
 
 void elv_rqhash_add(struct request_queue *q, struct request *rq)
 {
@@ -262,6 +284,7 @@ void elv_rqhash_add(struct request_queue *q, struct request *rq)
        hash_add(e->hash, &rq->hash, rq_hash_key(rq));
        rq->rq_flags |= RQF_HASHED;
 }
+EXPORT_SYMBOL_GPL(elv_rqhash_add);
 
 void elv_rqhash_reposition(struct request_queue *q, struct request *rq)
 {
@@ -405,11 +428,11 @@ void elv_dispatch_add_tail(struct request_queue *q, struct request *rq)
 }
 EXPORT_SYMBOL(elv_dispatch_add_tail);
 
-int elv_merge(struct request_queue *q, struct request **req, struct bio *bio)
+enum elv_merge elv_merge(struct request_queue *q, struct request **req,
+               struct bio *bio)
 {
        struct elevator_queue *e = q->elevator;
        struct request *__rq;
-       int ret;
 
        /*
         * Levels of merges:
@@ -424,7 +447,8 @@ int elv_merge(struct request_queue *q, struct request **req, struct bio *bio)
         * First try one-hit cache.
         */
        if (q->last_merge && elv_bio_merge_ok(q->last_merge, bio)) {
-               ret = blk_try_merge(q->last_merge, bio);
+               enum elv_merge ret = blk_try_merge(q->last_merge, bio);
+
                if (ret != ELEVATOR_NO_MERGE) {
                        *req = q->last_merge;
                        return ret;
@@ -443,8 +467,10 @@ int elv_merge(struct request_queue *q, struct request **req, struct bio *bio)
                return ELEVATOR_BACK_MERGE;
        }
 
-       if (e->type->ops.elevator_merge_fn)
-               return e->type->ops.elevator_merge_fn(q, req, bio);
+       if (e->uses_mq && e->type->ops.mq.request_merge)
+               return e->type->ops.mq.request_merge(q, req, bio);
+       else if (!e->uses_mq && e->type->ops.sq.elevator_merge_fn)
+               return e->type->ops.sq.elevator_merge_fn(q, req, bio);
 
        return ELEVATOR_NO_MERGE;
 }
@@ -456,8 +482,7 @@ int elv_merge(struct request_queue *q, struct request **req, struct bio *bio)
  *
  * Returns true if we merged, false otherwise
  */
-static bool elv_attempt_insert_merge(struct request_queue *q,
-                                    struct request *rq)
+bool elv_attempt_insert_merge(struct request_queue *q, struct request *rq)
 {
        struct request *__rq;
        bool ret;
@@ -491,12 +516,15 @@ static bool elv_attempt_insert_merge(struct request_queue *q,
        return ret;
 }
 
-void elv_merged_request(struct request_queue *q, struct request *rq, int type)
+void elv_merged_request(struct request_queue *q, struct request *rq,
+               enum elv_merge type)
 {
        struct elevator_queue *e = q->elevator;
 
-       if (e->type->ops.elevator_merged_fn)
-               e->type->ops.elevator_merged_fn(q, rq, type);
+       if (e->uses_mq && e->type->ops.mq.request_merged)
+               e->type->ops.mq.request_merged(q, rq, type);
+       else if (!e->uses_mq && e->type->ops.sq.elevator_merged_fn)
+               e->type->ops.sq.elevator_merged_fn(q, rq, type);
 
        if (type == ELEVATOR_BACK_MERGE)
                elv_rqhash_reposition(q, rq);
@@ -508,10 +536,15 @@ void elv_merge_requests(struct request_queue *q, struct request *rq,
                             struct request *next)
 {
        struct elevator_queue *e = q->elevator;
-       const int next_sorted = next->rq_flags & RQF_SORTED;
-
-       if (next_sorted && e->type->ops.elevator_merge_req_fn)
-               e->type->ops.elevator_merge_req_fn(q, rq, next);
+       bool next_sorted = false;
+
+       if (e->uses_mq && e->type->ops.mq.requests_merged)
+               e->type->ops.mq.requests_merged(q, rq, next);
+       else if (e->type->ops.sq.elevator_merge_req_fn) {
+               next_sorted = (__force bool)(next->rq_flags & RQF_SORTED);
+               if (next_sorted)
+                       e->type->ops.sq.elevator_merge_req_fn(q, rq, next);
+       }
 
        elv_rqhash_reposition(q, rq);
 
@@ -528,8 +561,11 @@ void elv_bio_merged(struct request_queue *q, struct request *rq,
 {
        struct elevator_queue *e = q->elevator;
 
-       if (e->type->ops.elevator_bio_merged_fn)
-               e->type->ops.elevator_bio_merged_fn(q, rq, bio);
+       if (WARN_ON_ONCE(e->uses_mq))
+               return;
+
+       if (e->type->ops.sq.elevator_bio_merged_fn)
+               e->type->ops.sq.elevator_bio_merged_fn(q, rq, bio);
 }
 
 #ifdef CONFIG_PM
@@ -574,11 +610,15 @@ void elv_requeue_request(struct request_queue *q, struct request *rq)
 
 void elv_drain_elevator(struct request_queue *q)
 {
+       struct elevator_queue *e = q->elevator;
        static int printed;
 
+       if (WARN_ON_ONCE(e->uses_mq))
+               return;
+
        lockdep_assert_held(q->queue_lock);
 
-       while (q->elevator->type->ops.elevator_dispatch_fn(q, 1))
+       while (e->type->ops.sq.elevator_dispatch_fn(q, 1))
                ;
        if (q->nr_sorted && printed++ < 10) {
                printk(KERN_ERR "%s: forced dispatching is broken "
@@ -597,7 +637,7 @@ void __elv_add_request(struct request_queue *q, struct request *rq, int where)
 
        if (rq->rq_flags & RQF_SOFTBARRIER) {
                /* barriers are scheduling boundary, update end_sector */
-               if (rq->cmd_type == REQ_TYPE_FS) {
+               if (!blk_rq_is_passthrough(rq)) {
                        q->end_sector = rq_end_sector(rq);
                        q->boundary_rq = rq;
                }
@@ -639,7 +679,7 @@ void __elv_add_request(struct request_queue *q, struct request *rq, int where)
                if (elv_attempt_insert_merge(q, rq))
                        break;
        case ELEVATOR_INSERT_SORT:
-               BUG_ON(rq->cmd_type != REQ_TYPE_FS);
+               BUG_ON(blk_rq_is_passthrough(rq));
                rq->rq_flags |= RQF_SORTED;
                q->nr_sorted++;
                if (rq_mergeable(rq)) {
@@ -653,7 +693,7 @@ void __elv_add_request(struct request_queue *q, struct request *rq, int where)
                 * rq cannot be accessed after calling
                 * elevator_add_req_fn.
                 */
-               q->elevator->type->ops.elevator_add_req_fn(q, rq);
+               q->elevator->type->ops.sq.elevator_add_req_fn(q, rq);
                break;
 
        case ELEVATOR_INSERT_FLUSH:
@@ -682,8 +722,11 @@ struct request *elv_latter_request(struct request_queue *q, struct request *rq)
 {
        struct elevator_queue *e = q->elevator;
 
-       if (e->type->ops.elevator_latter_req_fn)
-               return e->type->ops.elevator_latter_req_fn(q, rq);
+       if (e->uses_mq && e->type->ops.mq.next_request)
+               return e->type->ops.mq.next_request(q, rq);
+       else if (!e->uses_mq && e->type->ops.sq.elevator_latter_req_fn)
+               return e->type->ops.sq.elevator_latter_req_fn(q, rq);
+
        return NULL;
 }
 
@@ -691,8 +734,10 @@ struct request *elv_former_request(struct request_queue *q, struct request *rq)
 {
        struct elevator_queue *e = q->elevator;
 
-       if (e->type->ops.elevator_former_req_fn)
-               return e->type->ops.elevator_former_req_fn(q, rq);
+       if (e->uses_mq && e->type->ops.mq.former_request)
+               return e->type->ops.mq.former_request(q, rq);
+       if (!e->uses_mq && e->type->ops.sq.elevator_former_req_fn)
+               return e->type->ops.sq.elevator_former_req_fn(q, rq);
        return NULL;
 }
 
@@ -701,8 +746,11 @@ int elv_set_request(struct request_queue *q, struct request *rq,
 {
        struct elevator_queue *e = q->elevator;
 
-       if (e->type->ops.elevator_set_req_fn)
-               return e->type->ops.elevator_set_req_fn(q, rq, bio, gfp_mask);
+       if (WARN_ON_ONCE(e->uses_mq))
+               return 0;
+
+       if (e->type->ops.sq.elevator_set_req_fn)
+               return e->type->ops.sq.elevator_set_req_fn(q, rq, bio, gfp_mask);
        return 0;
 }
 
@@ -710,16 +758,22 @@ void elv_put_request(struct request_queue *q, struct request *rq)
 {
        struct elevator_queue *e = q->elevator;
 
-       if (e->type->ops.elevator_put_req_fn)
-               e->type->ops.elevator_put_req_fn(rq);
+       if (WARN_ON_ONCE(e->uses_mq))
+               return;
+
+       if (e->type->ops.sq.elevator_put_req_fn)
+               e->type->ops.sq.elevator_put_req_fn(rq);
 }
 
 int elv_may_queue(struct request_queue *q, unsigned int op)
 {
        struct elevator_queue *e = q->elevator;
 
-       if (e->type->ops.elevator_may_queue_fn)
-               return e->type->ops.elevator_may_queue_fn(q, op);
+       if (WARN_ON_ONCE(e->uses_mq))
+               return 0;
+
+       if (e->type->ops.sq.elevator_may_queue_fn)
+               return e->type->ops.sq.elevator_may_queue_fn(q, op);
 
        return ELV_MQUEUE_MAY;
 }
@@ -728,14 +782,17 @@ void elv_completed_request(struct request_queue *q, struct request *rq)
 {
        struct elevator_queue *e = q->elevator;
 
+       if (WARN_ON_ONCE(e->uses_mq))
+               return;
+
        /*
         * request is released from the driver, io must be done
         */
        if (blk_account_rq(rq)) {
                q->in_flight[rq_is_sync(rq)]--;
                if ((rq->rq_flags & RQF_SORTED) &&
-                   e->type->ops.elevator_completed_req_fn)
-                       e->type->ops.elevator_completed_req_fn(q, rq);
+                   e->type->ops.sq.elevator_completed_req_fn)
+                       e->type->ops.sq.elevator_completed_req_fn(q, rq);
        }
 }
 
@@ -803,8 +860,8 @@ int elv_register_queue(struct request_queue *q)
                }
                kobject_uevent(&e->kobj, KOBJ_ADD);
                e->registered = 1;
-               if (e->type->ops.elevator_registered_fn)
-                       e->type->ops.elevator_registered_fn(q);
+               if (!e->uses_mq && e->type->ops.sq.elevator_registered_fn)
+                       e->type->ops.sq.elevator_registered_fn(q);
        }
        return error;
 }
@@ -891,9 +948,14 @@ EXPORT_SYMBOL_GPL(elv_unregister);
 static int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
 {
        struct elevator_queue *old = q->elevator;
-       bool registered = old->registered;
+       bool old_registered = false;
        int err;
 
+       if (q->mq_ops) {
+               blk_mq_freeze_queue(q);
+               blk_mq_quiesce_queue(q);
+       }
+
        /*
         * Turn on BYPASS and drain all requests w/ elevator private data.
         * Block layer doesn't call into a quiesced elevator - all requests
@@ -901,42 +963,76 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
         * using INSERT_BACK.  All requests have SOFTBARRIER set and no
         * merge happens either.
         */
-       blk_queue_bypass_start(q);
+       if (old) {
+               old_registered = old->registered;
+
+               if (old->uses_mq)
+                       blk_mq_sched_teardown(q);
+
+               if (!q->mq_ops)
+                       blk_queue_bypass_start(q);
 
-       /* unregister and clear all auxiliary data of the old elevator */
-       if (registered)
-               elv_unregister_queue(q);
+               /* unregister and clear all auxiliary data of the old elevator */
+               if (old_registered)
+                       elv_unregister_queue(q);
 
-       spin_lock_irq(q->queue_lock);
-       ioc_clear_queue(q);
-       spin_unlock_irq(q->queue_lock);
+               spin_lock_irq(q->queue_lock);
+               ioc_clear_queue(q);
+               spin_unlock_irq(q->queue_lock);
+       }
 
        /* allocate, init and register new elevator */
-       err = new_e->ops.elevator_init_fn(q, new_e);
-       if (err)
-               goto fail_init;
+       if (new_e) {
+               if (new_e->uses_mq) {
+                       err = blk_mq_sched_setup(q);
+                       if (!err)
+                               err = new_e->ops.mq.init_sched(q, new_e);
+               } else
+                       err = new_e->ops.sq.elevator_init_fn(q, new_e);
+               if (err)
+                       goto fail_init;
 
-       if (registered) {
                err = elv_register_queue(q);
                if (err)
                        goto fail_register;
-       }
+       } else
+               q->elevator = NULL;
 
        /* done, kill the old one and finish */
-       elevator_exit(old);
-       blk_queue_bypass_end(q);
+       if (old) {
+               elevator_exit(old);
+               if (!q->mq_ops)
+                       blk_queue_bypass_end(q);
+       }
 
-       blk_add_trace_msg(q, "elv switch: %s", new_e->elevator_name);
+       if (q->mq_ops) {
+               blk_mq_unfreeze_queue(q);
+               blk_mq_start_stopped_hw_queues(q, true);
+       }
+
+       if (new_e)
+               blk_add_trace_msg(q, "elv switch: %s", new_e->elevator_name);
+       else
+               blk_add_trace_msg(q, "elv switch: none");
 
        return 0;
 
 fail_register:
+       if (q->mq_ops)
+               blk_mq_sched_teardown(q);
        elevator_exit(q->elevator);
 fail_init:
        /* switch failed, restore and re-register old elevator */
-       q->elevator = old;
-       elv_register_queue(q);
-       blk_queue_bypass_end(q);
+       if (old) {
+               q->elevator = old;
+               elv_register_queue(q);
+               if (!q->mq_ops)
+                       blk_queue_bypass_end(q);
+       }
+       if (q->mq_ops) {
+               blk_mq_unfreeze_queue(q);
+               blk_mq_start_stopped_hw_queues(q, true);
+       }
 
        return err;
 }
@@ -949,8 +1045,11 @@ static int __elevator_change(struct request_queue *q, const char *name)
        char elevator_name[ELV_NAME_MAX];
        struct elevator_type *e;
 
-       if (!q->elevator)
-               return -ENXIO;
+       /*
+        * Special case for mq, turn off scheduling
+        */
+       if (q->mq_ops && !strncmp(name, "none", 4))
+               return elevator_switch(q, NULL);
 
        strlcpy(elevator_name, name, sizeof(elevator_name));
        e = elevator_get(strstrip(elevator_name), true);
@@ -959,11 +1058,21 @@ static int __elevator_change(struct request_queue *q, const char *name)
                return -EINVAL;
        }
 
-       if (!strcmp(elevator_name, q->elevator->type->elevator_name)) {
+       if (q->elevator &&
+           !strcmp(elevator_name, q->elevator->type->elevator_name)) {
                elevator_put(e);
                return 0;
        }
 
+       if (!e->uses_mq && q->mq_ops) {
+               elevator_put(e);
+               return -EINVAL;
+       }
+       if (e->uses_mq && !q->mq_ops) {
+               elevator_put(e);
+               return -EINVAL;
+       }
+
        return elevator_switch(q, e);
 }
 
@@ -985,7 +1094,7 @@ ssize_t elv_iosched_store(struct request_queue *q, const char *name,
 {
        int ret;
 
-       if (!q->elevator)
+       if (!(q->mq_ops || q->request_fn))
                return count;
 
        ret = __elevator_change(q, name);
@@ -999,24 +1108,34 @@ ssize_t elv_iosched_store(struct request_queue *q, const char *name,
 ssize_t elv_iosched_show(struct request_queue *q, char *name)
 {
        struct elevator_queue *e = q->elevator;
-       struct elevator_type *elv;
+       struct elevator_type *elv = NULL;
        struct elevator_type *__e;
        int len = 0;
 
-       if (!q->elevator || !blk_queue_stackable(q))
+       if (!blk_queue_stackable(q))
                return sprintf(name, "none\n");
 
-       elv = e->type;
+       if (!q->elevator)
+               len += sprintf(name+len, "[none] ");
+       else
+               elv = e->type;
 
        spin_lock(&elv_list_lock);
        list_for_each_entry(__e, &elv_list, list) {
-               if (!strcmp(elv->elevator_name, __e->elevator_name))
+               if (elv && !strcmp(elv->elevator_name, __e->elevator_name)) {
                        len += sprintf(name+len, "[%s] ", elv->elevator_name);
-               else
+                       continue;
+               }
+               if (__e->uses_mq && q->mq_ops)
+                       len += sprintf(name+len, "%s ", __e->elevator_name);
+               else if (!__e->uses_mq && !q->mq_ops)
                        len += sprintf(name+len, "%s ", __e->elevator_name);
        }
        spin_unlock(&elv_list_lock);
 
+       if (q->mq_ops && q->elevator)
+               len += sprintf(name+len, "none");
+
        len += sprintf(len+name, "\n");
        return len;
 }
index fcd6d4fae657cfdf118274cec31780f9e8b8c1f8..3631cd4802955247d27316c10b172744700e6340 100644 (file)
@@ -572,6 +572,20 @@ exit:
        disk_part_iter_exit(&piter);
 }
 
+void put_disk_devt(struct disk_devt *disk_devt)
+{
+       if (disk_devt && atomic_dec_and_test(&disk_devt->count))
+               disk_devt->release(disk_devt);
+}
+EXPORT_SYMBOL(put_disk_devt);
+
+void get_disk_devt(struct disk_devt *disk_devt)
+{
+       if (disk_devt)
+               atomic_inc(&disk_devt->count);
+}
+EXPORT_SYMBOL(get_disk_devt);
+
 /**
  * device_add_disk - add partitioning information to kernel list
  * @parent: parent device for the disk
@@ -612,8 +626,15 @@ void device_add_disk(struct device *parent, struct gendisk *disk)
 
        disk_alloc_events(disk);
 
+       /*
+        * Take a reference on the devt and assign it to queue since it
+        * must not be reallocated while the bdi is registered
+        */
+       disk->queue->disk_devt = disk->disk_devt;
+       get_disk_devt(disk->disk_devt);
+
        /* Register BDI before referencing it from bdev */
-       bdi = &disk->queue->backing_dev_info;
+       bdi = disk->queue->backing_dev_info;
        bdi_register_owner(bdi, disk_to_dev(disk));
 
        blk_register_region(disk_devt(disk), disk->minors, NULL,
@@ -648,6 +669,8 @@ void del_gendisk(struct gendisk *disk)
        disk_part_iter_init(&piter, disk,
                             DISK_PITER_INCL_EMPTY | DISK_PITER_REVERSE);
        while ((part = disk_part_iter_next(&piter))) {
+               bdev_unhash_inode(MKDEV(disk->major,
+                                       disk->first_minor + part->partno));
                invalidate_partition(disk, part->partno);
                delete_partition(disk, part->partno);
        }
index be7f4de3eb3cfe7edc7a95644b2d9ee350703b88..7b88820b93d9d92a8368d29d3bda2d2e51f5f905 100644 (file)
@@ -505,7 +505,6 @@ static int blkdev_bszset(struct block_device *bdev, fmode_t mode,
 int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
                        unsigned long arg)
 {
-       struct backing_dev_info *bdi;
        void __user *argp = (void __user *)arg;
        loff_t size;
        unsigned int max_sectors;
@@ -532,8 +531,7 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
        case BLKFRAGET:
                if (!arg)
                        return -EINVAL;
-               bdi = blk_get_backing_dev_info(bdev);
-               return put_long(arg, (bdi->ra_pages * PAGE_SIZE) / 512);
+               return put_long(arg, (bdev->bd_bdi->ra_pages*PAGE_SIZE) / 512);
        case BLKROGET:
                return put_int(arg, bdev_read_only(bdev) != 0);
        case BLKBSZGET: /* get block device soft block size (cf. BLKSSZGET) */
@@ -560,8 +558,7 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
        case BLKFRASET:
                if(!capable(CAP_SYS_ADMIN))
                        return -EACCES;
-               bdi = blk_get_backing_dev_info(bdev);
-               bdi->ra_pages = (arg * 512) / PAGE_SIZE;
+               bdev->bd_bdi->ra_pages = (arg * 512) / PAGE_SIZE;
                return 0;
        case BLKBSZSET:
                return blkdev_bszset(bdev, mode, argp);
diff --git a/block/mq-deadline.c b/block/mq-deadline.c
new file mode 100644 (file)
index 0000000..2361216
--- /dev/null
@@ -0,0 +1,556 @@
+/*
+ *  MQ Deadline i/o scheduler - adaptation of the legacy deadline scheduler,
+ *  for the blk-mq scheduling framework
+ *
+ *  Copyright (C) 2016 Jens Axboe <axboe@kernel.dk>
+ */
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/blkdev.h>
+#include <linux/blk-mq.h>
+#include <linux/elevator.h>
+#include <linux/bio.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/compiler.h>
+#include <linux/rbtree.h>
+#include <linux/sbitmap.h>
+
+#include "blk.h"
+#include "blk-mq.h"
+#include "blk-mq-tag.h"
+#include "blk-mq-sched.h"
+
+/*
+ * See Documentation/block/deadline-iosched.txt
+ */
+static const int read_expire = HZ / 2;  /* max time before a read is submitted. */
+static const int write_expire = 5 * HZ; /* ditto for writes, these limits are SOFT! */
+static const int writes_starved = 2;    /* max times reads can starve a write */
+static const int fifo_batch = 16;       /* # of sequential requests treated as one
+                                    by the above parameters. For throughput. */
+
+struct deadline_data {
+       /*
+        * run time data
+        */
+
+       /*
+        * requests (deadline_rq s) are present on both sort_list and fifo_list
+        */
+       struct rb_root sort_list[2];
+       struct list_head fifo_list[2];
+
+       /*
+        * next in sort order. read, write or both are NULL
+        */
+       struct request *next_rq[2];
+       unsigned int batching;          /* number of sequential requests made */
+       unsigned int starved;           /* times reads have starved writes */
+
+       /*
+        * settings that change how the i/o scheduler behaves
+        */
+       int fifo_expire[2];
+       int fifo_batch;
+       int writes_starved;
+       int front_merges;
+
+       spinlock_t lock;
+       struct list_head dispatch;
+};
+
+static inline struct rb_root *
+deadline_rb_root(struct deadline_data *dd, struct request *rq)
+{
+       return &dd->sort_list[rq_data_dir(rq)];
+}
+
+/*
+ * get the request after `rq' in sector-sorted order
+ */
+static inline struct request *
+deadline_latter_request(struct request *rq)
+{
+       struct rb_node *node = rb_next(&rq->rb_node);
+
+       if (node)
+               return rb_entry_rq(node);
+
+       return NULL;
+}
+
+static void
+deadline_add_rq_rb(struct deadline_data *dd, struct request *rq)
+{
+       struct rb_root *root = deadline_rb_root(dd, rq);
+
+       elv_rb_add(root, rq);
+}
+
+static inline void
+deadline_del_rq_rb(struct deadline_data *dd, struct request *rq)
+{
+       const int data_dir = rq_data_dir(rq);
+
+       if (dd->next_rq[data_dir] == rq)
+               dd->next_rq[data_dir] = deadline_latter_request(rq);
+
+       elv_rb_del(deadline_rb_root(dd, rq), rq);
+}
+
+/*
+ * remove rq from rbtree and fifo.
+ */
+static void deadline_remove_request(struct request_queue *q, struct request *rq)
+{
+       struct deadline_data *dd = q->elevator->elevator_data;
+
+       list_del_init(&rq->queuelist);
+
+       /*
+        * We might not be on the rbtree, if we are doing an insert merge
+        */
+       if (!RB_EMPTY_NODE(&rq->rb_node))
+               deadline_del_rq_rb(dd, rq);
+
+       elv_rqhash_del(q, rq);
+       if (q->last_merge == rq)
+               q->last_merge = NULL;
+}
+
+static void dd_request_merged(struct request_queue *q, struct request *req,
+                             enum elv_merge type)
+{
+       struct deadline_data *dd = q->elevator->elevator_data;
+
+       /*
+        * if the merge was a front merge, we need to reposition request
+        */
+       if (type == ELEVATOR_FRONT_MERGE) {
+               elv_rb_del(deadline_rb_root(dd, req), req);
+               deadline_add_rq_rb(dd, req);
+       }
+}
+
+static void dd_merged_requests(struct request_queue *q, struct request *req,
+                              struct request *next)
+{
+       /*
+        * if next expires before rq, assign its expire time to rq
+        * and move into next position (next will be deleted) in fifo
+        */
+       if (!list_empty(&req->queuelist) && !list_empty(&next->queuelist)) {
+               if (time_before((unsigned long)next->fifo_time,
+                               (unsigned long)req->fifo_time)) {
+                       list_move(&req->queuelist, &next->queuelist);
+                       req->fifo_time = next->fifo_time;
+               }
+       }
+
+       /*
+        * kill knowledge of next, this one is a goner
+        */
+       deadline_remove_request(q, next);
+}
+
+/*
+ * move an entry to dispatch queue
+ */
+static void
+deadline_move_request(struct deadline_data *dd, struct request *rq)
+{
+       const int data_dir = rq_data_dir(rq);
+
+       dd->next_rq[READ] = NULL;
+       dd->next_rq[WRITE] = NULL;
+       dd->next_rq[data_dir] = deadline_latter_request(rq);
+
+       /*
+        * take it off the sort and fifo list
+        */
+       deadline_remove_request(rq->q, rq);
+}
+
+/*
+ * deadline_check_fifo returns 0 if there are no expired requests on the fifo,
+ * 1 otherwise. Requires !list_empty(&dd->fifo_list[data_dir])
+ */
+static inline int deadline_check_fifo(struct deadline_data *dd, int ddir)
+{
+       struct request *rq = rq_entry_fifo(dd->fifo_list[ddir].next);
+
+       /*
+        * rq is expired!
+        */
+       if (time_after_eq(jiffies, (unsigned long)rq->fifo_time))
+               return 1;
+
+       return 0;
+}
+
+/*
+ * deadline_dispatch_requests selects the best request according to
+ * read/write expire, fifo_batch, etc
+ */
+static struct request *__dd_dispatch_request(struct blk_mq_hw_ctx *hctx)
+{
+       struct deadline_data *dd = hctx->queue->elevator->elevator_data;
+       struct request *rq;
+       bool reads, writes;
+       int data_dir;
+
+       if (!list_empty(&dd->dispatch)) {
+               rq = list_first_entry(&dd->dispatch, struct request, queuelist);
+               list_del_init(&rq->queuelist);
+               goto done;
+       }
+
+       reads = !list_empty(&dd->fifo_list[READ]);
+       writes = !list_empty(&dd->fifo_list[WRITE]);
+
+       /*
+        * batches are currently reads XOR writes
+        */
+       if (dd->next_rq[WRITE])
+               rq = dd->next_rq[WRITE];
+       else
+               rq = dd->next_rq[READ];
+
+       if (rq && dd->batching < dd->fifo_batch)
+               /* we have a next request are still entitled to batch */
+               goto dispatch_request;
+
+       /*
+        * at this point we are not running a batch. select the appropriate
+        * data direction (read / write)
+        */
+
+       if (reads) {
+               BUG_ON(RB_EMPTY_ROOT(&dd->sort_list[READ]));
+
+               if (writes && (dd->starved++ >= dd->writes_starved))
+                       goto dispatch_writes;
+
+               data_dir = READ;
+
+               goto dispatch_find_request;
+       }
+
+       /*
+        * there are either no reads or writes have been starved
+        */
+
+       if (writes) {
+dispatch_writes:
+               BUG_ON(RB_EMPTY_ROOT(&dd->sort_list[WRITE]));
+
+               dd->starved = 0;
+
+               data_dir = WRITE;
+
+               goto dispatch_find_request;
+       }
+
+       return NULL;
+
+dispatch_find_request:
+       /*
+        * we are not running a batch, find best request for selected data_dir
+        */
+       if (deadline_check_fifo(dd, data_dir) || !dd->next_rq[data_dir]) {
+               /*
+                * A deadline has expired, the last request was in the other
+                * direction, or we have run out of higher-sectored requests.
+                * Start again from the request with the earliest expiry time.
+                */
+               rq = rq_entry_fifo(dd->fifo_list[data_dir].next);
+       } else {
+               /*
+                * The last req was the same dir and we have a next request in
+                * sort order. No expired requests so continue on from here.
+                */
+               rq = dd->next_rq[data_dir];
+       }
+
+       dd->batching = 0;
+
+dispatch_request:
+       /*
+        * rq is the selected appropriate request.
+        */
+       dd->batching++;
+       deadline_move_request(dd, rq);
+done:
+       rq->rq_flags |= RQF_STARTED;
+       return rq;
+}
+
+static struct request *dd_dispatch_request(struct blk_mq_hw_ctx *hctx)
+{
+       struct deadline_data *dd = hctx->queue->elevator->elevator_data;
+       struct request *rq;
+
+       spin_lock(&dd->lock);
+       rq = __dd_dispatch_request(hctx);
+       spin_unlock(&dd->lock);
+
+       return rq;
+}
+
+static void dd_exit_queue(struct elevator_queue *e)
+{
+       struct deadline_data *dd = e->elevator_data;
+
+       BUG_ON(!list_empty(&dd->fifo_list[READ]));
+       BUG_ON(!list_empty(&dd->fifo_list[WRITE]));
+
+       kfree(dd);
+}
+
+/*
+ * initialize elevator private data (deadline_data).
+ */
+static int dd_init_queue(struct request_queue *q, struct elevator_type *e)
+{
+       struct deadline_data *dd;
+       struct elevator_queue *eq;
+
+       eq = elevator_alloc(q, e);
+       if (!eq)
+               return -ENOMEM;
+
+       dd = kzalloc_node(sizeof(*dd), GFP_KERNEL, q->node);
+       if (!dd) {
+               kobject_put(&eq->kobj);
+               return -ENOMEM;
+       }
+       eq->elevator_data = dd;
+
+       INIT_LIST_HEAD(&dd->fifo_list[READ]);
+       INIT_LIST_HEAD(&dd->fifo_list[WRITE]);
+       dd->sort_list[READ] = RB_ROOT;
+       dd->sort_list[WRITE] = RB_ROOT;
+       dd->fifo_expire[READ] = read_expire;
+       dd->fifo_expire[WRITE] = write_expire;
+       dd->writes_starved = writes_starved;
+       dd->front_merges = 1;
+       dd->fifo_batch = fifo_batch;
+       spin_lock_init(&dd->lock);
+       INIT_LIST_HEAD(&dd->dispatch);
+
+       q->elevator = eq;
+       return 0;
+}
+
+static int dd_request_merge(struct request_queue *q, struct request **rq,
+                           struct bio *bio)
+{
+       struct deadline_data *dd = q->elevator->elevator_data;
+       sector_t sector = bio_end_sector(bio);
+       struct request *__rq;
+
+       if (!dd->front_merges)
+               return ELEVATOR_NO_MERGE;
+
+       __rq = elv_rb_find(&dd->sort_list[bio_data_dir(bio)], sector);
+       if (__rq) {
+               BUG_ON(sector != blk_rq_pos(__rq));
+
+               if (elv_bio_merge_ok(__rq, bio)) {
+                       *rq = __rq;
+                       return ELEVATOR_FRONT_MERGE;
+               }
+       }
+
+       return ELEVATOR_NO_MERGE;
+}
+
+static bool dd_bio_merge(struct blk_mq_hw_ctx *hctx, struct bio *bio)
+{
+       struct request_queue *q = hctx->queue;
+       struct deadline_data *dd = q->elevator->elevator_data;
+       struct request *free = NULL;
+       bool ret;
+
+       spin_lock(&dd->lock);
+       ret = blk_mq_sched_try_merge(q, bio, &free);
+       spin_unlock(&dd->lock);
+
+       if (free)
+               blk_mq_free_request(free);
+
+       return ret;
+}
+
+/*
+ * add rq to rbtree and fifo
+ */
+static void dd_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq,
+                             bool at_head)
+{
+       struct request_queue *q = hctx->queue;
+       struct deadline_data *dd = q->elevator->elevator_data;
+       const int data_dir = rq_data_dir(rq);
+
+       if (blk_mq_sched_try_insert_merge(q, rq))
+               return;
+
+       blk_mq_sched_request_inserted(rq);
+
+       if (at_head || blk_rq_is_passthrough(rq)) {
+               if (at_head)
+                       list_add(&rq->queuelist, &dd->dispatch);
+               else
+                       list_add_tail(&rq->queuelist, &dd->dispatch);
+       } else {
+               deadline_add_rq_rb(dd, rq);
+
+               if (rq_mergeable(rq)) {
+                       elv_rqhash_add(q, rq);
+                       if (!q->last_merge)
+                               q->last_merge = rq;
+               }
+
+               /*
+                * set expire time and add to fifo list
+                */
+               rq->fifo_time = jiffies + dd->fifo_expire[data_dir];
+               list_add_tail(&rq->queuelist, &dd->fifo_list[data_dir]);
+       }
+}
+
+static void dd_insert_requests(struct blk_mq_hw_ctx *hctx,
+                              struct list_head *list, bool at_head)
+{
+       struct request_queue *q = hctx->queue;
+       struct deadline_data *dd = q->elevator->elevator_data;
+
+       spin_lock(&dd->lock);
+       while (!list_empty(list)) {
+               struct request *rq;
+
+               rq = list_first_entry(list, struct request, queuelist);
+               list_del_init(&rq->queuelist);
+               dd_insert_request(hctx, rq, at_head);
+       }
+       spin_unlock(&dd->lock);
+}
+
+static bool dd_has_work(struct blk_mq_hw_ctx *hctx)
+{
+       struct deadline_data *dd = hctx->queue->elevator->elevator_data;
+
+       return !list_empty_careful(&dd->dispatch) ||
+               !list_empty_careful(&dd->fifo_list[0]) ||
+               !list_empty_careful(&dd->fifo_list[1]);
+}
+
+/*
+ * sysfs parts below
+ */
+static ssize_t
+deadline_var_show(int var, char *page)
+{
+       return sprintf(page, "%d\n", var);
+}
+
+static ssize_t
+deadline_var_store(int *var, const char *page, size_t count)
+{
+       char *p = (char *) page;
+
+       *var = simple_strtol(p, &p, 10);
+       return count;
+}
+
+#define SHOW_FUNCTION(__FUNC, __VAR, __CONV)                           \
+static ssize_t __FUNC(struct elevator_queue *e, char *page)            \
+{                                                                      \
+       struct deadline_data *dd = e->elevator_data;                    \
+       int __data = __VAR;                                             \
+       if (__CONV)                                                     \
+               __data = jiffies_to_msecs(__data);                      \
+       return deadline_var_show(__data, (page));                       \
+}
+SHOW_FUNCTION(deadline_read_expire_show, dd->fifo_expire[READ], 1);
+SHOW_FUNCTION(deadline_write_expire_show, dd->fifo_expire[WRITE], 1);
+SHOW_FUNCTION(deadline_writes_starved_show, dd->writes_starved, 0);
+SHOW_FUNCTION(deadline_front_merges_show, dd->front_merges, 0);
+SHOW_FUNCTION(deadline_fifo_batch_show, dd->fifo_batch, 0);
+#undef SHOW_FUNCTION
+
+#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV)                        \
+static ssize_t __FUNC(struct elevator_queue *e, const char *page, size_t count)        \
+{                                                                      \
+       struct deadline_data *dd = e->elevator_data;                    \
+       int __data;                                                     \
+       int ret = deadline_var_store(&__data, (page), count);           \
+       if (__data < (MIN))                                             \
+               __data = (MIN);                                         \
+       else if (__data > (MAX))                                        \
+               __data = (MAX);                                         \
+       if (__CONV)                                                     \
+               *(__PTR) = msecs_to_jiffies(__data);                    \
+       else                                                            \
+               *(__PTR) = __data;                                      \
+       return ret;                                                     \
+}
+STORE_FUNCTION(deadline_read_expire_store, &dd->fifo_expire[READ], 0, INT_MAX, 1);
+STORE_FUNCTION(deadline_write_expire_store, &dd->fifo_expire[WRITE], 0, INT_MAX, 1);
+STORE_FUNCTION(deadline_writes_starved_store, &dd->writes_starved, INT_MIN, INT_MAX, 0);
+STORE_FUNCTION(deadline_front_merges_store, &dd->front_merges, 0, 1, 0);
+STORE_FUNCTION(deadline_fifo_batch_store, &dd->fifo_batch, 0, INT_MAX, 0);
+#undef STORE_FUNCTION
+
+#define DD_ATTR(name) \
+       __ATTR(name, S_IRUGO|S_IWUSR, deadline_##name##_show, \
+                                     deadline_##name##_store)
+
+static struct elv_fs_entry deadline_attrs[] = {
+       DD_ATTR(read_expire),
+       DD_ATTR(write_expire),
+       DD_ATTR(writes_starved),
+       DD_ATTR(front_merges),
+       DD_ATTR(fifo_batch),
+       __ATTR_NULL
+};
+
+static struct elevator_type mq_deadline = {
+       .ops.mq = {
+               .insert_requests        = dd_insert_requests,
+               .dispatch_request       = dd_dispatch_request,
+               .next_request           = elv_rb_latter_request,
+               .former_request         = elv_rb_former_request,
+               .bio_merge              = dd_bio_merge,
+               .request_merge          = dd_request_merge,
+               .requests_merged        = dd_merged_requests,
+               .request_merged         = dd_request_merged,
+               .has_work               = dd_has_work,
+               .init_sched             = dd_init_queue,
+               .exit_sched             = dd_exit_queue,
+       },
+
+       .uses_mq        = true,
+       .elevator_attrs = deadline_attrs,
+       .elevator_name = "mq-deadline",
+       .elevator_owner = THIS_MODULE,
+};
+
+static int __init deadline_init(void)
+{
+       return elv_register(&mq_deadline);
+}
+
+static void __exit deadline_exit(void)
+{
+       elv_unregister(&mq_deadline);
+}
+
+module_init(deadline_init);
+module_exit(deadline_exit);
+
+MODULE_AUTHOR("Jens Axboe");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MQ deadline IO scheduler");
index a163c487cf38c8250ccbf0ec7beac913672796f0..2d1b15d89b4580e855eba7a7afe0b24650e029db 100644 (file)
@@ -92,7 +92,7 @@ static void noop_exit_queue(struct elevator_queue *e)
 }
 
 static struct elevator_type elevator_noop = {
-       .ops = {
+       .ops.sq = {
                .elevator_merge_req_fn          = noop_merged_requests,
                .elevator_dispatch_fn           = noop_dispatch,
                .elevator_add_req_fn            = noop_add_request,
diff --git a/block/opal_proto.h b/block/opal_proto.h
new file mode 100644 (file)
index 0000000..f40c9ac
--- /dev/null
@@ -0,0 +1,452 @@
+/*
+ * Copyright Â© 2016 Intel Corporation
+ *
+ * Authors:
+ *    Rafael Antognolli <rafael.antognolli@intel.com>
+ *    Scott  Bauer      <scott.bauer@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * 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>
+
+#ifndef _OPAL_PROTO_H
+#define _OPAL_PROTO_H
+
+/*
+ * These constant values come from:
+ * SPC-4 section
+ * 6.30 SECURITY PROTOCOL IN command / table 265.
+ */
+enum {
+       TCG_SECP_00 = 0,
+       TCG_SECP_01,
+};
+
+/*
+ * Token defs derived from:
+ * TCG_Storage_Architecture_Core_Spec_v2.01_r1.00
+ * 3.2.2 Data Stream Encoding
+ */
+enum opal_response_token {
+       OPAL_DTA_TOKENID_BYTESTRING = 0xe0,
+       OPAL_DTA_TOKENID_SINT = 0xe1,
+       OPAL_DTA_TOKENID_UINT = 0xe2,
+       OPAL_DTA_TOKENID_TOKEN = 0xe3, /* actual token is returned */
+       OPAL_DTA_TOKENID_INVALID = 0X0
+};
+
+#define DTAERROR_NO_METHOD_STATUS 0x89
+#define GENERIC_HOST_SESSION_NUM 0x41
+
+#define TPER_SYNC_SUPPORTED 0x01
+
+#define TINY_ATOM_DATA_MASK 0x3F
+#define TINY_ATOM_SIGNED 0x40
+
+#define SHORT_ATOM_ID 0x80
+#define SHORT_ATOM_BYTESTRING 0x20
+#define SHORT_ATOM_SIGNED 0x10
+#define SHORT_ATOM_LEN_MASK 0xF
+
+#define MEDIUM_ATOM_ID 0xC0
+#define MEDIUM_ATOM_BYTESTRING 0x10
+#define MEDIUM_ATOM_SIGNED 0x8
+#define MEDIUM_ATOM_LEN_MASK 0x7
+
+#define LONG_ATOM_ID 0xe0
+#define LONG_ATOM_BYTESTRING 0x2
+#define LONG_ATOM_SIGNED 0x1
+
+/* Derived from TCG Core spec 2.01 Section:
+ * 3.2.2.1
+ * Data Type
+ */
+#define TINY_ATOM_BYTE   0x7F
+#define SHORT_ATOM_BYTE  0xBF
+#define MEDIUM_ATOM_BYTE 0xDF
+#define LONG_ATOM_BYTE   0xE3
+
+#define OPAL_INVAL_PARAM 12
+#define OPAL_MANUFACTURED_INACTIVE 0x08
+#define OPAL_DISCOVERY_COMID 0x0001
+
+#define LOCKING_RANGE_NON_GLOBAL 0x03
+/*
+ * User IDs used in the TCG storage SSCs
+ * Derived from: TCG_Storage_Architecture_Core_Spec_v2.01_r1.00
+ * Section: 6.3 Assigned UIDs
+ */
+#define OPAL_UID_LENGTH 8
+#define OPAL_METHOD_LENGTH 8
+#define OPAL_MSID_KEYLEN 15
+#define OPAL_UID_LENGTH_HALF 4
+
+/* Enum to index OPALUID array */
+enum opal_uid {
+       /* users */
+       OPAL_SMUID_UID,
+       OPAL_THISSP_UID,
+       OPAL_ADMINSP_UID,
+       OPAL_LOCKINGSP_UID,
+       OPAL_ENTERPRISE_LOCKINGSP_UID,
+       OPAL_ANYBODY_UID,
+       OPAL_SID_UID,
+       OPAL_ADMIN1_UID,
+       OPAL_USER1_UID,
+       OPAL_USER2_UID,
+       OPAL_PSID_UID,
+       OPAL_ENTERPRISE_BANDMASTER0_UID,
+       OPAL_ENTERPRISE_ERASEMASTER_UID,
+       /* tables */
+       OPAL_LOCKINGRANGE_GLOBAL,
+       OPAL_LOCKINGRANGE_ACE_RDLOCKED,
+       OPAL_LOCKINGRANGE_ACE_WRLOCKED,
+       OPAL_MBRCONTROL,
+       OPAL_MBR,
+       OPAL_AUTHORITY_TABLE,
+       OPAL_C_PIN_TABLE,
+       OPAL_LOCKING_INFO_TABLE,
+       OPAL_ENTERPRISE_LOCKING_INFO_TABLE,
+       /* C_PIN_TABLE object ID's */
+       OPAL_C_PIN_MSID,
+       OPAL_C_PIN_SID,
+       OPAL_C_PIN_ADMIN1,
+       /* half UID's (only first 4 bytes used) */
+       OPAL_HALF_UID_AUTHORITY_OBJ_REF,
+       OPAL_HALF_UID_BOOLEAN_ACE,
+       /* omitted optional parameter */
+       OPAL_UID_HEXFF,
+};
+
+#define OPAL_METHOD_LENGTH 8
+
+/* Enum for indexing the OPALMETHOD array */
+enum opal_method {
+       OPAL_PROPERTIES,
+       OPAL_STARTSESSION,
+       OPAL_REVERT,
+       OPAL_ACTIVATE,
+       OPAL_EGET,
+       OPAL_ESET,
+       OPAL_NEXT,
+       OPAL_EAUTHENTICATE,
+       OPAL_GETACL,
+       OPAL_GENKEY,
+       OPAL_REVERTSP,
+       OPAL_GET,
+       OPAL_SET,
+       OPAL_AUTHENTICATE,
+       OPAL_RANDOM,
+       OPAL_ERASE,
+};
+
+enum opal_token {
+       /* Boolean */
+       OPAL_TRUE = 0x01,
+       OPAL_FALSE = 0x00,
+       OPAL_BOOLEAN_EXPR = 0x03,
+       /* cellblocks */
+       OPAL_TABLE = 0x00,
+       OPAL_STARTROW = 0x01,
+       OPAL_ENDROW = 0x02,
+       OPAL_STARTCOLUMN = 0x03,
+       OPAL_ENDCOLUMN = 0x04,
+       OPAL_VALUES = 0x01,
+       /* authority table */
+       OPAL_PIN = 0x03,
+       /* locking tokens */
+       OPAL_RANGESTART = 0x03,
+       OPAL_RANGELENGTH = 0x04,
+       OPAL_READLOCKENABLED = 0x05,
+       OPAL_WRITELOCKENABLED = 0x06,
+       OPAL_READLOCKED = 0x07,
+       OPAL_WRITELOCKED = 0x08,
+       OPAL_ACTIVEKEY = 0x0A,
+       /* locking info table */
+       OPAL_MAXRANGES = 0x04,
+        /* mbr control */
+       OPAL_MBRENABLE = 0x01,
+       OPAL_MBRDONE = 0x02,
+       /* properties */
+       OPAL_HOSTPROPERTIES = 0x00,
+       /* atoms */
+       OPAL_STARTLIST = 0xf0,
+       OPAL_ENDLIST = 0xf1,
+       OPAL_STARTNAME = 0xf2,
+       OPAL_ENDNAME = 0xf3,
+       OPAL_CALL = 0xf8,
+       OPAL_ENDOFDATA = 0xf9,
+       OPAL_ENDOFSESSION = 0xfa,
+       OPAL_STARTTRANSACTON = 0xfb,
+       OPAL_ENDTRANSACTON = 0xfC,
+       OPAL_EMPTYATOM = 0xff,
+       OPAL_WHERE = 0x00,
+};
+
+/* Locking state for a locking range */
+enum opal_lockingstate {
+       OPAL_LOCKING_READWRITE = 0x01,
+       OPAL_LOCKING_READONLY = 0x02,
+       OPAL_LOCKING_LOCKED = 0x03,
+};
+
+/* Packets derived from:
+ * TCG_Storage_Architecture_Core_Spec_v2.01_r1.00
+ * Secion: 3.2.3 ComPackets, Packets & Subpackets
+ */
+
+/* Comm Packet (header) for transmissions. */
+struct opal_compacket {
+       __be32 reserved0;
+       u8 extendedComID[4];
+       __be32 outstandingData;
+       __be32 minTransfer;
+       __be32 length;
+};
+
+/* Packet structure. */
+struct opal_packet {
+       __be32 tsn;
+       __be32 hsn;
+       __be32 seq_number;
+       __be16 reserved0;
+       __be16 ack_type;
+       __be32 acknowledgment;
+       __be32 length;
+};
+
+/* Data sub packet header */
+struct opal_data_subpacket {
+       u8 reserved0[6];
+       __be16 kind;
+       __be32 length;
+};
+
+/* header of a response */
+struct opal_header {
+       struct opal_compacket cp;
+       struct opal_packet pkt;
+       struct opal_data_subpacket subpkt;
+};
+
+#define FC_TPER       0x0001
+#define FC_LOCKING    0x0002
+#define FC_GEOMETRY   0x0003
+#define FC_ENTERPRISE 0x0100
+#define FC_DATASTORE  0x0202
+#define FC_SINGLEUSER 0x0201
+#define FC_OPALV100   0x0200
+#define FC_OPALV200   0x0203
+
+/*
+ * The Discovery 0 Header. As defined in
+ * Opal SSC Documentation
+ * Section: 3.3.5 Capability Discovery
+ */
+struct d0_header {
+       __be32 length; /* the length of the header 48 in 2.00.100 */
+       __be32 revision; /**< revision of the header 1 in 2.00.100 */
+       __be32 reserved01;
+       __be32 reserved02;
+       /*
+        * the remainder of the structure is vendor specific and will not be
+        * addressed now
+        */
+       u8 ignored[32];
+};
+
+/*
+ * TPer Feature Descriptor. Contains flags indicating support for the
+ * TPer features described in the OPAL specification. The names match the
+ * OPAL terminology
+ *
+ * code == 0x001 in 2.00.100
+ */
+struct d0_tper_features {
+       /*
+        * supported_features bits:
+        * bit 7: reserved
+        * bit 6: com ID management
+        * bit 5: reserved
+        * bit 4: streaming support
+        * bit 3: buffer management
+        * bit 2: ACK/NACK
+        * bit 1: async
+        * bit 0: sync
+        */
+       u8 supported_features;
+       /*
+        * bytes 5 through 15 are reserved, but we represent the first 3 as
+        * u8 to keep the other two 32bits integers aligned.
+        */
+       u8 reserved01[3];
+       __be32 reserved02;
+       __be32 reserved03;
+};
+
+/*
+ * Locking Feature Descriptor. Contains flags indicating support for the
+ * locking features described in the OPAL specification. The names match the
+ * OPAL terminology
+ *
+ * code == 0x0002 in 2.00.100
+ */
+struct d0_locking_features {
+       /*
+        * supported_features bits:
+        * bits 6-7: reserved
+        * bit 5: MBR done
+        * bit 4: MBR enabled
+        * bit 3: media encryption
+        * bit 2: locked
+        * bit 1: locking enabled
+        * bit 0: locking supported
+        */
+       u8 supported_features;
+       /*
+        * bytes 5 through 15 are reserved, but we represent the first 3 as
+        * u8 to keep the other two 32bits integers aligned.
+        */
+       u8 reserved01[3];
+       __be32 reserved02;
+       __be32 reserved03;
+};
+
+/*
+ * Geometry Feature Descriptor. Contains flags indicating support for the
+ * geometry features described in the OPAL specification. The names match the
+ * OPAL terminology
+ *
+ * code == 0x0003 in 2.00.100
+ */
+struct d0_geometry_features {
+       /*
+        * skip 32 bits from header, needed to align the struct to 64 bits.
+        */
+       u8 header[4];
+       /*
+        * reserved01:
+        * bits 1-6: reserved
+        * bit 0: align
+        */
+       u8 reserved01;
+       u8 reserved02[7];
+       __be32 logical_block_size;
+       __be64 alignment_granularity;
+       __be64 lowest_aligned_lba;
+};
+
+/*
+ * Enterprise SSC Feature
+ *
+ * code == 0x0100
+ */
+struct d0_enterprise_ssc {
+       __be16 baseComID;
+       __be16 numComIDs;
+       /* range_crossing:
+        * bits 1-6: reserved
+        * bit 0: range crossing
+        */
+       u8 range_crossing;
+       u8 reserved01;
+       __be16 reserved02;
+       __be32 reserved03;
+       __be32 reserved04;
+};
+
+/*
+ * Opal V1 feature
+ *
+ * code == 0x0200
+ */
+struct d0_opal_v100 {
+       __be16 baseComID;
+       __be16 numComIDs;
+};
+
+/*
+ * Single User Mode feature
+ *
+ * code == 0x0201
+ */
+struct d0_single_user_mode {
+       __be32 num_locking_objects;
+       /* reserved01:
+        * bit 0: any
+        * bit 1: all
+        * bit 2: policy
+        * bits 3-7: reserved
+        */
+       u8 reserved01;
+       u8 reserved02;
+       __be16 reserved03;
+       __be32 reserved04;
+};
+
+/*
+ * Additonal Datastores feature
+ *
+ * code == 0x0202
+ */
+struct d0_datastore_table {
+       __be16 reserved01;
+       __be16 max_tables;
+       __be32 max_size_tables;
+       __be32 table_size_alignment;
+};
+
+/*
+ * OPAL 2.0 feature
+ *
+ * code == 0x0203
+ */
+struct d0_opal_v200 {
+       __be16 baseComID;
+       __be16 numComIDs;
+       /* range_crossing:
+        * bits 1-6: reserved
+        * bit 0: range crossing
+        */
+       u8 range_crossing;
+       /* num_locking_admin_auth:
+        * not aligned to 16 bits, so use two u8.
+        * stored in big endian:
+        * 0: MSB
+        * 1: LSB
+        */
+       u8 num_locking_admin_auth[2];
+       /* num_locking_user_auth:
+        * not aligned to 16 bits, so use two u8.
+        * stored in big endian:
+        * 0: MSB
+        * 1: LSB
+        */
+       u8 num_locking_user_auth[2];
+       u8 initialPIN;
+       u8 revertedPIN;
+       u8 reserved01;
+       __be32 reserved02;
+};
+
+/* Union of features used to parse the discovery 0 response */
+struct d0_features {
+       __be16 code;
+       /*
+        * r_version bits:
+        * bits 4-7: version
+        * bits 0-3: reserved
+        */
+       u8 r_version;
+       u8 length;
+       u8 features[];
+};
+
+#endif /* _OPAL_PROTO_H */
index bcd86e5cd5460cc34750f3491d720f4b69e2a19c..39f70d968754e558ccb175dc3c56822d6da3fcab 100644 (file)
@@ -293,7 +293,7 @@ static gpt_entry *alloc_read_gpt_entries(struct parsed_partitions *state,
        if (!gpt)
                return NULL;
 
-       count = le32_to_cpu(gpt->num_partition_entries) *
+       count = (size_t)le32_to_cpu(gpt->num_partition_entries) *
                 le32_to_cpu(gpt->sizeof_partition_entry);
        if (!count)
                return NULL;
@@ -352,7 +352,7 @@ static int is_gpt_valid(struct parsed_partitions *state, u64 lba,
                        gpt_header **gpt, gpt_entry **ptes)
 {
        u32 crc, origcrc;
-       u64 lastlba;
+       u64 lastlba, pt_size;
 
        if (!ptes)
                return 0;
@@ -434,13 +434,20 @@ static int is_gpt_valid(struct parsed_partitions *state, u64 lba,
                goto fail;
        }
 
+       /* Sanity check partition table size */
+       pt_size = (u64)le32_to_cpu((*gpt)->num_partition_entries) *
+               le32_to_cpu((*gpt)->sizeof_partition_entry);
+       if (pt_size > KMALLOC_MAX_SIZE) {
+               pr_debug("GUID Partition Table is too large: %llu > %lu bytes\n",
+                        (unsigned long long)pt_size, KMALLOC_MAX_SIZE);
+               goto fail;
+       }
+
        if (!(*ptes = alloc_read_gpt_entries(state, *gpt)))
                goto fail;
 
        /* Check the GUID Partition Entry Array CRC */
-       crc = efi_crc32((const unsigned char *) (*ptes),
-                       le32_to_cpu((*gpt)->num_partition_entries) *
-                       le32_to_cpu((*gpt)->sizeof_partition_entry));
+       crc = efi_crc32((const unsigned char *) (*ptes), pt_size);
 
        if (crc != le32_to_cpu((*gpt)->partition_entry_array_crc32)) {
                pr_debug("GUID Partition Entry Array CRC check failed.\n");
index c2b64923ab66d8d89b6e92be71fe898fc834baa2..2a2fc768b27ad81583424252f13b89303269b755 100644 (file)
@@ -230,15 +230,17 @@ EXPORT_SYMBOL(blk_verify_command);
 static int blk_fill_sghdr_rq(struct request_queue *q, struct request *rq,
                             struct sg_io_hdr *hdr, fmode_t mode)
 {
-       if (copy_from_user(rq->cmd, hdr->cmdp, hdr->cmd_len))
+       struct scsi_request *req = scsi_req(rq);
+
+       if (copy_from_user(req->cmd, hdr->cmdp, hdr->cmd_len))
                return -EFAULT;
-       if (blk_verify_command(rq->cmd, mode & FMODE_WRITE))
+       if (blk_verify_command(req->cmd, mode & FMODE_WRITE))
                return -EPERM;
 
        /*
         * fill in request structure
         */
-       rq->cmd_len = hdr->cmd_len;
+       req->cmd_len = hdr->cmd_len;
 
        rq->timeout = msecs_to_jiffies(hdr->timeout);
        if (!rq->timeout)
@@ -254,6 +256,7 @@ static int blk_fill_sghdr_rq(struct request_queue *q, struct request *rq,
 static int blk_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr,
                                 struct bio *bio)
 {
+       struct scsi_request *req = scsi_req(rq);
        int r, ret = 0;
 
        /*
@@ -267,13 +270,13 @@ static int blk_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr,
        hdr->info = 0;
        if (hdr->masked_status || hdr->host_status || hdr->driver_status)
                hdr->info |= SG_INFO_CHECK;
-       hdr->resid = rq->resid_len;
+       hdr->resid = req->resid_len;
        hdr->sb_len_wr = 0;
 
-       if (rq->sense_len && hdr->sbp) {
-               int len = min((unsigned int) hdr->mx_sb_len, rq->sense_len);
+       if (req->sense_len && hdr->sbp) {
+               int len = min((unsigned int) hdr->mx_sb_len, req->sense_len);
 
-               if (!copy_to_user(hdr->sbp, rq->sense, len))
+               if (!copy_to_user(hdr->sbp, req->sense, len))
                        hdr->sb_len_wr = len;
                else
                        ret = -EFAULT;
@@ -294,7 +297,7 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
        int writing = 0;
        int at_head = 0;
        struct request *rq;
-       char sense[SCSI_SENSE_BUFFERSIZE];
+       struct scsi_request *req;
        struct bio *bio;
 
        if (hdr->interface_id != 'S')
@@ -318,14 +321,16 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
                at_head = 1;
 
        ret = -ENOMEM;
-       rq = blk_get_request(q, writing ? WRITE : READ, GFP_KERNEL);
+       rq = blk_get_request(q, writing ? REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN,
+                       GFP_KERNEL);
        if (IS_ERR(rq))
                return PTR_ERR(rq);
-       blk_rq_set_block_pc(rq);
+       req = scsi_req(rq);
+       scsi_req_init(rq);
 
        if (hdr->cmd_len > BLK_MAX_CDB) {
-               rq->cmd = kzalloc(hdr->cmd_len, GFP_KERNEL);
-               if (!rq->cmd)
+               req->cmd = kzalloc(hdr->cmd_len, GFP_KERNEL);
+               if (!req->cmd)
                        goto out_put_request;
        }
 
@@ -357,9 +362,6 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
                goto out_free_cdb;
 
        bio = rq->bio;
-       memset(sense, 0, sizeof(sense));
-       rq->sense = sense;
-       rq->sense_len = 0;
        rq->retries = 0;
 
        start_time = jiffies;
@@ -375,8 +377,7 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
        ret = blk_complete_sghdr_rq(rq, hdr, bio);
 
 out_free_cdb:
-       if (rq->cmd != rq->__cmd)
-               kfree(rq->cmd);
+       scsi_req_free_cmd(req);
 out_put_request:
        blk_put_request(rq);
        return ret;
@@ -420,9 +421,10 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode,
                struct scsi_ioctl_command __user *sic)
 {
        struct request *rq;
+       struct scsi_request *req;
        int err;
        unsigned int in_len, out_len, bytes, opcode, cmdlen;
-       char *buffer = NULL, sense[SCSI_SENSE_BUFFERSIZE];
+       char *buffer = NULL;
 
        if (!sic)
                return -EINVAL;
@@ -447,12 +449,14 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode,
 
        }
 
-       rq = blk_get_request(q, in_len ? WRITE : READ, __GFP_RECLAIM);
+       rq = blk_get_request(q, in_len ? REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN,
+                       __GFP_RECLAIM);
        if (IS_ERR(rq)) {
                err = PTR_ERR(rq);
                goto error_free_buffer;
        }
-       blk_rq_set_block_pc(rq);
+       req = scsi_req(rq);
+       scsi_req_init(rq);
 
        cmdlen = COMMAND_SIZE(opcode);
 
@@ -460,14 +464,14 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode,
         * get command and data to send to device, if any
         */
        err = -EFAULT;
-       rq->cmd_len = cmdlen;
-       if (copy_from_user(rq->cmd, sic->data, cmdlen))
+       req->cmd_len = cmdlen;
+       if (copy_from_user(req->cmd, sic->data, cmdlen))
                goto error;
 
        if (in_len && copy_from_user(buffer, sic->data + cmdlen, in_len))
                goto error;
 
-       err = blk_verify_command(rq->cmd, mode & FMODE_WRITE);
+       err = blk_verify_command(req->cmd, mode & FMODE_WRITE);
        if (err)
                goto error;
 
@@ -503,18 +507,14 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode,
                goto error;
        }
 
-       memset(sense, 0, sizeof(sense));
-       rq->sense = sense;
-       rq->sense_len = 0;
-
        blk_execute_rq(q, disk, rq, 0);
 
        err = rq->errors & 0xff;        /* only 8 bit SCSI status */
        if (err) {
-               if (rq->sense_len && rq->sense) {
-                       bytes = (OMAX_SB_LEN > rq->sense_len) ?
-                               rq->sense_len : OMAX_SB_LEN;
-                       if (copy_to_user(sic->data, rq->sense, bytes))
+               if (req->sense_len && req->sense) {
+                       bytes = (OMAX_SB_LEN > req->sense_len) ?
+                               req->sense_len : OMAX_SB_LEN;
+                       if (copy_to_user(sic->data, req->sense, bytes))
                                err = -EFAULT;
                }
        } else {
@@ -539,14 +539,14 @@ static int __blk_send_generic(struct request_queue *q, struct gendisk *bd_disk,
        struct request *rq;
        int err;
 
-       rq = blk_get_request(q, WRITE, __GFP_RECLAIM);
+       rq = blk_get_request(q, REQ_OP_SCSI_OUT, __GFP_RECLAIM);
        if (IS_ERR(rq))
                return PTR_ERR(rq);
-       blk_rq_set_block_pc(rq);
+       scsi_req_init(rq);
        rq->timeout = BLK_DEFAULT_SG_TIMEOUT;
-       rq->cmd[0] = cmd;
-       rq->cmd[4] = data;
-       rq->cmd_len = 6;
+       scsi_req(rq)->cmd[0] = cmd;
+       scsi_req(rq)->cmd[4] = data;
+       scsi_req(rq)->cmd_len = 6;
        err = blk_execute_rq(q, bd_disk, rq, 0);
        blk_put_request(rq);
 
@@ -743,6 +743,17 @@ int scsi_cmd_blk_ioctl(struct block_device *bd, fmode_t mode,
 }
 EXPORT_SYMBOL(scsi_cmd_blk_ioctl);
 
+void scsi_req_init(struct request *rq)
+{
+       struct scsi_request *req = scsi_req(rq);
+
+       memset(req->__cmd, 0, sizeof(req->__cmd));
+       req->cmd = req->__cmd;
+       req->cmd_len = BLK_MAX_CDB;
+       req->sense_len = 0;
+}
+EXPORT_SYMBOL(scsi_req_init);
+
 static int __init blk_scsi_ioctl_init(void)
 {
        blk_set_cmd_filter_defaults(&blk_default_cmd_filter);
diff --git a/block/sed-opal.c b/block/sed-opal.c
new file mode 100644 (file)
index 0000000..d1c52ba
--- /dev/null
@@ -0,0 +1,2488 @@
+/*
+ * Copyright Â© 2016 Intel Corporation
+ *
+ * Authors:
+ *    Scott  Bauer      <scott.bauer@intel.com>
+ *    Rafael Antognolli <rafael.antognolli@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * 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 ":OPAL: " fmt
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/genhd.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <uapi/linux/sed-opal.h>
+#include <linux/sed-opal.h>
+#include <linux/string.h>
+#include <linux/kdev_t.h>
+
+#include "opal_proto.h"
+
+#define IO_BUFFER_LENGTH 2048
+#define MAX_TOKS 64
+
+typedef int (*opal_step)(struct opal_dev *dev);
+
+enum opal_atom_width {
+       OPAL_WIDTH_TINY,
+       OPAL_WIDTH_SHORT,
+       OPAL_WIDTH_MEDIUM,
+       OPAL_WIDTH_LONG,
+       OPAL_WIDTH_TOKEN
+};
+
+/*
+ * On the parsed response, we don't store again the toks that are already
+ * stored in the response buffer. Instead, for each token, we just store a
+ * pointer to the position in the buffer where the token starts, and the size
+ * of the token in bytes.
+ */
+struct opal_resp_tok {
+       const u8 *pos;
+       size_t len;
+       enum opal_response_token type;
+       enum opal_atom_width width;
+       union {
+               u64 u;
+               s64 s;
+       } stored;
+};
+
+/*
+ * From the response header it's not possible to know how many tokens there are
+ * on the payload. So we hardcode that the maximum will be MAX_TOKS, and later
+ * if we start dealing with messages that have more than that, we can increase
+ * this number. This is done to avoid having to make two passes through the
+ * response, the first one counting how many tokens we have and the second one
+ * actually storing the positions.
+ */
+struct parsed_resp {
+       int num;
+       struct opal_resp_tok toks[MAX_TOKS];
+};
+
+struct opal_dev {
+       bool supported;
+
+       void *data;
+       sec_send_recv *send_recv;
+
+       const opal_step *funcs;
+       void **func_data;
+       int state;
+       struct mutex dev_lock;
+       u16 comid;
+       u32 hsn;
+       u32 tsn;
+       u64 align;
+       u64 lowest_lba;
+
+       size_t pos;
+       u8 cmd[IO_BUFFER_LENGTH];
+       u8 resp[IO_BUFFER_LENGTH];
+
+       struct parsed_resp parsed;
+       size_t prev_d_len;
+       void *prev_data;
+
+       struct list_head unlk_lst;
+};
+
+
+static const u8 opaluid[][OPAL_UID_LENGTH] = {
+       /* users */
+       [OPAL_SMUID_UID] =
+               { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff },
+       [OPAL_THISSP_UID] =
+               { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
+       [OPAL_ADMINSP_UID] =
+               { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x01 },
+       [OPAL_LOCKINGSP_UID] =
+               { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x02 },
+       [OPAL_ENTERPRISE_LOCKINGSP_UID] =
+               { 0x00, 0x00, 0x02, 0x05, 0x00, 0x01, 0x00, 0x01 },
+       [OPAL_ANYBODY_UID] =
+               { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01 },
+       [OPAL_SID_UID] =
+               { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06 },
+       [OPAL_ADMIN1_UID] =
+               { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0x01 },
+       [OPAL_USER1_UID] =
+               { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x01 },
+       [OPAL_USER2_UID] =
+               { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x02 },
+       [OPAL_PSID_UID] =
+               { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0xff, 0x01 },
+       [OPAL_ENTERPRISE_BANDMASTER0_UID] =
+               { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x80, 0x01 },
+       [OPAL_ENTERPRISE_ERASEMASTER_UID] =
+               { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x84, 0x01 },
+
+       /* tables */
+
+       [OPAL_LOCKINGRANGE_GLOBAL] =
+               { 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x01 },
+       [OPAL_LOCKINGRANGE_ACE_RDLOCKED] =
+               { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE0, 0x01 },
+       [OPAL_LOCKINGRANGE_ACE_WRLOCKED] =
+               { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE8, 0x01 },
+       [OPAL_MBRCONTROL] =
+               { 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x00, 0x01 },
+       [OPAL_MBR] =
+               { 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00 },
+       [OPAL_AUTHORITY_TABLE] =
+               { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00},
+       [OPAL_C_PIN_TABLE] =
+               { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00},
+       [OPAL_LOCKING_INFO_TABLE] =
+               { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x01 },
+       [OPAL_ENTERPRISE_LOCKING_INFO_TABLE] =
+               { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00 },
+
+       /* C_PIN_TABLE object ID's */
+
+        [OPAL_C_PIN_MSID] =
+               { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x84, 0x02},
+       [OPAL_C_PIN_SID] =
+               { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01},
+       [OPAL_C_PIN_ADMIN1] =
+               { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x01, 0x00, 0x01},
+
+       /* half UID's (only first 4 bytes used) */
+
+       [OPAL_HALF_UID_AUTHORITY_OBJ_REF] =
+               { 0x00, 0x00, 0x0C, 0x05, 0xff, 0xff, 0xff, 0xff },
+       [OPAL_HALF_UID_BOOLEAN_ACE] =
+               { 0x00, 0x00, 0x04, 0x0E, 0xff, 0xff, 0xff, 0xff },
+
+       /* special value for omitted optional parameter */
+       [OPAL_UID_HEXFF] =
+               { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+};
+
+/*
+ * TCG Storage SSC Methods.
+ * Derived from: TCG_Storage_Architecture_Core_Spec_v2.01_r1.00
+ * Section: 6.3 Assigned UIDs
+ */
+static const u8 opalmethod[][OPAL_UID_LENGTH] = {
+       [OPAL_PROPERTIES] =
+               { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01 },
+       [OPAL_STARTSESSION] =
+               { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02 },
+       [OPAL_REVERT] =
+               { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x02 },
+       [OPAL_ACTIVATE] =
+               { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x03 },
+       [OPAL_EGET] =
+               { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06 },
+       [OPAL_ESET] =
+               { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07 },
+       [OPAL_NEXT] =
+               { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08 },
+       [OPAL_EAUTHENTICATE] =
+               { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0c },
+       [OPAL_GETACL] =
+               { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0d },
+       [OPAL_GENKEY] =
+               { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10 },
+       [OPAL_REVERTSP] =
+               { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x11 },
+       [OPAL_GET] =
+               { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x16 },
+       [OPAL_SET] =
+               { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x17 },
+       [OPAL_AUTHENTICATE] =
+               { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c },
+       [OPAL_RANDOM] =
+               { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x01 },
+       [OPAL_ERASE] =
+               { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x08, 0x03 },
+};
+
+typedef int (cont_fn)(struct opal_dev *dev);
+
+static int end_opal_session_error(struct opal_dev *dev);
+
+struct opal_suspend_data {
+       struct opal_lock_unlock unlk;
+       u8 lr;
+       struct list_head node;
+};
+
+/*
+ * Derived from:
+ * TCG_Storage_Architecture_Core_Spec_v2.01_r1.00
+ * Section: 5.1.5 Method Status Codes
+ */
+static const char * const opal_errors[] = {
+       "Success",
+       "Not Authorized",
+       "Unknown Error",
+       "SP Busy",
+       "SP Failed",
+       "SP Disabled",
+       "SP Frozen",
+       "No Sessions Available",
+       "Uniqueness Conflict",
+       "Insufficient Space",
+       "Insufficient Rows",
+       "Invalid Function",
+       "Invalid Parameter",
+       "Invalid Reference",
+       "Unknown Error",
+       "TPER Malfunction",
+       "Transaction Failure",
+       "Response Overflow",
+       "Authority Locked Out",
+};
+
+static const char *opal_error_to_human(int error)
+{
+       if (error == 0x3f)
+               return "Failed";
+
+       if (error >= ARRAY_SIZE(opal_errors) || error < 0)
+               return "Unknown Error";
+
+       return opal_errors[error];
+}
+
+static void print_buffer(const u8 *ptr, u32 length)
+{
+#ifdef DEBUG
+       print_hex_dump_bytes("OPAL: ", DUMP_PREFIX_OFFSET, ptr, length);
+       pr_debug("\n");
+#endif
+}
+
+static bool check_tper(const void *data)
+{
+       const struct d0_tper_features *tper = data;
+       u8 flags = tper->supported_features;
+
+       if (!(flags & TPER_SYNC_SUPPORTED)) {
+               pr_err("TPer sync not supported. flags = %d\n",
+                      tper->supported_features);
+               return false;
+       }
+
+       return true;
+}
+
+static bool check_sum(const void *data)
+{
+       const struct d0_single_user_mode *sum = data;
+       u32 nlo = be32_to_cpu(sum->num_locking_objects);
+
+       if (nlo == 0) {
+               pr_err("Need at least one locking object.\n");
+               return false;
+       }
+
+       pr_debug("Number of locking objects: %d\n", nlo);
+
+       return true;
+}
+
+static u16 get_comid_v100(const void *data)
+{
+       const struct d0_opal_v100 *v100 = data;
+
+       return be16_to_cpu(v100->baseComID);
+}
+
+static u16 get_comid_v200(const void *data)
+{
+       const struct d0_opal_v200 *v200 = data;
+
+       return be16_to_cpu(v200->baseComID);
+}
+
+static int opal_send_cmd(struct opal_dev *dev)
+{
+       return dev->send_recv(dev->data, dev->comid, TCG_SECP_01,
+                             dev->cmd, IO_BUFFER_LENGTH,
+                             true);
+}
+
+static int opal_recv_cmd(struct opal_dev *dev)
+{
+       return dev->send_recv(dev->data, dev->comid, TCG_SECP_01,
+                             dev->resp, IO_BUFFER_LENGTH,
+                             false);
+}
+
+static int opal_recv_check(struct opal_dev *dev)
+{
+       size_t buflen = IO_BUFFER_LENGTH;
+       void *buffer = dev->resp;
+       struct opal_header *hdr = buffer;
+       int ret;
+
+       do {
+               pr_debug("Sent OPAL command: outstanding=%d, minTransfer=%d\n",
+                        hdr->cp.outstandingData,
+                        hdr->cp.minTransfer);
+
+               if (hdr->cp.outstandingData == 0 ||
+                   hdr->cp.minTransfer != 0)
+                       return 0;
+
+               memset(buffer, 0, buflen);
+               ret = opal_recv_cmd(dev);
+       } while (!ret);
+
+       return ret;
+}
+
+static int opal_send_recv(struct opal_dev *dev, cont_fn *cont)
+{
+       int ret;
+
+       ret = opal_send_cmd(dev);
+       if (ret)
+               return ret;
+       ret = opal_recv_cmd(dev);
+       if (ret)
+               return ret;
+       ret = opal_recv_check(dev);
+       if (ret)
+               return ret;
+       return cont(dev);
+}
+
+static void check_geometry(struct opal_dev *dev, const void *data)
+{
+       const struct d0_geometry_features *geo = data;
+
+       dev->align = geo->alignment_granularity;
+       dev->lowest_lba = geo->lowest_aligned_lba;
+}
+
+static int next(struct opal_dev *dev)
+{
+       opal_step func;
+       int error = 0;
+
+       do {
+               func = dev->funcs[dev->state];
+               if (!func)
+                       break;
+
+               error = func(dev);
+               if (error) {
+                       pr_err("Error on step function: %d with error %d: %s\n",
+                              dev->state, error,
+                              opal_error_to_human(error));
+
+                       /* For each OPAL command we do a discovery0 then we
+                        * start some sort of session.
+                        * If we haven't passed state 1 then there was an error
+                        * on discovery0 or during the attempt to start a
+                        * session. Therefore we shouldn't attempt to terminate
+                        * a session, as one has not yet been created.
+                        */
+                       if (dev->state > 1)
+                               return end_opal_session_error(dev);
+               }
+               dev->state++;
+       } while (!error);
+
+       return error;
+}
+
+static int opal_discovery0_end(struct opal_dev *dev)
+{
+       bool found_com_id = false, supported = true, single_user = false;
+       const struct d0_header *hdr = (struct d0_header *)dev->resp;
+       const u8 *epos = dev->resp, *cpos = dev->resp;
+       u16 comid = 0;
+
+       print_buffer(dev->resp, be32_to_cpu(hdr->length));
+
+       epos += be32_to_cpu(hdr->length); /* end of buffer */
+       cpos += sizeof(*hdr); /* current position on buffer */
+
+       while (cpos < epos && supported) {
+               const struct d0_features *body =
+                       (const struct d0_features *)cpos;
+
+               switch (be16_to_cpu(body->code)) {
+               case FC_TPER:
+                       supported = check_tper(body->features);
+                       break;
+               case FC_SINGLEUSER:
+                       single_user = check_sum(body->features);
+                       break;
+               case FC_GEOMETRY:
+                       check_geometry(dev, body);
+                       break;
+               case FC_LOCKING:
+               case FC_ENTERPRISE:
+               case FC_DATASTORE:
+                       /* some ignored properties */
+                       pr_debug("Found OPAL feature description: %d\n",
+                                be16_to_cpu(body->code));
+                       break;
+               case FC_OPALV100:
+                       comid = get_comid_v100(body->features);
+                       found_com_id = true;
+                       break;
+               case FC_OPALV200:
+                       comid = get_comid_v200(body->features);
+                       found_com_id = true;
+                       break;
+               case 0xbfff ... 0xffff:
+                       /* vendor specific, just ignore */
+                       break;
+               default:
+                       pr_debug("OPAL Unknown feature: %d\n",
+                                be16_to_cpu(body->code));
+
+               }
+               cpos += body->length + 4;
+       }
+
+       if (!supported) {
+               pr_debug("This device is not Opal enabled. Not Supported!\n");
+               return -EOPNOTSUPP;
+       }
+
+       if (!single_user)
+               pr_debug("Device doesn't support single user mode\n");
+
+
+       if (!found_com_id) {
+               pr_debug("Could not find OPAL comid for device. Returning early\n");
+               return -EOPNOTSUPP;;
+       }
+
+       dev->comid = comid;
+
+       return 0;
+}
+
+static int opal_discovery0(struct opal_dev *dev)
+{
+       int ret;
+
+       memset(dev->resp, 0, IO_BUFFER_LENGTH);
+       dev->comid = OPAL_DISCOVERY_COMID;
+       ret = opal_recv_cmd(dev);
+       if (ret)
+               return ret;
+       return opal_discovery0_end(dev);
+}
+
+static void add_token_u8(int *err, struct opal_dev *cmd, u8 tok)
+{
+       if (*err)
+               return;
+       if (cmd->pos >= IO_BUFFER_LENGTH - 1) {
+               pr_err("Error adding u8: end of buffer.\n");
+               *err = -ERANGE;
+               return;
+       }
+       cmd->cmd[cmd->pos++] = tok;
+}
+
+static void add_short_atom_header(struct opal_dev *cmd, bool bytestring,
+                                 bool has_sign, int len)
+{
+       u8 atom;
+       int err = 0;
+
+       atom = SHORT_ATOM_ID;
+       atom |= bytestring ? SHORT_ATOM_BYTESTRING : 0;
+       atom |= has_sign ? SHORT_ATOM_SIGNED : 0;
+       atom |= len & SHORT_ATOM_LEN_MASK;
+
+       add_token_u8(&err, cmd, atom);
+}
+
+static void add_medium_atom_header(struct opal_dev *cmd, bool bytestring,
+                                  bool has_sign, int len)
+{
+       u8 header0;
+
+       header0 = MEDIUM_ATOM_ID;
+       header0 |= bytestring ? MEDIUM_ATOM_BYTESTRING : 0;
+       header0 |= has_sign ? MEDIUM_ATOM_SIGNED : 0;
+       header0 |= (len >> 8) & MEDIUM_ATOM_LEN_MASK;
+       cmd->cmd[cmd->pos++] = header0;
+       cmd->cmd[cmd->pos++] = len;
+}
+
+static void add_token_u64(int *err, struct opal_dev *cmd, u64 number)
+{
+
+       size_t len;
+       int msb;
+       u8 n;
+
+       if (!(number & ~TINY_ATOM_DATA_MASK)) {
+               add_token_u8(err, cmd, number);
+               return;
+       }
+
+       msb = fls(number);
+       len = DIV_ROUND_UP(msb, 4);
+
+       if (cmd->pos >= IO_BUFFER_LENGTH - len - 1) {
+               pr_err("Error adding u64: end of buffer.\n");
+               *err = -ERANGE;
+               return;
+       }
+       add_short_atom_header(cmd, false, false, len);
+       while (len--) {
+               n = number >> (len * 8);
+               add_token_u8(err, cmd, n);
+       }
+}
+
+static void add_token_bytestring(int *err, struct opal_dev *cmd,
+                                const u8 *bytestring, size_t len)
+{
+       size_t header_len = 1;
+       bool is_short_atom = true;
+
+       if (*err)
+               return;
+
+       if (len & ~SHORT_ATOM_LEN_MASK) {
+               header_len = 2;
+               is_short_atom = false;
+       }
+
+       if (len >= IO_BUFFER_LENGTH - cmd->pos - header_len) {
+               pr_err("Error adding bytestring: end of buffer.\n");
+               *err = -ERANGE;
+               return;
+       }
+
+       if (is_short_atom)
+               add_short_atom_header(cmd, true, false, len);
+       else
+               add_medium_atom_header(cmd, true, false, len);
+
+       memcpy(&cmd->cmd[cmd->pos], bytestring, len);
+       cmd->pos += len;
+
+}
+
+static int build_locking_range(u8 *buffer, size_t length, u8 lr)
+{
+       if (length > OPAL_UID_LENGTH) {
+               pr_err("Can't build locking range. Length OOB\n");
+               return -ERANGE;
+       }
+
+       memcpy(buffer, opaluid[OPAL_LOCKINGRANGE_GLOBAL], OPAL_UID_LENGTH);
+
+       if (lr == 0)
+               return 0;
+       buffer[5] = LOCKING_RANGE_NON_GLOBAL;
+       buffer[7] = lr;
+
+       return 0;
+}
+
+static int build_locking_user(u8 *buffer, size_t length, u8 lr)
+{
+       if (length > OPAL_UID_LENGTH) {
+               pr_err("Can't build locking range user, Length OOB\n");
+               return -ERANGE;
+       }
+
+       memcpy(buffer, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
+
+       buffer[7] = lr + 1;
+
+       return 0;
+}
+
+static void set_comid(struct opal_dev *cmd, u16 comid)
+{
+       struct opal_header *hdr = (struct opal_header *)cmd->cmd;
+
+       hdr->cp.extendedComID[0] = comid >> 8;
+       hdr->cp.extendedComID[1] = comid;
+       hdr->cp.extendedComID[2] = 0;
+       hdr->cp.extendedComID[3] = 0;
+}
+
+static int cmd_finalize(struct opal_dev *cmd, u32 hsn, u32 tsn)
+{
+       struct opal_header *hdr;
+       int err = 0;
+
+       add_token_u8(&err, cmd, OPAL_ENDOFDATA);
+       add_token_u8(&err, cmd, OPAL_STARTLIST);
+       add_token_u8(&err, cmd, 0);
+       add_token_u8(&err, cmd, 0);
+       add_token_u8(&err, cmd, 0);
+       add_token_u8(&err, cmd, OPAL_ENDLIST);
+
+       if (err) {
+               pr_err("Error finalizing command.\n");
+               return -EFAULT;
+       }
+
+       hdr = (struct opal_header *) cmd->cmd;
+
+       hdr->pkt.tsn = cpu_to_be32(tsn);
+       hdr->pkt.hsn = cpu_to_be32(hsn);
+
+       hdr->subpkt.length = cpu_to_be32(cmd->pos - sizeof(*hdr));
+       while (cmd->pos % 4) {
+               if (cmd->pos >= IO_BUFFER_LENGTH) {
+                       pr_err("Error: Buffer overrun\n");
+                       return -ERANGE;
+               }
+               cmd->cmd[cmd->pos++] = 0;
+       }
+       hdr->pkt.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp) -
+                                     sizeof(hdr->pkt));
+       hdr->cp.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp));
+
+       return 0;
+}
+
+static enum opal_response_token token_type(const struct parsed_resp *resp,
+                                          int n)
+{
+       const struct opal_resp_tok *tok;
+
+       if (n >= resp->num) {
+               pr_err("Token number doesn't exist: %d, resp: %d\n",
+                      n, resp->num);
+               return OPAL_DTA_TOKENID_INVALID;
+       }
+
+       tok = &resp->toks[n];
+       if (tok->len == 0) {
+               pr_err("Token length must be non-zero\n");
+               return OPAL_DTA_TOKENID_INVALID;
+       }
+
+       return tok->type;
+}
+
+/*
+ * This function returns 0 in case of invalid token. One should call
+ * token_type() first to find out if the token is valid or not.
+ */
+static enum opal_token response_get_token(const struct parsed_resp *resp,
+                                         int n)
+{
+       const struct opal_resp_tok *tok;
+
+       if (n >= resp->num) {
+               pr_err("Token number doesn't exist: %d, resp: %d\n",
+                      n, resp->num);
+               return 0;
+       }
+
+       tok = &resp->toks[n];
+       if (tok->len == 0) {
+               pr_err("Token length must be non-zero\n");
+               return 0;
+       }
+
+       return tok->pos[0];
+}
+
+static size_t response_parse_tiny(struct opal_resp_tok *tok,
+                                 const u8 *pos)
+{
+       tok->pos = pos;
+       tok->len = 1;
+       tok->width = OPAL_WIDTH_TINY;
+
+       if (pos[0] & TINY_ATOM_SIGNED) {
+               tok->type = OPAL_DTA_TOKENID_SINT;
+       } else {
+               tok->type = OPAL_DTA_TOKENID_UINT;
+               tok->stored.u = pos[0] & 0x3f;
+       }
+
+       return tok->len;
+}
+
+static size_t response_parse_short(struct opal_resp_tok *tok,
+                                  const u8 *pos)
+{
+       tok->pos = pos;
+       tok->len = (pos[0] & SHORT_ATOM_LEN_MASK) + 1;
+       tok->width = OPAL_WIDTH_SHORT;
+
+       if (pos[0] & SHORT_ATOM_BYTESTRING) {
+               tok->type = OPAL_DTA_TOKENID_BYTESTRING;
+       } else if (pos[0] & SHORT_ATOM_SIGNED) {
+               tok->type = OPAL_DTA_TOKENID_SINT;
+       } else {
+               u64 u_integer = 0;
+               int i, b = 0;
+
+               tok->type = OPAL_DTA_TOKENID_UINT;
+               if (tok->len > 9) {
+                       pr_warn("uint64 with more than 8 bytes\n");
+                       return -EINVAL;
+               }
+               for (i = tok->len - 1; i > 0; i--) {
+                       u_integer |= ((u64)pos[i] << (8 * b));
+                       b++;
+               }
+               tok->stored.u = u_integer;
+       }
+
+       return tok->len;
+}
+
+static size_t response_parse_medium(struct opal_resp_tok *tok,
+                                   const u8 *pos)
+{
+       tok->pos = pos;
+       tok->len = (((pos[0] & MEDIUM_ATOM_LEN_MASK) << 8) | pos[1]) + 2;
+       tok->width = OPAL_WIDTH_MEDIUM;
+
+       if (pos[0] & MEDIUM_ATOM_BYTESTRING)
+               tok->type = OPAL_DTA_TOKENID_BYTESTRING;
+       else if (pos[0] & MEDIUM_ATOM_SIGNED)
+               tok->type = OPAL_DTA_TOKENID_SINT;
+       else
+               tok->type = OPAL_DTA_TOKENID_UINT;
+
+       return tok->len;
+}
+
+static size_t response_parse_long(struct opal_resp_tok *tok,
+                                 const u8 *pos)
+{
+       tok->pos = pos;
+       tok->len = ((pos[1] << 16) | (pos[2] << 8) | pos[3]) + 4;
+       tok->width = OPAL_WIDTH_LONG;
+
+       if (pos[0] & LONG_ATOM_BYTESTRING)
+               tok->type = OPAL_DTA_TOKENID_BYTESTRING;
+       else if (pos[0] & LONG_ATOM_SIGNED)
+               tok->type = OPAL_DTA_TOKENID_SINT;
+       else
+               tok->type = OPAL_DTA_TOKENID_UINT;
+
+       return tok->len;
+}
+
+static size_t response_parse_token(struct opal_resp_tok *tok,
+                                  const u8 *pos)
+{
+       tok->pos = pos;
+       tok->len = 1;
+       tok->type = OPAL_DTA_TOKENID_TOKEN;
+       tok->width = OPAL_WIDTH_TOKEN;
+
+       return tok->len;
+}
+
+static int response_parse(const u8 *buf, size_t length,
+                         struct parsed_resp *resp)
+{
+       const struct opal_header *hdr;
+       struct opal_resp_tok *iter;
+       int num_entries = 0;
+       int total;
+       size_t token_length;
+       const u8 *pos;
+
+       if (!buf)
+               return -EFAULT;
+
+       if (!resp)
+               return -EFAULT;
+
+       hdr = (struct opal_header *)buf;
+       pos = buf;
+       pos += sizeof(*hdr);
+
+       pr_debug("Response size: cp: %d, pkt: %d, subpkt: %d\n",
+                be32_to_cpu(hdr->cp.length),
+                be32_to_cpu(hdr->pkt.length),
+                be32_to_cpu(hdr->subpkt.length));
+
+       if (hdr->cp.length == 0 || hdr->pkt.length == 0 ||
+           hdr->subpkt.length == 0) {
+               pr_err("Bad header length. cp: %d, pkt: %d, subpkt: %d\n",
+                      be32_to_cpu(hdr->cp.length),
+                      be32_to_cpu(hdr->pkt.length),
+                      be32_to_cpu(hdr->subpkt.length));
+               print_buffer(pos, sizeof(*hdr));
+               return -EINVAL;
+       }
+
+       if (pos > buf + length)
+               return -EFAULT;
+
+       iter = resp->toks;
+       total = be32_to_cpu(hdr->subpkt.length);
+       print_buffer(pos, total);
+       while (total > 0) {
+               if (pos[0] <= TINY_ATOM_BYTE) /* tiny atom */
+                       token_length = response_parse_tiny(iter, pos);
+               else if (pos[0] <= SHORT_ATOM_BYTE) /* short atom */
+                       token_length = response_parse_short(iter, pos);
+               else if (pos[0] <= MEDIUM_ATOM_BYTE) /* medium atom */
+                       token_length = response_parse_medium(iter, pos);
+               else if (pos[0] <= LONG_ATOM_BYTE) /* long atom */
+                       token_length = response_parse_long(iter, pos);
+               else /* TOKEN */
+                       token_length = response_parse_token(iter, pos);
+
+               if (token_length == -EINVAL)
+                       return -EINVAL;
+
+               pos += token_length;
+               total -= token_length;
+               iter++;
+               num_entries++;
+       }
+
+       if (num_entries == 0) {
+               pr_err("Couldn't parse response.\n");
+               return -EINVAL;
+       }
+       resp->num = num_entries;
+
+       return 0;
+}
+
+static size_t response_get_string(const struct parsed_resp *resp, int n,
+                                 const char **store)
+{
+       *store = NULL;
+       if (!resp) {
+               pr_err("Response is NULL\n");
+               return 0;
+       }
+
+       if (n > resp->num) {
+               pr_err("Response has %d tokens. Can't access %d\n",
+                      resp->num, n);
+               return 0;
+       }
+
+       if (resp->toks[n].type != OPAL_DTA_TOKENID_BYTESTRING) {
+               pr_err("Token is not a byte string!\n");
+               return 0;
+       }
+
+       *store = resp->toks[n].pos + 1;
+       return resp->toks[n].len - 1;
+}
+
+static u64 response_get_u64(const struct parsed_resp *resp, int n)
+{
+       if (!resp) {
+               pr_err("Response is NULL\n");
+               return 0;
+       }
+
+       if (n > resp->num) {
+               pr_err("Response has %d tokens. Can't access %d\n",
+                      resp->num, n);
+               return 0;
+       }
+
+       if (resp->toks[n].type != OPAL_DTA_TOKENID_UINT) {
+               pr_err("Token is not unsigned it: %d\n",
+                      resp->toks[n].type);
+               return 0;
+       }
+
+       if (!(resp->toks[n].width == OPAL_WIDTH_TINY ||
+             resp->toks[n].width == OPAL_WIDTH_SHORT)) {
+               pr_err("Atom is not short or tiny: %d\n",
+                      resp->toks[n].width);
+               return 0;
+       }
+
+       return resp->toks[n].stored.u;
+}
+
+static u8 response_status(const struct parsed_resp *resp)
+{
+       if (token_type(resp, 0) == OPAL_DTA_TOKENID_TOKEN &&
+           response_get_token(resp, 0) == OPAL_ENDOFSESSION) {
+               return 0;
+       }
+
+       if (resp->num < 5)
+               return DTAERROR_NO_METHOD_STATUS;
+
+       if (token_type(resp, resp->num - 1) != OPAL_DTA_TOKENID_TOKEN ||
+           token_type(resp, resp->num - 5) != OPAL_DTA_TOKENID_TOKEN ||
+           response_get_token(resp, resp->num - 1) != OPAL_ENDLIST ||
+           response_get_token(resp, resp->num - 5) != OPAL_STARTLIST)
+               return DTAERROR_NO_METHOD_STATUS;
+
+       return response_get_u64(resp, resp->num - 4);
+}
+
+/* Parses and checks for errors */
+static int parse_and_check_status(struct opal_dev *dev)
+{
+       int error;
+
+       print_buffer(dev->cmd, dev->pos);
+
+       error = response_parse(dev->resp, IO_BUFFER_LENGTH, &dev->parsed);
+       if (error) {
+               pr_err("Couldn't parse response.\n");
+               return error;
+       }
+
+       return response_status(&dev->parsed);
+}
+
+static void clear_opal_cmd(struct opal_dev *dev)
+{
+       dev->pos = sizeof(struct opal_header);
+       memset(dev->cmd, 0, IO_BUFFER_LENGTH);
+}
+
+static int start_opal_session_cont(struct opal_dev *dev)
+{
+       u32 hsn, tsn;
+       int error = 0;
+
+       error = parse_and_check_status(dev);
+       if (error)
+               return error;
+
+       hsn = response_get_u64(&dev->parsed, 4);
+       tsn = response_get_u64(&dev->parsed, 5);
+
+       if (hsn == 0 && tsn == 0) {
+               pr_err("Couldn't authenticate session\n");
+               return -EPERM;
+       }
+
+       dev->hsn = hsn;
+       dev->tsn = tsn;
+       return 0;
+}
+
+static void add_suspend_info(struct opal_dev *dev,
+                            struct opal_suspend_data *sus)
+{
+       struct opal_suspend_data *iter;
+
+       list_for_each_entry(iter, &dev->unlk_lst, node) {
+               if (iter->lr == sus->lr) {
+                       list_del(&iter->node);
+                       kfree(iter);
+                       break;
+               }
+       }
+       list_add_tail(&sus->node, &dev->unlk_lst);
+}
+
+static int end_session_cont(struct opal_dev *dev)
+{
+       dev->hsn = 0;
+       dev->tsn = 0;
+       return parse_and_check_status(dev);
+}
+
+static int finalize_and_send(struct opal_dev *dev, cont_fn cont)
+{
+       int ret;
+
+       ret = cmd_finalize(dev, dev->hsn, dev->tsn);
+       if (ret) {
+               pr_err("Error finalizing command buffer: %d\n", ret);
+               return ret;
+       }
+
+       print_buffer(dev->cmd, dev->pos);
+
+       return opal_send_recv(dev, cont);
+}
+
+static int gen_key(struct opal_dev *dev)
+{
+       const u8 *method;
+       u8 uid[OPAL_UID_LENGTH];
+       int err = 0;
+
+       clear_opal_cmd(dev);
+       set_comid(dev, dev->comid);
+
+       memcpy(uid, dev->prev_data, min(sizeof(uid), dev->prev_d_len));
+       method = opalmethod[OPAL_GENKEY];
+       kfree(dev->prev_data);
+       dev->prev_data = NULL;
+
+       add_token_u8(&err, dev, OPAL_CALL);
+       add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
+       add_token_bytestring(&err, dev, opalmethod[OPAL_GENKEY],
+                            OPAL_UID_LENGTH);
+       add_token_u8(&err, dev, OPAL_STARTLIST);
+       add_token_u8(&err, dev, OPAL_ENDLIST);
+
+       if (err) {
+               pr_err("Error building gen key command\n");
+               return err;
+
+       }
+       return finalize_and_send(dev, parse_and_check_status);
+}
+
+static int get_active_key_cont(struct opal_dev *dev)
+{
+       const char *activekey;
+       size_t keylen;
+       int error = 0;
+
+       error = parse_and_check_status(dev);
+       if (error)
+               return error;
+       keylen = response_get_string(&dev->parsed, 4, &activekey);
+       if (!activekey) {
+               pr_err("%s: Couldn't extract the Activekey from the response\n",
+                      __func__);
+               return OPAL_INVAL_PARAM;
+       }
+       dev->prev_data = kmemdup(activekey, keylen, GFP_KERNEL);
+
+       if (!dev->prev_data)
+               return -ENOMEM;
+
+       dev->prev_d_len = keylen;
+
+       return 0;
+}
+
+static int get_active_key(struct opal_dev *dev)
+{
+       u8 uid[OPAL_UID_LENGTH];
+       int err = 0;
+       u8 *lr;
+
+       clear_opal_cmd(dev);
+       set_comid(dev, dev->comid);
+       lr = dev->func_data[dev->state];
+
+       err = build_locking_range(uid, sizeof(uid), *lr);
+       if (err)
+               return err;
+
+       err = 0;
+       add_token_u8(&err, dev, OPAL_CALL);
+       add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
+       add_token_bytestring(&err, dev, opalmethod[OPAL_GET], OPAL_UID_LENGTH);
+       add_token_u8(&err, dev, OPAL_STARTLIST);
+       add_token_u8(&err, dev, OPAL_STARTLIST);
+       add_token_u8(&err, dev, OPAL_STARTNAME);
+       add_token_u8(&err, dev, 3); /* startCloumn */
+       add_token_u8(&err, dev, 10); /* ActiveKey */
+       add_token_u8(&err, dev, OPAL_ENDNAME);
+       add_token_u8(&err, dev, OPAL_STARTNAME);
+       add_token_u8(&err, dev, 4); /* endColumn */
+       add_token_u8(&err, dev, 10); /* ActiveKey */
+       add_token_u8(&err, dev, OPAL_ENDNAME);
+       add_token_u8(&err, dev, OPAL_ENDLIST);
+       add_token_u8(&err, dev, OPAL_ENDLIST);
+       if (err) {
+               pr_err("Error building get active key command\n");
+               return err;
+       }
+
+       return finalize_and_send(dev, get_active_key_cont);
+}
+
+static int generic_lr_enable_disable(struct opal_dev *dev,
+                                    u8 *uid, bool rle, bool wle,
+                                    bool rl, bool wl)
+{
+       int err = 0;
+
+       add_token_u8(&err, dev, OPAL_CALL);
+       add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
+       add_token_bytestring(&err, dev, opalmethod[OPAL_SET], OPAL_UID_LENGTH);
+
+       add_token_u8(&err, dev, OPAL_STARTLIST);
+       add_token_u8(&err, dev, OPAL_STARTNAME);
+       add_token_u8(&err, dev, OPAL_VALUES);
+       add_token_u8(&err, dev, OPAL_STARTLIST);
+
+       add_token_u8(&err, dev, OPAL_STARTNAME);
+       add_token_u8(&err, dev, 5); /* ReadLockEnabled */
+       add_token_u8(&err, dev, rle);
+       add_token_u8(&err, dev, OPAL_ENDNAME);
+
+       add_token_u8(&err, dev, OPAL_STARTNAME);
+       add_token_u8(&err, dev, 6); /* WriteLockEnabled */
+       add_token_u8(&err, dev, wle);
+       add_token_u8(&err, dev, OPAL_ENDNAME);
+
+       add_token_u8(&err, dev, OPAL_STARTNAME);
+       add_token_u8(&err, dev, OPAL_READLOCKED);
+       add_token_u8(&err, dev, rl);
+       add_token_u8(&err, dev, OPAL_ENDNAME);
+
+       add_token_u8(&err, dev, OPAL_STARTNAME);
+       add_token_u8(&err, dev, OPAL_WRITELOCKED);
+       add_token_u8(&err, dev, wl);
+       add_token_u8(&err, dev, OPAL_ENDNAME);
+
+       add_token_u8(&err, dev, OPAL_ENDLIST);
+       add_token_u8(&err, dev, OPAL_ENDNAME);
+       add_token_u8(&err, dev, OPAL_ENDLIST);
+       return err;
+}
+
+static inline int enable_global_lr(struct opal_dev *dev, u8 *uid,
+                                  struct opal_user_lr_setup *setup)
+{
+       int err;
+
+       err = generic_lr_enable_disable(dev, uid, !!setup->RLE, !!setup->WLE,
+                                       0, 0);
+       if (err)
+               pr_err("Failed to create enable global lr command\n");
+       return err;
+}
+
+static int setup_locking_range(struct opal_dev *dev)
+{
+       u8 uid[OPAL_UID_LENGTH];
+       struct opal_user_lr_setup *setup;
+       u8 lr;
+       int err = 0;
+
+       clear_opal_cmd(dev);
+       set_comid(dev, dev->comid);
+
+       setup = dev->func_data[dev->state];
+       lr = setup->session.opal_key.lr;
+       err = build_locking_range(uid, sizeof(uid), lr);
+       if (err)
+               return err;
+
+       if (lr == 0)
+               err = enable_global_lr(dev, uid, setup);
+       else {
+               add_token_u8(&err, dev, OPAL_CALL);
+               add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
+               add_token_bytestring(&err, dev, opalmethod[OPAL_SET],
+                                    OPAL_UID_LENGTH);
+
+               add_token_u8(&err, dev, OPAL_STARTLIST);
+               add_token_u8(&err, dev, OPAL_STARTNAME);
+               add_token_u8(&err, dev, OPAL_VALUES);
+               add_token_u8(&err, dev, OPAL_STARTLIST);
+
+               add_token_u8(&err, dev, OPAL_STARTNAME);
+               add_token_u8(&err, dev, 3); /* Ranges Start */
+               add_token_u64(&err, dev, setup->range_start);
+               add_token_u8(&err, dev, OPAL_ENDNAME);
+
+               add_token_u8(&err, dev, OPAL_STARTNAME);
+               add_token_u8(&err, dev, 4); /* Ranges length */
+               add_token_u64(&err, dev, setup->range_length);
+               add_token_u8(&err, dev, OPAL_ENDNAME);
+
+               add_token_u8(&err, dev, OPAL_STARTNAME);
+               add_token_u8(&err, dev, 5); /*ReadLockEnabled */
+               add_token_u64(&err, dev, !!setup->RLE);
+               add_token_u8(&err, dev, OPAL_ENDNAME);
+
+               add_token_u8(&err, dev, OPAL_STARTNAME);
+               add_token_u8(&err, dev, 6); /*WriteLockEnabled*/
+               add_token_u64(&err, dev, !!setup->WLE);
+               add_token_u8(&err, dev, OPAL_ENDNAME);
+
+               add_token_u8(&err, dev, OPAL_ENDLIST);
+               add_token_u8(&err, dev, OPAL_ENDNAME);
+               add_token_u8(&err, dev, OPAL_ENDLIST);
+
+       }
+       if (err) {
+               pr_err("Error building Setup Locking range command.\n");
+               return err;
+
+       }
+
+       return finalize_and_send(dev, parse_and_check_status);
+}
+
+static int start_generic_opal_session(struct opal_dev *dev,
+                                     enum opal_uid auth,
+                                     enum opal_uid sp_type,
+                                     const char *key,
+                                     u8 key_len)
+{
+       u32 hsn;
+       int err = 0;
+
+       if (key == NULL && auth != OPAL_ANYBODY_UID) {
+               pr_err("%s: Attempted to open ADMIN_SP Session without a Host" \
+                      "Challenge, and not as the Anybody UID\n", __func__);
+               return OPAL_INVAL_PARAM;
+       }
+
+       clear_opal_cmd(dev);
+
+       set_comid(dev, dev->comid);
+       hsn = GENERIC_HOST_SESSION_NUM;
+
+       add_token_u8(&err, dev, OPAL_CALL);
+       add_token_bytestring(&err, dev, opaluid[OPAL_SMUID_UID],
+                            OPAL_UID_LENGTH);
+       add_token_bytestring(&err, dev, opalmethod[OPAL_STARTSESSION],
+                            OPAL_UID_LENGTH);
+       add_token_u8(&err, dev, OPAL_STARTLIST);
+       add_token_u64(&err, dev, hsn);
+       add_token_bytestring(&err, dev, opaluid[sp_type], OPAL_UID_LENGTH);
+       add_token_u8(&err, dev, 1);
+
+       switch (auth) {
+       case OPAL_ANYBODY_UID:
+               add_token_u8(&err, dev, OPAL_ENDLIST);
+               break;
+       case OPAL_ADMIN1_UID:
+       case OPAL_SID_UID:
+               add_token_u8(&err, dev, OPAL_STARTNAME);
+               add_token_u8(&err, dev, 0); /* HostChallenge */
+               add_token_bytestring(&err, dev, key, key_len);
+               add_token_u8(&err, dev, OPAL_ENDNAME);
+               add_token_u8(&err, dev, OPAL_STARTNAME);
+               add_token_u8(&err, dev, 3); /* HostSignAuth */
+               add_token_bytestring(&err, dev, opaluid[auth],
+                                    OPAL_UID_LENGTH);
+               add_token_u8(&err, dev, OPAL_ENDNAME);
+               add_token_u8(&err, dev, OPAL_ENDLIST);
+               break;
+       default:
+               pr_err("Cannot start Admin SP session with auth %d\n", auth);
+               return OPAL_INVAL_PARAM;
+       }
+
+       if (err) {
+               pr_err("Error building start adminsp session command.\n");
+               return err;
+       }
+
+       return finalize_and_send(dev, start_opal_session_cont);
+}
+
+static int start_anybodyASP_opal_session(struct opal_dev *dev)
+{
+       return start_generic_opal_session(dev, OPAL_ANYBODY_UID,
+                                         OPAL_ADMINSP_UID, NULL, 0);
+}
+
+static int start_SIDASP_opal_session(struct opal_dev *dev)
+{
+       int ret;
+       const u8 *key = dev->prev_data;
+       struct opal_key *okey;
+
+       if (!key) {
+               okey = dev->func_data[dev->state];
+               ret = start_generic_opal_session(dev, OPAL_SID_UID,
+                                                OPAL_ADMINSP_UID,
+                                                okey->key,
+                                                okey->key_len);
+       } else {
+               ret = start_generic_opal_session(dev, OPAL_SID_UID,
+                                                OPAL_ADMINSP_UID,
+                                                key, dev->prev_d_len);
+               kfree(key);
+               dev->prev_data = NULL;
+       }
+       return ret;
+}
+
+static inline int start_admin1LSP_opal_session(struct opal_dev *dev)
+{
+       struct opal_key *key = dev->func_data[dev->state];
+
+       return start_generic_opal_session(dev, OPAL_ADMIN1_UID,
+                                         OPAL_LOCKINGSP_UID,
+                                         key->key, key->key_len);
+}
+
+static int start_auth_opal_session(struct opal_dev *dev)
+{
+       u8 lk_ul_user[OPAL_UID_LENGTH];
+       int err = 0;
+
+       struct opal_session_info *session = dev->func_data[dev->state];
+       size_t keylen = session->opal_key.key_len;
+       u8 *key = session->opal_key.key;
+       u32 hsn = GENERIC_HOST_SESSION_NUM;
+
+       clear_opal_cmd(dev);
+       set_comid(dev, dev->comid);
+
+       if (session->sum) {
+               err = build_locking_user(lk_ul_user, sizeof(lk_ul_user),
+                                        session->opal_key.lr);
+               if (err)
+                       return err;
+
+       } else if (session->who != OPAL_ADMIN1 && !session->sum) {
+               err = build_locking_user(lk_ul_user, sizeof(lk_ul_user),
+                                        session->who - 1);
+               if (err)
+                       return err;
+       } else
+               memcpy(lk_ul_user, opaluid[OPAL_ADMIN1_UID], OPAL_UID_LENGTH);
+
+       add_token_u8(&err, dev, OPAL_CALL);
+       add_token_bytestring(&err, dev, opaluid[OPAL_SMUID_UID],
+                            OPAL_UID_LENGTH);
+       add_token_bytestring(&err, dev, opalmethod[OPAL_STARTSESSION],
+                            OPAL_UID_LENGTH);
+
+       add_token_u8(&err, dev, OPAL_STARTLIST);
+       add_token_u64(&err, dev, hsn);
+       add_token_bytestring(&err, dev, opaluid[OPAL_LOCKINGSP_UID],
+                            OPAL_UID_LENGTH);
+       add_token_u8(&err, dev, 1);
+       add_token_u8(&err, dev, OPAL_STARTNAME);
+       add_token_u8(&err, dev, 0);
+       add_token_bytestring(&err, dev, key, keylen);
+       add_token_u8(&err, dev, OPAL_ENDNAME);
+       add_token_u8(&err, dev, OPAL_STARTNAME);
+       add_token_u8(&err, dev, 3);
+       add_token_bytestring(&err, dev, lk_ul_user, OPAL_UID_LENGTH);
+       add_token_u8(&err, dev, OPAL_ENDNAME);
+       add_token_u8(&err, dev, OPAL_ENDLIST);
+
+       if (err) {
+               pr_err("Error building STARTSESSION command.\n");
+               return err;
+       }
+
+       return finalize_and_send(dev, start_opal_session_cont);
+}
+
+static int revert_tper(struct opal_dev *dev)
+{
+       int err = 0;
+
+       clear_opal_cmd(dev);
+       set_comid(dev, dev->comid);
+
+       add_token_u8(&err, dev, OPAL_CALL);
+       add_token_bytestring(&err, dev, opaluid[OPAL_ADMINSP_UID],
+                            OPAL_UID_LENGTH);
+       add_token_bytestring(&err, dev, opalmethod[OPAL_REVERT],
+                            OPAL_UID_LENGTH);
+       add_token_u8(&err, dev, OPAL_STARTLIST);
+       add_token_u8(&err, dev, OPAL_ENDLIST);
+       if (err) {
+               pr_err("Error building REVERT TPER command.\n");
+               return err;
+       }
+
+       return finalize_and_send(dev, parse_and_check_status);
+}
+
+static int internal_activate_user(struct opal_dev *dev)
+{
+       struct opal_session_info *session = dev->func_data[dev->state];
+       u8 uid[OPAL_UID_LENGTH];
+       int err = 0;
+
+       clear_opal_cmd(dev);
+       set_comid(dev, dev->comid);
+
+       memcpy(uid, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
+       uid[7] = session->who;
+
+       add_token_u8(&err, dev, OPAL_CALL);
+       add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
+       add_token_bytestring(&err, dev, opalmethod[OPAL_SET], OPAL_UID_LENGTH);
+       add_token_u8(&err, dev, OPAL_STARTLIST);
+       add_token_u8(&err, dev, OPAL_STARTNAME);
+       add_token_u8(&err, dev, OPAL_VALUES);
+       add_token_u8(&err, dev, OPAL_STARTLIST);
+       add_token_u8(&err, dev, OPAL_STARTNAME);
+       add_token_u8(&err, dev, 5); /* Enabled */
+       add_token_u8(&err, dev, OPAL_TRUE);
+       add_token_u8(&err, dev, OPAL_ENDNAME);
+       add_token_u8(&err, dev, OPAL_ENDLIST);
+       add_token_u8(&err, dev, OPAL_ENDNAME);
+       add_token_u8(&err, dev, OPAL_ENDLIST);
+
+       if (err) {
+               pr_err("Error building Activate UserN command.\n");
+               return err;
+       }
+
+       return finalize_and_send(dev, parse_and_check_status);
+}
+
+static int erase_locking_range(struct opal_dev *dev)
+{
+       struct opal_session_info *session;
+       u8 uid[OPAL_UID_LENGTH];
+       int err = 0;
+
+       clear_opal_cmd(dev);
+       set_comid(dev, dev->comid);
+       session = dev->func_data[dev->state];
+
+       if (build_locking_range(uid, sizeof(uid), session->opal_key.lr) < 0)
+               return -ERANGE;
+
+       add_token_u8(&err, dev, OPAL_CALL);
+       add_token_bytestring(&err, dev, uid, OPAL_UID_LENGTH);
+       add_token_bytestring(&err, dev, opalmethod[OPAL_ERASE],
+                            OPAL_UID_LENGTH);
+       add_token_u8(&err, dev, OPAL_STARTLIST);
+       add_token_u8(&err, dev, OPAL_ENDLIST);
+
+       if (err) {
+               pr_err("Error building Erase Locking Range Command.\n");
+               return err;
+       }
+       return finalize_and_send(dev, parse_and_check_status);
+}
+
+static int set_mbr_done(struct opal_dev *dev)
+{
+       u8 mbr_done_tf = *(u8 *)dev->func_data[dev->state];
+       int err = 0;
+
+       clear_opal_cmd(dev);
+       set_comid(dev, dev->comid);
+
+       add_token_u8(&err, dev, OPAL_CALL);
+       add_token_bytestring(&err, dev, opaluid[OPAL_MBRCONTROL],
+                            OPAL_UID_LENGTH);
+       add_token_bytestring(&err, dev, opalmethod[OPAL_SET], OPAL_UID_LENGTH);
+       add_token_u8(&err, dev, OPAL_STARTLIST);
+       add_token_u8(&err, dev, OPAL_STARTNAME);
+       add_token_u8(&err, dev, OPAL_VALUES);
+       add_token_u8(&err, dev, OPAL_STARTLIST);
+       add_token_u8(&err, dev, OPAL_STARTNAME);
+       add_token_u8(&err, dev, 2); /* Done */
+       add_token_u8(&err, dev, mbr_done_tf); /* Done T or F */
+       add_token_u8(&err, dev, OPAL_ENDNAME);
+       add_token_u8(&err, dev, OPAL_ENDLIST);
+       add_token_u8(&err, dev, OPAL_ENDNAME);
+       add_token_u8(&err, dev, OPAL_ENDLIST);
+
+       if (err) {
+               pr_err("Error Building set MBR Done command\n");
+               return err;
+       }
+
+       return finalize_and_send(dev, parse_and_check_status);
+}
+
+static int set_mbr_enable_disable(struct opal_dev *dev)
+{
+       u8 mbr_en_dis = *(u8 *)dev->func_data[dev->state];
+       int err = 0;
+
+       clear_opal_cmd(dev);
+       set_comid(dev, dev->comid);
+
+       add_token_u8(&err, dev, OPAL_CALL);
+       add_token_bytestring(&err, dev, opaluid[OPAL_MBRCONTROL],
+                            OPAL_UID_LENGTH);
+       add_token_bytestring(&err, dev, opalmethod[OPAL_SET], OPAL_UID_LENGTH);
+       add_token_u8(&err, dev, OPAL_STARTLIST);
+       add_token_u8(&err, dev, OPAL_STARTNAME);
+       add_token_u8(&err, dev, OPAL_VALUES);
+       add_token_u8(&err, dev, OPAL_STARTLIST);
+       add_token_u8(&err, dev, OPAL_STARTNAME);
+       add_token_u8(&err, dev, 1);
+       add_token_u8(&err, dev, mbr_en_dis);
+       add_token_u8(&err, dev, OPAL_ENDNAME);
+       add_token_u8(&err, dev, OPAL_ENDLIST);
+       add_token_u8(&err, dev, OPAL_ENDNAME);
+       add_token_u8(&err, dev, OPAL_ENDLIST);
+
+       if (err) {
+               pr_err("Error Building set MBR done command\n");
+               return err;
+       }
+
+       return finalize_and_send(dev, parse_and_check_status);
+}
+
+static int generic_pw_cmd(u8 *key, size_t key_len, u8 *cpin_uid,
+                         struct opal_dev *dev)
+{
+       int err = 0;
+
+       clear_opal_cmd(dev);
+       set_comid(dev, dev->comid);
+
+       add_token_u8(&err, dev, OPAL_CALL);
+       add_token_bytestring(&err, dev, cpin_uid, OPAL_UID_LENGTH);
+       add_token_bytestring(&err, dev, opalmethod[OPAL_SET],
+                            OPAL_UID_LENGTH);
+       add_token_u8(&err, dev, OPAL_STARTLIST);
+       add_token_u8(&err, dev, OPAL_STARTNAME);
+       add_token_u8(&err, dev, OPAL_VALUES);
+       add_token_u8(&err, dev, OPAL_STARTLIST);
+       add_token_u8(&err, dev, OPAL_STARTNAME);
+       add_token_u8(&err, dev, 3); /* PIN */
+       add_token_bytestring(&err, dev, key, key_len);
+       add_token_u8(&err, dev, OPAL_ENDNAME);
+       add_token_u8(&err, dev, OPAL_ENDLIST);
+       add_token_u8(&err, dev, OPAL_ENDNAME);
+       add_token_u8(&err, dev, OPAL_ENDLIST);
+
+       return err;
+}
+
+static int set_new_pw(struct opal_dev *dev)
+{
+       u8 cpin_uid[OPAL_UID_LENGTH];
+       struct opal_session_info *usr = dev->func_data[dev->state];
+
+
+       memcpy(cpin_uid, opaluid[OPAL_C_PIN_ADMIN1], OPAL_UID_LENGTH);
+
+       if (usr->who != OPAL_ADMIN1) {
+               cpin_uid[5] = 0x03;
+               if (usr->sum)
+                       cpin_uid[7] = usr->opal_key.lr + 1;
+               else
+                       cpin_uid[7] = usr->who;
+       }
+
+       if (generic_pw_cmd(usr->opal_key.key, usr->opal_key.key_len,
+                          cpin_uid, dev)) {
+               pr_err("Error building set password command.\n");
+               return -ERANGE;
+       }
+
+       return finalize_and_send(dev, parse_and_check_status);
+}
+
+static int set_sid_cpin_pin(struct opal_dev *dev)
+{
+       u8 cpin_uid[OPAL_UID_LENGTH];
+       struct opal_key *key = dev->func_data[dev->state];
+
+       memcpy(cpin_uid, opaluid[OPAL_C_PIN_SID], OPAL_UID_LENGTH);
+
+       if (generic_pw_cmd(key->key, key->key_len, cpin_uid, dev)) {
+               pr_err("Error building Set SID cpin\n");
+               return -ERANGE;
+       }
+       return finalize_and_send(dev, parse_and_check_status);
+}
+
+static int add_user_to_lr(struct opal_dev *dev)
+{
+       u8 lr_buffer[OPAL_UID_LENGTH];
+       u8 user_uid[OPAL_UID_LENGTH];
+       struct opal_lock_unlock *lkul;
+       int err = 0;
+
+       clear_opal_cmd(dev);
+       set_comid(dev, dev->comid);
+
+       lkul = dev->func_data[dev->state];
+
+       memcpy(lr_buffer, opaluid[OPAL_LOCKINGRANGE_ACE_RDLOCKED],
+              OPAL_UID_LENGTH);
+
+       if (lkul->l_state == OPAL_RW)
+               memcpy(lr_buffer, opaluid[OPAL_LOCKINGRANGE_ACE_WRLOCKED],
+                      OPAL_UID_LENGTH);
+
+       lr_buffer[7] = lkul->session.opal_key.lr;
+
+       memcpy(user_uid, opaluid[OPAL_USER1_UID], OPAL_UID_LENGTH);
+
+       user_uid[7] = lkul->session.who;
+
+       add_token_u8(&err, dev, OPAL_CALL);
+       add_token_bytestring(&err, dev, lr_buffer, OPAL_UID_LENGTH);
+       add_token_bytestring(&err, dev, opalmethod[OPAL_SET],
+                            OPAL_UID_LENGTH);
+
+       add_token_u8(&err, dev, OPAL_STARTLIST);
+       add_token_u8(&err, dev, OPAL_STARTNAME);
+       add_token_u8(&err, dev, OPAL_VALUES);
+
+       add_token_u8(&err, dev, OPAL_STARTLIST);
+       add_token_u8(&err, dev, OPAL_STARTNAME);
+       add_token_u8(&err, dev, 3);
+
+       add_token_u8(&err, dev, OPAL_STARTLIST);
+
+
+       add_token_u8(&err, dev, OPAL_STARTNAME);
+       add_token_bytestring(&err, dev,
+                            opaluid[OPAL_HALF_UID_AUTHORITY_OBJ_REF],
+                            OPAL_UID_LENGTH/2);
+       add_token_bytestring(&err, dev, user_uid, OPAL_UID_LENGTH);
+       add_token_u8(&err, dev, OPAL_ENDNAME);
+
+
+       add_token_u8(&err, dev, OPAL_STARTNAME);
+       add_token_bytestring(&err, dev,
+                            opaluid[OPAL_HALF_UID_AUTHORITY_OBJ_REF],
+                            OPAL_UID_LENGTH/2);
+       add_token_bytestring(&err, dev, user_uid, OPAL_UID_LENGTH);
+       add_token_u8(&err, dev, OPAL_ENDNAME);
+
+
+       add_token_u8(&err, dev, OPAL_STARTNAME);
+       add_token_bytestring(&err, dev, opaluid[OPAL_HALF_UID_BOOLEAN_ACE],
+                            OPAL_UID_LENGTH/2);
+       add_token_u8(&err, dev, 1);
+       add_token_u8(&err, dev, OPAL_ENDNAME);
+
+
+       add_token_u8(&err, dev, OPAL_ENDLIST);
+       add_token_u8(&err, dev, OPAL_ENDNAME);
+       add_token_u8(&err, dev, OPAL_ENDLIST);
+       add_token_u8(&err, dev, OPAL_ENDNAME);
+       add_token_u8(&err, dev, OPAL_ENDLIST);
+
+       if (err) {
+               pr_err("Error building add user to locking range command.\n");
+               return err;
+       }
+
+       return finalize_and_send(dev, parse_and_check_status);
+}
+
+static int lock_unlock_locking_range(struct opal_dev *dev)
+{
+       u8 lr_buffer[OPAL_UID_LENGTH];
+       const u8 *method;
+       struct opal_lock_unlock *lkul;
+       u8 read_locked = 1, write_locked = 1;
+       int err = 0;
+
+       clear_opal_cmd(dev);
+       set_comid(dev, dev->comid);
+
+       method = opalmethod[OPAL_SET];
+       lkul = dev->func_data[dev->state];
+       if (build_locking_range(lr_buffer, sizeof(lr_buffer),
+                               lkul->session.opal_key.lr) < 0)
+               return -ERANGE;
+
+       switch (lkul->l_state) {
+       case OPAL_RO:
+               read_locked = 0;
+               write_locked = 1;
+               break;
+       case OPAL_RW:
+               read_locked = 0;
+               write_locked = 0;
+               break;
+       case OPAL_LK:
+               /* vars are initalized to locked */
+               break;
+       default:
+               pr_err("Tried to set an invalid locking state... returning to uland\n");
+               return OPAL_INVAL_PARAM;
+       }
+
+       add_token_u8(&err, dev, OPAL_CALL);
+       add_token_bytestring(&err, dev, lr_buffer, OPAL_UID_LENGTH);
+       add_token_bytestring(&err, dev, opalmethod[OPAL_SET], OPAL_UID_LENGTH);
+       add_token_u8(&err, dev, OPAL_STARTLIST);
+       add_token_u8(&err, dev, OPAL_STARTNAME);
+       add_token_u8(&err, dev, OPAL_VALUES);
+       add_token_u8(&err, dev, OPAL_STARTLIST);
+
+       add_token_u8(&err, dev, OPAL_STARTNAME);
+       add_token_u8(&err, dev, OPAL_READLOCKED);
+       add_token_u8(&err, dev, read_locked);
+       add_token_u8(&err, dev, OPAL_ENDNAME);
+
+       add_token_u8(&err, dev, OPAL_STARTNAME);
+       add_token_u8(&err, dev, OPAL_WRITELOCKED);
+       add_token_u8(&err, dev, write_locked);
+       add_token_u8(&err, dev, OPAL_ENDNAME);
+
+       add_token_u8(&err, dev, OPAL_ENDLIST);
+       add_token_u8(&err, dev, OPAL_ENDNAME);
+       add_token_u8(&err, dev, OPAL_ENDLIST);
+
+       if (err) {
+               pr_err("Error building SET command.\n");
+               return err;
+       }
+       return finalize_and_send(dev, parse_and_check_status);
+}
+
+
+static int lock_unlock_locking_range_sum(struct opal_dev *dev)
+{
+       u8 lr_buffer[OPAL_UID_LENGTH];
+       u8 read_locked = 1, write_locked = 1;
+       const u8 *method;
+       struct opal_lock_unlock *lkul;
+       int ret;
+
+       clear_opal_cmd(dev);
+       set_comid(dev, dev->comid);
+
+       method = opalmethod[OPAL_SET];
+       lkul = dev->func_data[dev->state];
+       if (build_locking_range(lr_buffer, sizeof(lr_buffer),
+                               lkul->session.opal_key.lr) < 0)
+               return -ERANGE;
+
+       switch (lkul->l_state) {
+       case OPAL_RO:
+               read_locked = 0;
+               write_locked = 1;
+               break;
+       case OPAL_RW:
+               read_locked = 0;
+               write_locked = 0;
+               break;
+       case OPAL_LK:
+               /* vars are initalized to locked */
+               break;
+       default:
+               pr_err("Tried to set an invalid locking state.\n");
+               return OPAL_INVAL_PARAM;
+       }
+       ret = generic_lr_enable_disable(dev, lr_buffer, 1, 1,
+                                       read_locked, write_locked);
+
+       if (ret < 0) {
+               pr_err("Error building SET command.\n");
+               return ret;
+       }
+       return finalize_and_send(dev, parse_and_check_status);
+}
+
+static int activate_lsp(struct opal_dev *dev)
+{
+       struct opal_lr_act *opal_act;
+       u8 user_lr[OPAL_UID_LENGTH];
+       u8 uint_3 = 0x83;
+       int err = 0, i;
+
+       clear_opal_cmd(dev);
+       set_comid(dev, dev->comid);
+
+       opal_act = dev->func_data[dev->state];
+
+       add_token_u8(&err, dev, OPAL_CALL);
+       add_token_bytestring(&err, dev, opaluid[OPAL_LOCKINGSP_UID],
+                            OPAL_UID_LENGTH);
+       add_token_bytestring(&err, dev, opalmethod[OPAL_ACTIVATE],
+                            OPAL_UID_LENGTH);
+
+
+       if (opal_act->sum) {
+               err = build_locking_range(user_lr, sizeof(user_lr),
+                                         opal_act->lr[0]);
+               if (err)
+                       return err;
+
+               add_token_u8(&err, dev, OPAL_STARTLIST);
+               add_token_u8(&err, dev, OPAL_STARTNAME);
+               add_token_u8(&err, dev, uint_3);
+               add_token_u8(&err, dev, 6);
+               add_token_u8(&err, dev, 0);
+               add_token_u8(&err, dev, 0);
+
+               add_token_u8(&err, dev, OPAL_STARTLIST);
+               add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH);
+               for (i = 1; i < opal_act->num_lrs; i++) {
+                       user_lr[7] = opal_act->lr[i];
+                       add_token_bytestring(&err, dev, user_lr, OPAL_UID_LENGTH);
+               }
+               add_token_u8(&err, dev, OPAL_ENDLIST);
+               add_token_u8(&err, dev, OPAL_ENDNAME);
+               add_token_u8(&err, dev, OPAL_ENDLIST);
+
+       } else {
+               add_token_u8(&err, dev, OPAL_STARTLIST);
+               add_token_u8(&err, dev, OPAL_ENDLIST);
+       }
+
+       if (err) {
+               pr_err("Error building Activate LockingSP command.\n");
+               return err;
+       }
+
+       return finalize_and_send(dev, parse_and_check_status);
+}
+
+static int get_lsp_lifecycle_cont(struct opal_dev *dev)
+{
+       u8 lc_status;
+       int error = 0;
+
+       error = parse_and_check_status(dev);
+       if (error)
+               return error;
+
+       lc_status = response_get_u64(&dev->parsed, 4);
+       /* 0x08 is Manufacured Inactive */
+       /* 0x09 is Manufactured */
+       if (lc_status != OPAL_MANUFACTURED_INACTIVE) {
+               pr_err("Couldn't determine the status of the Lifcycle state\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+/* Determine if we're in the Manufactured Inactive or Active state */
+static int get_lsp_lifecycle(struct opal_dev *dev)
+{
+       int err = 0;
+
+       clear_opal_cmd(dev);
+       set_comid(dev, dev->comid);
+
+       add_token_u8(&err, dev, OPAL_CALL);
+       add_token_bytestring(&err, dev, opaluid[OPAL_LOCKINGSP_UID],
+                            OPAL_UID_LENGTH);
+       add_token_bytestring(&err, dev, opalmethod[OPAL_GET], OPAL_UID_LENGTH);
+
+       add_token_u8(&err, dev, OPAL_STARTLIST);
+       add_token_u8(&err, dev, OPAL_STARTLIST);
+
+       add_token_u8(&err, dev, OPAL_STARTNAME);
+       add_token_u8(&err, dev, 3); /* Start Column */
+       add_token_u8(&err, dev, 6); /* Lifecycle Column */
+       add_token_u8(&err, dev, OPAL_ENDNAME);
+
+       add_token_u8(&err, dev, OPAL_STARTNAME);
+       add_token_u8(&err, dev, 4); /* End Column */
+       add_token_u8(&err, dev, 6); /* Lifecycle Column */
+       add_token_u8(&err, dev, OPAL_ENDNAME);
+
+       add_token_u8(&err, dev, OPAL_ENDLIST);
+       add_token_u8(&err, dev, OPAL_ENDLIST);
+
+       if (err) {
+               pr_err("Error Building GET Lifecycle Status command\n");
+               return err;
+       }
+
+       return finalize_and_send(dev, get_lsp_lifecycle_cont);
+}
+
+static int get_msid_cpin_pin_cont(struct opal_dev *dev)
+{
+       const char *msid_pin;
+       size_t strlen;
+       int error = 0;
+
+       error = parse_and_check_status(dev);
+       if (error)
+               return error;
+
+       strlen = response_get_string(&dev->parsed, 4, &msid_pin);
+       if (!msid_pin) {
+               pr_err("%s: Couldn't extract PIN from response\n", __func__);
+               return OPAL_INVAL_PARAM;
+       }
+
+       dev->prev_data = kmemdup(msid_pin, strlen, GFP_KERNEL);
+       if (!dev->prev_data)
+               return -ENOMEM;
+
+       dev->prev_d_len = strlen;
+
+       return 0;
+}
+
+static int get_msid_cpin_pin(struct opal_dev *dev)
+{
+       int err = 0;
+
+       clear_opal_cmd(dev);
+       set_comid(dev, dev->comid);
+
+
+       add_token_u8(&err, dev, OPAL_CALL);
+       add_token_bytestring(&err, dev, opaluid[OPAL_C_PIN_MSID],
+                            OPAL_UID_LENGTH);
+       add_token_bytestring(&err, dev, opalmethod[OPAL_GET], OPAL_UID_LENGTH);
+
+       add_token_u8(&err, dev, OPAL_STARTLIST);
+       add_token_u8(&err, dev, OPAL_STARTLIST);
+
+       add_token_u8(&err, dev, OPAL_STARTNAME);
+       add_token_u8(&err, dev, 3); /* Start Column */
+       add_token_u8(&err, dev, 3); /* PIN */
+       add_token_u8(&err, dev, OPAL_ENDNAME);
+
+       add_token_u8(&err, dev, OPAL_STARTNAME);
+       add_token_u8(&err, dev, 4); /* End Column */
+       add_token_u8(&err, dev, 3); /* Lifecycle Column */
+       add_token_u8(&err, dev, OPAL_ENDNAME);
+
+       add_token_u8(&err, dev, OPAL_ENDLIST);
+       add_token_u8(&err, dev, OPAL_ENDLIST);
+
+       if (err) {
+               pr_err("Error building Get MSID CPIN PIN command.\n");
+               return err;
+       }
+
+       return finalize_and_send(dev, get_msid_cpin_pin_cont);
+}
+
+static int build_end_opal_session(struct opal_dev *dev)
+{
+       int err = 0;
+
+       clear_opal_cmd(dev);
+
+       set_comid(dev, dev->comid);
+       add_token_u8(&err, dev, OPAL_ENDOFSESSION);
+       return err;
+}
+
+static int end_opal_session(struct opal_dev *dev)
+{
+       int ret = build_end_opal_session(dev);
+
+       if (ret < 0)
+               return ret;
+       return finalize_and_send(dev, end_session_cont);
+}
+
+static int end_opal_session_error(struct opal_dev *dev)
+{
+       const opal_step error_end_session[] = {
+               end_opal_session,
+               NULL,
+       };
+       dev->funcs = error_end_session;
+       dev->state = 0;
+       return next(dev);
+}
+
+static inline void setup_opal_dev(struct opal_dev *dev,
+                                 const opal_step *funcs)
+{
+       dev->state = 0;
+       dev->funcs = funcs;
+       dev->tsn = 0;
+       dev->hsn = 0;
+       dev->func_data = NULL;
+       dev->prev_data = NULL;
+}
+
+static int check_opal_support(struct opal_dev *dev)
+{
+       static const opal_step funcs[] = {
+               opal_discovery0,
+               NULL
+       };
+       int ret;
+
+       mutex_lock(&dev->dev_lock);
+       setup_opal_dev(dev, funcs);
+       ret = next(dev);
+       dev->supported = !ret;
+       mutex_unlock(&dev->dev_lock);
+       return ret;
+}
+
+struct opal_dev *init_opal_dev(void *data, sec_send_recv *send_recv)
+{
+       struct opal_dev *dev;
+
+       dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return NULL;
+
+       INIT_LIST_HEAD(&dev->unlk_lst);
+       mutex_init(&dev->dev_lock);
+       dev->data = data;
+       dev->send_recv = send_recv;
+       if (check_opal_support(dev) != 0) {
+               pr_debug("Opal is not supported on this device\n");
+               kfree(dev);
+               return NULL;
+       }
+       return dev;
+}
+EXPORT_SYMBOL(init_opal_dev);
+
+static int opal_secure_erase_locking_range(struct opal_dev *dev,
+                                          struct opal_session_info *opal_session)
+{
+       void *data[3] = { NULL };
+       static const opal_step erase_funcs[] = {
+               opal_discovery0,
+               start_auth_opal_session,
+               get_active_key,
+               gen_key,
+               end_opal_session,
+               NULL,
+       };
+       int ret;
+
+       mutex_lock(&dev->dev_lock);
+       setup_opal_dev(dev, erase_funcs);
+
+       dev->func_data = data;
+       dev->func_data[1] = opal_session;
+       dev->func_data[2] = &opal_session->opal_key.lr;
+
+       ret = next(dev);
+       mutex_unlock(&dev->dev_lock);
+       return ret;
+}
+
+static int opal_erase_locking_range(struct opal_dev *dev,
+                                   struct opal_session_info *opal_session)
+{
+       void *data[3] = { NULL };
+       static const opal_step erase_funcs[] = {
+               opal_discovery0,
+               start_auth_opal_session,
+               erase_locking_range,
+               end_opal_session,
+               NULL,
+       };
+       int ret;
+
+       mutex_lock(&dev->dev_lock);
+       setup_opal_dev(dev, erase_funcs);
+
+       dev->func_data = data;
+       dev->func_data[1] = opal_session;
+       dev->func_data[2] = opal_session;
+
+       ret = next(dev);
+       mutex_unlock(&dev->dev_lock);
+       return ret;
+}
+
+static int opal_enable_disable_shadow_mbr(struct opal_dev *dev,
+                                         struct opal_mbr_data *opal_mbr)
+{
+       void *func_data[6] = { NULL };
+       static const opal_step mbr_funcs[] = {
+               opal_discovery0,
+               start_admin1LSP_opal_session,
+               set_mbr_done,
+               end_opal_session,
+               start_admin1LSP_opal_session,
+               set_mbr_enable_disable,
+               end_opal_session,
+               NULL,
+       };
+       int ret;
+
+       if (opal_mbr->enable_disable != OPAL_MBR_ENABLE &&
+           opal_mbr->enable_disable != OPAL_MBR_DISABLE)
+               return -EINVAL;
+
+       mutex_lock(&dev->dev_lock);
+       setup_opal_dev(dev, mbr_funcs);
+       dev->func_data = func_data;
+       dev->func_data[1] = &opal_mbr->key;
+       dev->func_data[2] = &opal_mbr->enable_disable;
+       dev->func_data[4] = &opal_mbr->key;
+       dev->func_data[5] = &opal_mbr->enable_disable;
+       ret = next(dev);
+       mutex_unlock(&dev->dev_lock);
+       return ret;
+}
+
+static int opal_save(struct opal_dev *dev, struct opal_lock_unlock *lk_unlk)
+{
+       struct opal_suspend_data *suspend;
+
+       suspend = kzalloc(sizeof(*suspend), GFP_KERNEL);
+       if (!suspend)
+               return -ENOMEM;
+
+       suspend->unlk = *lk_unlk;
+       suspend->lr = lk_unlk->session.opal_key.lr;
+
+       mutex_lock(&dev->dev_lock);
+       setup_opal_dev(dev, NULL);
+       add_suspend_info(dev, suspend);
+       mutex_unlock(&dev->dev_lock);
+       return 0;
+}
+
+static int opal_add_user_to_lr(struct opal_dev *dev,
+                              struct opal_lock_unlock *lk_unlk)
+{
+       void *func_data[3] = { NULL };
+       static const opal_step funcs[] = {
+               opal_discovery0,
+               start_admin1LSP_opal_session,
+               add_user_to_lr,
+               end_opal_session,
+               NULL
+       };
+       int ret;
+
+       if (lk_unlk->l_state != OPAL_RO &&
+           lk_unlk->l_state != OPAL_RW) {
+               pr_err("Locking state was not RO or RW\n");
+               return -EINVAL;
+       }
+       if (lk_unlk->session.who < OPAL_USER1 &&
+           lk_unlk->session.who > OPAL_USER9) {
+               pr_err("Authority was not within the range of users: %d\n",
+                      lk_unlk->session.who);
+               return -EINVAL;
+       }
+       if (lk_unlk->session.sum) {
+               pr_err("%s not supported in sum. Use setup locking range\n",
+                      __func__);
+               return -EINVAL;
+       }
+
+       mutex_lock(&dev->dev_lock);
+       setup_opal_dev(dev, funcs);
+       dev->func_data = func_data;
+       dev->func_data[1] = &lk_unlk->session.opal_key;
+       dev->func_data[2] = lk_unlk;
+       ret = next(dev);
+       mutex_unlock(&dev->dev_lock);
+       return ret;
+}
+
+static int opal_reverttper(struct opal_dev *dev, struct opal_key *opal)
+{
+       void *data[2] = { NULL };
+       static const opal_step revert_funcs[] = {
+               opal_discovery0,
+               start_SIDASP_opal_session,
+               revert_tper, /* controller will terminate session */
+               NULL,
+       };
+       int ret;
+
+       mutex_lock(&dev->dev_lock);
+       setup_opal_dev(dev, revert_funcs);
+       dev->func_data = data;
+       dev->func_data[1] = opal;
+       ret = next(dev);
+       mutex_unlock(&dev->dev_lock);
+       return ret;
+}
+
+static int __opal_lock_unlock_sum(struct opal_dev *dev)
+{
+       static const opal_step ulk_funcs_sum[] = {
+               opal_discovery0,
+               start_auth_opal_session,
+               lock_unlock_locking_range_sum,
+               end_opal_session,
+               NULL
+       };
+
+       dev->funcs = ulk_funcs_sum;
+       return next(dev);
+}
+
+static int __opal_lock_unlock(struct opal_dev *dev)
+{
+       static const opal_step _unlock_funcs[] = {
+               opal_discovery0,
+               start_auth_opal_session,
+               lock_unlock_locking_range,
+               end_opal_session,
+               NULL
+       };
+
+       dev->funcs = _unlock_funcs;
+       return next(dev);
+}
+
+static int opal_lock_unlock(struct opal_dev *dev, struct opal_lock_unlock *lk_unlk)
+{
+       void *func_data[3] = { NULL };
+       int ret;
+
+       if (lk_unlk->session.who < OPAL_ADMIN1 ||
+           lk_unlk->session.who > OPAL_USER9)
+               return -EINVAL;
+
+       mutex_lock(&dev->dev_lock);
+       setup_opal_dev(dev, NULL);
+       dev->func_data = func_data;
+       dev->func_data[1] = &lk_unlk->session;
+       dev->func_data[2] = lk_unlk;
+
+       if (lk_unlk->session.sum)
+               ret = __opal_lock_unlock_sum(dev);
+       else
+               ret = __opal_lock_unlock(dev);
+
+       mutex_unlock(&dev->dev_lock);
+       return ret;
+}
+
+static int opal_take_ownership(struct opal_dev *dev, struct opal_key *opal)
+{
+       static const opal_step owner_funcs[] = {
+               opal_discovery0,
+               start_anybodyASP_opal_session,
+               get_msid_cpin_pin,
+               end_opal_session,
+               start_SIDASP_opal_session,
+               set_sid_cpin_pin,
+               end_opal_session,
+               NULL
+       };
+       void *data[6] = { NULL };
+       int ret;
+
+       if (!dev)
+               return -ENODEV;
+
+       mutex_lock(&dev->dev_lock);
+       setup_opal_dev(dev, owner_funcs);
+       dev->func_data = data;
+       dev->func_data[4] = opal;
+       dev->func_data[5] = opal;
+       ret = next(dev);
+       mutex_unlock(&dev->dev_lock);
+       return ret;
+}
+
+static int opal_activate_lsp(struct opal_dev *dev, struct opal_lr_act *opal_lr_act)
+{
+       void *data[4] = { NULL };
+       static const opal_step active_funcs[] = {
+               opal_discovery0,
+               start_SIDASP_opal_session, /* Open session as SID auth */
+               get_lsp_lifecycle,
+               activate_lsp,
+               end_opal_session,
+               NULL
+       };
+       int ret;
+
+       if (!opal_lr_act->num_lrs || opal_lr_act->num_lrs > OPAL_MAX_LRS)
+               return -EINVAL;
+
+       mutex_lock(&dev->dev_lock);
+       setup_opal_dev(dev, active_funcs);
+       dev->func_data = data;
+       dev->func_data[1] = &opal_lr_act->key;
+       dev->func_data[3] = opal_lr_act;
+       ret = next(dev);
+       mutex_unlock(&dev->dev_lock);
+       return ret;
+}
+
+static int opal_setup_locking_range(struct opal_dev *dev,
+                                   struct opal_user_lr_setup *opal_lrs)
+{
+       void *data[3] = { NULL };
+       static const opal_step lr_funcs[] = {
+               opal_discovery0,
+               start_auth_opal_session,
+               setup_locking_range,
+               end_opal_session,
+               NULL,
+       };
+       int ret;
+
+       mutex_lock(&dev->dev_lock);
+       setup_opal_dev(dev, lr_funcs);
+       dev->func_data = data;
+       dev->func_data[1] = &opal_lrs->session;
+       dev->func_data[2] = opal_lrs;
+       ret = next(dev);
+       mutex_unlock(&dev->dev_lock);
+       return ret;
+}
+
+static int opal_set_new_pw(struct opal_dev *dev, struct opal_new_pw *opal_pw)
+{
+       static const opal_step pw_funcs[] = {
+               opal_discovery0,
+               start_auth_opal_session,
+               set_new_pw,
+               end_opal_session,
+               NULL
+       };
+       void *data[3] = { NULL };
+       int ret;
+
+       if (opal_pw->session.who < OPAL_ADMIN1 ||
+           opal_pw->session.who > OPAL_USER9  ||
+           opal_pw->new_user_pw.who < OPAL_ADMIN1 ||
+           opal_pw->new_user_pw.who > OPAL_USER9)
+               return -EINVAL;
+
+       mutex_lock(&dev->dev_lock);
+       setup_opal_dev(dev, pw_funcs);
+       dev->func_data = data;
+       dev->func_data[1] = (void *) &opal_pw->session;
+       dev->func_data[2] = (void *) &opal_pw->new_user_pw;
+
+       ret = next(dev);
+       mutex_unlock(&dev->dev_lock);
+       return ret;
+}
+
+static int opal_activate_user(struct opal_dev *dev,
+                             struct opal_session_info *opal_session)
+{
+       static const opal_step act_funcs[] = {
+               opal_discovery0,
+               start_admin1LSP_opal_session,
+               internal_activate_user,
+               end_opal_session,
+               NULL
+       };
+       void *data[3] = { NULL };
+       int ret;
+
+       /* We can't activate Admin1 it's active as manufactured */
+       if (opal_session->who < OPAL_USER1 &&
+           opal_session->who > OPAL_USER9) {
+               pr_err("Who was not a valid user: %d\n", opal_session->who);
+               return -EINVAL;
+       }
+
+       mutex_lock(&dev->dev_lock);
+       setup_opal_dev(dev, act_funcs);
+       dev->func_data = data;
+       dev->func_data[1] = &opal_session->opal_key;
+       dev->func_data[2] = opal_session;
+       ret = next(dev);
+       mutex_unlock(&dev->dev_lock);
+       return ret;
+}
+
+bool opal_unlock_from_suspend(struct opal_dev *dev)
+{
+       struct opal_suspend_data *suspend;
+       void *func_data[3] = { NULL };
+       bool was_failure = false;
+       int ret = 0;
+
+       if (!dev)
+               return false;
+       if (!dev->supported)
+               return false;
+
+       mutex_lock(&dev->dev_lock);
+       setup_opal_dev(dev, NULL);
+       dev->func_data = func_data;
+
+       list_for_each_entry(suspend, &dev->unlk_lst, node) {
+               dev->state = 0;
+               dev->func_data[1] = &suspend->unlk.session;
+               dev->func_data[2] = &suspend->unlk;
+               dev->tsn = 0;
+               dev->hsn = 0;
+
+               if (suspend->unlk.session.sum)
+                       ret = __opal_lock_unlock_sum(dev);
+               else
+                       ret = __opal_lock_unlock(dev);
+               if (ret) {
+                       pr_warn("Failed to unlock LR %hhu with sum %d\n",
+                               suspend->unlk.session.opal_key.lr,
+                               suspend->unlk.session.sum);
+                       was_failure = true;
+               }
+       }
+       mutex_unlock(&dev->dev_lock);
+       return was_failure;
+}
+EXPORT_SYMBOL(opal_unlock_from_suspend);
+
+int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *arg)
+{
+       void *p;
+       int ret = -ENOTTY;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+       if (!dev)
+               return -ENOTSUPP;
+       if (!dev->supported) {
+               pr_err("Not supported\n");
+               return -ENOTSUPP;
+       }
+
+       p = memdup_user(arg,  _IOC_SIZE(cmd));
+       if (IS_ERR(p))
+               return PTR_ERR(p);
+
+       switch (cmd) {
+       case IOC_OPAL_SAVE:
+               ret = opal_save(dev, p);
+               break;
+       case IOC_OPAL_LOCK_UNLOCK:
+               ret = opal_lock_unlock(dev, p);
+               break;
+       case IOC_OPAL_TAKE_OWNERSHIP:
+               ret = opal_take_ownership(dev, p);
+               break;
+       case IOC_OPAL_ACTIVATE_LSP:
+               ret = opal_activate_lsp(dev, p);
+               break;
+       case IOC_OPAL_SET_PW:
+               ret = opal_set_new_pw(dev, p);
+               break;
+       case IOC_OPAL_ACTIVATE_USR:
+               ret = opal_activate_user(dev, p);
+               break;
+       case IOC_OPAL_REVERT_TPR:
+               ret = opal_reverttper(dev, p);
+               break;
+       case IOC_OPAL_LR_SETUP:
+               ret = opal_setup_locking_range(dev, p);
+               break;
+       case IOC_OPAL_ADD_USR_TO_LR:
+               ret = opal_add_user_to_lr(dev, p);
+               break;
+       case IOC_OPAL_ENABLE_DISABLE_MBR:
+               ret = opal_enable_disable_shadow_mbr(dev, p);
+               break;
+       case IOC_OPAL_ERASE_LR:
+               ret = opal_erase_locking_range(dev, p);
+               break;
+       case IOC_OPAL_SECURE_ERASE_LR:
+               ret = opal_secure_erase_locking_range(dev, p);
+               break;
+       default:
+               pr_warn("No such Opal Ioctl %u\n", cmd);
+       }
+
+       kfree(p);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(sed_ioctl);
index 3de3b6b8f0f1b756adc455229aedba9731113e5d..4467a8089ab890695ccf7072220d9c43d1f29c2d 100644 (file)
@@ -165,7 +165,7 @@ static int acpi_processor_errata(void)
 
 #ifdef CONFIG_ACPI_HOTPLUG_CPU
 int __weak acpi_map_cpu(acpi_handle handle,
-               phys_cpuid_t physid, int *pcpu)
+               phys_cpuid_t physid, u32 acpi_id, int *pcpu)
 {
        return -ENODEV;
 }
@@ -203,7 +203,7 @@ static int acpi_processor_hotadd_init(struct acpi_processor *pr)
        cpu_maps_update_begin();
        cpu_hotplug_begin();
 
-       ret = acpi_map_cpu(pr->handle, pr->phys_id, &pr->id);
+       ret = acpi_map_cpu(pr->handle, pr->phys_id, pr->acpi_id, &pr->id);
        if (ret)
                goto out;
 
index 0bd6307e1f3cabf199c7b4cefdfb92153a8817bd..b65f2731e9e23d9493413e2088435bd308ead065 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 /* Common info for tool signons */
 
 #define ACPICA_NAME                 "Intel ACPI Component Architecture"
-#define ACPICA_COPYRIGHT            "Copyright (c) 2000 - 2016 Intel Corporation"
+#define ACPICA_COPYRIGHT            "Copyright (c) 2000 - 2017 Intel Corporation"
 
 #if ACPI_MACHINE_WIDTH == 64
-#define ACPI_WIDTH          "-64"
+#define ACPI_WIDTH          " (64-bit version)"
 
 #elif ACPI_MACHINE_WIDTH == 32
-#define ACPI_WIDTH          "-32"
+#define ACPI_WIDTH          " (32-bit version)"
 
 #else
 #error unknown ACPI_MACHINE_WIDTH
-#define ACPI_WIDTH          "-??"
+#define ACPI_WIDTH          " (unknown bit width, not 32 or 64)"
 
 #endif
 
 /* Macros for signons and file headers */
 
 #define ACPI_COMMON_SIGNON(utility_name) \
-       "\n%s\n%s version %8.8X%s\n%s\n\n", \
+       "\n%s\n%s version %8.8X\n%s\n\n", \
        ACPICA_NAME, \
-       utility_name, ((u32) ACPI_CA_VERSION), ACPI_WIDTH, \
+       utility_name, ((u32) ACPI_CA_VERSION), \
        ACPICA_COPYRIGHT
 
 #define ACPI_COMMON_HEADER(utility_name, prefix) \
index 19d6ec815d1281bdef40c77a94d933e0a92b762f..49bf47ca54777ee0cd3cec943a14bbe29e4c7460 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 94737f8845ac6bfa23f4d6a2925d444d67444263..71743e5252f5736b6c5cb0f4b438558f4a66816a 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index dcd48bfedb4d2c8b5bb48ca5f6921ad3b31cc1fa..0d95c85cce066d5345f95581709adf9826cc0d36 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 8a0049d5cdf31b0b7655cb43b6400261d4ae727b..a2adfd42f85ccbcd0d6774f51e4600939cd9d8c3 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index edbb42e251a65334140203003fa0f0e6e4610808..1d955fe216c4b68c6b1391577d249fbf70fb95d0 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 27addcf50c379f07bb7e55a901ac350071324d2d..fd4f3cacb356aa005d49f90572f32194894c6f75 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 7ead235555cfa6e060b0cd09b00bc8789e07ce7a..29a863c8531835e7d17a82c649fca240f770d751 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 7926600549925873ca8a40d45588ddd17ee74b0d..8fd495e8fdcef2dcc68c0e3ce09e9755ff1eb861 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -770,7 +770,7 @@ union acpi_parse_value {
        char                            *operator_symbol;/* Used for C-style operator name strings */\
        char                            aml_op_name[16])        /* Op name (debug only) */
 
-/* Flags for disasm_flags field above */
+/* Internal opcodes for disasm_opcode field above */
 
 #define ACPI_DASM_BUFFER                0x00   /* Buffer is a simple data buffer */
 #define ACPI_DASM_RESOURCE              0x01   /* Buffer is a Resource Descriptor */
@@ -783,7 +783,10 @@ union acpi_parse_value {
 #define ACPI_DASM_LNOT_PREFIX           0x08   /* Start of a Lnot_equal (etc.) pair of opcodes */
 #define ACPI_DASM_LNOT_SUFFIX           0x09   /* End  of a Lnot_equal (etc.) pair of opcodes */
 #define ACPI_DASM_HID_STRING            0x0A   /* String is a _HID or _CID */
-#define ACPI_DASM_IGNORE                0x0B   /* Not used at this time */
+#define ACPI_DASM_IGNORE_SINGLE         0x0B   /* Ignore the opcode but not it's children */
+#define ACPI_DASM_SWITCH_PREDICATE      0x0C   /* Object is a predicate for a Switch or Case block */
+#define ACPI_DASM_CASE                  0x0D   /* If/Else is a Case in a Switch/Case block */
+#define ACPI_DASM_DEFAULT               0x0E   /* Else is a Default in a Switch/Case block */
 
 /*
  * Generic operation (for example:  If, While, Store)
index a3b95431b7c5cb09e3a135d3e072f7cc4685bdc8..c3337514e0ed3e5152eb3a194e45e8930b756e85 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -46,7 +46,7 @@
 
 /*
  * Extract data using a pointer. Any more than a byte and we
- * get into potential aligment issues -- see the STORE macros below.
+ * get into potential alignment issues -- see the STORE macros below.
  * Use with care.
  */
 #define ACPI_CAST8(ptr)                 ACPI_CAST_PTR (u8, (ptr))
@@ -63,7 +63,7 @@
 #define ACPI_SET64(ptr, val)            (*ACPI_CAST64 (ptr) = (u64) (val))
 
 /*
- * printf() format helper. This macros is a workaround for the difficulties
+ * printf() format helper. This macro is a workaround for the difficulties
  * with emitting 64-bit integers and 64-bit pointers with the same code
  * for both 32-bit and 64-bit hosts.
  */
 
 #define ACPI_IS_MISALIGNED(value)           (((acpi_size) value) & (sizeof(acpi_size)-1))
 
+/* Generic bit manipulation */
+
+#ifndef ACPI_USE_NATIVE_BIT_FINDER
+
+#define __ACPI_FIND_LAST_BIT_2(a, r)        ((((u8)  (a)) & 0x02) ? (r)+1 : (r))
+#define __ACPI_FIND_LAST_BIT_4(a, r)        ((((u8)  (a)) & 0x0C) ? \
+                                                                                        __ACPI_FIND_LAST_BIT_2  ((a)>>2,  (r)+2) : \
+                                                                                        __ACPI_FIND_LAST_BIT_2  ((a), (r)))
+#define __ACPI_FIND_LAST_BIT_8(a, r)        ((((u8)  (a)) & 0xF0) ? \
+                                                                                        __ACPI_FIND_LAST_BIT_4  ((a)>>4,  (r)+4) : \
+                                                                                        __ACPI_FIND_LAST_BIT_4  ((a), (r)))
+#define __ACPI_FIND_LAST_BIT_16(a, r)       ((((u16) (a)) & 0xFF00) ? \
+                                                                                        __ACPI_FIND_LAST_BIT_8  ((a)>>8,  (r)+8) : \
+                                                                                        __ACPI_FIND_LAST_BIT_8  ((a), (r)))
+#define __ACPI_FIND_LAST_BIT_32(a, r)       ((((u32) (a)) & 0xFFFF0000) ? \
+                                                                                        __ACPI_FIND_LAST_BIT_16 ((a)>>16, (r)+16) : \
+                                                                                        __ACPI_FIND_LAST_BIT_16 ((a), (r)))
+#define __ACPI_FIND_LAST_BIT_64(a, r)       ((((u64) (a)) & 0xFFFFFFFF00000000) ? \
+                                                                                        __ACPI_FIND_LAST_BIT_32 ((a)>>32, (r)+32) : \
+                                                                                        __ACPI_FIND_LAST_BIT_32 ((a), (r)))
+
+#define ACPI_FIND_LAST_BIT_8(a)             ((a) ? __ACPI_FIND_LAST_BIT_8 (a, 1) : 0)
+#define ACPI_FIND_LAST_BIT_16(a)            ((a) ? __ACPI_FIND_LAST_BIT_16 (a, 1) : 0)
+#define ACPI_FIND_LAST_BIT_32(a)            ((a) ? __ACPI_FIND_LAST_BIT_32 (a, 1) : 0)
+#define ACPI_FIND_LAST_BIT_64(a)            ((a) ? __ACPI_FIND_LAST_BIT_64 (a, 1) : 0)
+
+#define __ACPI_FIND_FIRST_BIT_2(a, r)       ((((u8) (a)) & 0x01) ? (r) : (r)+1)
+#define __ACPI_FIND_FIRST_BIT_4(a, r)       ((((u8) (a)) & 0x03) ? \
+                                                                                        __ACPI_FIND_FIRST_BIT_2  ((a), (r)) : \
+                                                                                        __ACPI_FIND_FIRST_BIT_2  ((a)>>2, (r)+2))
+#define __ACPI_FIND_FIRST_BIT_8(a, r)       ((((u8) (a)) & 0x0F) ? \
+                                                                                        __ACPI_FIND_FIRST_BIT_4  ((a), (r)) : \
+                                                                                        __ACPI_FIND_FIRST_BIT_4  ((a)>>4, (r)+4))
+#define __ACPI_FIND_FIRST_BIT_16(a, r)      ((((u16) (a)) & 0x00FF) ? \
+                                                                                        __ACPI_FIND_FIRST_BIT_8  ((a), (r)) : \
+                                                                                        __ACPI_FIND_FIRST_BIT_8  ((a)>>8, (r)+8))
+#define __ACPI_FIND_FIRST_BIT_32(a, r)      ((((u32) (a)) & 0x0000FFFF) ? \
+                                                                                        __ACPI_FIND_FIRST_BIT_16 ((a), (r)) : \
+                                                                                        __ACPI_FIND_FIRST_BIT_16 ((a)>>16, (r)+16))
+#define __ACPI_FIND_FIRST_BIT_64(a, r)      ((((u64) (a)) & 0x00000000FFFFFFFF) ? \
+                                                                                        __ACPI_FIND_FIRST_BIT_32 ((a), (r)) : \
+                                                                                        __ACPI_FIND_FIRST_BIT_32 ((a)>>32, (r)+32))
+
+#define ACPI_FIND_FIRST_BIT_8(a)            ((a) ? __ACPI_FIND_FIRST_BIT_8 (a, 1) : 0)
+#define ACPI_FIND_FIRST_BIT_16(a)           ((a) ? __ACPI_FIND_FIRST_BIT_16 (a, 1) : 0)
+#define ACPI_FIND_FIRST_BIT_32(a)           ((a) ? __ACPI_FIND_FIRST_BIT_32 (a, 1) : 0)
+#define ACPI_FIND_FIRST_BIT_64(a)           ((a) ? __ACPI_FIND_FIRST_BIT_64 (a, 1) : 0)
+
+#endif                         /* ACPI_USE_NATIVE_BIT_FINDER */
+
 /* Generic (power-of-two) rounding */
 
+#define ACPI_ROUND_UP_POWER_OF_TWO_8(a)     ((u8) \
+                                                                                       (((u16) 1) <<  ACPI_FIND_LAST_BIT_8  ((a)  - 1)))
+#define ACPI_ROUND_DOWN_POWER_OF_TWO_8(a)   ((u8) \
+                                                                                       (((u16) 1) << (ACPI_FIND_LAST_BIT_8  ((a)) - 1)))
+#define ACPI_ROUND_UP_POWER_OF_TWO_16(a)    ((u16) \
+                                                                                       (((u32) 1) <<  ACPI_FIND_LAST_BIT_16 ((a)  - 1)))
+#define ACPI_ROUND_DOWN_POWER_OF_TWO_16(a)  ((u16) \
+                                                                                       (((u32) 1) << (ACPI_FIND_LAST_BIT_16 ((a)) - 1)))
+#define ACPI_ROUND_UP_POWER_OF_TWO_32(a)    ((u32) \
+                                                                                       (((u64) 1) <<  ACPI_FIND_LAST_BIT_32 ((a)  - 1)))
+#define ACPI_ROUND_DOWN_POWER_OF_TWO_32(a)  ((u32) \
+                                                                                       (((u64) 1) << (ACPI_FIND_LAST_BIT_32 ((a)) - 1)))
 #define ACPI_IS_ALIGNED(a, s)               (((a) & ((s) - 1)) == 0)
 #define ACPI_IS_POWER_OF_TWO(a)             ACPI_IS_ALIGNED(a, a)
 
  * Bit positions start at zero.
  * MASK_BITS_ABOVE creates a mask starting AT the position and above
  * MASK_BITS_BELOW creates a mask starting one bit BELOW the position
- * MASK_BITS_ABOVE/BELOW accpets a bit offset to create a mask
- * MASK_BITS_ABOVE/BELOW_32/64 accpets a bit width to create a mask
+ * MASK_BITS_ABOVE/BELOW accepts a bit offset to create a mask
+ * MASK_BITS_ABOVE/BELOW_32/64 accepts a bit width to create a mask
  * Note: The ACPI_INTEGER_BIT_SIZE check is used to bypass compiler
  * differences with the shift operator
  */
  */
 #ifndef ACPI_NO_ERROR_MESSAGES
 /*
- * Error reporting. Callers module and line number are inserted by AE_INFO,
+ * Error reporting. The callers module and line number are inserted by AE_INFO,
  * the plist contains a set of parens to allow variable-length lists.
  * These macros are used for both the debug and non-debug versions of the code.
  */
index 7affdcdfcc816e827651f83c82979fd398c74a14..54a0c51b3e37ef7d3ca2856318d3c7740d0fd738 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 094b042678f7ab43775196817619f2a474d57708..27c3f982d8105fc5399ca357daf2c4032b55af38 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ca4bda1a60bebffe193ec2f32be34ab719fa188a..e758f098ff4b14a7d075fa8a66d1074cbc6a95ff 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -92,7 +92,7 @@
 #define ARGP_BYTELIST_OP                ARGP_LIST1 (ARGP_NAMESTRING)
 #define ARGP_CONCAT_OP                  ARGP_LIST3 (ARGP_TERMARG,    ARGP_TERMARG,       ARGP_TARGET)
 #define ARGP_CONCAT_RES_OP              ARGP_LIST3 (ARGP_TERMARG,    ARGP_TERMARG,       ARGP_TARGET)
-#define ARGP_COND_REF_OF_OP             ARGP_LIST2 (ARGP_NAME_OR_REF,ARGP_TARGET)
+#define ARGP_COND_REF_OF_OP             ARGP_LIST2 (ARGP_SIMPLENAME, ARGP_TARGET)
 #define ARGP_CONNECTFIELD_OP            ARGP_LIST1 (ARGP_NAMESTRING)
 #define ARGP_CONTINUE_OP                ARG_NONE
 #define ARGP_COPY_OP                    ARGP_LIST2 (ARGP_TERMARG,    ARGP_SIMPLENAME)
 #define ARGP_DATA_REGION_OP             ARGP_LIST4 (ARGP_NAME,       ARGP_TERMARG,       ARGP_TERMARG,   ARGP_TERMARG)
 #define ARGP_DEBUG_OP                   ARG_NONE
 #define ARGP_DECREMENT_OP               ARGP_LIST1 (ARGP_SUPERNAME)
-#define ARGP_DEREF_OF_OP                ARGP_LIST1 (ARGP_TERMARG)
+#define ARGP_DEREF_OF_OP                ARGP_LIST1 (ARGP_SUPERNAME)
 #define ARGP_DEVICE_OP                  ARGP_LIST3 (ARGP_PKGLENGTH,  ARGP_NAME,          ARGP_OBJLIST)
 #define ARGP_DIVIDE_OP                  ARGP_LIST4 (ARGP_TERMARG,    ARGP_TERMARG,       ARGP_TARGET,    ARGP_TARGET)
 #define ARGP_DWORD_OP                   ARGP_LIST1 (ARGP_DWORDDATA)
 #define ARGP_NAMEPATH_OP                ARGP_LIST1 (ARGP_NAMESTRING)
 #define ARGP_NOOP_OP                    ARG_NONE
 #define ARGP_NOTIFY_OP                  ARGP_LIST2 (ARGP_SUPERNAME,  ARGP_TERMARG)
-#define ARGP_OBJECT_TYPE_OP             ARGP_LIST1 (ARGP_NAME_OR_REF)
+#define ARGP_OBJECT_TYPE_OP             ARGP_LIST1 (ARGP_SIMPLENAME)
 #define ARGP_ONE_OP                     ARG_NONE
 #define ARGP_ONES_OP                    ARG_NONE
 #define ARGP_PACKAGE_OP                 ARGP_LIST3 (ARGP_PKGLENGTH,  ARGP_BYTEDATA,      ARGP_DATAOBJLIST)
 #define ARGP_POWER_RES_OP               ARGP_LIST5 (ARGP_PKGLENGTH,  ARGP_NAME,          ARGP_BYTEDATA,  ARGP_WORDDATA,  ARGP_OBJLIST)
 #define ARGP_PROCESSOR_OP               ARGP_LIST6 (ARGP_PKGLENGTH,  ARGP_NAME,          ARGP_BYTEDATA,  ARGP_DWORDDATA, ARGP_BYTEDATA,  ARGP_OBJLIST)
 #define ARGP_QWORD_OP                   ARGP_LIST1 (ARGP_QWORDDATA)
-#define ARGP_REF_OF_OP                  ARGP_LIST1 (ARGP_NAME_OR_REF)
+#define ARGP_REF_OF_OP                  ARGP_LIST1 (ARGP_SIMPLENAME)
 #define ARGP_REGION_OP                  ARGP_LIST4 (ARGP_NAME,       ARGP_BYTEDATA,      ARGP_TERMARG,   ARGP_TERMARG)
 #define ARGP_RELEASE_OP                 ARGP_LIST1 (ARGP_SUPERNAME)
 #define ARGP_RESERVEDFIELD_OP           ARGP_LIST1 (ARGP_NAMESTRING)
 #define ARGI_FIELD_OP                   ARGI_INVALID_OPCODE
 #define ARGI_FIND_SET_LEFT_BIT_OP       ARGI_LIST2 (ARGI_INTEGER,    ARGI_TARGETREF)
 #define ARGI_FIND_SET_RIGHT_BIT_OP      ARGI_LIST2 (ARGI_INTEGER,    ARGI_TARGETREF)
-#define ARGI_FROM_BCD_OP                ARGI_LIST2 (ARGI_INTEGER,    ARGI_FIXED_TARGET)
+#define ARGI_FROM_BCD_OP                ARGI_LIST2 (ARGI_INTEGER,    ARGI_TARGETREF)
 #define ARGI_IF_OP                      ARGI_INVALID_OPCODE
 #define ARGI_INCREMENT_OP               ARGI_LIST1 (ARGI_TARGETREF)
 #define ARGI_INDEX_FIELD_OP             ARGI_INVALID_OPCODE
 #define ARGI_SUBTRACT_OP                ARGI_LIST3 (ARGI_INTEGER,    ARGI_INTEGER,       ARGI_TARGETREF)
 #define ARGI_THERMAL_ZONE_OP            ARGI_INVALID_OPCODE
 #define ARGI_TIMER_OP                   ARG_NONE
-#define ARGI_TO_BCD_OP                  ARGI_LIST2 (ARGI_INTEGER,    ARGI_FIXED_TARGET)
-#define ARGI_TO_BUFFER_OP               ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET)
-#define ARGI_TO_DEC_STR_OP              ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET)
-#define ARGI_TO_HEX_STR_OP              ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET)
-#define ARGI_TO_INTEGER_OP              ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET)
-#define ARGI_TO_STRING_OP               ARGI_LIST3 (ARGI_BUFFER,     ARGI_INTEGER,       ARGI_FIXED_TARGET)
+#define ARGI_TO_BCD_OP                  ARGI_LIST2 (ARGI_INTEGER,    ARGI_TARGETREF)
+#define ARGI_TO_BUFFER_OP               ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_TARGETREF)
+#define ARGI_TO_DEC_STR_OP              ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_TARGETREF)
+#define ARGI_TO_HEX_STR_OP              ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_TARGETREF)
+#define ARGI_TO_INTEGER_OP              ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_TARGETREF)
+#define ARGI_TO_STRING_OP               ARGI_LIST3 (ARGI_BUFFER,     ARGI_INTEGER,       ARGI_TARGETREF)
 #define ARGI_UNLOAD_OP                  ARGI_LIST1 (ARGI_DDBHANDLE)
 #define ARGI_VAR_PACKAGE_OP             ARGI_LIST1 (ARGI_INTEGER)
 #define ARGI_WAIT_OP                    ARGI_LIST2 (ARGI_EVENT,      ARGI_INTEGER)
index 939d41113970e4dab42eb2c1d12135f079f953f0..c23c47328060b72df3ce80ce3cf51ff5f54312dd 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 888440b2cf2edc70bc5bf3293a2bcdeed9badb0e..dcfc05d40e366037bdf7e7574926882467be0ebc 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 63da1e37caba535be16d5d691ecc12de8f516469..b4d22f6e48e2773ca09288ba944079d9d3987414 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 6235642e31d38af81c8605789f8391ab58ef26c2..62134bdbeda65f442449ec2d3cfdb9b28c739165 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 94be8a8e6c082cbe5b808b049187db0657ad5cb0..c8da453bd96078fdb9899ffbffbf6a5418d0c281 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 845afb180a7e94ca67a92d0d554bea820ff678a3..6f28cfae22128671e18125d68aae11339ada64c2 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 6bd8d4bcff6540b6bed02382f47136261d529ca2..b536fd4712925184650fc411193d987fb84cdeb8 100644 (file)
@@ -7,7 +7,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #define ARGI_DEVICE_REF             0x0D
 #define ARGI_REFERENCE              0x0E
 #define ARGI_TARGETREF              0x0F       /* Target, subject to implicit conversion */
-#define ARGI_FIXED_TARGET           0x10       /* Target, no implicit conversion */
-#define ARGI_SIMPLE_TARGET          0x11       /* Name, Local, Arg -- no implicit conversion */
-#define ARGI_STORE_TARGET           0x12       /* Target for store is TARGETREF + package objects */
+#define ARGI_SIMPLE_TARGET          0x10       /* Name, Local, Arg -- no implicit conversion */
+#define ARGI_STORE_TARGET           0x11       /* Target for store is TARGETREF + package objects */
+/*
+ * #define ARGI_FIXED_TARGET           0x10     Target, no implicit conversion
+ *
+ * Removed 10/2016. ARGI_FIXED_TARGET was used for these operators:
+ *      from_BCD
+ *      to_BCD
+ *      to_decimal_string
+ *      to_hex_string
+ *      to_integer
+ *      to_buffer
+ * The purpose of this type was to disable "implicit result conversion",
+ * but this was incorrect per the ACPI spec and other ACPI implementations.
+ * These operators now have the target operand defined as a normal
+ * ARGI_TARGETREF.
+ */
 
 /* Multiple/complex types */
 
index dee6c7ea477353ab0dfd582e062f82e8828279f5..653a3d1ef5d54c2f362eb696a8ca9159e59156af 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 62bd446535f5dfacbd65af7ed25a4884ce7e3f27..5984b90eb5907cd9e465f906a566358673b1a7a5 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 147ce8894f76f85a28f28744a24b94194bc611e8..251f9477a98411ef0cc7d116dfffb6c24eb595a1 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 502bb587f1128a8a2e37194aed9e581be29f3f99..46bf270ac5256956ce77929c89e6966b611c160a 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index fe3da7c31bb71453ab69244b2b56b5ba84a9bc6c..b611cd92b5f59e266fa970ab8e0dec8b9e441b3b 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 6f05b8c271a5c9a3098ae49fb3ce40c4c4f7cfaa..4d81ea291d9388c391de2dd3c74c82523ef2e5b9 100644 (file)
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 46bd65d38df966cf3c953476c6d16f110056824a..7d08974c64c2c8f5c4fcbe154e7ffe488d191bcd 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 068214f9cc9d5b439d5b455d0ed2fdce620dad78..2626d79db064efa6a93516a7f23e7b16326c6817 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 314b94cf086ad9b4253e1a52de99f6bff6be3c7e..15c8237b8a80a711573300cf504720bd3e6c578d 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 8667f14d535edcc58020c0ac82055ac297c17c9f..8c207c7725179732059e65a44afb46b4eb2432e6 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 08eaaf350b24dcb7998fd007842a54769067810f..f2252b1ac0b3bdf532d5c7b75391d6f65a9a680d 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a414e1fa6f9dd3e9177f5c434df2dfec21a91e6b..99fb0160b8fb5c10f43f5f386f39c75cd2caffe1 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 74aa38156cdc089ed1f84bd5d93d19425cafdbad..c6bee6143266b6ee71d6ecda46c82f72ced6e94f 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ae80106d100052da4ce5196be2fbeebac23488e7..bfa972b6417196d31b9efd204c594bfa86637c9f 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 124db237775db8192d271c0f5dc9ab4fd174670a..205b8e0eded581151f2729ee950325f9d5e53897 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -430,7 +430,7 @@ acpi_status acpi_initialize_debugger(void)
 
                /* These were created with one unit, grab it */
 
-               status = acpi_os_initialize_command_signals();
+               status = acpi_os_initialize_debugger();
                if (ACPI_FAILURE(status)) {
                        acpi_os_printf("Could not get debugger mutex\n");
                        return_ACPI_STATUS(status);
@@ -482,7 +482,7 @@ void acpi_terminate_debugger(void)
                        acpi_os_sleep(100);
                }
 
-               acpi_os_terminate_command_signals();
+               acpi_os_terminate_debugger();
        }
 
        if (acpi_gbl_db_buffer) {
index ad0413beeeae61f14c8b0670406c7b83bad2cec4..287b3fd73cfcbe687bfb3a08f052c82e82656f59 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 4ddcbf1002346b284042ad89d592714cf46e524f..d31b49feaa79c308f6878feece2e2ad467963771 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 56c3aadb4cba082c553f3002b3646c3672397d61..4d885eb8eda920f4076d50876e8ddd18b4b9f1de 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 6a4b603d0e83418af244caf049180042bfdec762..c5dccc54307d105bfbd573b0578c78cb91a81e9e 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 5de3f10cab03bd315ad02d0f129e5ebed9bda524..b1842dd4edf7e31e4e1d080ce3d8346022fe62b0 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 2b3210f42a46966f608c7729f02aef6b3aadffde..31c9c7aec3d592343bdef9a626e7373208848bb8 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 45cbebaa32c08d5aec9cfb0706423ace6ad885ae..adcc72cd53a7a375c30eb61daa70e51b4d102042 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a91de2b4603c78cfe7a627c092e3e37b922bbdd8..8deaa16493a07f9382dd335f909b43a90e0c7bb3 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 77fd7c84ec39ce8da79d5b1b7345d9b6e4bf62a1..148523205d4151276e32a07d15fcf46709622c9a 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 7d8ef52fb88d23308599a1389771b7676dc66215..049fbab4e5a6183c4d1225a143ecdb5946b35eb8 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 438597cf6cc521347b7fb6134d762fae2c09cf32..78f8e6a4f72f241abb79239abd56aae88bef87b0 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index fd34040d4f44afdda54c8b7d87c76c2f9d3a4869..cafb3ab567abc10687292aeaa6ed1b397e135898 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 651f35a66cc287c1f0f30852972a11ed2b784fc9..44d4553dfbdd24d80379b23c2689942423f9afdd 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 9f32e08a07d98d8b3c2294769de9475ea9a5bddb..3e081983d2ee626561169424da66d1cd91eadf20 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index e3338698e56bf6ed0b56313fd8346b3b25481af2..da111a1f5bfbc3f5a13dcb2c249a09c8cb507634 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 80fc0b9b11e542c5a2d5b8f158a3a57fba1c5c60..d3b6b314fa5070012b65ac6431c0ee137e2966f9 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 9f015782cdd317813fdf56f49095bd3bc1855451..0ce33b0f430c4d3ecc81031918158ff86dbbbfca 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index bdb10bee13ce0fc498d73b6beabf4b921ba43f01..229382035550bc4473d13272f76753fcc6e6e8e4 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d54014cab01d7fda62ad3dc22b4071d4be0bf1fb..9c941947a06381c9f41ac4c7338c87793ec5644d 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 16ce4835e7d023eec158a0f639a94dfab259e78d..8649c6242478efa005deea96004a2d8998276f8e 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3f150d567e6486a599e8d4c288c3b1ba30d9b0fc..c8adb400330af8dc33b3dd5f6ba23169ab70907e 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 24768ca03f191ae5fc98f8c130c6c2099c53d8e5..2db61ef1b4a3bf460dabf46ef0d63ed1a085126c 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f51d43adb7d1c70743fba9d4715b6a7588fc437a..4f6bb3f016abdb94c923136b98610e59e19aa40c 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 4c6f795140402a3d74231882cb67561fe0c15115..28b447ff92df6ef7803026ca99a22d974729109a 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a9092251ce80ad05d4afba422ced31ab706bc05f..93ec528bcd9a967770f0c3d9d5a4968e36f2ac28 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3b7757c9c9168f4cae89506f4ac0531d915e69e2..8ce73b962006fbd077849cf41e53fe6a6b62f086 100644 (file)
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index e4e9260cdc574b2f80758caee70d5dc1e744a3b8..dd1b9dd64cef8e30b63087618de1502b5aebdb48 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 9179e9abe3db2e4a12f0596450985699c513836c..82e8971f23a43fb091aaebc70ea11fb3b50f02e1 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d7a3b2775505817f1e5f1849ba412c330af095fd..57718a3e029a4df3d161bd62b7e25ffad6279325 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d2743067126aff25af1dd6038041ae5368c95634..beba9d56a0d8711142fffa9ae5c20cda1f4d7f5e 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 5429c2a6bc41159053e902bef311816b0b313093..76bfb7dcae2f083f1fb7f1a5231a2e973a65c673 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c32c7829878a86719181ec025292c1f97f5a8621..61813bd43f9e42155f5a8c8730cb30e1096ffefd 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 588ad1409dbe67cc629d6ac5c55715bae1a2cdc6..f71028e334eefe6fcdf65b0ab832031c19d6263e 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -592,7 +592,6 @@ acpi_ex_convert_to_target_type(acpi_object_type destination_type,
         */
        switch (GET_CURRENT_ARG_TYPE(walk_state->op_info->runtime_args)) {
        case ARGI_SIMPLE_TARGET:
-       case ARGI_FIXED_TARGET:
        case ARGI_INTEGER_REF:  /* Handles Increment, Decrement cases */
 
                switch (destination_type) {
index 613ba6eb08bbb8899be5c7a0440a944da04a655c..d43d7da4c73486c3102597dc3f4089da48aed9d4 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 37a509d016da17313a9bfdbb018c35df6375cd42..ec614f5a3bcbf214b6499efd2dc731a28f316691 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index fce6b2e10209b01747ae2106f93cb2ad21f120af..970dc6c539949e37d653ea4afb9b44c6cfb62e0f 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d7d3ee36338b4b49d11b8112ba01a2ea53288efb..5fda981f6498863fe012dad017a4c9e3cd2bc5e8 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ee76d299b3d0da7588b09022ac6a3f668b208dd1..a656608dca84972b070a83f9c11442f0f6920e60 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 37c88b424a0286342a4870df959e244c788add6d..1a6f59079ea54449e1d917be49b895e5b153aab0 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 26faa91e930c42b013a8f6125c72dd745ec7cc1b..ecd95b3f35f19540778ee8fd6fdf948272e55ff8 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3d6af93fe5618093b5e3d69d58024b23bd63288a..ee7b62a86661644b64b31a830170a0ddcc36b2a7 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 007300433cdea4edaf31c54306cdb6ff6d9400a3..af73fcde7e5c2e1e73e8e6cd298be8bd5216c6b8 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 79ef3b6811a985fdfe16cdb6584fe0393e75d150..44ecba50c0da258b1bf10c52263b29a27dc7239e 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 69e4e269ad2f900ce1d4114d869218f3ca1f3580..ce857addc8dbd6d53a90bdf0f90d594ac3843389 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 786d53b0bb373cc6d6e0c928a375c5d3b031c296..31e4df97cbe1852728b43785d37159417cd784b4 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index aed8d345922098a1d0e6178ba98f76e5c34f7822..8de060664204eca9518477507b63ce07d9acf2de 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 31b381cae94df6c66553e52388e63a2cd3881c7e..7bcc9d809b7e97e68cd7ce7fb68b9fd8b54d8afd 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a183cb740d24d2dbf7f50435867d3a6960453351..91c1de046442f6acf668bcd7b9626ff51f1523dc 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index e1d3878be2c6e058460d9943fe47d840c678d355..7fecefc2e1b4665f73c9797f698f0fb743128010 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f29eba1dc5e9baae01fe4a1637ad775e8dfb112f..c4852429e2fff62a561e7e495da1502983e5518c 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -305,7 +305,6 @@ acpi_ex_resolve_operands(u16 opcode,
                case ARGI_OBJECT_REF:
                case ARGI_DEVICE_REF:
                case ARGI_TARGETREF:    /* Allows implicit conversion rules before store */
-               case ARGI_FIXED_TARGET: /* No implicit conversion before store to target */
                case ARGI_SIMPLE_TARGET:        /* Name, Local, or arg - no implicit conversion  */
                case ARGI_STORE_TARGET:
 
index cd70cbcf6de647ae9ec0ad7f850e37a8b64dbb07..a2f8001aeb862edf54059f2c698d5d0d021d8f11 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 13bbb2b241a3c91df26ab2456dba404e85e8c4ed..85db4716a043dbaabe9f4b64ae47f5624e65006e 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1dab82746d06b2231d580e914cb25ee51357f68e..4ba7fcbf23b052de365b0636d44bd3e7269c1309 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ac09c31cc70e4e8461f443fa94f1d7f1a94d1022..ad3b610057f3decac863ffcccb31bb01f8ee26d4 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c9ca82610d776ae7e3d46385c00168b0f5ca80c4..ae9df8672d9ef69dc10645465dfc6d99fa764c9a 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a8b857a7e9fb63291fcd5fb2dbf914b079b6cb08..34d608358eaf046dfc7b1995d04d9cad0fb12922 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3ebbb09030b40472b44805e5a611aacb004f4a9f..fad249e774b41a734c1b30e0afbbe906fbde2693 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3f2fb4b31fdc06779ba43c5a88d9b021f671b697..12626d021a9b5e546c2e591ceb5502243fc0c146 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -43,7 +43,6 @@
  */
 
 #include <acpi/acpi.h>
-#include <linux/acpi.h>
 #include "accommon.h"
 
 #define _COMPONENT          ACPI_HARDWARE
@@ -103,7 +102,7 @@ void acpi_hw_execute_sleep_method(char *method_pathname, u32 integer_argument)
 acpi_status acpi_hw_extended_sleep(u8 sleep_state)
 {
        acpi_status status;
-       u8 sleep_type_value;
+       u8 sleep_control;
        u64 sleep_status;
 
        ACPI_FUNCTION_TRACE(hw_extended_sleep);
@@ -125,18 +124,6 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state)
 
        acpi_gbl_system_awake_and_running = FALSE;
 
-       /* Flush caches, as per ACPI specification */
-
-       ACPI_FLUSH_CPU_CACHE();
-
-       status = acpi_os_prepare_extended_sleep(sleep_state,
-                                               acpi_gbl_sleep_type_a,
-                                               acpi_gbl_sleep_type_b);
-       if (ACPI_SKIP(status))
-               return_ACPI_STATUS(AE_OK);
-       if (ACPI_FAILURE(status))
-               return_ACPI_STATUS(status);
-
        /*
         * Set the SLP_TYP and SLP_EN bits.
         *
@@ -146,12 +133,22 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state)
        ACPI_DEBUG_PRINT((ACPI_DB_INIT,
                          "Entering sleep state [S%u]\n", sleep_state));
 
-       sleep_type_value =
-           ((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) &
-            ACPI_X_SLEEP_TYPE_MASK);
+       sleep_control = ((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) &
+                        ACPI_X_SLEEP_TYPE_MASK) | ACPI_X_SLEEP_ENABLE;
+
+       /* Flush caches, as per ACPI specification */
+
+       ACPI_FLUSH_CPU_CACHE();
+
+       status = acpi_os_enter_sleep(sleep_state, sleep_control, 0);
+       if (status == AE_CTRL_TERMINATE) {
+               return_ACPI_STATUS(AE_OK);
+       }
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(status);
+       }
 
-       status = acpi_write((u64)(sleep_type_value | ACPI_X_SLEEP_ENABLE),
-                           &acpi_gbl_FADT.sleep_control);
+       status = acpi_write((u64)sleep_control, &acpi_gbl_FADT.sleep_control);
        if (ACPI_FAILURE(status)) {
                return_ACPI_STATUS(status);
        }
index 76b0e350f5bb0de70f41d51db70deea785b12f84..5eb11b30a79e6c685118e660a5d294c93d02e527 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3dd60c96aa07398bb8072ccce5c3ea0545cc72c0..283819930be6b57607ad3000c59e684b685b5920 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3b7fb99362b6945ecc5ebe3f192405718ecd33fb..de74a4c25085b63b1b0fa8d0d29e8ac1a0b93521 100644 (file)
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -52,7 +52,8 @@ ACPI_MODULE_NAME("hwregs")
 #if (!ACPI_REDUCED_HARDWARE)
 /* Local Prototypes */
 static u8
-acpi_hw_get_access_bit_width(struct acpi_generic_address *reg,
+acpi_hw_get_access_bit_width(u64 address,
+                            struct acpi_generic_address *reg,
                             u8 max_bit_width);
 
 static acpi_status
@@ -71,7 +72,8 @@ acpi_hw_write_multiple(u32 value,
  *
  * FUNCTION:    acpi_hw_get_access_bit_width
  *
- * PARAMETERS:  reg                 - GAS register structure
+ * PARAMETERS:  address             - GAS register address
+ *              reg                 - GAS register structure
  *              max_bit_width       - Max bit_width supported (32 or 64)
  *
  * RETURN:      Status
@@ -81,27 +83,59 @@ acpi_hw_write_multiple(u32 value,
  ******************************************************************************/
 
 static u8
-acpi_hw_get_access_bit_width(struct acpi_generic_address *reg, u8 max_bit_width)
+acpi_hw_get_access_bit_width(u64 address,
+                            struct acpi_generic_address *reg, u8 max_bit_width)
 {
-       if (!reg->access_width) {
-               if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
-                       max_bit_width = 32;
-               }
+       u8 access_bit_width;
 
-               /*
-                * Detect old register descriptors where only the bit_width field
-                * makes senses.
-                */
-               if (reg->bit_width < max_bit_width &&
-                   !reg->bit_offset && reg->bit_width &&
-                   ACPI_IS_POWER_OF_TWO(reg->bit_width) &&
-                   ACPI_IS_ALIGNED(reg->bit_width, 8)) {
-                       return (reg->bit_width);
-               }
-               return (max_bit_width);
+       /*
+        * GAS format "register", used by FADT:
+        *  1. Detected if bit_offset is 0 and bit_width is 8/16/32/64;
+        *  2. access_size field is ignored and bit_width field is used for
+        *     determining the boundary of the IO accesses.
+        * GAS format "region", used by APEI registers:
+        *  1. Detected if bit_offset is not 0 or bit_width is not 8/16/32/64;
+        *  2. access_size field is used for determining the boundary of the
+        *     IO accesses;
+        *  3. bit_offset/bit_width fields are used to describe the "region".
+        *
+        * Note: This algorithm assumes that the "Address" fields should always
+        *       contain aligned values.
+        */
+       if (!reg->bit_offset && reg->bit_width &&
+           ACPI_IS_POWER_OF_TWO(reg->bit_width) &&
+           ACPI_IS_ALIGNED(reg->bit_width, 8)) {
+               access_bit_width = reg->bit_width;
+       } else if (reg->access_width) {
+               access_bit_width = (1 << (reg->access_width + 2));
        } else {
-               return (1 << (reg->access_width + 2));
+               access_bit_width =
+                   ACPI_ROUND_UP_POWER_OF_TWO_8(reg->bit_offset +
+                                                reg->bit_width);
+               if (access_bit_width <= 8) {
+                       access_bit_width = 8;
+               } else {
+                       while (!ACPI_IS_ALIGNED(address, access_bit_width >> 3)) {
+                               access_bit_width >>= 1;
+                       }
+               }
        }
+
+       /* Maximum IO port access bit width is 32 */
+
+       if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
+               max_bit_width = 32;
+       }
+
+       /*
+        * Return access width according to the requested maximum access bit width,
+        * as the caller should know the format of the register and may enforce
+        * a 32-bit accesses.
+        */
+       if (access_bit_width < max_bit_width) {
+               return (access_bit_width);
+       }
+       return (max_bit_width);
 }
 
 /******************************************************************************
@@ -163,7 +197,8 @@ acpi_hw_validate_register(struct acpi_generic_address *reg,
 
        /* Validate the bit_width, convert access_width into number of bits */
 
-       access_width = acpi_hw_get_access_bit_width(reg, max_bit_width);
+       access_width =
+           acpi_hw_get_access_bit_width(*address, reg, max_bit_width);
        bit_width =
            ACPI_ROUND_UP(reg->bit_offset + reg->bit_width, access_width);
        if (max_bit_width < bit_width) {
@@ -219,7 +254,7 @@ acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
         * into number of bits based
         */
        *value = 0;
-       access_width = acpi_hw_get_access_bit_width(reg, 32);
+       access_width = acpi_hw_get_access_bit_width(address, reg, 32);
        bit_width = reg->bit_offset + reg->bit_width;
        bit_offset = reg->bit_offset;
 
@@ -252,20 +287,6 @@ acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
                                                           &value32,
                                                           access_width);
                        }
-
-                       /*
-                        * Use offset style bit masks because:
-                        * bit_offset < access_width/bit_width < access_width, and
-                        * access_width is ensured to be less than 32-bits by
-                        * acpi_hw_validate_register().
-                        */
-                       if (bit_offset) {
-                               value32 &= ACPI_MASK_BITS_BELOW(bit_offset);
-                               bit_offset = 0;
-                       }
-                       if (bit_width < access_width) {
-                               value32 &= ACPI_MASK_BITS_ABOVE(bit_width);
-                       }
                }
 
                /*
@@ -306,6 +327,12 @@ acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
 acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg)
 {
        u64 address;
+       u8 access_width;
+       u32 bit_width;
+       u8 bit_offset;
+       u64 value64;
+       u32 value32;
+       u8 index;
        acpi_status status;
 
        ACPI_FUNCTION_NAME(hw_write);
@@ -317,23 +344,61 @@ acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg)
                return (status);
        }
 
+       /* Convert access_width into number of bits based */
+
+       access_width = acpi_hw_get_access_bit_width(address, reg, 32);
+       bit_width = reg->bit_offset + reg->bit_width;
+       bit_offset = reg->bit_offset;
+
        /*
         * Two address spaces supported: Memory or IO. PCI_Config is
         * not supported here because the GAS structure is insufficient
         */
-       if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
-               status = acpi_os_write_memory((acpi_physical_address)
-                                             address, (u64)value,
-                                             reg->bit_width);
-       } else {                /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
-
-               status = acpi_hw_write_port((acpi_io_address)
-                                           address, value, reg->bit_width);
+       index = 0;
+       while (bit_width) {
+               /*
+                * Use offset style bit reads because "Index * AccessWidth" is
+                * ensured to be less than 32-bits by acpi_hw_validate_register().
+                */
+               value32 = ACPI_GET_BITS(&value, index * access_width,
+                                       ACPI_MASK_BITS_ABOVE_32(access_width));
+
+               if (bit_offset >= access_width) {
+                       bit_offset -= access_width;
+               } else {
+                       if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+                               value64 = (u64)value32;
+                               status =
+                                   acpi_os_write_memory((acpi_physical_address)
+                                                        address +
+                                                        index *
+                                                        ACPI_DIV_8
+                                                        (access_width),
+                                                        value64, access_width);
+                       } else {        /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
+
+                               status = acpi_hw_write_port((acpi_io_address)
+                                                           address +
+                                                           index *
+                                                           ACPI_DIV_8
+                                                           (access_width),
+                                                           value32,
+                                                           access_width);
+                       }
+               }
+
+               /*
+                * Index * access_width is ensured to be less than 32-bits by
+                * acpi_hw_validate_register().
+                */
+               bit_width -=
+                   bit_width > access_width ? access_width : bit_width;
+               index++;
        }
 
        ACPI_DEBUG_PRINT((ACPI_DB_IO,
                          "Wrote: %8.8X width %2d   to %8.8X%8.8X (%s)\n",
-                         value, reg->bit_width, ACPI_FORMAT_UINT64(address),
+                         value, access_width, ACPI_FORMAT_UINT64(address),
                          acpi_ut_get_region_name(reg->space_id)));
 
        return (status);
index d00c9810845b2f3a2ccf3827674db1fd5678bcf2..1fe7387a00e6789daef9cabc946679150ea8f58b 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -43,7 +43,6 @@
  */
 
 #include <acpi/acpi.h>
-#include <linux/acpi.h>
 #include "accommon.h"
 
 #define _COMPONENT          ACPI_HARDWARE
@@ -152,12 +151,14 @@ acpi_status acpi_hw_legacy_sleep(u8 sleep_state)
 
        ACPI_FLUSH_CPU_CACHE();
 
-       status = acpi_os_prepare_sleep(sleep_state, pm1a_control,
-                                      pm1b_control);
-       if (ACPI_SKIP(status))
+       status = acpi_os_enter_sleep(sleep_state, pm1a_control, pm1b_control);
+       if (status == AE_CTRL_TERMINATE) {
                return_ACPI_STATUS(AE_OK);
-       if (ACPI_FAILURE(status))
+       }
+       if (ACPI_FAILURE(status)) {
                return_ACPI_STATUS(status);
+       }
+
        /* Write #2: Write both SLP_TYP + SLP_EN */
 
        status = acpi_hw_write_pm1_control(pm1a_control, pm1b_control);
index 04cc9406c7d8c3296fe500fb2b3f0e07d1f95611..b3c5d8c754bb864a0ddf18ac4759bbb301a1e93f 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ad0a745712a97efdf44068e0e1f2cebcbc4ccd82..531620abed803c7ffac13ba6425e9be0486684d3 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 98c26ff394092fa74e5f63c1b910289343d7e4e0..34684ae899810889738fee7bbe3c2d2f806d4d01 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f76e0eab32b8ec6b8ae48c68f489ddf19845690e..5733b1167e46cd1207d1d6c88345c4c541a745d8 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 73f98d3fed25e13e1f33ebf5e268d8dc1b971e87..498bb8f70e6beba2506c822fed98b97f6f8d30e7 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c2cf73fd3918b633a5d797c6e48aa24aec0b4f6d..8ba5b32c9f717316d40eb43a75e861ae91e9ca29 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f45bff6326920ce710a575cd0b7a6f53b1ab4a18..9095d51f6b372cf479b6dd37b7606496bfc5b768 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 2b85dee6d4c04621d9bb06a3888b6ba5ef97a318..e4a7da8a11f0ac014cee2a8b3013f5d8e3bc9024 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 84f35dd270338fc099f98ca9823fe20ec8e3085e..4123b5077a7d4e50b78f20ccf69bdc0ea56398f7 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 7060a5668989cfa4d1f14548059435a46a92678d..5026594763eaf0192e141418d967deef8d48ea29 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 5d59cfcef6f4eb8a5e8fa0a1b1fdaee40fff1dba..d22167cbd0ca65d8b758ffcc2c7d0afa40e5cc36 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 36643a8cf65a03b7694401befecf6000192f0c52..ce33e7297ea7768ccd937c2cda2f46132d887a93 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d1f20143bb113ffdc751514d793f929aab38bec1..d2915e186ae14a108743f392f1aefedffdadef10 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 94d5d3339845f954110c5214305c775117c3d231..3db9ca25a62086eb59ce6f6481fd7f2a246ff707 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index cfa2bb7162d83ef9056c38e3389d313f81000c7a..707b2aa501e1b4b98f113e189de862923b795f6a 100644 (file)
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 4f14e9205bff75b841aebdb897cc6f498b1d551d..2fc33a5203f40a609f2c625a80b69d007d7c6d25 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 6d7844580b2a1c0e852824fa249d668a958f5ea5..3dbbecf220879cc7bd551b807f35d9b1fb8ad390 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index fbedc6e8ab3653e1fce44ba8c1c88f1232fed69f..4954cb6c909010cef7e91e816ab3cb9491624c04 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 9523d41c7ae900c99266668b248b85059224a606..38316266521ea3f67367c1b4549a5166ec4cd750 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d5336122486bb2a568086d468278708f2e74deef..352265498e90e9298ab7cf4fe0c6a715de478d0c 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 61036d210274bb4ba00bbdfaedb75cc8c4da0f51..5de8957f5ef025ecb8ba5d16d8c880feffc20eb3 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 691814dfed313123b739bcb5a4a53e58d6d32ddc..661676714f7b8227e58e2f6343946ad4c1685eab 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ebd731fe8e457733cf6d52840ca1569072b1d81f..6b6e6f498cffb614250b48cb7da7c201ccc6aaca 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d2a9b4fd739f66447d72d282a11a997b921cd515..8e365c0e766bfa85aedcd9e7945148d2d26ce3c0 100644 (file)
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index e525cbe7d83b63966e9050ebd6d8bbfb36c3fa9f..10696623580505135c9a9ea96437a5996e2d75e3 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 32d372b8524335f03bb69bca5a08201334d8a3df..47f689ec3fcbca48d3824c41e2b80ac722ab59a7 100644 (file)
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c29c930ffa0862bf8bc4ebfae09536a93de7d770..05b62ad44c3ecb4f3d4943695113a36026d0d5a7 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -269,23 +269,27 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state,
         */
        if (ACPI_SUCCESS(status) &&
            possible_method_call && (node->type == ACPI_TYPE_METHOD)) {
-               if (walk_state->opcode == AML_UNLOAD_OP) {
+               if ((GET_CURRENT_ARG_TYPE(walk_state->arg_types) ==
+                    ARGP_SUPERNAME)
+                   || (GET_CURRENT_ARG_TYPE(walk_state->arg_types) ==
+                       ARGP_TARGET)) {
                        /*
-                        * acpi_ps_get_next_namestring has increased the AML pointer,
-                        * so we need to restore the saved AML pointer for method call.
+                        * acpi_ps_get_next_namestring has increased the AML pointer past
+                        * the method invocation namestring, so we need to restore the
+                        * saved AML pointer back to the original method invocation
+                        * namestring.
                         */
                        walk_state->parser_state.aml = start;
                        walk_state->arg_count = 1;
                        acpi_ps_init_op(arg, AML_INT_METHODCALL_OP);
-                       return_ACPI_STATUS(AE_OK);
                }
 
                /* This name is actually a control method invocation */
 
                method_desc = acpi_ns_get_attached_object(node);
                ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
-                                 "Control Method - %p Desc %p Path=%p\n", node,
-                                 method_desc, path));
+                                 "Control Method invocation %4.4s - %p Desc %p Path=%p\n",
+                                 node->name.ascii, node, method_desc, path));
 
                name_op = acpi_ps_alloc_op(AML_INT_NAMEPATH_OP, start);
                if (!name_op) {
@@ -719,6 +723,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
 
        ACPI_FUNCTION_TRACE_PTR(ps_get_next_arg, parser_state);
 
+       ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
+                         "Expected argument type ARGP: %s (%2.2X)\n",
+                         acpi_ut_get_argument_type_name(arg_type), arg_type));
+
        switch (arg_type) {
        case ARGP_BYTEDATA:
        case ARGP_WORDDATA:
@@ -796,11 +804,14 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
                }
                break;
 
-       case ARGP_TARGET:
-       case ARGP_SUPERNAME:
        case ARGP_SIMPLENAME:
        case ARGP_NAME_OR_REF:
 
+               ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
+                                 "**** SimpleName/NameOrRef: %s (%2.2X)\n",
+                                 acpi_ut_get_argument_type_name(arg_type),
+                                 arg_type));
+
                subop = acpi_ps_peek_opcode(parser_state);
                if (subop == 0 ||
                    acpi_ps_is_leading_char(subop) ||
@@ -816,28 +827,49 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
                                return_ACPI_STATUS(AE_NO_MEMORY);
                        }
 
-                       /* To support super_name arg of Unload */
-
-                       if (walk_state->opcode == AML_UNLOAD_OP) {
-                               status =
-                                   acpi_ps_get_next_namepath(walk_state,
-                                                             parser_state, arg,
-                                                             ACPI_POSSIBLE_METHOD_CALL);
-
-                               /*
-                                * If the super_name argument is a method call, we have
-                                * already restored the AML pointer, just free this Arg
-                                */
-                               if (arg->common.aml_opcode ==
-                                   AML_INT_METHODCALL_OP) {
-                                       acpi_ps_free_op(arg);
-                                       arg = NULL;
-                               }
-                       } else {
-                               status =
-                                   acpi_ps_get_next_namepath(walk_state,
-                                                             parser_state, arg,
-                                                             ACPI_NOT_METHOD_CALL);
+                       status =
+                           acpi_ps_get_next_namepath(walk_state, parser_state,
+                                                     arg,
+                                                     ACPI_NOT_METHOD_CALL);
+               } else {
+                       /* Single complex argument, nothing returned */
+
+                       walk_state->arg_count = 1;
+               }
+               break;
+
+       case ARGP_TARGET:
+       case ARGP_SUPERNAME:
+
+               ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
+                                 "**** Target/Supername: %s (%2.2X)\n",
+                                 acpi_ut_get_argument_type_name(arg_type),
+                                 arg_type));
+
+               subop = acpi_ps_peek_opcode(parser_state);
+               if (subop == 0 ||
+                   acpi_ps_is_leading_char(subop) ||
+                   ACPI_IS_ROOT_PREFIX(subop) ||
+                   ACPI_IS_PARENT_PREFIX(subop)) {
+
+                       /* NULL target (zero). Convert to a NULL namepath */
+
+                       arg =
+                           acpi_ps_alloc_op(AML_INT_NAMEPATH_OP,
+                                            parser_state->aml);
+                       if (!arg) {
+                               return_ACPI_STATUS(AE_NO_MEMORY);
+                       }
+
+                       status =
+                           acpi_ps_get_next_namepath(walk_state, parser_state,
+                                                     arg,
+                                                     ACPI_POSSIBLE_METHOD_CALL);
+
+                       if (arg->common.aml_opcode == AML_INT_METHODCALL_OP) {
+                               acpi_ps_free_op(arg);
+                               arg = NULL;
+                               walk_state->arg_count = 1;
                        }
                } else {
                        /* Single complex argument, nothing returned */
@@ -849,6 +881,11 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
        case ARGP_DATAOBJ:
        case ARGP_TERMARG:
 
+               ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
+                                 "**** TermArg/DataObj: %s (%2.2X)\n",
+                                 acpi_ut_get_argument_type_name(arg_type),
+                                 arg_type));
+
                /* Single complex argument, nothing returned */
 
                walk_state->arg_count = 1;
index 6a9f5059f682cbe0f24f26f875a826cc41e1324b..14d689606d2f5695c7a9c956bd62a3e2795a195a 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -92,6 +92,10 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
 
        ACPI_FUNCTION_TRACE_PTR(ps_get_arguments, walk_state);
 
+       ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
+                         "Get arguments for opcode [%s]\n",
+                         op->common.aml_op_name));
+
        switch (op->common.aml_opcode) {
        case AML_BYTE_OP:       /* AML_BYTEDATA_ARG */
        case AML_WORD_OP:       /* AML_WORDDATA_ARG */
index db0e90342e82f5cb498b875ac62247a9d5ea6d02..5c4aff0f4f26e116a0c4e125883fb1eda97c072c 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -348,7 +348,15 @@ acpi_ps_create_op(struct acpi_walk_state *walk_state,
                            argument_count) {
                                op->common.flags |= ACPI_PARSEOP_TARGET;
                        }
-               } else if (parent_scope->common.aml_opcode == AML_INCREMENT_OP) {
+               }
+
+               /*
+                * Special case for both Increment() and Decrement(), where
+                * the lone argument is both a source and a target.
+                */
+               else if ((parent_scope->common.aml_opcode == AML_INCREMENT_OP)
+                        || (parent_scope->common.aml_opcode ==
+                            AML_DECREMENT_OP)) {
                        op->common.flags |= ACPI_PARSEOP_TARGET;
                }
        }
index 8e0c97dca01f7b32855db39a8867082584699a78..451b672915f11f7eacc7c3b6f81148e3c1dd09d2 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 177b05b239b701235105dbfcd746de7fbe2a553b..89f95b7f26e9ec3f68060a9384b4c25164843507 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1ce26d9f8ff66057c4b3cba078824ae596212a38..a813bbbd5a8bc0bf6454e5de8c4c7e3e66b250ae 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 560c3684ef431431d521d36b8f68a23e952788a6..22d7f1d6849b31284643653f78168c422d409935 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 0288cdbda88e8422e9393cdcdf5213da838eb96f..9677fff8fd4723a925ebb3a37fd3e827361b5a28 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -129,10 +129,10 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg)
        union acpi_parse_object *prev_arg;
        const struct acpi_opcode_info *op_info;
 
-       ACPI_FUNCTION_ENTRY();
+       ACPI_FUNCTION_TRACE(ps_append_arg);
 
        if (!op) {
-               return;
+               return_VOID;
        }
 
        /* Get the info structure for this opcode */
@@ -144,7 +144,7 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg)
 
                ACPI_ERROR((AE_INFO, "Invalid AML Opcode: 0x%2.2X",
                            op->common.aml_opcode));
-               return;
+               return_VOID;
        }
 
        /* Check if this opcode requires argument sub-objects */
@@ -153,7 +153,7 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg)
 
                /* Has no linked argument objects */
 
-               return;
+               return_VOID;
        }
 
        /* Append the argument to the linked argument list */
@@ -181,6 +181,8 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg)
 
                op->common.arg_list_length++;
        }
+
+       return_VOID;
 }
 
 /*******************************************************************************
index 89cb4bffcc7c047b2fd9f86721cc7e70aeb6feae..2fa38bb76a55d708a3036be3a4a57b30b03cb720 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 04f98c0a768486ec4309b6163773931de5ab27b1..22a37c82af19acafe90f21e6e91aff06194c92d6 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f3c87264bd1b061824f6683cafc2c5c6fe7ec261..c88a681586bf3b8739f2bf2e2184a74040a04752 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 492d5b011f33add0cbad6bc7f7e9cf4cbdb02cff..a131a28bb09d6dc7698da8c10ad0090fb7d2579e 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f1e83addd5b431c5522c1d9b9e20901ecd51b0b7..74e47f829ccbaace449a20a20ab3cfff8743a42a 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 809b61c114fef1c008565bead600c1bcd28499b1..f72ff0b54a639d543eb8636c4a4e36c4ff4b15a5 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 5ffdb5602d8db31d2c06776e4f5846252f1129da..f4cdf8d832dcd5a3c4953edd02d993cbc5f8914d 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 61e8f16c857d66413e7dfc5fc52255fb482434fc..8aacd28293fab8145836fa6b8433698f9f07715c 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 8e067cb7397397de588f471b8f55d6b72bf29e95..475da9d6aed5a31daed58976f934e5ec59cff0d6 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 07dfbed10d556a01d5aa230061a1f9afa4933d0f..b7a47fbc519b6566aa7ddb488545a468f7d7734e 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index bc8f34590d9565cba48f429d7e7bd7750bfdb2a1..092a733c42b80fbab2800271ef1175c4416c0cb8 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 8c42dd73455902dd2f016e659710005de91177c4..36a6657dd34d210702c547efbe6f858e844d8cca 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 88b53ef9105d9a1ba92983ada98565cb2a4a4e23..273eecb3001b428526fbee98c7543a52f588df05 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 25165ca420514435ae119435712c7287fc581654..2ae79613f6b703f04a019da4c07cd7476f1af0c7 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index b82c061f205a0c6888986c9705d4c6454fe46390..c20e6d07928df25eb5e3fbdd83f80193a707fcaf 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index fa491c64c0404bef4c16904e1a1535c663a199e8..b2aeca01204a096ef52eec6e9eeae70d92515010 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 465ed8137167ce6112387e719c4d299b14aa1268..59a4f9ed06a7cc61b9e0435aaa2361a377fdfb26 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index b0399e8f6d27df774b175cb2a3aa7c8f3cce7189..27c5c27d481810ded9d5baf08e63d9005bf2798d 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 81473a4880ce219febb9024515cc92759362d426..51860bfc111e82a5a73a265220f9b2c0ea5908db 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f6b9b4e4298bac5f74a93b7dd1a776dd2d4f7215..fea89c8d305cb405bc541d58157ac6cc92cffa9c 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 01e1b3d63fc0dc8ae0e0b17767dae535be2bec68..4620f3c68c13d9c653f8ef92ab7a688a404c4b4c 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 26d61dbace0a1fa67b8706cc1ee0d124ac3d7e01..edfd7b10be19f2725cc08792b74f769097ab2134 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 86854e84680056e164c6adad591ad772e85a3e79..5a968a78652bd23d269fbc871957a4488fb03af6 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 7684707b254b93cf7b7c9aa90ef3346d50609ee7..010b1c43df922be2796a54c6f9131232f345d4d6 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 82019c01a0e58edd7c8382fb9bcf7fadddf4f67b..b71ce3b817ea4d2d91a983bcfd907d26816f0419 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 0adb1c78d863d30a80cf9cc4726bb92d8ecd81c6..f9f9a7da2cadeec6792e386b50a2ad981937b9cf 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 433d822798b6a742924fdaedf5aa206d7f62cdaa..26a0633115be33c8cc9b8177e36a2ff8d908bba2 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 13324a27b99b3ea666807f6698bd0685a2a1dc28..a3401bd29413a17b7a2decec19c406cbc05ab3f2 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 706c1f346490a4c165b7d67815723f40e8565a17..909bdb19865158ed61cf25a884b2d57dd88b6cee 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ff2981275b9aeacb6041617c066d1f9ebbf3b0cf..f17eaa009dde7597caa98a8481b16c2411130c84 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3b8d23ef351fe5dff1996d268a9689f14e2d2d79..11c7f72f2d5608d4baa2e441275e7ad39e7aa707 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 82f971402d85dd62d5bc29e0dd3e4e766380ee5e..e9382255d6c6cc91bcbf4b656d6e3d7f231bfc03 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 044df9b0356e876bb80a1d7b51c47af42188124b..bd5ea3101eb77a07082f65089caa14855233f86f 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index b3d8421cfb8079b1f3b78b71f43cc4d2bbb63402..60868309e32662489d609a86d650ae1d9ac2a333 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -238,7 +238,7 @@ const char *acpi_ut_get_object_type_name(union acpi_operand_object *obj_desc)
 
        if (!obj_desc) {
                ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Null Object Descriptor\n"));
-               return_PTR("[NULL Object Descriptor]");
+               return_STR("[NULL Object Descriptor]");
        }
 
        /* These descriptor types share a common area */
@@ -251,7 +251,7 @@ const char *acpi_ut_get_object_type_name(union acpi_operand_object *obj_desc)
                                  acpi_ut_get_descriptor_name(obj_desc),
                                  obj_desc));
 
-               return_PTR("Invalid object");
+               return_STR("Invalid object");
        }
 
        return_STR(acpi_ut_get_type_name(obj_desc->common.type));
index 529d6c38ea7cea181743b8d9ec1883b303368fa5..c6eb9fae70f9a6feeb082dc07c1b9a404a22030f 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -421,8 +421,10 @@ acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action)
                }
 
                ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
-                                 "Obj %p Type %.2X Refs %.2X [Incremented]\n",
-                                 object, object->common.type, new_count));
+                                 "Obj %p Type %.2X [%s] Refs %.2X [Incremented]\n",
+                                 object, object->common.type,
+                                 acpi_ut_get_object_type_name(object),
+                                 new_count));
                break;
 
        case REF_DECREMENT:
index 475932cecf1a647b02789f0c2cc062b5532ff8f9..e3368186e1c1bd72e903a0625a3d6639cb55ebaf 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 7bad13f2e518a184f8fd79c7b09512af3b5a7abf..3fce7519c6902fcad2c65e9cda915611496d1087 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 695240338e0061f0c5cc4a09519beeab535a9aa2..eb6dcab33d2f895c78c49150de219db1170fdd6b 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index dd3fd7f97f8e2520fffeb17495c879e314845ed0..230a50c82f22c4b17b3de8686132f811f97a87d9 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 36d2fc789088526b73aa7152f4b87faa50a92e56..6600bc257516a0c79454f988766249bc169aa25f 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f7cd2d52643b99a69609ad0e600d7bd4df532266..a6eb580ee21d7a6a0f0f920a6570b8135f557593 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1711fdf417093edef47a452d3147e74edb14e080..23e766d1691d25bef090dfed3d1db25c3a481281 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3cd0978925ef25f139611ac21e667c3140b987de..db2d9910866ee2a5daf403d80b467c403132495b 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 2d6530ee7e51df61f25aed5fd676f93f9c65d042..aa0502d1d019ff3a4ed602a9b0307fc40bd7026c 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 389de3bd1ff1fa2c27b511d1671d9b43c9a2fae0..443ffad01209b551786ac62af100c29f5fcdc015 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 15073375bd002994fa11c4165d68e56812698aaa..5863547880182423b8917d7d458496f8b5ac9438 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 2514239282c2adf6463576372c98c9f8578f9c69..792664982ea3c0d610cd7f439910230c461ff4ab 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 72b9a062bbabff22eb52ace5918d648f10d848f1..64e6641bfe824a5e6afd4bf7a4fa92766917d7e4 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f0484b058c4493088ce63a5f685ec68bbada94a7..3175b133c0e4fb87ea0bbe606e615364984e1f7a 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3cd573c5f7f9249e075a561170f1223b0b3534b2..c82399f9b4561112b98a0baaa6b6dbc2c4fc5290 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ce18346b614427124e63ecc23fadd0522dd13cb2..350709f23e4cf76869462aac97627fa19076821a 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 40eba804d49c56b6b126a878a0840ed5d3218f8e..7e6e1ae6140fd8cc7bbe0e5469f31835204bcc80 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1de3376da66a5ec4ff19cafa292b0bba32815a1e..c86bae7b1d0fc4d0fce5832a1f2716f59d91a7e6 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -421,8 +421,10 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state,
 
        ACPI_FUNCTION_TRACE(ut_walk_aml_resources);
 
-       /* The absolute minimum resource template is one end_tag descriptor */
-
+       /*
+        * The absolute minimum resource template is one end_tag descriptor.
+        * However, we will treat a lone end_tag as just a simple buffer.
+        */
        if (aml_length < sizeof(struct aml_resource_end_tag)) {
                return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
        }
@@ -454,9 +456,8 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state,
                /* Invoke the user function */
 
                if (user_function) {
-                       status =
-                           user_function(aml, length, offset, resource_index,
-                                         context);
+                       status = user_function(aml, length, offset,
+                                              resource_index, context);
                        if (ACPI_FAILURE(status)) {
                                return_ACPI_STATUS(status);
                        }
@@ -480,6 +481,12 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state,
                                *context = aml;
                        }
 
+                       /* Check if buffer is defined to be longer than the resource length */
+
+                       if (aml_length > (offset + length)) {
+                               return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
+                       }
+
                        /* Normal exit */
 
                        return_ACPI_STATUS(AE_OK);
index f3d4dbd5fac0d1e8000eb257e7df84c75a1c6d7a..64308c304ade735f795fe3a091997d9db1173080 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 288913a0e709791ded0e6752eade316738e42ba0..9eacbcb9e4f457806c0b5d5e3d155778463b25ee 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index b4f341c98a9584d7a8a55fc0500bef2983e96320..f42be01d99fdd48d22edbbf9ce56c275e949e253 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index df31d71ce596fa7279566940fe6f78f7ca554ce3..9a07a42cae3495f96d4e2a00266a41a2d3fdd820 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 81088ff9d67b799999adef4a0189117b58bf7946..5028e06718b1c2742e51a18fffa82ea09f7244d0 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ec503c8629616ba23d1834374e02bbbf4df717f0..6b9ba4029f8e968c4e4ce5ec0410fa86fdd7ee64 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d9f15cbcd8a0b9228382042abdd802b4322d11ba..a16bd9eac6537b4660539d9669156cce2eb924a2 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a5ca0f57cd08f790334c1a7302b4c1dfb15a757c..6d5180601cf2a395c8e067560948da57dc127336 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 850de0155528853096017983ecbde94c9b7c9f4c..c016211c35ae1249100903357b0a2b4f50eb3105 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index eebb7e39c49c7c94dd9f31b0d5d992d323a62c63..ec50c32ea3da0496ca20e7d7fe8e7970b4cbd124 100644 (file)
@@ -711,7 +711,7 @@ static int __init einj_init(void)
 
        rc = einj_check_table(einj_tab);
        if (rc) {
-               pr_warn(FW_BUG "Invalid EINJ table.n");
+               pr_warn(FW_BUG "Invalid EINJ table.\n");
                return -EINVAL;
        }
 
index 95855cb9d6fb772634e2dd6f683c62a1de819ffd..80cb5eb75b633db8aa278b5e709cfddd697f9a7e 100644 (file)
@@ -677,6 +677,48 @@ static bool acpi_of_match_device(struct acpi_device *adev,
        return false;
 }
 
+static bool acpi_of_modalias(struct acpi_device *adev,
+                            char *modalias, size_t len)
+{
+       const union acpi_object *of_compatible;
+       const union acpi_object *obj;
+       const char *str, *chr;
+
+       of_compatible = adev->data.of_compatible;
+       if (!of_compatible)
+               return false;
+
+       if (of_compatible->type == ACPI_TYPE_PACKAGE)
+               obj = of_compatible->package.elements;
+       else /* Must be ACPI_TYPE_STRING. */
+               obj = of_compatible;
+
+       str = obj->string.pointer;
+       chr = strchr(str, ',');
+       strlcpy(modalias, chr ? chr + 1 : str, len);
+
+       return true;
+}
+
+/**
+ * acpi_set_modalias - Set modalias using "compatible" property or supplied ID
+ * @adev:      ACPI device object to match
+ * @default_id:        ID string to use as default if no compatible string found
+ * @modalias:   Pointer to buffer that modalias value will be copied into
+ * @len:       Length of modalias buffer
+ *
+ * This is a counterpart of of_modalias_node() for struct acpi_device objects.
+ * If there is a compatible string for @adev, it will be copied to @modalias
+ * with the vendor prefix stripped; otherwise, @default_id will be used.
+ */
+void acpi_set_modalias(struct acpi_device *adev, const char *default_id,
+                      char *modalias, size_t len)
+{
+       if (!acpi_of_modalias(adev, modalias, len))
+               strlcpy(modalias, default_id, len);
+}
+EXPORT_SYMBOL_GPL(acpi_set_modalias);
+
 static bool __acpi_match_device_cls(const struct acpi_device_id *id,
                                    struct acpi_hardware_id *hwid)
 {
index e19f530f1083a13732328516925e3bbeb6493e14..668137e4a0697cf230b074e13cbb6dd255c7bf59 100644 (file)
@@ -57,7 +57,6 @@
 
 #define ACPI_BUTTON_LID_INIT_IGNORE    0x00
 #define ACPI_BUTTON_LID_INIT_OPEN      0x01
-#define ACPI_BUTTON_LID_INIT_METHOD    0x02
 
 #define _COMPONENT             ACPI_BUTTON_COMPONENT
 ACPI_MODULE_NAME("button");
@@ -113,7 +112,7 @@ struct acpi_button {
 
 static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier);
 static struct acpi_device *lid_device;
-static u8 lid_init_state = ACPI_BUTTON_LID_INIT_METHOD;
+static u8 lid_init_state = ACPI_BUTTON_LID_INIT_OPEN;
 
 static unsigned long lid_report_interval __read_mostly = 500;
 module_param(lid_report_interval, ulong, 0644);
@@ -377,9 +376,6 @@ static void acpi_lid_initialize_state(struct acpi_device *device)
        case ACPI_BUTTON_LID_INIT_OPEN:
                (void)acpi_lid_notify_state(device, 1);
                break;
-       case ACPI_BUTTON_LID_INIT_METHOD:
-               (void)acpi_lid_update_state(device);
-               break;
        case ACPI_BUTTON_LID_INIT_IGNORE:
        default:
                break;
@@ -563,9 +559,6 @@ static int param_set_lid_init_state(const char *val, struct kernel_param *kp)
        if (!strncmp(val, "open", sizeof("open") - 1)) {
                lid_init_state = ACPI_BUTTON_LID_INIT_OPEN;
                pr_info("Notify initial lid state as open\n");
-       } else if (!strncmp(val, "method", sizeof("method") - 1)) {
-               lid_init_state = ACPI_BUTTON_LID_INIT_METHOD;
-               pr_info("Notify initial lid state with _LID return value\n");
        } else if (!strncmp(val, "ignore", sizeof("ignore") - 1)) {
                lid_init_state = ACPI_BUTTON_LID_INIT_IGNORE;
                pr_info("Do not notify initial lid state\n");
@@ -579,8 +572,6 @@ static int param_get_lid_init_state(char *buffer, struct kernel_param *kp)
        switch (lid_init_state) {
        case ACPI_BUTTON_LID_INIT_OPEN:
                return sprintf(buffer, "open");
-       case ACPI_BUTTON_LID_INIT_METHOD:
-               return sprintf(buffer, "method");
        case ACPI_BUTTON_LID_INIT_IGNORE:
                return sprintf(buffer, "ignore");
        default:
index 48e19d013170936ef494d0fa88d275d37f25071a..c24235d8fb52636dc05c2deb78d2bc4574c50ad9 100644 (file)
@@ -188,7 +188,6 @@ EXPORT_SYMBOL(first_ec);
 static bool boot_ec_is_ecdt = false;
 static struct workqueue_struct *ec_query_wq;
 
-static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
 static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */
 static int EC_FLAGS_CORRECT_ECDT; /* Needs ECDT port address correction */
 
@@ -492,26 +491,6 @@ static inline void __acpi_ec_disable_event(struct acpi_ec *ec)
                ec_log_drv("event blocked");
 }
 
-/*
- * Process _Q events that might have accumulated in the EC.
- * Run with locked ec mutex.
- */
-static void acpi_ec_clear(struct acpi_ec *ec)
-{
-       int i, status;
-       u8 value = 0;
-
-       for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) {
-               status = acpi_ec_query(ec, &value);
-               if (status || !value)
-                       break;
-       }
-       if (unlikely(i == ACPI_EC_CLEAR_MAX))
-               pr_warn("Warning: Maximum of %d stale EC events cleared\n", i);
-       else
-               pr_info("%d stale EC events cleared\n", i);
-}
-
 static void acpi_ec_enable_event(struct acpi_ec *ec)
 {
        unsigned long flags;
@@ -520,10 +499,6 @@ static void acpi_ec_enable_event(struct acpi_ec *ec)
        if (acpi_ec_started(ec))
                __acpi_ec_enable_event(ec);
        spin_unlock_irqrestore(&ec->lock, flags);
-
-       /* Drain additional events if hardware requires that */
-       if (EC_FLAGS_CLEAR_ON_RESUME)
-               acpi_ec_clear(ec);
 }
 
 #ifdef CONFIG_PM_SLEEP
@@ -729,12 +704,12 @@ static void start_transaction(struct acpi_ec *ec)
 
 static int ec_guard(struct acpi_ec *ec)
 {
-       unsigned long guard = usecs_to_jiffies(ec_polling_guard);
+       unsigned long guard = usecs_to_jiffies(ec->polling_guard);
        unsigned long timeout = ec->timestamp + guard;
 
        /* Ensure guarding period before polling EC status */
        do {
-               if (ec_busy_polling) {
+               if (ec->busy_polling) {
                        /* Perform busy polling */
                        if (ec_transaction_completed(ec))
                                return 0;
@@ -998,6 +973,28 @@ static void acpi_ec_stop(struct acpi_ec *ec, bool suspending)
        spin_unlock_irqrestore(&ec->lock, flags);
 }
 
+static void acpi_ec_enter_noirq(struct acpi_ec *ec)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ec->lock, flags);
+       ec->busy_polling = true;
+       ec->polling_guard = 0;
+       ec_log_drv("interrupt blocked");
+       spin_unlock_irqrestore(&ec->lock, flags);
+}
+
+static void acpi_ec_leave_noirq(struct acpi_ec *ec)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ec->lock, flags);
+       ec->busy_polling = ec_busy_polling;
+       ec->polling_guard = ec_polling_guard;
+       ec_log_drv("interrupt unblocked");
+       spin_unlock_irqrestore(&ec->lock, flags);
+}
+
 void acpi_ec_block_transactions(void)
 {
        struct acpi_ec *ec = first_ec;
@@ -1278,7 +1275,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
        if (function != ACPI_READ && function != ACPI_WRITE)
                return AE_BAD_PARAMETER;
 
-       if (ec_busy_polling || bits > 8)
+       if (ec->busy_polling || bits > 8)
                acpi_ec_burst_enable(ec);
 
        for (i = 0; i < bytes; ++i, ++address, ++value)
@@ -1286,7 +1283,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
                        acpi_ec_read(ec, address, value) :
                        acpi_ec_write(ec, address, *value);
 
-       if (ec_busy_polling || bits > 8)
+       if (ec->busy_polling || bits > 8)
                acpi_ec_burst_disable(ec);
 
        switch (result) {
@@ -1329,6 +1326,8 @@ static struct acpi_ec *acpi_ec_alloc(void)
        spin_lock_init(&ec->lock);
        INIT_WORK(&ec->work, acpi_ec_event_handler);
        ec->timestamp = jiffies;
+       ec->busy_polling = true;
+       ec->polling_guard = 0;
        return ec;
 }
 
@@ -1390,6 +1389,7 @@ static int ec_install_handlers(struct acpi_ec *ec, bool handle_events)
        acpi_ec_start(ec, false);
 
        if (!test_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags)) {
+               acpi_ec_enter_noirq(ec);
                status = acpi_install_address_space_handler(ec->handle,
                                                            ACPI_ADR_SPACE_EC,
                                                            &acpi_ec_space_handler,
@@ -1429,6 +1429,7 @@ static int ec_install_handlers(struct acpi_ec *ec, bool handle_events)
                /* This is not fatal as we can poll EC events */
                if (ACPI_SUCCESS(status)) {
                        set_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags);
+                       acpi_ec_leave_noirq(ec);
                        if (test_bit(EC_FLAGS_STARTED, &ec->flags) &&
                            ec->reference_count >= 1)
                                acpi_ec_enable_gpe(ec, true);
@@ -1740,31 +1741,6 @@ static int ec_flag_query_handshake(const struct dmi_system_id *id)
 }
 #endif
 
-/*
- * On some hardware it is necessary to clear events accumulated by the EC during
- * sleep. These ECs stop reporting GPEs until they are manually polled, if too
- * many events are accumulated. (e.g. Samsung Series 5/9 notebooks)
- *
- * https://bugzilla.kernel.org/show_bug.cgi?id=44161
- *
- * Ideally, the EC should also be instructed NOT to accumulate events during
- * sleep (which Windows seems to do somehow), but the interface to control this
- * behaviour is not known at this time.
- *
- * Models known to be affected are Samsung 530Uxx/535Uxx/540Uxx/550Pxx/900Xxx,
- * however it is very likely that other Samsung models are affected.
- *
- * On systems which don't accumulate _Q events during sleep, this extra check
- * should be harmless.
- */
-static int ec_clear_on_resume(const struct dmi_system_id *id)
-{
-       pr_debug("Detected system needing EC poll on resume.\n");
-       EC_FLAGS_CLEAR_ON_RESUME = 1;
-       ec_event_clearing = ACPI_EC_EVT_TIMING_STATUS;
-       return 0;
-}
-
 /*
  * Some ECDTs contain wrong register addresses.
  * MSI MS-171F
@@ -1782,9 +1758,6 @@ static struct dmi_system_id ec_dmi_table[] __initdata = {
        ec_correct_ecdt, "MSI MS-171F", {
        DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star"),
        DMI_MATCH(DMI_PRODUCT_NAME, "MS-171F"),}, NULL},
-       {
-       ec_clear_on_resume, "Samsung hardware", {
-       DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL},
        {},
 };
 
@@ -1839,34 +1812,6 @@ error:
 }
 
 #ifdef CONFIG_PM_SLEEP
-static void acpi_ec_enter_noirq(struct acpi_ec *ec)
-{
-       unsigned long flags;
-
-       if (ec == first_ec) {
-               spin_lock_irqsave(&ec->lock, flags);
-               ec->saved_busy_polling = ec_busy_polling;
-               ec->saved_polling_guard = ec_polling_guard;
-               ec_busy_polling = true;
-               ec_polling_guard = 0;
-               ec_log_drv("interrupt blocked");
-               spin_unlock_irqrestore(&ec->lock, flags);
-       }
-}
-
-static void acpi_ec_leave_noirq(struct acpi_ec *ec)
-{
-       unsigned long flags;
-
-       if (ec == first_ec) {
-               spin_lock_irqsave(&ec->lock, flags);
-               ec_busy_polling = ec->saved_busy_polling;
-               ec_polling_guard = ec->saved_polling_guard;
-               ec_log_drv("interrupt unblocked");
-               spin_unlock_irqrestore(&ec->lock, flags);
-       }
-}
-
 static int acpi_ec_suspend_noirq(struct device *dev)
 {
        struct acpi_ec *ec =
index 0c452265c11110213ddde5c5c4440e52d2a523a5..219b90bc092297c753639f84972939710de25298 100644 (file)
@@ -172,8 +172,8 @@ struct acpi_ec {
        struct work_struct work;
        unsigned long timestamp;
        unsigned long nr_pending_queries;
-       bool saved_busy_polling;
-       unsigned int saved_polling_guard;
+       bool busy_polling;
+       unsigned int polling_guard;
 };
 
 extern struct acpi_ec *first_ec;
index 57fb5f468ac2025ecb80775d420bebc9a867b998..db78d353bab1f94b4d88c8b767b105a1da486d0b 100644 (file)
@@ -1686,7 +1686,7 @@ acpi_status acpi_os_prepare_sleep(u8 sleep_state, u32 pm1a_control,
        if (rc < 0)
                return AE_ERROR;
        else if (rc > 0)
-               return AE_CTRL_SKIP;
+               return AE_CTRL_TERMINATE;
 
        return AE_OK;
 }
@@ -1697,6 +1697,7 @@ void acpi_os_set_prepare_sleep(int (*func)(u8 sleep_state,
        __acpi_os_prepare_sleep = func;
 }
 
+#if (ACPI_REDUCED_HARDWARE)
 acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, u32 val_a,
                                  u32 val_b)
 {
@@ -1707,13 +1708,35 @@ acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, u32 val_a,
        if (rc < 0)
                return AE_ERROR;
        else if (rc > 0)
-               return AE_CTRL_SKIP;
+               return AE_CTRL_TERMINATE;
 
        return AE_OK;
 }
+#else
+acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, u32 val_a,
+                                 u32 val_b)
+{
+       return AE_OK;
+}
+#endif
 
 void acpi_os_set_prepare_extended_sleep(int (*func)(u8 sleep_state,
                               u32 val_a, u32 val_b))
 {
        __acpi_os_prepare_extended_sleep = func;
 }
+
+acpi_status acpi_os_enter_sleep(u8 sleep_state,
+                               u32 reg_a_value, u32 reg_b_value)
+{
+       acpi_status status;
+
+       if (acpi_gbl_reduced_hardware)
+               status = acpi_os_prepare_extended_sleep(sleep_state,
+                                                       reg_a_value,
+                                                       reg_b_value);
+       else
+               status = acpi_os_prepare_sleep(sleep_state,
+                                              reg_a_value, reg_b_value);
+       return status;
+}
index f0b4a981b8d38250f4954b7ef26d2edba5c8b2e1..18b72eec350764813dcde187cdd665e3d21ba191 100644 (file)
@@ -75,10 +75,8 @@ static int acpi_processor_ppc_notifier(struct notifier_block *nb,
        struct acpi_processor *pr;
        unsigned int ppc = 0;
 
-       if (event == CPUFREQ_START && ignore_ppc <= 0) {
+       if (ignore_ppc < 0)
                ignore_ppc = 0;
-               return 0;
-       }
 
        if (ignore_ppc)
                return 0;
index 54abb26b736639ca54aa7051ae742d6657a501bc..a4327af676fe81948cdb76c3b15786256929ffa8 100644 (file)
@@ -130,6 +130,12 @@ void __init acpi_nvs_nosave_s3(void)
        nvs_nosave_s3 = true;
 }
 
+static int __init init_nvs_save_s3(const struct dmi_system_id *d)
+{
+       nvs_nosave_s3 = false;
+       return 0;
+}
+
 /*
  * ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the
  * user to request that behavior by using the 'acpi_old_suspend_ordering'
@@ -324,6 +330,19 @@ static struct dmi_system_id acpisleep_dmi_table[] __initdata = {
                DMI_MATCH(DMI_PRODUCT_NAME, "K54HR"),
                },
        },
+       /*
+        * https://bugzilla.kernel.org/show_bug.cgi?id=189431
+        * Lenovo G50-45 is a platform later than 2012, but needs nvs memory
+        * saving during S3.
+        */
+       {
+       .callback = init_nvs_save_s3,
+       .ident = "Lenovo G50-45",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "80E3"),
+               },
+       },
        {},
 };
 
index 2c8be74f401de1bcfc698deec75287bc56f5efbf..70b57d2229d6657c57c054fa9272484bdc397ca1 100644 (file)
@@ -14,7 +14,7 @@ menuconfig ATA
        tristate "Serial ATA and Parallel ATA drivers (libata)"
        depends on HAS_IOMEM
        depends on BLOCK
-       depends on !(M32R || M68K || S390) || BROKEN
+       depends on !(M32R || S390) || BROKEN
        select SCSI
        select GLOB
        ---help---
@@ -80,6 +80,8 @@ config SATA_PMP
          This option adds support for SATA Port Multipliers
          (the SATA version of an ethernet hub, or SAS expander).
 
+if HAS_DMA
+
 comment "Controllers with non-SFF native interface"
 
 config SATA_AHCI
@@ -127,6 +129,7 @@ config AHCI_ST
 config AHCI_IMX
        tristate "Freescale i.MX AHCI SATA support"
        depends on MFD_SYSCON && (ARCH_MXC || COMPILE_TEST)
+       depends on (HWMON && (THERMAL || !THERMAL_OF)) || !HWMON
        help
          This option enables support for the Freescale i.MX SoC's
          onboard AHCI SATA.
@@ -232,6 +235,8 @@ config SATA_SIL24
 
          If unsure, say N.
 
+endif # HAS_DMA
+
 config ATA_SFF
        bool "ATA SFF support (for legacy IDE and PATA)"
        default y
@@ -289,6 +294,7 @@ config SATA_SX4
 
 config ATA_BMDMA
        bool "ATA BMDMA support"
+       depends on HAS_DMA
        default y
        help
          This option adds support for SFF ATA controllers with BMDMA
@@ -344,6 +350,7 @@ config SATA_DWC_VDEBUG
 
 config SATA_HIGHBANK
        tristate "Calxeda Highbank SATA support"
+       depends on HAS_DMA
        depends on ARCH_HIGHBANK || COMPILE_TEST
        help
          This option enables support for the Calxeda Highbank SoC's
@@ -353,6 +360,7 @@ config SATA_HIGHBANK
 
 config SATA_MV
        tristate "Marvell SATA support"
+       depends on HAS_DMA
        depends on PCI || ARCH_DOVE || ARCH_MV78XX0 || \
                   ARCH_MVEBU || ARCH_ORION5X || COMPILE_TEST
        select GENERIC_PHY
@@ -895,6 +903,15 @@ config PATA_CMD640_PCI
 
          If unsure, say N.
 
+config PATA_FALCON
+       tristate "Atari Falcon PATA support"
+       depends on M68K && ATARI
+       help
+         This option enables support for the on-board IDE
+         interface on the Atari Falcon.
+
+         If unsure, say N.
+
 config PATA_ISAPNP
        tristate "ISA Plug and Play PATA support"
        depends on ISAPNP
index a46e6b784bda5a5947571341934299c200434a75..89a0a1915d36081e4c6ee9dc6ad4b4dfd055b5c9 100644 (file)
@@ -93,6 +93,7 @@ obj-$(CONFIG_PATA_WINBOND)    += pata_sl82c105.o
 obj-$(CONFIG_PATA_AT32)                += pata_at32.o
 obj-$(CONFIG_PATA_AT91)                += pata_at91.o
 obj-$(CONFIG_PATA_CMD640_PCI)  += pata_cmd640.o
+obj-$(CONFIG_PATA_FALCON)      += pata_falcon.o
 obj-$(CONFIG_PATA_ISAPNP)      += pata_isapnp.o
 obj-$(CONFIG_PATA_IXP4XX_CF)   += pata_ixp4xx_cf.o
 obj-$(CONFIG_PATA_MPIIX)       += pata_mpiix.o
index 3f3a7db208ae51d2734f0be82e01d9682ce9c80b..787567e840bd776b32415c481124b8d153becc5c 100644 (file)
@@ -26,6 +26,9 @@
 #include <linux/mfd/syscon.h>
 #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
 #include <linux/libata.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/thermal.h>
 #include "ahci.h"
 
 #define DRV_NAME "ahci-imx"
@@ -214,6 +217,180 @@ static int imx_sata_phy_reset(struct ahci_host_priv *hpriv)
        return timeout ? 0 : -ETIMEDOUT;
 }
 
+enum {
+       /* SATA PHY Register */
+       SATA_PHY_CR_CLOCK_CRCMP_LT_LIMIT = 0x0001,
+       SATA_PHY_CR_CLOCK_DAC_CTL = 0x0008,
+       SATA_PHY_CR_CLOCK_RTUNE_CTL = 0x0009,
+       SATA_PHY_CR_CLOCK_ADC_OUT = 0x000A,
+       SATA_PHY_CR_CLOCK_MPLL_TST = 0x0017,
+};
+
+static int read_adc_sum(void *dev, u16 rtune_ctl_reg, void __iomem * mmio)
+{
+       u16 adc_out_reg, read_sum;
+       u32 index, read_attempt;
+       const u32 attempt_limit = 100;
+
+       imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_RTUNE_CTL, mmio);
+       imx_phy_reg_write(rtune_ctl_reg, mmio);
+
+       /* two dummy read */
+       index = 0;
+       read_attempt = 0;
+       adc_out_reg = 0;
+       imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_ADC_OUT, mmio);
+       while (index < 2) {
+               imx_phy_reg_read(&adc_out_reg, mmio);
+               /* check if valid */
+               if (adc_out_reg & 0x400)
+                       index++;
+
+               read_attempt++;
+               if (read_attempt > attempt_limit) {
+                       dev_err(dev, "Read REG more than %d times!\n",
+                               attempt_limit);
+                       break;
+               }
+       }
+
+       index = 0;
+       read_attempt = 0;
+       read_sum = 0;
+       while (index < 80) {
+               imx_phy_reg_read(&adc_out_reg, mmio);
+               if (adc_out_reg & 0x400) {
+                       read_sum = read_sum + (adc_out_reg & 0x3FF);
+                       index++;
+               }
+               read_attempt++;
+               if (read_attempt > attempt_limit) {
+                       dev_err(dev, "Read REG more than %d times!\n",
+                               attempt_limit);
+                       break;
+               }
+       }
+
+       /* Use the U32 to make 1000 precision */
+       return (read_sum * 1000) / 80;
+}
+
+/* SATA AHCI temperature monitor */
+static int sata_ahci_read_temperature(void *dev, int *temp)
+{
+       u16 mpll_test_reg, rtune_ctl_reg, dac_ctl_reg, read_sum;
+       u32 str1, str2, str3, str4;
+       int m1, m2, a;
+       struct ahci_host_priv *hpriv = dev_get_drvdata(dev);
+       void __iomem *mmio = hpriv->mmio;
+
+       /* check rd-wr to reg */
+       read_sum = 0;
+       imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_CRCMP_LT_LIMIT, mmio);
+       imx_phy_reg_write(read_sum, mmio);
+       imx_phy_reg_read(&read_sum, mmio);
+       if ((read_sum & 0xffff) != 0)
+               dev_err(dev, "Read/Write REG error, 0x%x!\n", read_sum);
+
+       imx_phy_reg_write(0x5A5A, mmio);
+       imx_phy_reg_read(&read_sum, mmio);
+       if ((read_sum & 0xffff) != 0x5A5A)
+               dev_err(dev, "Read/Write REG error, 0x%x!\n", read_sum);
+
+       imx_phy_reg_write(0x1234, mmio);
+       imx_phy_reg_read(&read_sum, mmio);
+       if ((read_sum & 0xffff) != 0x1234)
+               dev_err(dev, "Read/Write REG error, 0x%x!\n", read_sum);
+
+       /* start temperature test */
+       imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_MPLL_TST, mmio);
+       imx_phy_reg_read(&mpll_test_reg, mmio);
+       imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_RTUNE_CTL, mmio);
+       imx_phy_reg_read(&rtune_ctl_reg, mmio);
+       imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_DAC_CTL, mmio);
+       imx_phy_reg_read(&dac_ctl_reg, mmio);
+
+       /* mpll_tst.meas_iv   ([12:2]) */
+       str1 = (mpll_test_reg >> 2) & 0x7FF;
+       /* rtune_ctl.mode     ([1:0]) */
+       str2 = (rtune_ctl_reg) & 0x3;
+       /* dac_ctl.dac_mode   ([14:12]) */
+       str3 = (dac_ctl_reg >> 12)  & 0x7;
+       /* rtune_ctl.sel_atbp ([4]) */
+       str4 = (rtune_ctl_reg >> 4);
+
+       /* Calculate the m1 */
+       /* mpll_tst.meas_iv */
+       mpll_test_reg = (mpll_test_reg & 0xE03) | (512) << 2;
+       /* rtune_ctl.mode */
+       rtune_ctl_reg = (rtune_ctl_reg & 0xFFC) | (1);
+       /* dac_ctl.dac_mode */
+       dac_ctl_reg = (dac_ctl_reg & 0x8FF) | (4) << 12;
+       /* rtune_ctl.sel_atbp */
+       rtune_ctl_reg = (rtune_ctl_reg & 0xFEF) | (0) << 4;
+       imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_MPLL_TST, mmio);
+       imx_phy_reg_write(mpll_test_reg, mmio);
+       imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_DAC_CTL, mmio);
+       imx_phy_reg_write(dac_ctl_reg, mmio);
+       m1 = read_adc_sum(dev, rtune_ctl_reg, mmio);
+
+       /* Calculate the m2 */
+       /* rtune_ctl.sel_atbp */
+       rtune_ctl_reg = (rtune_ctl_reg & 0xFEF) | (1) << 4;
+       m2 = read_adc_sum(dev, rtune_ctl_reg, mmio);
+
+       /* restore the status  */
+       /* mpll_tst.meas_iv */
+       mpll_test_reg = (mpll_test_reg & 0xE03) | (str1) << 2;
+       /* rtune_ctl.mode */
+       rtune_ctl_reg = (rtune_ctl_reg & 0xFFC) | (str2);
+       /* dac_ctl.dac_mode */
+       dac_ctl_reg = (dac_ctl_reg & 0x8FF) | (str3) << 12;
+       /* rtune_ctl.sel_atbp */
+       rtune_ctl_reg = (rtune_ctl_reg & 0xFEF) | (str4) << 4;
+
+       imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_MPLL_TST, mmio);
+       imx_phy_reg_write(mpll_test_reg, mmio);
+       imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_DAC_CTL, mmio);
+       imx_phy_reg_write(dac_ctl_reg, mmio);
+       imx_phy_reg_addressing(SATA_PHY_CR_CLOCK_RTUNE_CTL, mmio);
+       imx_phy_reg_write(rtune_ctl_reg, mmio);
+
+       /* Compute temperature */
+       if (!(m2 / 1000))
+               m2 = 1000;
+       a = (m2 - m1) / (m2/1000);
+       *temp = ((-559) * a * a) / 1000 + (1379) * a + (-458000);
+
+       return 0;
+}
+
+static ssize_t sata_ahci_show_temp(struct device *dev,
+                                  struct device_attribute *da,
+                                  char *buf)
+{
+       unsigned int temp = 0;
+       int err;
+
+       err = sata_ahci_read_temperature(dev, &temp);
+       if (err < 0)
+               return err;
+
+       return sprintf(buf, "%u\n", temp);
+}
+
+static const struct thermal_zone_of_device_ops fsl_sata_ahci_of_thermal_ops = {
+       .get_temp = sata_ahci_read_temperature,
+};
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, sata_ahci_show_temp, NULL, 0);
+
+static struct attribute *fsl_sata_ahci_attrs[] = {
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       NULL
+};
+ATTRIBUTE_GROUPS(fsl_sata_ahci);
+
 static int imx_sata_enable(struct ahci_host_priv *hpriv)
 {
        struct imx_ahci_priv *imxpriv = hpriv->plat_data;
@@ -597,6 +774,25 @@ static int imx_ahci_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       if (imxpriv->type == AHCI_IMX53 &&
+           IS_ENABLED(CONFIG_HWMON)) {
+               /* Add the temperature monitor */
+               struct device *hwmon_dev;
+
+               hwmon_dev =
+                       devm_hwmon_device_register_with_groups(dev,
+                                                       "sata_ahci",
+                                                       hpriv,
+                                                       fsl_sata_ahci_groups);
+               if (IS_ERR(hwmon_dev)) {
+                       ret = PTR_ERR(hwmon_dev);
+                       goto disable_clk;
+               }
+               devm_thermal_zone_of_sensor_register(hwmon_dev, 0, hwmon_dev,
+                                            &fsl_sata_ahci_of_thermal_ops);
+               dev_info(dev, "%s: sensor 'sata_ahci'\n", dev_name(hwmon_dev));
+       }
+
        ret = imx_sata_enable(hpriv);
        if (ret)
                goto disable_clk;
index 9884c8c6e93447fac77e2b74a322b526eaae26f7..85d833289f28f85de9aa98efe52a05a921cdc3bd 100644 (file)
 #define LS1021A_AXICC_ADDR     0xC0
 
 #define SATA_ECC_DISABLE       0x00020000
-#define LS1046A_SATA_ECC_DIS   0x80000000
+#define ECC_DIS_ARMV8_CH2      0x80000000
 
 enum ahci_qoriq_type {
        AHCI_LS1021A,
        AHCI_LS1043A,
        AHCI_LS2080A,
        AHCI_LS1046A,
+       AHCI_LS2088A,
 };
 
 struct ahci_qoriq_priv {
        struct ccsr_ahci *reg_base;
        enum ahci_qoriq_type type;
        void __iomem *ecc_addr;
+       bool is_dmacoherent;
 };
 
 static const struct of_device_id ahci_qoriq_of_match[] = {
@@ -66,6 +68,7 @@ static const struct of_device_id ahci_qoriq_of_match[] = {
        { .compatible = "fsl,ls1043a-ahci", .data = (void *)AHCI_LS1043A},
        { .compatible = "fsl,ls2080a-ahci", .data = (void *)AHCI_LS2080A},
        { .compatible = "fsl,ls1046a-ahci", .data = (void *)AHCI_LS1046A},
+       { .compatible = "fsl,ls2088a-ahci", .data = (void *)AHCI_LS2088A},
        {},
 };
 MODULE_DEVICE_TABLE(of, ahci_qoriq_of_match);
@@ -157,6 +160,8 @@ static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv)
 
        switch (qpriv->type) {
        case AHCI_LS1021A:
+               if (!qpriv->ecc_addr)
+                       return -EINVAL;
                writel(SATA_ECC_DISABLE, qpriv->ecc_addr);
                writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
                writel(LS1021A_PORT_PHY2, reg_base + PORT_PHY2);
@@ -164,26 +169,43 @@ static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv)
                writel(LS1021A_PORT_PHY4, reg_base + PORT_PHY4);
                writel(LS1021A_PORT_PHY5, reg_base + PORT_PHY5);
                writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
-               writel(AHCI_PORT_AXICC_CFG, reg_base + LS1021A_AXICC_ADDR);
+               if (qpriv->is_dmacoherent)
+                       writel(AHCI_PORT_AXICC_CFG,
+                                       reg_base + LS1021A_AXICC_ADDR);
                break;
 
        case AHCI_LS1043A:
+               if (!qpriv->ecc_addr)
+                       return -EINVAL;
+               writel(ECC_DIS_ARMV8_CH2, qpriv->ecc_addr);
                writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
                writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
-               writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
+               if (qpriv->is_dmacoherent)
+                       writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
                break;
 
        case AHCI_LS2080A:
                writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
                writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
-               writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
+               if (qpriv->is_dmacoherent)
+                       writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
                break;
 
        case AHCI_LS1046A:
-               writel(LS1046A_SATA_ECC_DIS, qpriv->ecc_addr);
+               if (!qpriv->ecc_addr)
+                       return -EINVAL;
+               writel(ECC_DIS_ARMV8_CH2, qpriv->ecc_addr);
                writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
                writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
-               writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
+               if (qpriv->is_dmacoherent)
+                       writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
+               break;
+
+       case AHCI_LS2088A:
+               writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
+               writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
+               if (qpriv->is_dmacoherent)
+                       writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
                break;
        }
 
@@ -221,6 +243,7 @@ static int ahci_qoriq_probe(struct platform_device *pdev)
                if (IS_ERR(qoriq_priv->ecc_addr))
                        return PTR_ERR(qoriq_priv->ecc_addr);
        }
+       qoriq_priv->is_dmacoherent = of_dma_is_coherent(np);
 
        rc = ahci_platform_enable_resources(hpriv);
        if (rc)
index 73b19b2771385517b094d5fd548f3abf91751b2f..c2b5941d9184db2637604864baf4597d398c4911 100644 (file)
@@ -821,8 +821,10 @@ static int xgene_ahci_probe(struct platform_device *pdev)
                                dev_warn(&pdev->dev, "%s: Error reading device info. Assume version1\n",
                                        __func__);
                                version = XGENE_AHCI_V1;
-                       } else if (info->valid & ACPI_VALID_CID) {
-                               version = XGENE_AHCI_V2;
+                       } else {
+                               if (info->valid & ACPI_VALID_CID)
+                                       version = XGENE_AHCI_V2;
+                               kfree(info);
                        }
                }
        }
index c2d3785ec2279f42013cdc4816beb60785279d95..ca75823697dd1d7c359fcc396946c57070f6e41d 100644 (file)
@@ -4815,32 +4815,6 @@ static unsigned int ata_dev_init_params(struct ata_device *dev,
        return err_mask;
 }
 
-/**
- *     ata_sg_clean - Unmap DMA memory associated with command
- *     @qc: Command containing DMA memory to be released
- *
- *     Unmap all mapped DMA memory associated with this command.
- *
- *     LOCKING:
- *     spin_lock_irqsave(host lock)
- */
-void ata_sg_clean(struct ata_queued_cmd *qc)
-{
-       struct ata_port *ap = qc->ap;
-       struct scatterlist *sg = qc->sg;
-       int dir = qc->dma_dir;
-
-       WARN_ON_ONCE(sg == NULL);
-
-       VPRINTK("unmapping %u sg elements\n", qc->n_elem);
-
-       if (qc->n_elem)
-               dma_unmap_sg(ap->dev, sg, qc->orig_n_elem, dir);
-
-       qc->flags &= ~ATA_QCFLAG_DMAMAP;
-       qc->sg = NULL;
-}
-
 /**
  *     atapi_check_dma - Check whether ATAPI DMA can be supported
  *     @qc: Metadata associated with taskfile to check
@@ -4925,6 +4899,34 @@ void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
        qc->cursg = qc->sg;
 }
 
+#ifdef CONFIG_HAS_DMA
+
+/**
+ *     ata_sg_clean - Unmap DMA memory associated with command
+ *     @qc: Command containing DMA memory to be released
+ *
+ *     Unmap all mapped DMA memory associated with this command.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host lock)
+ */
+void ata_sg_clean(struct ata_queued_cmd *qc)
+{
+       struct ata_port *ap = qc->ap;
+       struct scatterlist *sg = qc->sg;
+       int dir = qc->dma_dir;
+
+       WARN_ON_ONCE(sg == NULL);
+
+       VPRINTK("unmapping %u sg elements\n", qc->n_elem);
+
+       if (qc->n_elem)
+               dma_unmap_sg(ap->dev, sg, qc->orig_n_elem, dir);
+
+       qc->flags &= ~ATA_QCFLAG_DMAMAP;
+       qc->sg = NULL;
+}
+
 /**
  *     ata_sg_setup - DMA-map the scatter-gather table associated with a command.
  *     @qc: Command with scatter-gather table to be mapped.
@@ -4957,6 +4959,13 @@ static int ata_sg_setup(struct ata_queued_cmd *qc)
        return 0;
 }
 
+#else /* !CONFIG_HAS_DMA */
+
+static inline void ata_sg_clean(struct ata_queued_cmd *qc) {}
+static inline int ata_sg_setup(struct ata_queued_cmd *qc) { return -1; }
+
+#endif /* !CONFIG_HAS_DMA */
+
 /**
  *     swap_buf_le16 - swap halves of 16-bit words in place
  *     @buf:  Buffer to swap
index 0e1ec37070d19b641ed37d9a75c216197c0fc557..4e5bf36c5f4680fb079b7d4391d65e6a07cb0254 100644 (file)
@@ -549,6 +549,7 @@ enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
        DPRINTK("EXIT, ret=%d\n", ret);
        return ret;
 }
+EXPORT_SYMBOL(ata_scsi_timed_out);
 
 static void ata_eh_unload(struct ata_port *ap)
 {
@@ -2606,21 +2607,39 @@ static void ata_eh_link_report(struct ata_link *link)
                                [DMA_TO_DEVICE]         = "out",
                                [DMA_FROM_DEVICE]       = "in",
                        };
-                       static const char *prot_str[] = {
-                               [ATA_PROT_UNKNOWN]      = "unknown",
-                               [ATA_PROT_NODATA]       = "nodata",
-                               [ATA_PROT_PIO]          = "pio",
-                               [ATA_PROT_DMA]          = "dma",
-                               [ATA_PROT_NCQ]          = "ncq dma",
-                               [ATA_PROT_NCQ_NODATA]   = "ncq nodata",
-                               [ATAPI_PROT_NODATA]     = "nodata",
-                               [ATAPI_PROT_PIO]        = "pio",
-                               [ATAPI_PROT_DMA]        = "dma",
-                       };
+                       const char *prot_str = NULL;
 
+                       switch (qc->tf.protocol) {
+                       case ATA_PROT_UNKNOWN:
+                               prot_str = "unknown";
+                               break;
+                       case ATA_PROT_NODATA:
+                               prot_str = "nodata";
+                               break;
+                       case ATA_PROT_PIO:
+                               prot_str = "pio";
+                               break;
+                       case ATA_PROT_DMA:
+                               prot_str = "dma";
+                               break;
+                       case ATA_PROT_NCQ:
+                               prot_str = "ncq dma";
+                               break;
+                       case ATA_PROT_NCQ_NODATA:
+                               prot_str = "ncq nodata";
+                               break;
+                       case ATAPI_PROT_NODATA:
+                               prot_str = "nodata";
+                               break;
+                       case ATAPI_PROT_PIO:
+                               prot_str = "pio";
+                               break;
+                       case ATAPI_PROT_DMA:
+                               prot_str = "dma";
+                               break;
+                       }
                        snprintf(data_buf, sizeof(data_buf), " %s %u %s",
-                                prot_str[qc->tf.protocol], qc->nbytes,
-                                dma_str[qc->dma_dir]);
+                                prot_str, qc->nbytes, dma_str[qc->dma_dir]);
                }
 
                if (ata_is_atapi(qc->tf.protocol)) {
index 1f863e757ee47189e9cef517a09d3045d0f2fd1f..12d3a66600a3f7a7a7c693b604a6c89ee7bc5576 100644 (file)
@@ -484,13 +484,6 @@ struct device_attribute *ata_common_sdev_attrs[] = {
 };
 EXPORT_SYMBOL_GPL(ata_common_sdev_attrs);
 
-static void ata_scsi_invalid_field(struct ata_device *dev,
-                                  struct scsi_cmnd *cmd, u16 field)
-{
-       ata_scsi_set_invalid_field(dev, cmd, field, 0xff);
-       cmd->scsi_done(cmd);
-}
-
 /**
  *     ata_std_bios_param - generic bios head/sector/cylinder calculator used by sd.
  *     @sdev: SCSI device for which BIOS geometry is to be determined
@@ -1265,13 +1258,13 @@ static void ata_scsi_sdev_config(struct scsi_device *sdev)
  */
 static int atapi_drain_needed(struct request *rq)
 {
-       if (likely(rq->cmd_type != REQ_TYPE_BLOCK_PC))
+       if (likely(!blk_rq_is_passthrough(rq)))
                return 0;
 
        if (!blk_rq_bytes(rq) || op_is_write(req_op(rq)))
                return 0;
 
-       return atapi_cmd_type(rq->cmd[0]) == ATAPI_MISC;
+       return atapi_cmd_type(scsi_req(rq)->cmd[0]) == ATAPI_MISC;
 }
 
 static int ata_scsi_dev_config(struct scsi_device *sdev,
@@ -2057,6 +2050,12 @@ defer:
                return SCSI_MLQUEUE_HOST_BUSY;
 }
 
+struct ata_scsi_args {
+       struct ata_device       *dev;
+       u16                     *id;
+       struct scsi_cmnd        *cmd;
+};
+
 /**
  *     ata_scsi_rbuf_get - Map response buffer.
  *     @cmd: SCSI command containing buffer to be mapped.
@@ -2133,7 +2132,6 @@ static void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
 
        if (rc == 0)
                cmd->result = SAM_STAT_GOOD;
-       args->done(cmd);
 }
 
 /**
@@ -2454,23 +2452,6 @@ static unsigned int ata_scsiop_inq_b6(struct ata_scsi_args *args, u8 *rbuf)
        return 0;
 }
 
-/**
- *     ata_scsiop_noop - Command handler that simply returns success.
- *     @args: device IDENTIFY data / SCSI command of interest.
- *     @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- *
- *     No operation.  Simply returns success to caller, to indicate
- *     that the caller should successfully complete this SCSI command.
- *
- *     LOCKING:
- *     spin_lock_irqsave(host lock)
- */
-static unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf)
-{
-       VPRINTK("ENTER\n");
-       return 0;
-}
-
 /**
  *     modecpy - Prepare response for MODE SENSE
  *     @dest: output buffer
@@ -2873,6 +2854,26 @@ static void atapi_request_sense(struct ata_queued_cmd *qc)
        DPRINTK("EXIT\n");
 }
 
+/*
+ * ATAPI devices typically report zero for their SCSI version, and sometimes
+ * deviate from the spec WRT response data format.  If SCSI version is
+ * reported as zero like normal, then we make the following fixups:
+ *   1) Fake MMC-5 version, to indicate to the Linux scsi midlayer this is a
+ *     modern device.
+ *   2) Ensure response data format / ATAPI information are always correct.
+ */
+static void atapi_fixup_inquiry(struct scsi_cmnd *cmd)
+{
+       u8 buf[4];
+
+       sg_copy_to_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), buf, 4);
+       if (buf[2] == 0) {
+               buf[2] = 0x5;
+               buf[3] = 0x32;
+       }
+       sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), buf, 4);
+}
+
 static void atapi_qc_complete(struct ata_queued_cmd *qc)
 {
        struct scsi_cmnd *cmd = qc->scsicmd;
@@ -2927,30 +2928,8 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc)
                 */
                ata_gen_passthru_sense(qc);
        } else {
-               u8 *scsicmd = cmd->cmnd;
-
-               if ((scsicmd[0] == INQUIRY) && ((scsicmd[1] & 0x03) == 0)) {
-                       unsigned long flags;
-                       u8 *buf;
-
-                       buf = ata_scsi_rbuf_get(cmd, true, &flags);
-
-       /* ATAPI devices typically report zero for their SCSI version,
-        * and sometimes deviate from the spec WRT response data
-        * format.  If SCSI version is reported as zero like normal,
-        * then we make the following fixups:  1) Fake MMC-5 version,
-        * to indicate to the Linux scsi midlayer this is a modern
-        * device.  2) Ensure response data format / ATAPI information
-        * are always correct.
-        */
-                       if (buf[2] == 0) {
-                               buf[2] = 0x5;
-                               buf[3] = 0x32;
-                       }
-
-                       ata_scsi_rbuf_put(cmd, true, &flags);
-               }
-
+               if (cmd->cmnd[0] == INQUIRY && (cmd->cmnd[1] & 0x03) == 0)
+                       atapi_fixup_inquiry(cmd);
                cmd->result = SAM_STAT_GOOD;
        }
 
@@ -4352,12 +4331,11 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)
        args.dev = dev;
        args.id = dev->id;
        args.cmd = cmd;
-       args.done = cmd->scsi_done;
 
        switch(scsicmd[0]) {
        case INQUIRY:
                if (scsicmd[1] & 2)                /* is CmdDt set?  */
-                   ata_scsi_invalid_field(dev, cmd, 1);
+                       ata_scsi_set_invalid_field(dev, cmd, 1, 0xff);
                else if ((scsicmd[1] & 1) == 0)    /* is EVPD clear? */
                        ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std);
                else switch (scsicmd[2]) {
@@ -4389,7 +4367,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)
                        }
                        /* Fallthrough */
                default:
-                       ata_scsi_invalid_field(dev, cmd, 2);
+                       ata_scsi_set_invalid_field(dev, cmd, 2, 0xff);
                        break;
                }
                break;
@@ -4407,7 +4385,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)
                if ((scsicmd[1] & 0x1f) == SAI_READ_CAPACITY_16)
                        ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
                else
-                       ata_scsi_invalid_field(dev, cmd, 1);
+                       ata_scsi_set_invalid_field(dev, cmd, 1, 0xff);
                break;
 
        case REPORT_LUNS:
@@ -4417,7 +4395,6 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)
        case REQUEST_SENSE:
                ata_scsi_set_sense(dev, cmd, 0, 0, 0);
                cmd->result = (DRIVER_SENSE << 24);
-               cmd->scsi_done(cmd);
                break;
 
        /* if we reach this, then writeback caching is disabled,
@@ -4431,31 +4408,29 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)
        case SEEK_6:
        case SEEK_10:
        case TEST_UNIT_READY:
-               ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
                break;
 
        case SEND_DIAGNOSTIC:
                tmp8 = scsicmd[1] & ~(1 << 3);
-               if ((tmp8 == 0x4) && (!scsicmd[3]) && (!scsicmd[4]))
-                       ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
-               else
-                       ata_scsi_invalid_field(dev, cmd, 1);
+               if (tmp8 != 0x4 || scsicmd[3] || scsicmd[4])
+                       ata_scsi_set_invalid_field(dev, cmd, 1, 0xff);
                break;
 
        case MAINTENANCE_IN:
                if (scsicmd[1] == MI_REPORT_SUPPORTED_OPERATION_CODES)
                        ata_scsi_rbuf_fill(&args, ata_scsiop_maint_in);
                else
-                       ata_scsi_invalid_field(dev, cmd, 1);
+                       ata_scsi_set_invalid_field(dev, cmd, 1, 0xff);
                break;
 
        /* all other commands */
        default:
                ata_scsi_set_sense(dev, cmd, ILLEGAL_REQUEST, 0x20, 0x0);
                /* "Invalid command operation code" */
-               cmd->scsi_done(cmd);
                break;
        }
+
+       cmd->scsi_done(cmd);
 }
 
 int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
index 051b6158d1b7f45b7116b9debc98376a9d4d240f..2bd92dca3e6204027f6c1b5fb07ba519cbe039fa 100644 (file)
@@ -542,7 +542,7 @@ static inline void ata_tf_to_host(struct ata_port *ap,
 
 /**
  *     ata_sff_data_xfer - Transfer data by PIO
- *     @dev: device to target
+ *     @qc: queued command
  *     @buf: data buffer
  *     @buflen: buffer length
  *     @rw: read/write
@@ -555,10 +555,10 @@ static inline void ata_tf_to_host(struct ata_port *ap,
  *     RETURNS:
  *     Bytes consumed.
  */
-unsigned int ata_sff_data_xfer(struct ata_device *dev, unsigned char *buf,
+unsigned int ata_sff_data_xfer(struct ata_queued_cmd *qc, unsigned char *buf,
                               unsigned int buflen, int rw)
 {
-       struct ata_port *ap = dev->link->ap;
+       struct ata_port *ap = qc->dev->link->ap;
        void __iomem *data_addr = ap->ioaddr.data_addr;
        unsigned int words = buflen >> 1;
 
@@ -595,7 +595,7 @@ EXPORT_SYMBOL_GPL(ata_sff_data_xfer);
 
 /**
  *     ata_sff_data_xfer32 - Transfer data by PIO
- *     @dev: device to target
+ *     @qc: queued command
  *     @buf: data buffer
  *     @buflen: buffer length
  *     @rw: read/write
@@ -610,16 +610,17 @@ EXPORT_SYMBOL_GPL(ata_sff_data_xfer);
  *     Bytes consumed.
  */
 
-unsigned int ata_sff_data_xfer32(struct ata_device *dev, unsigned char *buf,
+unsigned int ata_sff_data_xfer32(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 >> 2;
        int slop = buflen & 3;
 
        if (!(ap->pflags & ATA_PFLAG_PIO32))
-               return ata_sff_data_xfer(dev, buf, buflen, rw);
+               return ata_sff_data_xfer(qc, buf, buflen, rw);
 
        /* Transfer multiple of 4 bytes */
        if (rw == READ)
@@ -658,7 +659,7 @@ EXPORT_SYMBOL_GPL(ata_sff_data_xfer32);
 
 /**
  *     ata_sff_data_xfer_noirq - Transfer data by PIO
- *     @dev: device to target
+ *     @qc: queued command
  *     @buf: data buffer
  *     @buflen: buffer length
  *     @rw: read/write
@@ -672,14 +673,14 @@ EXPORT_SYMBOL_GPL(ata_sff_data_xfer32);
  *     RETURNS:
  *     Bytes consumed.
  */
-unsigned int ata_sff_data_xfer_noirq(struct ata_device *dev, unsigned char *buf,
+unsigned int ata_sff_data_xfer_noirq(struct ata_queued_cmd *qc, unsigned char *buf,
                                     unsigned int buflen, int rw)
 {
        unsigned long flags;
        unsigned int consumed;
 
        local_irq_save(flags);
-       consumed = ata_sff_data_xfer32(dev, buf, buflen, rw);
+       consumed = ata_sff_data_xfer32(qc, buf, buflen, rw);
        local_irq_restore(flags);
 
        return consumed;
@@ -723,14 +724,14 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
                buf = kmap_atomic(page);
 
                /* do the actual data transfer */
-               ap->ops->sff_data_xfer(qc->dev, buf + offset, qc->sect_size,
+               ap->ops->sff_data_xfer(qc, buf + offset, qc->sect_size,
                                       do_write);
 
                kunmap_atomic(buf);
                local_irq_restore(flags);
        } else {
                buf = page_address(page);
-               ap->ops->sff_data_xfer(qc->dev, buf + offset, qc->sect_size,
+               ap->ops->sff_data_xfer(qc, buf + offset, qc->sect_size,
                                       do_write);
        }
 
@@ -791,7 +792,7 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc)
        DPRINTK("send cdb\n");
        WARN_ON_ONCE(qc->dev->cdb_len < 12);
 
-       ap->ops->sff_data_xfer(qc->dev, qc->cdb, qc->dev->cdb_len, 1);
+       ap->ops->sff_data_xfer(qc, qc->cdb, qc->dev->cdb_len, 1);
        ata_sff_sync(ap);
        /* FIXME: If the CDB is for DMA do we need to do the transition delay
           or is bmdma_start guaranteed to do it ? */
@@ -868,14 +869,14 @@ next_sg:
                buf = kmap_atomic(page);
 
                /* do the actual data transfer */
-               consumed = ap->ops->sff_data_xfer(dev,  buf + offset,
+               consumed = ap->ops->sff_data_xfer(qc, buf + offset,
                                                                count, rw);
 
                kunmap_atomic(buf);
                local_irq_restore(flags);
        } else {
                buf = page_address(page);
-               consumed = ap->ops->sff_data_xfer(dev,  buf + offset,
+               consumed = ap->ops->sff_data_xfer(qc, buf + offset,
                                                                count, rw);
        }
 
@@ -2427,11 +2428,21 @@ int ata_pci_sff_activate_host(struct ata_host *host,
                return rc;
 
        if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
-               u8 tmp8, mask;
+               u8 tmp8, mask = 0;
 
-               /* TODO: What if one channel is in native mode ... */
+               /*
+                * ATA spec says we should use legacy mode when one
+                * port is in legacy mode, but disabled ports on some
+                * PCI hosts appear as fixed legacy ports, e.g SB600/700
+                * on which the secondary port is not wired, so
+                * ignore ports that are marked as 'dummy' during
+                * this check
+                */
                pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
-               mask = (1 << 2) | (1 << 0);
+               if (!ata_port_is_dummy(host->ports[0]))
+                       mask |= (1 << 0);
+               if (!ata_port_is_dummy(host->ports[1]))
+                       mask |= (1 << 2);
                if ((tmp8 & mask) != mask)
                        legacy_mode = 1;
        }
index 7ef16c08505879127a3b433979119455e17d1ff4..46698232e6bff069293200a5da842e196a4a0730 100644 (file)
@@ -716,7 +716,6 @@ struct scsi_transport_template *ata_attach_transport(void)
                return NULL;
 
        i->t.eh_strategy_handler        = ata_scsi_error;
-       i->t.eh_timed_out               = ata_scsi_timed_out;
        i->t.user_scan                  = ata_scsi_user_scan;
 
        i->t.host_attrs.ac.attrs = &i->port_attrs[0];
index 8f3a5596dd676b95ee6bf6500d1e8be560b3c73c..120fce0befd3a5a40d8878d96728636b4fe59fc1 100644 (file)
 #define DRV_NAME       "libata"
 #define DRV_VERSION    "3.00"  /* must be exactly four chars */
 
-struct ata_scsi_args {
-       struct ata_device       *dev;
-       u16                     *id;
-       struct scsi_cmnd        *cmd;
-       void                    (*done)(struct scsi_cmnd *);
-};
-
 /* libata-core.c */
 enum {
        /* flags for ata_dev_read_id() */
@@ -89,7 +82,6 @@ extern int sata_down_spd_limit(struct ata_link *link, u32 spd_limit);
 extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel);
 extern unsigned int ata_dev_set_feature(struct ata_device *dev,
                                        u8 enable, u8 feature);
-extern void ata_sg_clean(struct ata_queued_cmd *qc);
 extern void ata_qc_free(struct ata_queued_cmd *qc);
 extern void ata_qc_issue(struct ata_queued_cmd *qc);
 extern void __ata_qc_complete(struct ata_queued_cmd *qc);
@@ -159,7 +151,6 @@ extern unsigned long ata_internal_cmd_timeout(struct ata_device *dev, u8 cmd);
 extern void ata_internal_cmd_timed_out(struct ata_device *dev, u8 cmd);
 extern void ata_eh_acquire(struct ata_port *ap);
 extern void ata_eh_release(struct ata_port *ap);
-extern enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
 extern void ata_scsi_error(struct Scsi_Host *host);
 extern void ata_eh_fastdrain_timerfn(unsigned long arg);
 extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
index 1611e0e8d767816d86127f007f36818ab8a04434..fd5b34f0d007d2ac5c16f231f346c1050a104b03 100644 (file)
@@ -286,10 +286,10 @@ static void pata_at91_set_piomode(struct ata_port *ap, struct ata_device *adev)
        set_smc_timing(ap->dev, adev, info, &timing);
 }
 
-static unsigned int pata_at91_data_xfer_noirq(struct ata_device *dev,
+static unsigned int pata_at91_data_xfer_noirq(struct ata_queued_cmd *qc,
                unsigned char *buf, unsigned int buflen, int rw)
 {
-       struct at91_ide_info *info = dev->link->ap->host->private_data;
+       struct at91_ide_info *info = qc->dev->link->ap->host->private_data;
        unsigned int consumed;
        unsigned int mode;
        unsigned long flags;
@@ -301,7 +301,7 @@ static unsigned int pata_at91_data_xfer_noirq(struct ata_device *dev,
        regmap_fields_write(fields.mode, info->cs, (mode & ~AT91_SMC_DBW) |
                            AT91_SMC_DBW_16);
 
-       consumed = ata_sff_data_xfer(dev, buf, buflen, rw);
+       consumed = ata_sff_data_xfer(qc, buf, buflen, rw);
 
        /* restore 8bit mode after data is written */
        regmap_fields_write(fields.mode, info->cs, (mode & ~AT91_SMC_DBW) |
index 49d705c9f0f7b9c6b2ef2549769b6901438c2854..6c9aa95a9a050cc070ab222a382f5dabd55ec7ea 100644 (file)
@@ -278,6 +278,11 @@ static int atiixp_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
        };
        const struct ata_port_info *ppi[] = { &info, &info };
 
+       /* SB600/700 don't have secondary port wired */
+       if ((pdev->device == PCI_DEVICE_ID_ATI_IXP600_IDE) ||
+               (pdev->device == PCI_DEVICE_ID_ATI_IXP700_IDE))
+               ppi[1] = &ata_dummy_port_info;
+
        return ata_pci_bmdma_init_one(pdev, ppi, &atiixp_sht, NULL,
                                      ATA_HOST_PARALLEL_SCAN);
 }
index ec748d31928d26863f352579304bbb7d08090263..9c5780a7e1b925dc668b6bade617d07c0bb0a2a2 100644 (file)
@@ -1143,7 +1143,7 @@ static unsigned char bfin_bmdma_status(struct ata_port *ap)
 
 /**
  *     bfin_data_xfer - Transfer data by PIO
- *     @adev: device for this I/O
+ *     @qc: queued command
  *     @buf: data buffer
  *     @buflen: buffer length
  *     @write_data: read/write
@@ -1151,10 +1151,11 @@ static unsigned char bfin_bmdma_status(struct ata_port *ap)
  *     Note: Original code is ata_sff_data_xfer().
  */
 
-static unsigned int bfin_data_xfer(struct ata_device *dev, unsigned char *buf,
+static unsigned int bfin_data_xfer(struct ata_queued_cmd *qc,
+                                  unsigned char *buf,
                                   unsigned int buflen, int rw)
 {
-       struct ata_port *ap = dev->link->ap;
+       struct ata_port *ap = qc->dev->link->ap;
        void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
        unsigned int words = buflen >> 1;
        unsigned short *buf16 = (u16 *)buf;
index bd6b089c67a3aa220fa2aaf3803f8eb7737b2d4d..bf1b910c5d691b7032b7f1751b62237547f58570 100644 (file)
@@ -474,11 +474,11 @@ static void ep93xx_pata_set_devctl(struct ata_port *ap, u8 ctl)
 }
 
 /* Note: original code is ata_sff_data_xfer */
-static unsigned int ep93xx_pata_data_xfer(struct ata_device *adev,
+static unsigned int ep93xx_pata_data_xfer(struct ata_queued_cmd *qc,
                                          unsigned char *buf,
                                          unsigned int buflen, int rw)
 {
-       struct ata_port *ap = adev->link->ap;
+       struct ata_port *ap = qc->dev->link->ap;
        struct ep93xx_pata_data *drv_data = ap->host->private_data;
        u16 *data = (u16 *)buf;
        unsigned int words = buflen >> 1;
diff --git a/drivers/ata/pata_falcon.c b/drivers/ata/pata_falcon.c
new file mode 100644 (file)
index 0000000..5b0c57d
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Atari Falcon PATA controller driver
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * 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>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <linux/ata.h>
+#include <linux/libata.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <asm/setup.h>
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+#include <asm/atari_stdma.h>
+#include <asm/ide.h>
+
+#define DRV_NAME "pata_falcon"
+#define DRV_VERSION "0.1.0"
+
+#define ATA_HD_BASE    0xfff00000
+#define ATA_HD_CONTROL 0x39
+
+static struct scsi_host_template pata_falcon_sht = {
+       ATA_PIO_SHT(DRV_NAME),
+};
+
+static unsigned int pata_falcon_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;
+       struct scsi_cmnd *cmd = qc->scsicmd;
+       bool swap = 1;
+
+       if (dev->class == ATA_DEV_ATA && cmd && cmd->request &&
+           !blk_rq_is_passthrough(cmd->request))
+               swap = 0;
+
+       /* Transfer multiple of 2 bytes */
+       if (rw == READ) {
+               if (swap)
+                       raw_insw_swapw((u16 *)data_addr, (u16 *)buf, words);
+               else
+                       raw_insw((u16 *)data_addr, (u16 *)buf, words);
+       } else {
+               if (swap)
+                       raw_outsw_swapw((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) {
+                       if (swap)
+                               raw_insw_swapw((u16 *)data_addr, (u16 *)pad, 1);
+                       else
+                               raw_insw((u16 *)data_addr, (u16 *)pad, 1);
+                       *buf = pad[0];
+               } else {
+                       pad[0] = *buf;
+                       if (swap)
+                               raw_outsw_swapw((u16 *)data_addr, (u16 *)pad, 1);
+                       else
+                               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_falcon_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 struct ata_port_operations pata_falcon_ops = {
+       .inherits       = &ata_sff_port_ops,
+       .sff_data_xfer  = pata_falcon_data_xfer,
+       .cable_detect   = ata_cable_unknown,
+       .set_mode       = pata_falcon_set_mode,
+};
+
+static int pata_falcon_init_one(void)
+{
+       struct ata_host *host;
+       struct ata_port *ap;
+       struct platform_device *pdev;
+       void __iomem *base;
+
+       if (!MACH_IS_ATARI || !ATARIHW_PRESENT(IDE))
+               return -ENODEV;
+
+       pr_info(DRV_NAME ": Atari Falcon PATA controller\n");
+
+       pdev = platform_device_register_simple(DRV_NAME, 0, NULL, 0);
+       if (IS_ERR(pdev))
+               return PTR_ERR(pdev);
+
+       if (!devm_request_mem_region(&pdev->dev, ATA_HD_BASE, 0x40, 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];
+
+       ap->ops = &pata_falcon_ops;
+       ap->pio_mask = ATA_PIO4;
+       ap->flags |= ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_IORDY;
+       ap->flags |= ATA_FLAG_PIO_POLLING;
+
+       base = (void __iomem *)ATA_HD_BASE;
+       ap->ioaddr.data_addr            = base;
+       ap->ioaddr.error_addr           = base + 1 + 1 * 4;
+       ap->ioaddr.feature_addr         = base + 1 + 1 * 4;
+       ap->ioaddr.nsect_addr           = base + 1 + 2 * 4;
+       ap->ioaddr.lbal_addr            = base + 1 + 3 * 4;
+       ap->ioaddr.lbam_addr            = base + 1 + 4 * 4;
+       ap->ioaddr.lbah_addr            = base + 1 + 5 * 4;
+       ap->ioaddr.device_addr          = base + 1 + 6 * 4;
+       ap->ioaddr.status_addr          = base + 1 + 7 * 4;
+       ap->ioaddr.command_addr         = base + 1 + 7 * 4;
+
+       ap->ioaddr.altstatus_addr       = base + ATA_HD_CONTROL;
+       ap->ioaddr.ctl_addr             = base + ATA_HD_CONTROL;
+
+       ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", (unsigned long)base,
+                     (unsigned long)base + ATA_HD_CONTROL);
+
+       /* activate */
+       return ata_host_activate(host, 0, NULL, 0, &pata_falcon_sht);
+}
+
+module_init(pata_falcon_init_one);
+
+MODULE_AUTHOR("Bartlomiej Zolnierkiewicz");
+MODULE_DESCRIPTION("low-level driver for Atari Falcon PATA");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
index abda44183512263c7b806eec2b3d2c2210d64326..0b0d93065f5a1a09cbc692a2c53544a23c8fdfeb 100644 (file)
@@ -40,13 +40,13 @@ static int ixp4xx_set_mode(struct ata_link *link, struct ata_device **error)
        return 0;
 }
 
-static unsigned int ixp4xx_mmio_data_xfer(struct ata_device *dev,
+static unsigned int ixp4xx_mmio_data_xfer(struct ata_queued_cmd *qc,
                                unsigned char *buf, unsigned int buflen, int rw)
 {
        unsigned int i;
        unsigned int words = buflen >> 1;
        u16 *buf16 = (u16 *) buf;
-       struct ata_port *ap = dev->link->ap;
+       struct ata_port *ap = qc->dev->link->ap;
        void __iomem *mmio = ap->ioaddr.data_addr;
        struct ixp4xx_pata_data *data = dev_get_platdata(ap->host->dev);
 
index bce2a8ca4678ace5375b6a0f90699481b8ff9659..53828b6c30441735b62a36103d42d67df58794b6 100644 (file)
@@ -303,11 +303,12 @@ static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev)
 
 }
 
-static unsigned int pdc_data_xfer_vlb(struct ata_device *dev,
+static unsigned int pdc_data_xfer_vlb(struct ata_queued_cmd *qc,
                        unsigned char *buf, unsigned int buflen, int rw)
 {
-       int slop = buflen & 3;
+       struct ata_device *dev = qc->dev;
        struct ata_port *ap = dev->link->ap;
+       int slop = buflen & 3;
 
        /* 32bit I/O capable *and* we need to write a whole number of dwords */
        if (ata_id_has_dword_io(dev->id) && (slop == 0 || slop == 3)
@@ -340,7 +341,7 @@ static unsigned int pdc_data_xfer_vlb(struct ata_device *dev,
                }
                local_irq_restore(flags);
        } else
-               buflen = ata_sff_data_xfer_noirq(dev, buf, buflen, rw);
+               buflen = ata_sff_data_xfer_noirq(qc, buf, buflen, rw);
 
        return buflen;
 }
@@ -702,9 +703,11 @@ static unsigned int qdi_qc_issue(struct ata_queued_cmd *qc)
        return ata_sff_qc_issue(qc);
 }
 
-static unsigned int vlb32_data_xfer(struct ata_device *adev, unsigned char *buf,
-                                       unsigned int buflen, int rw)
+static unsigned int vlb32_data_xfer(struct ata_queued_cmd *qc,
+                                   unsigned char *buf,
+                                   unsigned int buflen, int rw)
 {
+       struct ata_device *adev = qc->dev;
        struct ata_port *ap = adev->link->ap;
        int slop = buflen & 3;
 
@@ -727,7 +730,7 @@ static unsigned int vlb32_data_xfer(struct ata_device *adev, unsigned char *buf,
                }
                return (buflen + 3) & ~3;
        } else
-               return ata_sff_data_xfer(adev, buf, buflen, rw);
+               return ata_sff_data_xfer(qc, buf, buflen, rw);
 }
 
 static int qdi_port(struct platform_device *dev,
index 475a006694273bed1262dd457e8a9f683ba0367e..f524a9099d012017fc068206081d90b59d12b808 100644 (file)
@@ -138,9 +138,7 @@ static void octeon_cf_set_piomode(struct ata_port *ap, struct ata_device *dev)
        int trh;
        int pause;
        /* These names are timing parameters from the ATA spec */
-       int t1;
        int t2;
-       int t2i;
 
        /*
         * A divisor value of four will overflow the timing fields at
@@ -154,15 +152,9 @@ static void octeon_cf_set_piomode(struct ata_port *ap, struct ata_device *dev)
 
        BUG_ON(ata_timing_compute(dev, dev->pio_mode, &timing, T, T));
 
-       t1 = timing.setup;
-       if (t1)
-               t1--;
        t2 = timing.active;
        if (t2)
                t2--;
-       t2i = timing.act8b;
-       if (t2i)
-               t2i--;
 
        trh = ns_to_tim_reg(div, 20);
        if (trh)
@@ -293,17 +285,17 @@ static void octeon_cf_set_dmamode(struct ata_port *ap, struct ata_device *dev)
 /**
  * Handle an 8 bit I/O request.
  *
- * @dev:        Device to access
+ * @qc:         Queued command
  * @buffer:     Data buffer
  * @buflen:     Length of the buffer.
  * @rw:         True to write.
  */
-static unsigned int octeon_cf_data_xfer8(struct ata_device *dev,
+static unsigned int octeon_cf_data_xfer8(struct ata_queued_cmd *qc,
                                         unsigned char *buffer,
                                         unsigned int buflen,
                                         int rw)
 {
-       struct ata_port *ap             = dev->link->ap;
+       struct ata_port *ap             = qc->dev->link->ap;
        void __iomem *data_addr         = ap->ioaddr.data_addr;
        unsigned long words;
        int count;
@@ -332,17 +324,17 @@ static unsigned int octeon_cf_data_xfer8(struct ata_device *dev,
 /**
  * Handle a 16 bit I/O request.
  *
- * @dev:        Device to access
+ * @qc:         Queued command
  * @buffer:     Data buffer
  * @buflen:     Length of the buffer.
  * @rw:         True to write.
  */
-static unsigned int octeon_cf_data_xfer16(struct ata_device *dev,
+static unsigned int octeon_cf_data_xfer16(struct ata_queued_cmd *qc,
                                          unsigned char *buffer,
                                          unsigned int buflen,
                                          int rw)
 {
-       struct ata_port *ap             = dev->link->ap;
+       struct ata_port *ap             = qc->dev->link->ap;
        void __iomem *data_addr         = ap->ioaddr.data_addr;
        unsigned long words;
        int count;
index b6b7af894d9dae92a40d140554e7c0923a2c8a7d..201a32d0627fb5fd44d0b1abc9e87f605fd587b2 100644 (file)
@@ -32,7 +32,6 @@ static int pata_of_platform_probe(struct platform_device *ofdev)
        unsigned int reg_shift = 0;
        int pio_mode = 0;
        int pio_mask;
-       const u32 *prop;
 
        ret = of_address_to_resource(dn, 0, &io_res);
        if (ret) {
@@ -50,13 +49,9 @@ static int pata_of_platform_probe(struct platform_device *ofdev)
 
        irq_res = platform_get_resource(ofdev, IORESOURCE_IRQ, 0);
 
-       prop = of_get_property(dn, "reg-shift", NULL);
-       if (prop)
-               reg_shift = be32_to_cpup(prop);
+       of_property_read_u32(dn, "reg-shift", &reg_shift);
 
-       prop = of_get_property(dn, "pio-mode", NULL);
-       if (prop) {
-               pio_mode = be32_to_cpup(prop);
+       if (!of_property_read_u32(dn, "pio-mode", &pio_mode)) {
                if (pio_mode > 6) {
                        dev_err(&ofdev->dev, "invalid pio-mode\n");
                        return -EINVAL;
index bcc4b968c0497cb74ec005c433a993054fe42273..a541eacc5e95c3278598c4b849146280b1f6cc87 100644 (file)
@@ -90,7 +90,7 @@ static int pcmcia_set_mode_8bit(struct ata_link *link,
 
 /**
  *     ata_data_xfer_8bit       -      Transfer data by 8bit PIO
- *     @dev: device to target
+ *     @qc: queued command
  *     @buf: data buffer
  *     @buflen: buffer length
  *     @rw: read/write
@@ -101,10 +101,10 @@ static int pcmcia_set_mode_8bit(struct ata_link *link,
  *     Inherited from caller.
  */
 
-static unsigned int ata_data_xfer_8bit(struct ata_device *dev,
+static unsigned int ata_data_xfer_8bit(struct ata_queued_cmd *qc,
                                unsigned char *buf, unsigned int buflen, int rw)
 {
-       struct ata_port *ap = dev->link->ap;
+       struct ata_port *ap = qc->dev->link->ap;
 
        if (rw == READ)
                ioread8_rep(ap->ioaddr.data_addr, buf, buflen);
index f6facd686f9431b344468b7ba94653bdfac446f4..431c7de30ce64ebd431ddaf01ca87c2127debfad 100644 (file)
@@ -263,10 +263,10 @@ static u8 pata_s3c_check_altstatus(struct ata_port *ap)
 /*
  * pata_s3c_data_xfer - Transfer data by PIO
  */
-static unsigned int pata_s3c_data_xfer(struct ata_device *dev,
+static unsigned int pata_s3c_data_xfer(struct ata_queued_cmd *qc,
                                unsigned char *buf, unsigned int buflen, int rw)
 {
-       struct ata_port *ap = dev->link->ap;
+       struct ata_port *ap = qc->dev->link->ap;
        struct s3c_ide_info *info = ap->host->private_data;
        void __iomem *data_addr = ap->ioaddr.data_addr;
        unsigned int words = buflen >> 1, i;
index 2f32782cea6d9c584797d1f7d9dc8e99eac0b796..00ce26d0c04703a102802d951775e62268239d7f 100644 (file)
@@ -4067,6 +4067,7 @@ static int mv_platform_probe(struct platform_device *pdev)
        struct ata_host *host;
        struct mv_host_priv *hpriv;
        struct resource *res;
+       void __iomem *mmio;
        int n_ports = 0, irq = 0;
        int rc;
        int port;
@@ -4085,8 +4086,9 @@ static int mv_platform_probe(struct platform_device *pdev)
         * Get the register base first
         */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (res == NULL)
-               return -EINVAL;
+       mmio = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(mmio))
+               return PTR_ERR(mmio);
 
        /* allocate host */
        if (pdev->dev.of_node) {
@@ -4130,12 +4132,7 @@ static int mv_platform_probe(struct platform_device *pdev)
        hpriv->board_idx = chip_soc;
 
        host->iomap = NULL;
-       hpriv->base = devm_ioremap(&pdev->dev, res->start,
-                                  resource_size(res));
-       if (!hpriv->base)
-               return -ENOMEM;
-
-       hpriv->base -= SATAHC0_REG_BASE;
+       hpriv->base = mmio - SATAHC0_REG_BASE;
 
        hpriv->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(hpriv->clk))
@@ -4529,7 +4526,7 @@ static void __exit mv_exit(void)
 
 MODULE_AUTHOR("Brett Russ");
 MODULE_DESCRIPTION("SCSI low-level driver for Marvell SATA controllers");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_DEVICE_TABLE(pci, mv_pci_tbl);
 MODULE_VERSION(DRV_VERSION);
 MODULE_ALIAS("platform:" DRV_NAME);
index f72d601e300aa9f85aab64ba4a6d31d001ff075b..5d38245a7a73a7cc4fa0d49255a52c7daead7886 100644 (file)
@@ -447,11 +447,11 @@ static void sata_rcar_exec_command(struct ata_port *ap,
        ata_sff_pause(ap);
 }
 
-static unsigned int sata_rcar_data_xfer(struct ata_device *dev,
+static unsigned int sata_rcar_data_xfer(struct ata_queued_cmd *qc,
                                              unsigned char *buf,
                                              unsigned int buflen, int rw)
 {
-       struct ata_port *ap = dev->link->ap;
+       struct ata_port *ap = qc->dev->link->ap;
        void __iomem *data_addr = ap->ioaddr.data_addr;
        unsigned int words = buflen >> 1;
 
index 4c28e1a0978666e3f228a005661981e44205bd49..2c3b359b3536a15cdb21fbc60af80644368c655d 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/of.h>
 #include <linux/cpufeature.h>
 #include <linux/tick.h>
+#include <linux/pm_qos.h>
 
 #include "base.h"
 
@@ -376,6 +377,7 @@ int register_cpu(struct cpu *cpu, int num)
 
        per_cpu(cpu_sys_devices, num) = &cpu->dev;
        register_cpu_under_node(num, cpu_to_node(num));
+       dev_pm_qos_expose_latency_limit(&cpu->dev, 0);
 
        return 0;
 }
index 2997026b4dfb00c1daec88f1f18264656a61ffb0..3a75fb1b4126f04c934bfa6a37cbe8dbac48fe10 100644 (file)
@@ -130,7 +130,7 @@ static inline bool irq_safe_dev_in_no_sleep_domain(struct device *dev,
 
        ret = pm_runtime_is_irq_safe(dev) && !genpd_is_irq_safe(genpd);
 
-       /* Warn once for each IRQ safe dev in no sleep domain */
+       /* Warn once if IRQ safe dev in no sleep domain */
        if (ret)
                dev_warn_once(dev, "PM domain %s will not be powered off\n",
                                genpd->name);
@@ -201,7 +201,7 @@ static void genpd_sd_counter_inc(struct generic_pm_domain *genpd)
        smp_mb__after_atomic();
 }
 
-static int genpd_power_on(struct generic_pm_domain *genpd, bool timed)
+static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
 {
        unsigned int state_idx = genpd->state_idx;
        ktime_t time_start;
@@ -231,7 +231,7 @@ static int genpd_power_on(struct generic_pm_domain *genpd, bool timed)
        return ret;
 }
 
-static int genpd_power_off(struct generic_pm_domain *genpd, bool timed)
+static int _genpd_power_off(struct generic_pm_domain *genpd, bool timed)
 {
        unsigned int state_idx = genpd->state_idx;
        ktime_t time_start;
@@ -262,10 +262,10 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool timed)
 }
 
 /**
- * genpd_queue_power_off_work - Queue up the execution of genpd_poweroff().
+ * genpd_queue_power_off_work - Queue up the execution of genpd_power_off().
  * @genpd: PM domain to power off.
  *
- * Queue up the execution of genpd_poweroff() unless it's already been done
+ * Queue up the execution of genpd_power_off() unless it's already been done
  * before.
  */
 static void genpd_queue_power_off_work(struct generic_pm_domain *genpd)
@@ -274,14 +274,14 @@ static void genpd_queue_power_off_work(struct generic_pm_domain *genpd)
 }
 
 /**
- * genpd_poweron - Restore power to a given PM domain and its masters.
+ * genpd_power_on - Restore power to a given PM domain and its masters.
  * @genpd: PM domain to power up.
  * @depth: nesting count for lockdep.
  *
  * Restore power to @genpd and all of its masters so that it is possible to
  * resume a device belonging to it.
  */
-static int genpd_poweron(struct generic_pm_domain *genpd, unsigned int depth)
+static int genpd_power_on(struct generic_pm_domain *genpd, unsigned int depth)
 {
        struct gpd_link *link;
        int ret = 0;
@@ -300,7 +300,7 @@ static int genpd_poweron(struct generic_pm_domain *genpd, unsigned int depth)
                genpd_sd_counter_inc(master);
 
                genpd_lock_nested(master, depth + 1);
-               ret = genpd_poweron(master, depth + 1);
+               ret = genpd_power_on(master, depth + 1);
                genpd_unlock(master);
 
                if (ret) {
@@ -309,7 +309,7 @@ static int genpd_poweron(struct generic_pm_domain *genpd, unsigned int depth)
                }
        }
 
-       ret = genpd_power_on(genpd, true);
+       ret = _genpd_power_on(genpd, true);
        if (ret)
                goto err;
 
@@ -368,14 +368,14 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
 }
 
 /**
- * genpd_poweroff - Remove power from a given PM domain.
+ * genpd_power_off - Remove power from a given PM domain.
  * @genpd: PM domain to power down.
  * @is_async: PM domain is powered down from a scheduled work
  *
  * If all of the @genpd's devices have been suspended and all of its subdomains
  * have been powered down, remove power from @genpd.
  */
-static int genpd_poweroff(struct generic_pm_domain *genpd, bool is_async)
+static int genpd_power_off(struct generic_pm_domain *genpd, bool is_async)
 {
        struct pm_domain_data *pdd;
        struct gpd_link *link;
@@ -427,13 +427,13 @@ static int genpd_poweroff(struct generic_pm_domain *genpd, bool is_async)
 
                /*
                 * If sd_count > 0 at this point, one of the subdomains hasn't
-                * managed to call genpd_poweron() for the master yet after
-                * incrementing it.  In that case genpd_poweron() will wait
+                * managed to call genpd_power_on() for the master yet after
+                * incrementing it.  In that case genpd_power_on() will wait
                 * for us to drop the lock, so we can call .power_off() and let
-                * the genpd_poweron() restore power for us (this shouldn't
+                * the genpd_power_on() restore power for us (this shouldn't
                 * happen very often).
                 */
-               ret = genpd_power_off(genpd, true);
+               ret = _genpd_power_off(genpd, true);
                if (ret)
                        return ret;
        }
@@ -459,7 +459,7 @@ static void genpd_power_off_work_fn(struct work_struct *work)
        genpd = container_of(work, struct generic_pm_domain, power_off_work);
 
        genpd_lock(genpd);
-       genpd_poweroff(genpd, true);
+       genpd_power_off(genpd, true);
        genpd_unlock(genpd);
 }
 
@@ -578,7 +578,7 @@ static int genpd_runtime_suspend(struct device *dev)
                return 0;
 
        genpd_lock(genpd);
-       genpd_poweroff(genpd, false);
+       genpd_power_off(genpd, false);
        genpd_unlock(genpd);
 
        return 0;
@@ -618,7 +618,7 @@ static int genpd_runtime_resume(struct device *dev)
        }
 
        genpd_lock(genpd);
-       ret = genpd_poweron(genpd, 0);
+       ret = genpd_power_on(genpd, 0);
        genpd_unlock(genpd);
 
        if (ret)
@@ -658,7 +658,7 @@ err_poweroff:
        if (!pm_runtime_is_irq_safe(dev) ||
                (pm_runtime_is_irq_safe(dev) && genpd_is_irq_safe(genpd))) {
                genpd_lock(genpd);
-               genpd_poweroff(genpd, 0);
+               genpd_power_off(genpd, 0);
                genpd_unlock(genpd);
        }
 
@@ -674,9 +674,9 @@ static int __init pd_ignore_unused_setup(char *__unused)
 __setup("pd_ignore_unused", pd_ignore_unused_setup);
 
 /**
- * genpd_poweroff_unused - Power off all PM domains with no devices in use.
+ * genpd_power_off_unused - Power off all PM domains with no devices in use.
  */
-static int __init genpd_poweroff_unused(void)
+static int __init genpd_power_off_unused(void)
 {
        struct generic_pm_domain *genpd;
 
@@ -694,7 +694,7 @@ static int __init genpd_poweroff_unused(void)
 
        return 0;
 }
-late_initcall(genpd_poweroff_unused);
+late_initcall(genpd_power_off_unused);
 
 #if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_GENERIC_DOMAINS_OF)
 
@@ -727,18 +727,20 @@ static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd,
 }
 
 /**
- * genpd_sync_poweroff - Synchronously power off a PM domain and its masters.
+ * genpd_sync_power_off - Synchronously power off a PM domain and its masters.
  * @genpd: PM domain to power off, if possible.
+ * @use_lock: use the lock.
+ * @depth: nesting count for lockdep.
  *
  * Check if the given PM domain can be powered off (during system suspend or
  * hibernation) and do that if so.  Also, in that case propagate to its masters.
  *
  * This function is only called in "noirq" and "syscore" stages of system power
- * transitions, so it need not acquire locks (all of the "noirq" callbacks are
- * executed sequentially, so it is guaranteed that it will never run twice in
- * parallel).
+ * transitions. The "noirq" callbacks may be executed asynchronously, thus in
+ * these cases the lock must be held.
  */
-static void genpd_sync_poweroff(struct generic_pm_domain *genpd)
+static void genpd_sync_power_off(struct generic_pm_domain *genpd, bool use_lock,
+                                unsigned int depth)
 {
        struct gpd_link *link;
 
@@ -751,26 +753,35 @@ static void genpd_sync_poweroff(struct generic_pm_domain *genpd)
 
        /* Choose the deepest state when suspending */
        genpd->state_idx = genpd->state_count - 1;
-       genpd_power_off(genpd, false);
+       _genpd_power_off(genpd, false);
 
        genpd->status = GPD_STATE_POWER_OFF;
 
        list_for_each_entry(link, &genpd->slave_links, slave_node) {
                genpd_sd_counter_dec(link->master);
-               genpd_sync_poweroff(link->master);
+
+               if (use_lock)
+                       genpd_lock_nested(link->master, depth + 1);
+
+               genpd_sync_power_off(link->master, use_lock, depth + 1);
+
+               if (use_lock)
+                       genpd_unlock(link->master);
        }
 }
 
 /**
- * genpd_sync_poweron - Synchronously power on a PM domain and its masters.
+ * genpd_sync_power_on - Synchronously power on a PM domain and its masters.
  * @genpd: PM domain to power on.
+ * @use_lock: use the lock.
+ * @depth: nesting count for lockdep.
  *
  * This function is only called in "noirq" and "syscore" stages of system power
- * transitions, so it need not acquire locks (all of the "noirq" callbacks are
- * executed sequentially, so it is guaranteed that it will never run twice in
- * parallel).
+ * transitions. The "noirq" callbacks may be executed asynchronously, thus in
+ * these cases the lock must be held.
  */
-static void genpd_sync_poweron(struct generic_pm_domain *genpd)
+static void genpd_sync_power_on(struct generic_pm_domain *genpd, bool use_lock,
+                               unsigned int depth)
 {
        struct gpd_link *link;
 
@@ -778,11 +789,18 @@ static void genpd_sync_poweron(struct generic_pm_domain *genpd)
                return;
 
        list_for_each_entry(link, &genpd->slave_links, slave_node) {
-               genpd_sync_poweron(link->master);
                genpd_sd_counter_inc(link->master);
+
+               if (use_lock)
+                       genpd_lock_nested(link->master, depth + 1);
+
+               genpd_sync_power_on(link->master, use_lock, depth + 1);
+
+               if (use_lock)
+                       genpd_unlock(link->master);
        }
 
-       genpd_power_on(genpd, false);
+       _genpd_power_on(genpd, false);
 
        genpd->status = GPD_STATE_ACTIVE;
 }
@@ -888,13 +906,10 @@ static int pm_genpd_suspend_noirq(struct device *dev)
                        return ret;
        }
 
-       /*
-        * Since all of the "noirq" callbacks are executed sequentially, it is
-        * guaranteed that this function will never run twice in parallel for
-        * the same PM domain, so it is not necessary to use locking here.
-        */
+       genpd_lock(genpd);
        genpd->suspended_count++;
-       genpd_sync_poweroff(genpd);
+       genpd_sync_power_off(genpd, true, 0);
+       genpd_unlock(genpd);
 
        return 0;
 }
@@ -919,13 +934,10 @@ static int pm_genpd_resume_noirq(struct device *dev)
        if (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))
                return 0;
 
-       /*
-        * Since all of the "noirq" callbacks are executed sequentially, it is
-        * guaranteed that this function will never run twice in parallel for
-        * the same PM domain, so it is not necessary to use locking here.
-        */
-       genpd_sync_poweron(genpd);
+       genpd_lock(genpd);
+       genpd_sync_power_on(genpd, true, 0);
        genpd->suspended_count--;
+       genpd_unlock(genpd);
 
        if (genpd->dev_ops.stop && genpd->dev_ops.start)
                ret = pm_runtime_force_resume(dev);
@@ -1002,22 +1014,20 @@ static int pm_genpd_restore_noirq(struct device *dev)
                return -EINVAL;
 
        /*
-        * Since all of the "noirq" callbacks are executed sequentially, it is
-        * guaranteed that this function will never run twice in parallel for
-        * the same PM domain, so it is not necessary to use locking here.
-        *
         * At this point suspended_count == 0 means we are being run for the
         * first time for the given domain in the present cycle.
         */
+       genpd_lock(genpd);
        if (genpd->suspended_count++ == 0)
                /*
                 * The boot kernel might put the domain into arbitrary state,
-                * so make it appear as powered off to genpd_sync_poweron(),
+                * so make it appear as powered off to genpd_sync_power_on(),
                 * so that it tries to power it on in case it was really off.
                 */
                genpd->status = GPD_STATE_POWER_OFF;
 
-       genpd_sync_poweron(genpd);
+       genpd_sync_power_on(genpd, true, 0);
+       genpd_unlock(genpd);
 
        if (genpd->dev_ops.stop && genpd->dev_ops.start)
                ret = pm_runtime_force_resume(dev);
@@ -1072,9 +1082,9 @@ static void genpd_syscore_switch(struct device *dev, bool suspend)
 
        if (suspend) {
                genpd->suspended_count++;
-               genpd_sync_poweroff(genpd);
+               genpd_sync_power_off(genpd, false, 0);
        } else {
-               genpd_sync_poweron(genpd);
+               genpd_sync_power_on(genpd, false, 0);
                genpd->suspended_count--;
        }
 }
@@ -2043,7 +2053,7 @@ int genpd_dev_pm_attach(struct device *dev)
        dev->pm_domain->sync = genpd_dev_pm_sync;
 
        genpd_lock(pd);
-       ret = genpd_poweron(pd, 0);
+       ret = genpd_power_on(pd, 0);
        genpd_unlock(pd);
 out:
        return ret ? -EPROBE_DEFER : 0;
index 35ff06283738036e8388ea19a502b9434874ab99..91ec3232d6300420b5ec0ec8b9359c44a9fba994 100644 (file)
@@ -32,13 +32,7 @@ LIST_HEAD(opp_tables);
 /* Lock to allow exclusive modification to the device and opp lists */
 DEFINE_MUTEX(opp_table_lock);
 
-#define opp_rcu_lockdep_assert()                                       \
-do {                                                                   \
-       RCU_LOCKDEP_WARN(!rcu_read_lock_held() &&                       \
-                        !lockdep_is_held(&opp_table_lock),             \
-                        "Missing rcu_read_lock() or "                  \
-                        "opp_table_lock protection");                  \
-} while (0)
+static void dev_pm_opp_get(struct dev_pm_opp *opp);
 
 static struct opp_device *_find_opp_dev(const struct device *dev,
                                        struct opp_table *opp_table)
@@ -52,38 +46,46 @@ static struct opp_device *_find_opp_dev(const struct device *dev,
        return NULL;
 }
 
+static struct opp_table *_find_opp_table_unlocked(struct device *dev)
+{
+       struct opp_table *opp_table;
+
+       list_for_each_entry(opp_table, &opp_tables, node) {
+               if (_find_opp_dev(dev, opp_table)) {
+                       _get_opp_table_kref(opp_table);
+
+                       return opp_table;
+               }
+       }
+
+       return ERR_PTR(-ENODEV);
+}
+
 /**
  * _find_opp_table() - find opp_table struct using device pointer
  * @dev:       device pointer used to lookup OPP table
  *
- * Search OPP table for one containing matching device. Does a RCU reader
- * operation to grab the pointer needed.
+ * Search OPP table for one containing matching device.
  *
  * Return: pointer to 'struct opp_table' if found, otherwise -ENODEV or
  * -EINVAL based on type of error.
  *
- * Locking: For readers, this function must be called under rcu_read_lock().
- * opp_table is a RCU protected pointer, which means that opp_table is valid
- * as long as we are under RCU lock.
- *
- * For Writers, this function must be called with opp_table_lock held.
+ * The callers must call dev_pm_opp_put_opp_table() after the table is used.
  */
 struct opp_table *_find_opp_table(struct device *dev)
 {
        struct opp_table *opp_table;
 
-       opp_rcu_lockdep_assert();
-
        if (IS_ERR_OR_NULL(dev)) {
                pr_err("%s: Invalid parameters\n", __func__);
                return ERR_PTR(-EINVAL);
        }
 
-       list_for_each_entry_rcu(opp_table, &opp_tables, node)
-               if (_find_opp_dev(dev, opp_table))
-                       return opp_table;
+       mutex_lock(&opp_table_lock);
+       opp_table = _find_opp_table_unlocked(dev);
+       mutex_unlock(&opp_table_lock);
 
-       return ERR_PTR(-ENODEV);
+       return opp_table;
 }
 
 /**
@@ -94,29 +96,15 @@ struct opp_table *_find_opp_table(struct device *dev)
  * return 0
  *
  * This is useful only for devices with single power supply.
- *
- * Locking: This function must be called under rcu_read_lock(). opp is a rcu
- * protected pointer. This means that opp which could have been fetched by
- * opp_find_freq_{exact,ceil,floor} functions is valid as long as we are
- * under RCU lock. The pointer returned by the opp_find_freq family must be
- * used in the same section as the usage of this function with the pointer
- * prior to unlocking with rcu_read_unlock() to maintain the integrity of the
- * pointer.
  */
 unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp)
 {
-       struct dev_pm_opp *tmp_opp;
-       unsigned long v = 0;
-
-       opp_rcu_lockdep_assert();
-
-       tmp_opp = rcu_dereference(opp);
-       if (IS_ERR_OR_NULL(tmp_opp))
+       if (IS_ERR_OR_NULL(opp)) {
                pr_err("%s: Invalid parameters\n", __func__);
-       else
-               v = tmp_opp->supplies[0].u_volt;
+               return 0;
+       }
 
-       return v;
+       return opp->supplies[0].u_volt;
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_get_voltage);
 
@@ -126,29 +114,15 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_voltage);
  *
  * Return: frequency in hertz corresponding to the opp, else
  * return 0
- *
- * Locking: This function must be called under rcu_read_lock(). opp is a rcu
- * protected pointer. This means that opp which could have been fetched by
- * opp_find_freq_{exact,ceil,floor} functions is valid as long as we are
- * under RCU lock. The pointer returned by the opp_find_freq family must be
- * used in the same section as the usage of this function with the pointer
- * prior to unlocking with rcu_read_unlock() to maintain the integrity of the
- * pointer.
  */
 unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp)
 {
-       struct dev_pm_opp *tmp_opp;
-       unsigned long f = 0;
-
-       opp_rcu_lockdep_assert();
-
-       tmp_opp = rcu_dereference(opp);
-       if (IS_ERR_OR_NULL(tmp_opp) || !tmp_opp->available)
+       if (IS_ERR_OR_NULL(opp) || !opp->available) {
                pr_err("%s: Invalid parameters\n", __func__);
-       else
-               f = tmp_opp->rate;
+               return 0;
+       }
 
-       return f;
+       return opp->rate;
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq);
 
@@ -161,28 +135,15 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq);
  * quickly. Running on them for longer times may overheat the chip.
  *
  * Return: true if opp is turbo opp, else false.
- *
- * Locking: This function must be called under rcu_read_lock(). opp is a rcu
- * protected pointer. This means that opp which could have been fetched by
- * opp_find_freq_{exact,ceil,floor} functions is valid as long as we are
- * under RCU lock. The pointer returned by the opp_find_freq family must be
- * used in the same section as the usage of this function with the pointer
- * prior to unlocking with rcu_read_unlock() to maintain the integrity of the
- * pointer.
  */
 bool dev_pm_opp_is_turbo(struct dev_pm_opp *opp)
 {
-       struct dev_pm_opp *tmp_opp;
-
-       opp_rcu_lockdep_assert();
-
-       tmp_opp = rcu_dereference(opp);
-       if (IS_ERR_OR_NULL(tmp_opp) || !tmp_opp->available) {
+       if (IS_ERR_OR_NULL(opp) || !opp->available) {
                pr_err("%s: Invalid parameters\n", __func__);
                return false;
        }
 
-       return tmp_opp->turbo;
+       return opp->turbo;
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_is_turbo);
 
@@ -191,52 +152,29 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_is_turbo);
  * @dev:       device for which we do this operation
  *
  * Return: This function returns the max clock latency in nanoseconds.
- *
- * Locking: This function takes rcu_read_lock().
  */
 unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev)
 {
        struct opp_table *opp_table;
        unsigned long clock_latency_ns;
 
-       rcu_read_lock();
-
        opp_table = _find_opp_table(dev);
        if (IS_ERR(opp_table))
-               clock_latency_ns = 0;
-       else
-               clock_latency_ns = opp_table->clock_latency_ns_max;
-
-       rcu_read_unlock();
-       return clock_latency_ns;
-}
-EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_clock_latency);
-
-static int _get_regulator_count(struct device *dev)
-{
-       struct opp_table *opp_table;
-       int count;
+               return 0;
 
-       rcu_read_lock();
+       clock_latency_ns = opp_table->clock_latency_ns_max;
 
-       opp_table = _find_opp_table(dev);
-       if (!IS_ERR(opp_table))
-               count = opp_table->regulator_count;
-       else
-               count = 0;
+       dev_pm_opp_put_opp_table(opp_table);
 
-       rcu_read_unlock();
-
-       return count;
+       return clock_latency_ns;
 }
+EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_clock_latency);
 
 /**
  * dev_pm_opp_get_max_volt_latency() - Get max voltage latency in nanoseconds
  * @dev: device for which we do this operation
  *
  * Return: This function returns the max voltage latency in nanoseconds.
- *
- * Locking: This function takes rcu_read_lock().
  */
 unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev)
 {
@@ -250,35 +188,33 @@ unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev)
                unsigned long max;
        } *uV;
 
-       count = _get_regulator_count(dev);
+       opp_table = _find_opp_table(dev);
+       if (IS_ERR(opp_table))
+               return 0;
+
+       count = opp_table->regulator_count;
 
        /* Regulator may not be required for the device */
        if (!count)
-               return 0;
+               goto put_opp_table;
 
        regulators = kmalloc_array(count, sizeof(*regulators), GFP_KERNEL);
        if (!regulators)
-               return 0;
+               goto put_opp_table;
 
        uV = kmalloc_array(count, sizeof(*uV), GFP_KERNEL);
        if (!uV)
                goto free_regulators;
 
-       rcu_read_lock();
-
-       opp_table = _find_opp_table(dev);
-       if (IS_ERR(opp_table)) {
-               rcu_read_unlock();
-               goto free_uV;
-       }
-
        memcpy(regulators, opp_table->regulators, count * sizeof(*regulators));
 
+       mutex_lock(&opp_table->lock);
+
        for (i = 0; i < count; i++) {
                uV[i].min = ~0;
                uV[i].max = 0;
 
-               list_for_each_entry_rcu(opp, &opp_table->opp_list, node) {
+               list_for_each_entry(opp, &opp_table->opp_list, node) {
                        if (!opp->available)
                                continue;
 
@@ -289,7 +225,7 @@ unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev)
                }
        }
 
-       rcu_read_unlock();
+       mutex_unlock(&opp_table->lock);
 
        /*
         * The caller needs to ensure that opp_table (and hence the regulator)
@@ -301,10 +237,11 @@ unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev)
                        latency_ns += ret * 1000;
        }
 
-free_uV:
        kfree(uV);
 free_regulators:
        kfree(regulators);
+put_opp_table:
+       dev_pm_opp_put_opp_table(opp_table);
 
        return latency_ns;
 }
@@ -317,8 +254,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_volt_latency);
  *
  * Return: This function returns the max transition latency, in nanoseconds, to
  * switch from one OPP to other.
- *
- * Locking: This function takes rcu_read_lock().
  */
 unsigned long dev_pm_opp_get_max_transition_latency(struct device *dev)
 {
@@ -328,32 +263,29 @@ unsigned long dev_pm_opp_get_max_transition_latency(struct device *dev)
 EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_transition_latency);
 
 /**
- * dev_pm_opp_get_suspend_opp() - Get suspend opp
+ * dev_pm_opp_get_suspend_opp_freq() - Get frequency of suspend opp in Hz
  * @dev:       device for which we do this operation
  *
- * Return: This function returns pointer to the suspend opp if it is
- * defined and available, otherwise it returns NULL.
- *
- * Locking: This function must be called under rcu_read_lock(). opp is a rcu
- * protected pointer. The reason for the same is that the opp pointer which is
- * returned will remain valid for use with opp_get_{voltage, freq} only while
- * under the locked area. The pointer returned must be used prior to unlocking
- * with rcu_read_unlock() to maintain the integrity of the pointer.
+ * Return: This function returns the frequency of the OPP marked as suspend_opp
+ * if one is available, else returns 0;
  */
-struct dev_pm_opp *dev_pm_opp_get_suspend_opp(struct device *dev)
+unsigned long dev_pm_opp_get_suspend_opp_freq(struct device *dev)
 {
        struct opp_table *opp_table;
-
-       opp_rcu_lockdep_assert();
+       unsigned long freq = 0;
 
        opp_table = _find_opp_table(dev);
-       if (IS_ERR(opp_table) || !opp_table->suspend_opp ||
-           !opp_table->suspend_opp->available)
-               return NULL;
+       if (IS_ERR(opp_table))
+               return 0;
+
+       if (opp_table->suspend_opp && opp_table->suspend_opp->available)
+               freq = dev_pm_opp_get_freq(opp_table->suspend_opp);
 
-       return opp_table->suspend_opp;
+       dev_pm_opp_put_opp_table(opp_table);
+
+       return freq;
 }
-EXPORT_SYMBOL_GPL(dev_pm_opp_get_suspend_opp);
+EXPORT_SYMBOL_GPL(dev_pm_opp_get_suspend_opp_freq);
 
 /**
  * dev_pm_opp_get_opp_count() - Get number of opps available in the opp table
@@ -361,8 +293,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_suspend_opp);
  *
  * Return: This function returns the number of available opps if there are any,
  * else returns 0 if none or the corresponding error value.
- *
- * Locking: This function takes rcu_read_lock().
  */
 int dev_pm_opp_get_opp_count(struct device *dev)
 {
@@ -370,23 +300,24 @@ int dev_pm_opp_get_opp_count(struct device *dev)
        struct dev_pm_opp *temp_opp;
        int count = 0;
 
-       rcu_read_lock();
-
        opp_table = _find_opp_table(dev);
        if (IS_ERR(opp_table)) {
                count = PTR_ERR(opp_table);
                dev_err(dev, "%s: OPP table not found (%d)\n",
                        __func__, count);
-               goto out_unlock;
+               return count;
        }
 
-       list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) {
+       mutex_lock(&opp_table->lock);
+
+       list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
                if (temp_opp->available)
                        count++;
        }
 
-out_unlock:
-       rcu_read_unlock();
+       mutex_unlock(&opp_table->lock);
+       dev_pm_opp_put_opp_table(opp_table);
+
        return count;
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_count);
@@ -411,11 +342,8 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_count);
  * This provides a mechanism to enable an opp which is not available currently
  * or the opposite as well.
  *
- * Locking: This function must be called under rcu_read_lock(). opp is a rcu
- * protected pointer. The reason for the same is that the opp pointer which is
- * returned will remain valid for use with opp_get_{voltage, freq} only while
- * under the locked area. The pointer returned must be used prior to unlocking
- * with rcu_read_unlock() to maintain the integrity of the pointer.
+ * The callers are required to call dev_pm_opp_put() for the returned OPP after
+ * use.
  */
 struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
                                              unsigned long freq,
@@ -424,8 +352,6 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
        struct opp_table *opp_table;
        struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
 
-       opp_rcu_lockdep_assert();
-
        opp_table = _find_opp_table(dev);
        if (IS_ERR(opp_table)) {
                int r = PTR_ERR(opp_table);
@@ -434,14 +360,22 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
                return ERR_PTR(r);
        }
 
-       list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) {
+       mutex_lock(&opp_table->lock);
+
+       list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
                if (temp_opp->available == available &&
                                temp_opp->rate == freq) {
                        opp = temp_opp;
+
+                       /* Increment the reference count of OPP */
+                       dev_pm_opp_get(opp);
                        break;
                }
        }
 
+       mutex_unlock(&opp_table->lock);
+       dev_pm_opp_put_opp_table(opp_table);
+
        return opp;
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact);
@@ -451,14 +385,21 @@ static noinline struct dev_pm_opp *_find_freq_ceil(struct opp_table *opp_table,
 {
        struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
 
-       list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) {
+       mutex_lock(&opp_table->lock);
+
+       list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
                if (temp_opp->available && temp_opp->rate >= *freq) {
                        opp = temp_opp;
                        *freq = opp->rate;
+
+                       /* Increment the reference count of OPP */
+                       dev_pm_opp_get(opp);
                        break;
                }
        }
 
+       mutex_unlock(&opp_table->lock);
+
        return opp;
 }
 
@@ -477,18 +418,14 @@ static noinline struct dev_pm_opp *_find_freq_ceil(struct opp_table *opp_table,
  * ERANGE:     no match found for search
  * ENODEV:     if device not found in list of registered devices
  *
- * Locking: This function must be called under rcu_read_lock(). opp is a rcu
- * protected pointer. The reason for the same is that the opp pointer which is
- * returned will remain valid for use with opp_get_{voltage, freq} only while
- * under the locked area. The pointer returned must be used prior to unlocking
- * with rcu_read_unlock() to maintain the integrity of the pointer.
+ * The callers are required to call dev_pm_opp_put() for the returned OPP after
+ * use.
  */
 struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
                                             unsigned long *freq)
 {
        struct opp_table *opp_table;
-
-       opp_rcu_lockdep_assert();
+       struct dev_pm_opp *opp;
 
        if (!dev || !freq) {
                dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
@@ -499,7 +436,11 @@ struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
        if (IS_ERR(opp_table))
                return ERR_CAST(opp_table);
 
-       return _find_freq_ceil(opp_table, freq);
+       opp = _find_freq_ceil(opp_table, freq);
+
+       dev_pm_opp_put_opp_table(opp_table);
+
+       return opp;
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil);
 
@@ -518,11 +459,8 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil);
  * ERANGE:     no match found for search
  * ENODEV:     if device not found in list of registered devices
  *
- * Locking: This function must be called under rcu_read_lock(). opp is a rcu
- * protected pointer. The reason for the same is that the opp pointer which is
- * returned will remain valid for use with opp_get_{voltage, freq} only while
- * under the locked area. The pointer returned must be used prior to unlocking
- * with rcu_read_unlock() to maintain the integrity of the pointer.
+ * The callers are required to call dev_pm_opp_put() for the returned OPP after
+ * use.
  */
 struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
                                              unsigned long *freq)
@@ -530,8 +468,6 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
        struct opp_table *opp_table;
        struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
 
-       opp_rcu_lockdep_assert();
-
        if (!dev || !freq) {
                dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
                return ERR_PTR(-EINVAL);
@@ -541,7 +477,9 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
        if (IS_ERR(opp_table))
                return ERR_CAST(opp_table);
 
-       list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) {
+       mutex_lock(&opp_table->lock);
+
+       list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
                if (temp_opp->available) {
                        /* go to the next node, before choosing prev */
                        if (temp_opp->rate > *freq)
@@ -550,6 +488,13 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
                                opp = temp_opp;
                }
        }
+
+       /* Increment the reference count of OPP */
+       if (!IS_ERR(opp))
+               dev_pm_opp_get(opp);
+       mutex_unlock(&opp_table->lock);
+       dev_pm_opp_put_opp_table(opp_table);
+
        if (!IS_ERR(opp))
                *freq = opp->rate;
 
@@ -557,34 +502,6 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor);
 
-/*
- * The caller needs to ensure that opp_table (and hence the clk) isn't freed,
- * while clk returned here is used.
- */
-static struct clk *_get_opp_clk(struct device *dev)
-{
-       struct opp_table *opp_table;
-       struct clk *clk;
-
-       rcu_read_lock();
-
-       opp_table = _find_opp_table(dev);
-       if (IS_ERR(opp_table)) {
-               dev_err(dev, "%s: device opp doesn't exist\n", __func__);
-               clk = ERR_CAST(opp_table);
-               goto unlock;
-       }
-
-       clk = opp_table->clk;
-       if (IS_ERR(clk))
-               dev_err(dev, "%s: No clock available for the device\n",
-                       __func__);
-
-unlock:
-       rcu_read_unlock();
-       return clk;
-}
-
 static int _set_opp_voltage(struct device *dev, struct regulator *reg,
                            struct dev_pm_opp_supply *supply)
 {
@@ -680,8 +597,6 @@ restore_voltage:
  *
  * This configures the power-supplies and clock source to the levels specified
  * by the OPP corresponding to the target_freq.
- *
- * Locking: This function takes rcu_read_lock().
  */
 int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
 {
@@ -700,9 +615,19 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
                return -EINVAL;
        }
 
-       clk = _get_opp_clk(dev);
-       if (IS_ERR(clk))
-               return PTR_ERR(clk);
+       opp_table = _find_opp_table(dev);
+       if (IS_ERR(opp_table)) {
+               dev_err(dev, "%s: device opp doesn't exist\n", __func__);
+               return PTR_ERR(opp_table);
+       }
+
+       clk = opp_table->clk;
+       if (IS_ERR(clk)) {
+               dev_err(dev, "%s: No clock available for the device\n",
+                       __func__);
+               ret = PTR_ERR(clk);
+               goto put_opp_table;
+       }
 
        freq = clk_round_rate(clk, target_freq);
        if ((long)freq <= 0)
@@ -714,16 +639,8 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
        if (old_freq == freq) {
                dev_dbg(dev, "%s: old/new frequencies (%lu Hz) are same, nothing to do\n",
                        __func__, freq);
-               return 0;
-       }
-
-       rcu_read_lock();
-
-       opp_table = _find_opp_table(dev);
-       if (IS_ERR(opp_table)) {
-               dev_err(dev, "%s: device opp doesn't exist\n", __func__);
-               rcu_read_unlock();
-               return PTR_ERR(opp_table);
+               ret = 0;
+               goto put_opp_table;
        }
 
        old_opp = _find_freq_ceil(opp_table, &old_freq);
@@ -737,8 +654,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
                ret = PTR_ERR(opp);
                dev_err(dev, "%s: failed to find OPP for freq %lu (%d)\n",
                        __func__, freq, ret);
-               rcu_read_unlock();
-               return ret;
+               goto put_old_opp;
        }
 
        dev_dbg(dev, "%s: switching OPP: %lu Hz --> %lu Hz\n", __func__,
@@ -748,8 +664,8 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
 
        /* Only frequency scaling */
        if (!regulators) {
-               rcu_read_unlock();
-               return _generic_set_opp_clk_only(dev, clk, old_freq, freq);
+               ret = _generic_set_opp_clk_only(dev, clk, old_freq, freq);
+               goto put_opps;
        }
 
        if (opp_table->set_opp)
@@ -773,28 +689,26 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
        data->new_opp.rate = freq;
        memcpy(data->new_opp.supplies, opp->supplies, size);
 
-       rcu_read_unlock();
+       ret = set_opp(data);
 
-       return set_opp(data);
+put_opps:
+       dev_pm_opp_put(opp);
+put_old_opp:
+       if (!IS_ERR(old_opp))
+               dev_pm_opp_put(old_opp);
+put_opp_table:
+       dev_pm_opp_put_opp_table(opp_table);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_set_rate);
 
 /* OPP-dev Helpers */
-static void _kfree_opp_dev_rcu(struct rcu_head *head)
-{
-       struct opp_device *opp_dev;
-
-       opp_dev = container_of(head, struct opp_device, rcu_head);
-       kfree_rcu(opp_dev, rcu_head);
-}
-
 static void _remove_opp_dev(struct opp_device *opp_dev,
                            struct opp_table *opp_table)
 {
        opp_debug_unregister(opp_dev, opp_table);
        list_del(&opp_dev->node);
-       call_srcu(&opp_table->srcu_head.srcu, &opp_dev->rcu_head,
-                 _kfree_opp_dev_rcu);
+       kfree(opp_dev);
 }
 
 struct opp_device *_add_opp_dev(const struct device *dev,
@@ -809,7 +723,7 @@ struct opp_device *_add_opp_dev(const struct device *dev,
 
        /* Initialize opp-dev */
        opp_dev->dev = dev;
-       list_add_rcu(&opp_dev->node, &opp_table->dev_list);
+       list_add(&opp_dev->node, &opp_table->dev_list);
 
        /* Create debugfs entries for the opp_table */
        ret = opp_debug_register(opp_dev, opp_table);
@@ -820,26 +734,12 @@ struct opp_device *_add_opp_dev(const struct device *dev,
        return opp_dev;
 }
 
-/**
- * _add_opp_table() - Find OPP table or allocate a new one
- * @dev:       device for which we do this operation
- *
- * It tries to find an existing table first, if it couldn't find one, it
- * allocates a new OPP table and returns that.
- *
- * Return: valid opp_table pointer if success, else NULL.
- */
-static struct opp_table *_add_opp_table(struct device *dev)
+static struct opp_table *_allocate_opp_table(struct device *dev)
 {
        struct opp_table *opp_table;
        struct opp_device *opp_dev;
        int ret;
 
-       /* Check for existing table for 'dev' first */
-       opp_table = _find_opp_table(dev);
-       if (!IS_ERR(opp_table))
-               return opp_table;
-
        /*
         * Allocate a new OPP table. In the infrequent case where a new
         * device is needed to be added, we pay this penalty.
@@ -867,50 +767,45 @@ static struct opp_table *_add_opp_table(struct device *dev)
                                ret);
        }
 
-       srcu_init_notifier_head(&opp_table->srcu_head);
+       BLOCKING_INIT_NOTIFIER_HEAD(&opp_table->head);
        INIT_LIST_HEAD(&opp_table->opp_list);
+       mutex_init(&opp_table->lock);
+       kref_init(&opp_table->kref);
 
        /* Secure the device table modification */
-       list_add_rcu(&opp_table->node, &opp_tables);
+       list_add(&opp_table->node, &opp_tables);
        return opp_table;
 }
 
-/**
- * _kfree_device_rcu() - Free opp_table RCU handler
- * @head:      RCU head
- */
-static void _kfree_device_rcu(struct rcu_head *head)
+void _get_opp_table_kref(struct opp_table *opp_table)
 {
-       struct opp_table *opp_table = container_of(head, struct opp_table,
-                                                  rcu_head);
-
-       kfree_rcu(opp_table, rcu_head);
+       kref_get(&opp_table->kref);
 }
 
-/**
- * _remove_opp_table() - Removes a OPP table
- * @opp_table: OPP table to be removed.
- *
- * Removes/frees OPP table if it doesn't contain any OPPs.
- */
-static void _remove_opp_table(struct opp_table *opp_table)
+struct opp_table *dev_pm_opp_get_opp_table(struct device *dev)
 {
-       struct opp_device *opp_dev;
+       struct opp_table *opp_table;
 
-       if (!list_empty(&opp_table->opp_list))
-               return;
+       /* Hold our table modification lock here */
+       mutex_lock(&opp_table_lock);
 
-       if (opp_table->supported_hw)
-               return;
+       opp_table = _find_opp_table_unlocked(dev);
+       if (!IS_ERR(opp_table))
+               goto unlock;
 
-       if (opp_table->prop_name)
-               return;
+       opp_table = _allocate_opp_table(dev);
 
-       if (opp_table->regulators)
-               return;
+unlock:
+       mutex_unlock(&opp_table_lock);
 
-       if (opp_table->set_opp)
-               return;
+       return opp_table;
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_table);
+
+static void _opp_table_kref_release(struct kref *kref)
+{
+       struct opp_table *opp_table = container_of(kref, struct opp_table, kref);
+       struct opp_device *opp_dev;
 
        /* Release clk */
        if (!IS_ERR(opp_table->clk))
@@ -924,63 +819,60 @@ static void _remove_opp_table(struct opp_table *opp_table)
        /* dev_list must be empty now */
        WARN_ON(!list_empty(&opp_table->dev_list));
 
-       list_del_rcu(&opp_table->node);
-       call_srcu(&opp_table->srcu_head.srcu, &opp_table->rcu_head,
-                 _kfree_device_rcu);
+       mutex_destroy(&opp_table->lock);
+       list_del(&opp_table->node);
+       kfree(opp_table);
+
+       mutex_unlock(&opp_table_lock);
 }
 
-/**
- * _kfree_opp_rcu() - Free OPP RCU handler
- * @head:      RCU head
- */
-static void _kfree_opp_rcu(struct rcu_head *head)
+void dev_pm_opp_put_opp_table(struct opp_table *opp_table)
 {
-       struct dev_pm_opp *opp = container_of(head, struct dev_pm_opp, rcu_head);
+       kref_put_mutex(&opp_table->kref, _opp_table_kref_release,
+                      &opp_table_lock);
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_put_opp_table);
 
-       kfree_rcu(opp, rcu_head);
+void _opp_free(struct dev_pm_opp *opp)
+{
+       kfree(opp);
 }
 
-/**
- * _opp_remove()  - Remove an OPP from a table definition
- * @opp_table: points back to the opp_table struct this opp belongs to
- * @opp:       pointer to the OPP to remove
- * @notify:    OPP_EVENT_REMOVE notification should be sent or not
- *
- * This function removes an opp definition from the opp table.
- *
- * Locking: The internal opp_table and opp structures are RCU protected.
- * It is assumed that the caller holds required mutex for an RCU updater
- * strategy.
- */
-void _opp_remove(struct opp_table *opp_table, struct dev_pm_opp *opp,
-                bool notify)
+static void _opp_kref_release(struct kref *kref)
 {
+       struct dev_pm_opp *opp = container_of(kref, struct dev_pm_opp, kref);
+       struct opp_table *opp_table = opp->opp_table;
+
        /*
         * Notify the changes in the availability of the operable
         * frequency/voltage list.
         */
-       if (notify)
-               srcu_notifier_call_chain(&opp_table->srcu_head,
-                                        OPP_EVENT_REMOVE, opp);
+       blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_REMOVE, opp);
        opp_debug_remove_one(opp);
-       list_del_rcu(&opp->node);
-       call_srcu(&opp_table->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu);
+       list_del(&opp->node);
+       kfree(opp);
 
-       _remove_opp_table(opp_table);
+       mutex_unlock(&opp_table->lock);
+       dev_pm_opp_put_opp_table(opp_table);
+}
+
+static void dev_pm_opp_get(struct dev_pm_opp *opp)
+{
+       kref_get(&opp->kref);
 }
 
+void dev_pm_opp_put(struct dev_pm_opp *opp)
+{
+       kref_put_mutex(&opp->kref, _opp_kref_release, &opp->opp_table->lock);
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_put);
+
 /**
  * dev_pm_opp_remove()  - Remove an OPP from OPP table
  * @dev:       device for which we do this operation
  * @freq:      OPP to remove with matching 'freq'
  *
  * This function removes an opp from the opp table.
- *
- * Locking: The internal opp_table and opp structures are RCU protected.
- * Hence this function internally uses RCU updater strategy with mutex locks
- * to keep the integrity of the internal data structures. Callers should ensure
- * that this function is *NOT* called under RCU protection or in contexts where
- * mutex cannot be locked.
  */
 void dev_pm_opp_remove(struct device *dev, unsigned long freq)
 {
@@ -988,12 +880,11 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq)
        struct opp_table *opp_table;
        bool found = false;
 
-       /* Hold our table modification lock here */
-       mutex_lock(&opp_table_lock);
-
        opp_table = _find_opp_table(dev);
        if (IS_ERR(opp_table))
-               goto unlock;
+               return;
+
+       mutex_lock(&opp_table->lock);
 
        list_for_each_entry(opp, &opp_table->opp_list, node) {
                if (opp->rate == freq) {
@@ -1002,28 +893,23 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq)
                }
        }
 
-       if (!found) {
+       mutex_unlock(&opp_table->lock);
+
+       if (found) {
+               dev_pm_opp_put(opp);
+       } else {
                dev_warn(dev, "%s: Couldn't find OPP with freq: %lu\n",
                         __func__, freq);
-               goto unlock;
        }
 
-       _opp_remove(opp_table, opp, true);
-unlock:
-       mutex_unlock(&opp_table_lock);
+       dev_pm_opp_put_opp_table(opp_table);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_remove);
 
-struct dev_pm_opp *_allocate_opp(struct device *dev,
-                                struct opp_table **opp_table)
+struct dev_pm_opp *_opp_allocate(struct opp_table *table)
 {
        struct dev_pm_opp *opp;
        int count, supply_size;
-       struct opp_table *table;
-
-       table = _add_opp_table(dev);
-       if (!table)
-               return NULL;
 
        /* Allocate space for at least one supply */
        count = table->regulator_count ? table->regulator_count : 1;
@@ -1031,17 +917,13 @@ struct dev_pm_opp *_allocate_opp(struct device *dev,
 
        /* allocate new OPP node and supplies structures */
        opp = kzalloc(sizeof(*opp) + supply_size, GFP_KERNEL);
-       if (!opp) {
-               kfree(table);
+       if (!opp)
                return NULL;
-       }
 
        /* Put the supplies at the end of the OPP structure as an empty array */
        opp->supplies = (struct dev_pm_opp_supply *)(opp + 1);
        INIT_LIST_HEAD(&opp->node);
 
-       *opp_table = table;
-
        return opp;
 }
 
@@ -1067,11 +949,21 @@ static bool _opp_supported_by_regulators(struct dev_pm_opp *opp,
        return true;
 }
 
+/*
+ * Returns:
+ * 0: On success. And appropriate error message for duplicate OPPs.
+ * -EBUSY: For OPP with same freq/volt and is available. The callers of
+ *  _opp_add() must return 0 if they receive -EBUSY from it. This is to make
+ *  sure we don't print error messages unnecessarily if different parts of
+ *  kernel try to initialize the OPP table.
+ * -EEXIST: For OPP with same freq but different volt or is unavailable. This
+ *  should be considered an error by the callers of _opp_add().
+ */
 int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
             struct opp_table *opp_table)
 {
        struct dev_pm_opp *opp;
-       struct list_head *head = &opp_table->opp_list;
+       struct list_head *head;
        int ret;
 
        /*
@@ -1082,7 +974,10 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
         * loop, don't replace it with head otherwise it will become an infinite
         * loop.
         */
-       list_for_each_entry_rcu(opp, &opp_table->opp_list, node) {
+       mutex_lock(&opp_table->lock);
+       head = &opp_table->opp_list;
+
+       list_for_each_entry(opp, &opp_table->opp_list, node) {
                if (new_opp->rate > opp->rate) {
                        head = &opp->node;
                        continue;
@@ -1098,12 +993,21 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
                         new_opp->supplies[0].u_volt, new_opp->available);
 
                /* Should we compare voltages for all regulators here ? */
-               return opp->available &&
-                      new_opp->supplies[0].u_volt == opp->supplies[0].u_volt ? 0 : -EEXIST;
+               ret = opp->available &&
+                     new_opp->supplies[0].u_volt == opp->supplies[0].u_volt ? -EBUSY : -EEXIST;
+
+               mutex_unlock(&opp_table->lock);
+               return ret;
        }
 
+       list_add(&new_opp->node, head);
+       mutex_unlock(&opp_table->lock);
+
        new_opp->opp_table = opp_table;
-       list_add_rcu(&new_opp->node, head);
+       kref_init(&new_opp->kref);
+
+       /* Get a reference to the OPP table */
+       _get_opp_table_kref(opp_table);
 
        ret = opp_debug_create_one(new_opp, opp_table);
        if (ret)
@@ -1121,6 +1025,7 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
 
 /**
  * _opp_add_v1() - Allocate a OPP based on v1 bindings.
+ * @opp_table: OPP table
  * @dev:       device for which we do this operation
  * @freq:      Frequency in Hz for this OPP
  * @u_volt:    Voltage in uVolts for this OPP
@@ -1133,12 +1038,6 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
  * NOTE: "dynamic" parameter impacts OPPs added by the dev_pm_opp_of_add_table
  * and freed by dev_pm_opp_of_remove_table.
  *
- * Locking: The internal opp_table and opp structures are RCU protected.
- * Hence this function internally uses RCU updater strategy with mutex locks
- * to keep the integrity of the internal data structures. Callers should ensure
- * that this function is *NOT* called under RCU protection or in contexts where
- * mutex cannot be locked.
- *
  * Return:
  * 0           On success OR
  *             Duplicate OPPs (both freq and volt are same) and opp->available
@@ -1146,22 +1045,16 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
  *             Duplicate OPPs (both freq and volt are same) and !opp->available
  * -ENOMEM     Memory allocation failure
  */
-int _opp_add_v1(struct device *dev, unsigned long freq, long u_volt,
-               bool dynamic)
+int _opp_add_v1(struct opp_table *opp_table, struct device *dev,
+               unsigned long freq, long u_volt, bool dynamic)
 {
-       struct opp_table *opp_table;
        struct dev_pm_opp *new_opp;
        unsigned long tol;
        int ret;
 
-       /* Hold our table modification lock here */
-       mutex_lock(&opp_table_lock);
-
-       new_opp = _allocate_opp(dev, &opp_table);
-       if (!new_opp) {
-               ret = -ENOMEM;
-               goto unlock;
-       }
+       new_opp = _opp_allocate(opp_table);
+       if (!new_opp)
+               return -ENOMEM;
 
        /* populate the opp table */
        new_opp->rate = freq;
@@ -1173,22 +1066,23 @@ int _opp_add_v1(struct device *dev, unsigned long freq, long u_volt,
        new_opp->dynamic = dynamic;
 
        ret = _opp_add(dev, new_opp, opp_table);
-       if (ret)
+       if (ret) {
+               /* Don't return error for duplicate OPPs */
+               if (ret == -EBUSY)
+                       ret = 0;
                goto free_opp;
-
-       mutex_unlock(&opp_table_lock);
+       }
 
        /*
         * Notify the changes in the availability of the operable
         * frequency/voltage list.
         */
-       srcu_notifier_call_chain(&opp_table->srcu_head, OPP_EVENT_ADD, new_opp);
+       blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ADD, new_opp);
        return 0;
 
 free_opp:
-       _opp_remove(opp_table, new_opp, false);
-unlock:
-       mutex_unlock(&opp_table_lock);
+       _opp_free(new_opp);
+
        return ret;
 }
 
@@ -1202,27 +1096,16 @@ unlock:
  * specify the hierarchy of versions it supports. OPP layer will then enable
  * OPPs, which are available for those versions, based on its 'opp-supported-hw'
  * property.
- *
- * Locking: The internal opp_table and opp structures are RCU protected.
- * Hence this function internally uses RCU updater strategy with mutex locks
- * to keep the integrity of the internal data structures. Callers should ensure
- * that this function is *NOT* called under RCU protection or in contexts where
- * mutex cannot be locked.
  */
-int dev_pm_opp_set_supported_hw(struct device *dev, const u32 *versions,
-                               unsigned int count)
+struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev,
+                       const u32 *versions, unsigned int count)
 {
        struct opp_table *opp_table;
-       int ret = 0;
-
-       /* Hold our table modification lock here */
-       mutex_lock(&opp_table_lock);
+       int ret;
 
-       opp_table = _add_opp_table(dev);
-       if (!opp_table) {
-               ret = -ENOMEM;
-               goto unlock;
-       }
+       opp_table = dev_pm_opp_get_opp_table(dev);
+       if (!opp_table)
+               return ERR_PTR(-ENOMEM);
 
        /* Make sure there are no concurrent readers while updating opp_table */
        WARN_ON(!list_empty(&opp_table->opp_list));
@@ -1243,65 +1126,40 @@ int dev_pm_opp_set_supported_hw(struct device *dev, const u32 *versions,
        }
 
        opp_table->supported_hw_count = count;
-       mutex_unlock(&opp_table_lock);
-       return 0;
+
+       return opp_table;
 
 err:
-       _remove_opp_table(opp_table);
-unlock:
-       mutex_unlock(&opp_table_lock);
+       dev_pm_opp_put_opp_table(opp_table);
 
-       return ret;
+       return ERR_PTR(ret);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_set_supported_hw);
 
 /**
  * dev_pm_opp_put_supported_hw() - Releases resources blocked for supported hw
- * @dev: Device for which supported-hw has to be put.
+ * @opp_table: OPP table returned by dev_pm_opp_set_supported_hw().
  *
  * This is required only for the V2 bindings, and is called for a matching
  * dev_pm_opp_set_supported_hw(). Until this is called, the opp_table structure
  * will not be freed.
- *
- * Locking: The internal opp_table and opp structures are RCU protected.
- * Hence this function internally uses RCU updater strategy with mutex locks
- * to keep the integrity of the internal data structures. Callers should ensure
- * that this function is *NOT* called under RCU protection or in contexts where
- * mutex cannot be locked.
  */
-void dev_pm_opp_put_supported_hw(struct device *dev)
+void dev_pm_opp_put_supported_hw(struct opp_table *opp_table)
 {
-       struct opp_table *opp_table;
-
-       /* Hold our table modification lock here */
-       mutex_lock(&opp_table_lock);
-
-       /* Check for existing table for 'dev' first */
-       opp_table = _find_opp_table(dev);
-       if (IS_ERR(opp_table)) {
-               dev_err(dev, "Failed to find opp_table: %ld\n",
-                       PTR_ERR(opp_table));
-               goto unlock;
-       }
-
        /* Make sure there are no concurrent readers while updating opp_table */
        WARN_ON(!list_empty(&opp_table->opp_list));
 
        if (!opp_table->supported_hw) {
-               dev_err(dev, "%s: Doesn't have supported hardware list\n",
-                       __func__);
-               goto unlock;
+               pr_err("%s: Doesn't have supported hardware list\n",
+                      __func__);
+               return;
        }
 
        kfree(opp_table->supported_hw);
        opp_table->supported_hw = NULL;
        opp_table->supported_hw_count = 0;
 
-       /* Try freeing opp_table if this was the last blocking resource */
-       _remove_opp_table(opp_table);
-
-unlock:
-       mutex_unlock(&opp_table_lock);
+       dev_pm_opp_put_opp_table(opp_table);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_put_supported_hw);
 
@@ -1314,26 +1172,15 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_put_supported_hw);
  * specify the extn to be used for certain property names. The properties to
  * which the extension will apply are opp-microvolt and opp-microamp. OPP core
  * should postfix the property name with -<name> while looking for them.
- *
- * Locking: The internal opp_table and opp structures are RCU protected.
- * Hence this function internally uses RCU updater strategy with mutex locks
- * to keep the integrity of the internal data structures. Callers should ensure
- * that this function is *NOT* called under RCU protection or in contexts where
- * mutex cannot be locked.
  */
-int dev_pm_opp_set_prop_name(struct device *dev, const char *name)
+struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name)
 {
        struct opp_table *opp_table;
-       int ret = 0;
-
-       /* Hold our table modification lock here */
-       mutex_lock(&opp_table_lock);
+       int ret;
 
-       opp_table = _add_opp_table(dev);
-       if (!opp_table) {
-               ret = -ENOMEM;
-               goto unlock;
-       }
+       opp_table = dev_pm_opp_get_opp_table(dev);
+       if (!opp_table)
+               return ERR_PTR(-ENOMEM);
 
        /* Make sure there are no concurrent readers while updating opp_table */
        WARN_ON(!list_empty(&opp_table->opp_list));
@@ -1352,63 +1199,37 @@ int dev_pm_opp_set_prop_name(struct device *dev, const char *name)
                goto err;
        }
 
-       mutex_unlock(&opp_table_lock);
-       return 0;
+       return opp_table;
 
 err:
-       _remove_opp_table(opp_table);
-unlock:
-       mutex_unlock(&opp_table_lock);
+       dev_pm_opp_put_opp_table(opp_table);
 
-       return ret;
+       return ERR_PTR(ret);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_set_prop_name);
 
 /**
  * dev_pm_opp_put_prop_name() - Releases resources blocked for prop-name
- * @dev: Device for which the prop-name has to be put.
+ * @opp_table: OPP table returned by dev_pm_opp_set_prop_name().
  *
  * This is required only for the V2 bindings, and is called for a matching
  * dev_pm_opp_set_prop_name(). Until this is called, the opp_table structure
  * will not be freed.
- *
- * Locking: The internal opp_table and opp structures are RCU protected.
- * Hence this function internally uses RCU updater strategy with mutex locks
- * to keep the integrity of the internal data structures. Callers should ensure
- * that this function is *NOT* called under RCU protection or in contexts where
- * mutex cannot be locked.
  */
-void dev_pm_opp_put_prop_name(struct device *dev)
+void dev_pm_opp_put_prop_name(struct opp_table *opp_table)
 {
-       struct opp_table *opp_table;
-
-       /* Hold our table modification lock here */
-       mutex_lock(&opp_table_lock);
-
-       /* Check for existing table for 'dev' first */
-       opp_table = _find_opp_table(dev);
-       if (IS_ERR(opp_table)) {
-               dev_err(dev, "Failed to find opp_table: %ld\n",
-                       PTR_ERR(opp_table));
-               goto unlock;
-       }
-
        /* Make sure there are no concurrent readers while updating opp_table */
        WARN_ON(!list_empty(&opp_table->opp_list));
 
        if (!opp_table->prop_name) {
-               dev_err(dev, "%s: Doesn't have a prop-name\n", __func__);
-               goto unlock;
+               pr_err("%s: Doesn't have a prop-name\n", __func__);
+               return;
        }
 
        kfree(opp_table->prop_name);
        opp_table->prop_name = NULL;
 
-       /* Try freeing opp_table if this was the last blocking resource */
-       _remove_opp_table(opp_table);
-
-unlock:
-       mutex_unlock(&opp_table_lock);
+       dev_pm_opp_put_opp_table(opp_table);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name);
 
@@ -1455,12 +1276,6 @@ static void _free_set_opp_data(struct opp_table *opp_table)
  * well.
  *
  * This must be called before any OPPs are initialized for the device.
- *
- * Locking: The internal opp_table and opp structures are RCU protected.
- * Hence this function internally uses RCU updater strategy with mutex locks
- * to keep the integrity of the internal data structures. Callers should ensure
- * that this function is *NOT* called under RCU protection or in contexts where
- * mutex cannot be locked.
  */
 struct opp_table *dev_pm_opp_set_regulators(struct device *dev,
                                            const char * const names[],
@@ -1470,13 +1285,9 @@ struct opp_table *dev_pm_opp_set_regulators(struct device *dev,
        struct regulator *reg;
        int ret, i;
 
-       mutex_lock(&opp_table_lock);
-
-       opp_table = _add_opp_table(dev);
-       if (!opp_table) {
-               ret = -ENOMEM;
-               goto unlock;
-       }
+       opp_table = dev_pm_opp_get_opp_table(dev);
+       if (!opp_table)
+               return ERR_PTR(-ENOMEM);
 
        /* This should be called before OPPs are initialized */
        if (WARN_ON(!list_empty(&opp_table->opp_list))) {
@@ -1518,7 +1329,6 @@ struct opp_table *dev_pm_opp_set_regulators(struct device *dev,
        if (ret)
                goto free_regulators;
 
-       mutex_unlock(&opp_table_lock);
        return opp_table;
 
 free_regulators:
@@ -1529,9 +1339,7 @@ free_regulators:
        opp_table->regulators = NULL;
        opp_table->regulator_count = 0;
 err:
-       _remove_opp_table(opp_table);
-unlock:
-       mutex_unlock(&opp_table_lock);
+       dev_pm_opp_put_opp_table(opp_table);
 
        return ERR_PTR(ret);
 }
@@ -1540,22 +1348,14 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulators);
 /**
  * dev_pm_opp_put_regulators() - Releases resources blocked for regulator
  * @opp_table: OPP table returned from dev_pm_opp_set_regulators().
- *
- * Locking: The internal opp_table and opp structures are RCU protected.
- * Hence this function internally uses RCU updater strategy with mutex locks
- * to keep the integrity of the internal data structures. Callers should ensure
- * that this function is *NOT* called under RCU protection or in contexts where
- * mutex cannot be locked.
  */
 void dev_pm_opp_put_regulators(struct opp_table *opp_table)
 {
        int i;
 
-       mutex_lock(&opp_table_lock);
-
        if (!opp_table->regulators) {
                pr_err("%s: Doesn't have regulators set\n", __func__);
-               goto unlock;
+               return;
        }
 
        /* Make sure there are no concurrent readers while updating opp_table */
@@ -1570,11 +1370,7 @@ void dev_pm_opp_put_regulators(struct opp_table *opp_table)
        opp_table->regulators = NULL;
        opp_table->regulator_count = 0;
 
-       /* Try freeing opp_table if this was the last blocking resource */
-       _remove_opp_table(opp_table);
-
-unlock:
-       mutex_unlock(&opp_table_lock);
+       dev_pm_opp_put_opp_table(opp_table);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulators);
 
@@ -1587,29 +1383,19 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulators);
  * regulators per device), instead of the generic OPP set rate helper.
  *
  * This must be called before any OPPs are initialized for the device.
- *
- * Locking: The internal opp_table and opp structures are RCU protected.
- * Hence this function internally uses RCU updater strategy with mutex locks
- * to keep the integrity of the internal data structures. Callers should ensure
- * that this function is *NOT* called under RCU protection or in contexts where
- * mutex cannot be locked.
  */
-int dev_pm_opp_register_set_opp_helper(struct device *dev,
+struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev,
                        int (*set_opp)(struct dev_pm_set_opp_data *data))
 {
        struct opp_table *opp_table;
        int ret;
 
        if (!set_opp)
-               return -EINVAL;
-
-       mutex_lock(&opp_table_lock);
+               return ERR_PTR(-EINVAL);
 
-       opp_table = _add_opp_table(dev);
-       if (!opp_table) {
-               ret = -ENOMEM;
-               goto unlock;
-       }
+       opp_table = dev_pm_opp_get_opp_table(dev);
+       if (!opp_table)
+               return ERR_PTR(-ENOMEM);
 
        /* This should be called before OPPs are initialized */
        if (WARN_ON(!list_empty(&opp_table->opp_list))) {
@@ -1625,47 +1411,28 @@ int dev_pm_opp_register_set_opp_helper(struct device *dev,
 
        opp_table->set_opp = set_opp;
 
-       mutex_unlock(&opp_table_lock);
-       return 0;
+       return opp_table;
 
 err:
-       _remove_opp_table(opp_table);
-unlock:
-       mutex_unlock(&opp_table_lock);
+       dev_pm_opp_put_opp_table(opp_table);
 
-       return ret;
+       return ERR_PTR(ret);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_register_set_opp_helper);
 
 /**
  * dev_pm_opp_register_put_opp_helper() - Releases resources blocked for
  *                                        set_opp helper
- * @dev: Device for which custom set_opp helper has to be cleared.
+ * @opp_table: OPP table returned from dev_pm_opp_register_set_opp_helper().
  *
- * Locking: The internal opp_table and opp structures are RCU protected.
- * Hence this function internally uses RCU updater strategy with mutex locks
- * to keep the integrity of the internal data structures. Callers should ensure
- * that this function is *NOT* called under RCU protection or in contexts where
- * mutex cannot be locked.
+ * Release resources blocked for platform specific set_opp helper.
  */
-void dev_pm_opp_register_put_opp_helper(struct device *dev)
+void dev_pm_opp_register_put_opp_helper(struct opp_table *opp_table)
 {
-       struct opp_table *opp_table;
-
-       mutex_lock(&opp_table_lock);
-
-       /* Check for existing table for 'dev' first */
-       opp_table = _find_opp_table(dev);
-       if (IS_ERR(opp_table)) {
-               dev_err(dev, "Failed to find opp_table: %ld\n",
-                       PTR_ERR(opp_table));
-               goto unlock;
-       }
-
        if (!opp_table->set_opp) {
-               dev_err(dev, "%s: Doesn't have custom set_opp helper set\n",
-                       __func__);
-               goto unlock;
+               pr_err("%s: Doesn't have custom set_opp helper set\n",
+                      __func__);
+               return;
        }
 
        /* Make sure there are no concurrent readers while updating opp_table */
@@ -1673,11 +1440,7 @@ void dev_pm_opp_register_put_opp_helper(struct device *dev)
 
        opp_table->set_opp = NULL;
 
-       /* Try freeing opp_table if this was the last blocking resource */
-       _remove_opp_table(opp_table);
-
-unlock:
-       mutex_unlock(&opp_table_lock);
+       dev_pm_opp_put_opp_table(opp_table);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_register_put_opp_helper);
 
@@ -1691,12 +1454,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_register_put_opp_helper);
  * The opp is made available by default and it can be controlled using
  * dev_pm_opp_enable/disable functions.
  *
- * Locking: The internal opp_table and opp structures are RCU protected.
- * Hence this function internally uses RCU updater strategy with mutex locks
- * to keep the integrity of the internal data structures. Callers should ensure
- * that this function is *NOT* called under RCU protection or in contexts where
- * mutex cannot be locked.
- *
  * Return:
  * 0           On success OR
  *             Duplicate OPPs (both freq and volt are same) and opp->available
@@ -1706,7 +1463,17 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_register_put_opp_helper);
  */
 int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
 {
-       return _opp_add_v1(dev, freq, u_volt, true);
+       struct opp_table *opp_table;
+       int ret;
+
+       opp_table = dev_pm_opp_get_opp_table(dev);
+       if (!opp_table)
+               return -ENOMEM;
+
+       ret = _opp_add_v1(opp_table, dev, freq, u_volt, true);
+
+       dev_pm_opp_put_opp_table(opp_table);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_add);
 
@@ -1716,41 +1483,30 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_add);
  * @freq:              OPP frequency to modify availability
  * @availability_req:  availability status requested for this opp
  *
- * Set the availability of an OPP with an RCU operation, opp_{enable,disable}
- * share a common logic which is isolated here.
+ * Set the availability of an OPP, opp_{enable,disable} share a common logic
+ * which is isolated here.
  *
  * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the
  * copy operation, returns 0 if no modification was done OR modification was
  * successful.
- *
- * Locking: The internal opp_table and opp structures are RCU protected.
- * Hence this function internally uses RCU updater strategy with mutex locks to
- * keep the integrity of the internal data structures. Callers should ensure
- * that this function is *NOT* called under RCU protection or in contexts where
- * mutex locking or synchronize_rcu() blocking calls cannot be used.
  */
 static int _opp_set_availability(struct device *dev, unsigned long freq,
                                 bool availability_req)
 {
        struct opp_table *opp_table;
-       struct dev_pm_opp *new_opp, *tmp_opp, *opp = ERR_PTR(-ENODEV);
+       struct dev_pm_opp *tmp_opp, *opp = ERR_PTR(-ENODEV);
        int r = 0;
 
-       /* keep the node allocated */
-       new_opp = kmalloc(sizeof(*new_opp), GFP_KERNEL);
-       if (!new_opp)
-               return -ENOMEM;
-
-       mutex_lock(&opp_table_lock);
-
        /* Find the opp_table */
        opp_table = _find_opp_table(dev);
        if (IS_ERR(opp_table)) {
                r = PTR_ERR(opp_table);
                dev_warn(dev, "%s: Device OPP not found (%d)\n", __func__, r);
-               goto unlock;
+               return r;
        }
 
+       mutex_lock(&opp_table->lock);
+
        /* Do we have the frequency? */
        list_for_each_entry(tmp_opp, &opp_table->opp_list, node) {
                if (tmp_opp->rate == freq) {
@@ -1758,6 +1514,7 @@ static int _opp_set_availability(struct device *dev, unsigned long freq,
                        break;
                }
        }
+
        if (IS_ERR(opp)) {
                r = PTR_ERR(opp);
                goto unlock;
@@ -1766,29 +1523,20 @@ static int _opp_set_availability(struct device *dev, unsigned long freq,
        /* Is update really needed? */
        if (opp->available == availability_req)
                goto unlock;
-       /* copy the old data over */
-       *new_opp = *opp;
 
-       /* plug in new node */
-       new_opp->available = availability_req;
-
-       list_replace_rcu(&opp->node, &new_opp->node);
-       mutex_unlock(&opp_table_lock);
-       call_srcu(&opp_table->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu);
+       opp->available = availability_req;
 
        /* Notify the change of the OPP availability */
        if (availability_req)
-               srcu_notifier_call_chain(&opp_table->srcu_head,
-                                        OPP_EVENT_ENABLE, new_opp);
+               blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ENABLE,
+                                            opp);
        else
-               srcu_notifier_call_chain(&opp_table->srcu_head,
-                                        OPP_EVENT_DISABLE, new_opp);
-
-       return 0;
+               blocking_notifier_call_chain(&opp_table->head,
+                                            OPP_EVENT_DISABLE, opp);
 
 unlock:
-       mutex_unlock(&opp_table_lock);
-       kfree(new_opp);
+       mutex_unlock(&opp_table->lock);
+       dev_pm_opp_put_opp_table(opp_table);
        return r;
 }
 
@@ -1801,12 +1549,6 @@ unlock:
  * corresponding error value. It is meant to be used for users an OPP available
  * after being temporarily made unavailable with dev_pm_opp_disable.
  *
- * Locking: The internal opp_table and opp structures are RCU protected.
- * Hence this function indirectly uses RCU and mutex locks to keep the
- * integrity of the internal data structures. Callers should ensure that
- * this function is *NOT* called under RCU protection or in contexts where
- * mutex locking or synchronize_rcu() blocking calls cannot be used.
- *
  * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the
  * copy operation, returns 0 if no modification was done OR modification was
  * successful.
@@ -1827,12 +1569,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_enable);
  * control by users to make this OPP not available until the circumstances are
  * right to make it available again (with a call to dev_pm_opp_enable).
  *
- * Locking: The internal opp_table and opp structures are RCU protected.
- * Hence this function indirectly uses RCU and mutex locks to keep the
- * integrity of the internal data structures. Callers should ensure that
- * this function is *NOT* called under RCU protection or in contexts where
- * mutex locking or synchronize_rcu() blocking calls cannot be used.
- *
  * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the
  * copy operation, returns 0 if no modification was done OR modification was
  * successful.
@@ -1844,41 +1580,78 @@ int dev_pm_opp_disable(struct device *dev, unsigned long freq)
 EXPORT_SYMBOL_GPL(dev_pm_opp_disable);
 
 /**
- * dev_pm_opp_get_notifier() - find notifier_head of the device with opp
- * @dev:       device pointer used to lookup OPP table.
+ * dev_pm_opp_register_notifier() - Register OPP notifier for the device
+ * @dev:       Device for which notifier needs to be registered
+ * @nb:                Notifier block to be registered
  *
- * Return: pointer to  notifier head if found, otherwise -ENODEV or
- * -EINVAL based on type of error casted as pointer. value must be checked
- *  with IS_ERR to determine valid pointer or error result.
+ * Return: 0 on success or a negative error value.
+ */
+int dev_pm_opp_register_notifier(struct device *dev, struct notifier_block *nb)
+{
+       struct opp_table *opp_table;
+       int ret;
+
+       opp_table = _find_opp_table(dev);
+       if (IS_ERR(opp_table))
+               return PTR_ERR(opp_table);
+
+       ret = blocking_notifier_chain_register(&opp_table->head, nb);
+
+       dev_pm_opp_put_opp_table(opp_table);
+
+       return ret;
+}
+EXPORT_SYMBOL(dev_pm_opp_register_notifier);
+
+/**
+ * dev_pm_opp_unregister_notifier() - Unregister OPP notifier for the device
+ * @dev:       Device for which notifier needs to be unregistered
+ * @nb:                Notifier block to be unregistered
  *
- * Locking: This function must be called under rcu_read_lock(). opp_table is a
- * RCU protected pointer. The reason for the same is that the opp pointer which
- * is returned will remain valid for use with opp_get_{voltage, freq} only while
- * under the locked area. The pointer returned must be used prior to unlocking
- * with rcu_read_unlock() to maintain the integrity of the pointer.
+ * Return: 0 on success or a negative error value.
  */
-struct srcu_notifier_head *dev_pm_opp_get_notifier(struct device *dev)
+int dev_pm_opp_unregister_notifier(struct device *dev,
+                                  struct notifier_block *nb)
 {
-       struct opp_table *opp_table = _find_opp_table(dev);
+       struct opp_table *opp_table;
+       int ret;
 
+       opp_table = _find_opp_table(dev);
        if (IS_ERR(opp_table))
-               return ERR_CAST(opp_table); /* matching type */
+               return PTR_ERR(opp_table);
+
+       ret = blocking_notifier_chain_unregister(&opp_table->head, nb);
 
-       return &opp_table->srcu_head;
+       dev_pm_opp_put_opp_table(opp_table);
+
+       return ret;
 }
-EXPORT_SYMBOL_GPL(dev_pm_opp_get_notifier);
+EXPORT_SYMBOL(dev_pm_opp_unregister_notifier);
 
 /*
  * Free OPPs either created using static entries present in DT or even the
  * dynamically added entries based on remove_all param.
  */
-void _dev_pm_opp_remove_table(struct device *dev, bool remove_all)
+void _dev_pm_opp_remove_table(struct opp_table *opp_table, struct device *dev,
+                             bool remove_all)
 {
-       struct opp_table *opp_table;
        struct dev_pm_opp *opp, *tmp;
 
-       /* Hold our table modification lock here */
-       mutex_lock(&opp_table_lock);
+       /* Find if opp_table manages a single device */
+       if (list_is_singular(&opp_table->dev_list)) {
+               /* Free static OPPs */
+               list_for_each_entry_safe(opp, tmp, &opp_table->opp_list, node) {
+                       if (remove_all || !opp->dynamic)
+                               dev_pm_opp_put(opp);
+               }
+       } else {
+               _remove_opp_dev(_find_opp_dev(dev, opp_table), opp_table);
+       }
+}
+
+void _dev_pm_opp_find_and_remove_table(struct device *dev, bool remove_all)
+{
+       struct opp_table *opp_table;
 
        /* Check for existing table for 'dev' */
        opp_table = _find_opp_table(dev);
@@ -1890,22 +1663,12 @@ void _dev_pm_opp_remove_table(struct device *dev, bool remove_all)
                             IS_ERR_OR_NULL(dev) ?
                                        "Invalid device" : dev_name(dev),
                             error);
-               goto unlock;
+               return;
        }
 
-       /* Find if opp_table manages a single device */
-       if (list_is_singular(&opp_table->dev_list)) {
-               /* Free static OPPs */
-               list_for_each_entry_safe(opp, tmp, &opp_table->opp_list, node) {
-                       if (remove_all || !opp->dynamic)
-                               _opp_remove(opp_table, opp, true);
-               }
-       } else {
-               _remove_opp_dev(_find_opp_dev(dev, opp_table), opp_table);
-       }
+       _dev_pm_opp_remove_table(opp_table, dev, remove_all);
 
-unlock:
-       mutex_unlock(&opp_table_lock);
+       dev_pm_opp_put_opp_table(opp_table);
 }
 
 /**
@@ -1914,15 +1677,9 @@ unlock:
  *
  * Free both OPPs created using static entries present in DT and the
  * dynamically added entries.
- *
- * Locking: The internal opp_table and opp structures are RCU protected.
- * Hence this function indirectly uses RCU updater strategy with mutex locks
- * to keep the integrity of the internal data structures. Callers should ensure
- * that this function is *NOT* called under RCU protection or in contexts where
- * mutex cannot be locked.
  */
 void dev_pm_opp_remove_table(struct device *dev)
 {
-       _dev_pm_opp_remove_table(dev, true);
+       _dev_pm_opp_find_and_remove_table(dev, true);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_remove_table);
index 8c3434bdb26dee8c23a637798b18a3963666ee70..2d87bc1adf38b682d5416a72987115eb68737000 100644 (file)
  *
  * WARNING: It is  important for the callers to ensure refreshing their copy of
  * the table if any of the mentioned functions have been invoked in the interim.
- *
- * Locking: The internal opp_table and opp structures are RCU protected.
- * Since we just use the regular accessor functions to access the internal data
- * structures, we use RCU read lock inside this function. As a result, users of
- * this function DONOT need to use explicit locks for invoking.
  */
 int dev_pm_opp_init_cpufreq_table(struct device *dev,
                                  struct cpufreq_frequency_table **table)
@@ -56,19 +51,13 @@ int dev_pm_opp_init_cpufreq_table(struct device *dev,
        int i, max_opps, ret = 0;
        unsigned long rate;
 
-       rcu_read_lock();
-
        max_opps = dev_pm_opp_get_opp_count(dev);
-       if (max_opps <= 0) {
-               ret = max_opps ? max_opps : -ENODATA;
-               goto out;
-       }
+       if (max_opps <= 0)
+               return max_opps ? max_opps : -ENODATA;
 
        freq_table = kcalloc((max_opps + 1), sizeof(*freq_table), GFP_ATOMIC);
-       if (!freq_table) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!freq_table)
+               return -ENOMEM;
 
        for (i = 0, rate = 0; i < max_opps; i++, rate++) {
                /* find next rate */
@@ -83,6 +72,8 @@ int dev_pm_opp_init_cpufreq_table(struct device *dev,
                /* Is Boost/turbo opp ? */
                if (dev_pm_opp_is_turbo(opp))
                        freq_table[i].flags = CPUFREQ_BOOST_FREQ;
+
+               dev_pm_opp_put(opp);
        }
 
        freq_table[i].driver_data = i;
@@ -91,7 +82,6 @@ int dev_pm_opp_init_cpufreq_table(struct device *dev,
        *table = &freq_table[0];
 
 out:
-       rcu_read_unlock();
        if (ret)
                kfree(freq_table);
 
@@ -147,12 +137,6 @@ void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, bool of)
  * This removes the OPP tables for CPUs present in the @cpumask.
  * This should be used to remove all the OPPs entries associated with
  * the cpus in @cpumask.
- *
- * Locking: The internal opp_table and opp structures are RCU protected.
- * Hence this function internally uses RCU updater strategy with mutex locks
- * to keep the integrity of the internal data structures. Callers should ensure
- * that this function is *NOT* called under RCU protection or in contexts where
- * mutex cannot be locked.
  */
 void dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask)
 {
@@ -169,12 +153,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_cpumask_remove_table);
  * @cpumask.
  *
  * Returns -ENODEV if OPP table isn't already present.
- *
- * Locking: The internal opp_table and opp structures are RCU protected.
- * Hence this function internally uses RCU updater strategy with mutex locks
- * to keep the integrity of the internal data structures. Callers should ensure
- * that this function is *NOT* called under RCU protection or in contexts where
- * mutex cannot be locked.
  */
 int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev,
                                const struct cpumask *cpumask)
@@ -184,13 +162,9 @@ int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev,
        struct device *dev;
        int cpu, ret = 0;
 
-       mutex_lock(&opp_table_lock);
-
        opp_table = _find_opp_table(cpu_dev);
-       if (IS_ERR(opp_table)) {
-               ret = PTR_ERR(opp_table);
-               goto unlock;
-       }
+       if (IS_ERR(opp_table))
+               return PTR_ERR(opp_table);
 
        for_each_cpu(cpu, cpumask) {
                if (cpu == cpu_dev->id)
@@ -213,8 +187,8 @@ int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev,
                /* Mark opp-table as multiple CPUs are sharing it now */
                opp_table->shared_opp = OPP_TABLE_ACCESS_SHARED;
        }
-unlock:
-       mutex_unlock(&opp_table_lock);
+
+       dev_pm_opp_put_opp_table(opp_table);
 
        return ret;
 }
@@ -229,12 +203,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_set_sharing_cpus);
  *
  * Returns -ENODEV if OPP table isn't already present and -EINVAL if the OPP
  * table's status is access-unknown.
- *
- * Locking: The internal opp_table and opp structures are RCU protected.
- * Hence this function internally uses RCU updater strategy with mutex locks
- * to keep the integrity of the internal data structures. Callers should ensure
- * that this function is *NOT* called under RCU protection or in contexts where
- * mutex cannot be locked.
  */
 int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask)
 {
@@ -242,17 +210,13 @@ int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask)
        struct opp_table *opp_table;
        int ret = 0;
 
-       mutex_lock(&opp_table_lock);
-
        opp_table = _find_opp_table(cpu_dev);
-       if (IS_ERR(opp_table)) {
-               ret = PTR_ERR(opp_table);
-               goto unlock;
-       }
+       if (IS_ERR(opp_table))
+               return PTR_ERR(opp_table);
 
        if (opp_table->shared_opp == OPP_TABLE_ACCESS_UNKNOWN) {
                ret = -EINVAL;
-               goto unlock;
+               goto put_opp_table;
        }
 
        cpumask_clear(cpumask);
@@ -264,8 +228,8 @@ int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask)
                cpumask_set_cpu(cpu_dev->id, cpumask);
        }
 
-unlock:
-       mutex_unlock(&opp_table_lock);
+put_opp_table:
+       dev_pm_opp_put_opp_table(opp_table);
 
        return ret;
 }
index 3f7d2591b173f97e87588077fd9ef41bb76ade2b..779428676f63c07e8f0e05982e6354d623b4a821 100644 (file)
 
 static struct opp_table *_managed_opp(const struct device_node *np)
 {
-       struct opp_table *opp_table;
+       struct opp_table *opp_table, *managed_table = NULL;
+
+       mutex_lock(&opp_table_lock);
 
-       list_for_each_entry_rcu(opp_table, &opp_tables, node) {
+       list_for_each_entry(opp_table, &opp_tables, node) {
                if (opp_table->np == np) {
                        /*
                         * Multiple devices can point to the same OPP table and
@@ -35,14 +37,18 @@ static struct opp_table *_managed_opp(const struct device_node *np)
                         * But the OPPs will be considered as shared only if the
                         * OPP table contains a "opp-shared" property.
                         */
-                       if (opp_table->shared_opp == OPP_TABLE_ACCESS_SHARED)
-                               return opp_table;
+                       if (opp_table->shared_opp == OPP_TABLE_ACCESS_SHARED) {
+                               _get_opp_table_kref(opp_table);
+                               managed_table = opp_table;
+                       }
 
-                       return NULL;
+                       break;
                }
        }
 
-       return NULL;
+       mutex_unlock(&opp_table_lock);
+
+       return managed_table;
 }
 
 void _of_init_opp_table(struct opp_table *opp_table, struct device *dev)
@@ -229,34 +235,28 @@ free_microvolt:
  * @dev:       device pointer used to lookup OPP table.
  *
  * Free OPPs created using static entries present in DT.
- *
- * Locking: The internal opp_table and opp structures are RCU protected.
- * Hence this function indirectly uses RCU updater strategy with mutex locks
- * to keep the integrity of the internal data structures. Callers should ensure
- * that this function is *NOT* called under RCU protection or in contexts where
- * mutex cannot be locked.
  */
 void dev_pm_opp_of_remove_table(struct device *dev)
 {
-       _dev_pm_opp_remove_table(dev, false);
+       _dev_pm_opp_find_and_remove_table(dev, false);
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table);
 
 /* Returns opp descriptor node for a device, caller must do of_node_put() */
-static struct device_node *_of_get_opp_desc_node(struct device *dev)
+struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev)
 {
        /*
-        * TODO: Support for multiple OPP tables.
-        *
         * There should be only ONE phandle present in "operating-points-v2"
         * property.
         */
 
        return of_parse_phandle(dev->of_node, "operating-points-v2", 0);
 }
+EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_opp_desc_node);
 
 /**
  * _opp_add_static_v2() - Allocate static OPPs (As per 'v2' DT bindings)
+ * @opp_table: OPP table
  * @dev:       device for which we do this operation
  * @np:                device node
  *
@@ -264,12 +264,6 @@ static struct device_node *_of_get_opp_desc_node(struct device *dev)
  * opp can be controlled using dev_pm_opp_enable/disable functions and may be
  * removed by dev_pm_opp_remove.
  *
- * Locking: The internal opp_table and opp structures are RCU protected.
- * Hence this function internally uses RCU updater strategy with mutex locks
- * to keep the integrity of the internal data structures. Callers should ensure
- * that this function is *NOT* called under RCU protection or in contexts where
- * mutex cannot be locked.
- *
  * Return:
  * 0           On success OR
  *             Duplicate OPPs (both freq and volt are same) and opp->available
@@ -278,22 +272,17 @@ static struct device_node *_of_get_opp_desc_node(struct device *dev)
  * -ENOMEM     Memory allocation failure
  * -EINVAL     Failed parsing the OPP node
  */
-static int _opp_add_static_v2(struct device *dev, struct device_node *np)
+static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev,
+                             struct device_node *np)
 {
-       struct opp_table *opp_table;
        struct dev_pm_opp *new_opp;
        u64 rate;
        u32 val;
        int ret;
 
-       /* Hold our table modification lock here */
-       mutex_lock(&opp_table_lock);
-
-       new_opp = _allocate_opp(dev, &opp_table);
-       if (!new_opp) {
-               ret = -ENOMEM;
-               goto unlock;
-       }
+       new_opp = _opp_allocate(opp_table);
+       if (!new_opp)
+               return -ENOMEM;
 
        ret = of_property_read_u64(np, "opp-hz", &rate);
        if (ret < 0) {
@@ -327,8 +316,12 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np)
                goto free_opp;
 
        ret = _opp_add(dev, new_opp, opp_table);
-       if (ret)
+       if (ret) {
+               /* Don't return error for duplicate OPPs */
+               if (ret == -EBUSY)
+                       ret = 0;
                goto free_opp;
+       }
 
        /* OPP to select on device suspend */
        if (of_property_read_bool(np, "opp-suspend")) {
@@ -345,8 +338,6 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np)
        if (new_opp->clock_latency_ns > opp_table->clock_latency_ns_max)
                opp_table->clock_latency_ns_max = new_opp->clock_latency_ns;
 
-       mutex_unlock(&opp_table_lock);
-
        pr_debug("%s: turbo:%d rate:%lu uv:%lu uvmin:%lu uvmax:%lu latency:%lu\n",
                 __func__, new_opp->turbo, new_opp->rate,
                 new_opp->supplies[0].u_volt, new_opp->supplies[0].u_volt_min,
@@ -356,13 +347,12 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np)
         * Notify the changes in the availability of the operable
         * frequency/voltage list.
         */
-       srcu_notifier_call_chain(&opp_table->srcu_head, OPP_EVENT_ADD, new_opp);
+       blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ADD, new_opp);
        return 0;
 
 free_opp:
-       _opp_remove(opp_table, new_opp, false);
-unlock:
-       mutex_unlock(&opp_table_lock);
+       _opp_free(new_opp);
+
        return ret;
 }
 
@@ -373,41 +363,35 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np)
        struct opp_table *opp_table;
        int ret = 0, count = 0;
 
-       mutex_lock(&opp_table_lock);
-
        opp_table = _managed_opp(opp_np);
        if (opp_table) {
                /* OPPs are already managed */
                if (!_add_opp_dev(dev, opp_table))
                        ret = -ENOMEM;
-               mutex_unlock(&opp_table_lock);
-               return ret;
+               goto put_opp_table;
        }
-       mutex_unlock(&opp_table_lock);
+
+       opp_table = dev_pm_opp_get_opp_table(dev);
+       if (!opp_table)
+               return -ENOMEM;
 
        /* We have opp-table node now, iterate over it and add OPPs */
        for_each_available_child_of_node(opp_np, np) {
                count++;
 
-               ret = _opp_add_static_v2(dev, np);
+               ret = _opp_add_static_v2(opp_table, dev, np);
                if (ret) {
                        dev_err(dev, "%s: Failed to add OPP, %d\n", __func__,
                                ret);
-                       goto free_table;
+                       _dev_pm_opp_remove_table(opp_table, dev, false);
+                       goto put_opp_table;
                }
        }
 
        /* There should be one of more OPP defined */
-       if (WARN_ON(!count))
-               return -ENOENT;
-
-       mutex_lock(&opp_table_lock);
-
-       opp_table = _find_opp_table(dev);
-       if (WARN_ON(IS_ERR(opp_table))) {
-               ret = PTR_ERR(opp_table);
-               mutex_unlock(&opp_table_lock);
-               goto free_table;
+       if (WARN_ON(!count)) {
+               ret = -ENOENT;
+               goto put_opp_table;
        }
 
        opp_table->np = opp_np;
@@ -416,12 +400,8 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np)
        else
                opp_table->shared_opp = OPP_TABLE_ACCESS_EXCLUSIVE;
 
-       mutex_unlock(&opp_table_lock);
-
-       return 0;
-
-free_table:
-       dev_pm_opp_of_remove_table(dev);
+put_opp_table:
+       dev_pm_opp_put_opp_table(opp_table);
 
        return ret;
 }
@@ -429,9 +409,10 @@ free_table:
 /* Initializes OPP tables based on old-deprecated bindings */
 static int _of_add_opp_table_v1(struct device *dev)
 {
+       struct opp_table *opp_table;
        const struct property *prop;
        const __be32 *val;
-       int nr;
+       int nr, ret = 0;
 
        prop = of_find_property(dev->of_node, "operating-points", NULL);
        if (!prop)
@@ -449,18 +430,27 @@ static int _of_add_opp_table_v1(struct device *dev)
                return -EINVAL;
        }
 
+       opp_table = dev_pm_opp_get_opp_table(dev);
+       if (!opp_table)
+               return -ENOMEM;
+
        val = prop->value;
        while (nr) {
                unsigned long freq = be32_to_cpup(val++) * 1000;
                unsigned long volt = be32_to_cpup(val++);
 
-               if (_opp_add_v1(dev, freq, volt, false))
-                       dev_warn(dev, "%s: Failed to add OPP %ld\n",
-                                __func__, freq);
+               ret = _opp_add_v1(opp_table, dev, freq, volt, false);
+               if (ret) {
+                       dev_err(dev, "%s: Failed to add OPP %ld (%d)\n",
+                               __func__, freq, ret);
+                       _dev_pm_opp_remove_table(opp_table, dev, false);
+                       break;
+               }
                nr -= 2;
        }
 
-       return 0;
+       dev_pm_opp_put_opp_table(opp_table);
+       return ret;
 }
 
 /**
@@ -469,12 +459,6 @@ static int _of_add_opp_table_v1(struct device *dev)
  *
  * Register the initial OPP table with the OPP library for given device.
  *
- * Locking: The internal opp_table and opp structures are RCU protected.
- * Hence this function indirectly uses RCU updater strategy with mutex locks
- * to keep the integrity of the internal data structures. Callers should ensure
- * that this function is *NOT* called under RCU protection or in contexts where
- * mutex cannot be locked.
- *
  * Return:
  * 0           On success OR
  *             Duplicate OPPs (both freq and volt are same) and opp->available
@@ -495,7 +479,7 @@ int dev_pm_opp_of_add_table(struct device *dev)
         * OPPs have two version of bindings now. The older one is deprecated,
         * try for the new binding first.
         */
-       opp_np = _of_get_opp_desc_node(dev);
+       opp_np = dev_pm_opp_of_get_opp_desc_node(dev);
        if (!opp_np) {
                /*
                 * Try old-deprecated bindings for backward compatibility with
@@ -519,12 +503,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table);
  *
  * This removes the OPP tables for CPUs present in the @cpumask.
  * This should be used only to remove static entries created from DT.
- *
- * Locking: The internal opp_table and opp structures are RCU protected.
- * Hence this function internally uses RCU updater strategy with mutex locks
- * to keep the integrity of the internal data structures. Callers should ensure
- * that this function is *NOT* called under RCU protection or in contexts where
- * mutex cannot be locked.
  */
 void dev_pm_opp_of_cpumask_remove_table(const struct cpumask *cpumask)
 {
@@ -537,12 +515,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_remove_table);
  * @cpumask:   cpumask for which OPP table needs to be added.
  *
  * This adds the OPP tables for CPUs present in the @cpumask.
- *
- * Locking: The internal opp_table and opp structures are RCU protected.
- * Hence this function internally uses RCU updater strategy with mutex locks
- * to keep the integrity of the internal data structures. Callers should ensure
- * that this function is *NOT* called under RCU protection or in contexts where
- * mutex cannot be locked.
  */
 int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask)
 {
@@ -590,12 +562,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_add_table);
  * This updates the @cpumask with CPUs that are sharing OPPs with @cpu_dev.
  *
  * Returns -ENOENT if operating-points-v2 isn't present for @cpu_dev.
- *
- * Locking: The internal opp_table and opp structures are RCU protected.
- * Hence this function internally uses RCU updater strategy with mutex locks
- * to keep the integrity of the internal data structures. Callers should ensure
- * that this function is *NOT* called under RCU protection or in contexts where
- * mutex cannot be locked.
  */
 int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev,
                                   struct cpumask *cpumask)
@@ -605,7 +571,7 @@ int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev,
        int cpu, ret = 0;
 
        /* Get OPP descriptor node */
-       np = _of_get_opp_desc_node(cpu_dev);
+       np = dev_pm_opp_of_get_opp_desc_node(cpu_dev);
        if (!np) {
                dev_dbg(cpu_dev, "%s: Couldn't find opp node.\n", __func__);
                return -ENOENT;
@@ -630,7 +596,7 @@ int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev,
                }
 
                /* Get OPP descriptor node */
-               tmp_np = _of_get_opp_desc_node(tcpu_dev);
+               tmp_np = dev_pm_opp_of_get_opp_desc_node(tcpu_dev);
                if (!tmp_np) {
                        dev_err(tcpu_dev, "%s: Couldn't find opp node.\n",
                                __func__);
index af9f2b849a66c3de5c3f7f67ce9ea87d25d5376d..166eef99059955ca315126cc1f62a6f239e16616 100644 (file)
 
 #include <linux/device.h>
 #include <linux/kernel.h>
+#include <linux/kref.h>
 #include <linux/list.h>
 #include <linux/limits.h>
 #include <linux/pm_opp.h>
-#include <linux/rculist.h>
-#include <linux/rcupdate.h>
+#include <linux/notifier.h>
 
 struct clk;
 struct regulator;
@@ -51,11 +51,9 @@ extern struct list_head opp_tables;
  * @node:      opp table node. The nodes are maintained throughout the lifetime
  *             of boot. It is expected only an optimal set of OPPs are
  *             added to the library by the SoC framework.
- *             RCU usage: opp table is traversed with RCU locks. node
- *             modification is possible realtime, hence the modifications
- *             are protected by the opp_table_lock for integrity.
  *             IMPORTANT: the opp nodes should be maintained in increasing
  *             order.
+ * @kref:      for reference count of the OPP.
  * @available: true/false - marks if this OPP as available or not
  * @dynamic:   not-created from static DT entries.
  * @turbo:     true if turbo (boost) OPP
@@ -65,7 +63,6 @@ extern struct list_head opp_tables;
  * @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's
  *             frequency from any other OPP's frequency.
  * @opp_table: points back to the opp_table struct this opp belongs to
- * @rcu_head:  RCU callback head used for deferred freeing
  * @np:                OPP's device node.
  * @dentry:    debugfs dentry pointer (per opp)
  *
@@ -73,6 +70,7 @@ extern struct list_head opp_tables;
  */
 struct dev_pm_opp {
        struct list_head node;
+       struct kref kref;
 
        bool available;
        bool dynamic;
@@ -85,7 +83,6 @@ struct dev_pm_opp {
        unsigned long clock_latency_ns;
 
        struct opp_table *opp_table;
-       struct rcu_head rcu_head;
 
        struct device_node *np;
 
@@ -98,7 +95,6 @@ struct dev_pm_opp {
  * struct opp_device - devices managed by 'struct opp_table'
  * @node:      list node
  * @dev:       device to which the struct object belongs
- * @rcu_head:  RCU callback head used for deferred freeing
  * @dentry:    debugfs dentry pointer (per device)
  *
  * This is an internal data structure maintaining the devices that are managed
@@ -107,7 +103,6 @@ struct dev_pm_opp {
 struct opp_device {
        struct list_head node;
        const struct device *dev;
-       struct rcu_head rcu_head;
 
 #ifdef CONFIG_DEBUG_FS
        struct dentry *dentry;
@@ -125,12 +120,11 @@ enum opp_table_access {
  * @node:      table node - contains the devices with OPPs that
  *             have been registered. Nodes once added are not modified in this
  *             table.
- *             RCU usage: nodes are not modified in the table of opp_table,
- *             however addition is possible and is secured by opp_table_lock
- * @srcu_head: notifier head to notify the OPP availability changes.
- * @rcu_head:  RCU callback head used for deferred freeing
+ * @head:      notifier head to notify the OPP availability changes.
  * @dev_list:  list of devices that share these OPPs
  * @opp_list:  table of opps
+ * @kref:      for reference count of the table.
+ * @lock:      mutex protecting the opp_list.
  * @np:                struct device_node pointer for opp's DT node.
  * @clock_latency_ns_max: Max clock latency in nanoseconds.
  * @shared_opp: OPP is shared between multiple devices.
@@ -151,18 +145,15 @@ enum opp_table_access {
  * This is an internal data structure maintaining the link to opps attached to
  * a device. This structure is not meant to be shared to users as it is
  * meant for book keeping and private to OPP library.
- *
- * Because the opp structures can be used from both rcu and srcu readers, we
- * need to wait for the grace period of both of them before freeing any
- * resources. And so we have used kfree_rcu() from within call_srcu() handlers.
  */
 struct opp_table {
        struct list_head node;
 
-       struct srcu_notifier_head srcu_head;
-       struct rcu_head rcu_head;
+       struct blocking_notifier_head head;
        struct list_head dev_list;
        struct list_head opp_list;
+       struct kref kref;
+       struct mutex lock;
 
        struct device_node *np;
        unsigned long clock_latency_ns_max;
@@ -190,14 +181,17 @@ struct opp_table {
 };
 
 /* Routines internal to opp core */
+void _get_opp_table_kref(struct opp_table *opp_table);
 struct opp_table *_find_opp_table(struct device *dev);
 struct opp_device *_add_opp_dev(const struct device *dev, struct opp_table *opp_table);
-void _dev_pm_opp_remove_table(struct device *dev, bool remove_all);
-struct dev_pm_opp *_allocate_opp(struct device *dev, struct opp_table **opp_table);
+void _dev_pm_opp_remove_table(struct opp_table *opp_table, struct device *dev, bool remove_all);
+void _dev_pm_opp_find_and_remove_table(struct device *dev, bool remove_all);
+struct dev_pm_opp *_opp_allocate(struct opp_table *opp_table);
+void _opp_free(struct dev_pm_opp *opp);
 int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table);
-void _opp_remove(struct opp_table *opp_table, struct dev_pm_opp *opp, bool notify);
-int _opp_add_v1(struct device *dev, unsigned long freq, long u_volt, bool dynamic);
+int _opp_add_v1(struct opp_table *opp_table, struct device *dev, unsigned long freq, long u_volt, bool dynamic);
 void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, bool of);
+struct opp_table *_add_opp_table(struct device *dev);
 
 #ifdef CONFIG_OF
 void _of_init_opp_table(struct opp_table *opp_table, struct device *dev);
index 58fcc758334e5bd230a5929a70844d35f4615628..d888d9869b6a52919df98dfa2ef286a45f9b801b 100644 (file)
@@ -281,7 +281,7 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
        dev->power.qos = ERR_PTR(-ENODEV);
        spin_unlock_irq(&dev->power.lock);
 
-       kfree(c->notifiers);
+       kfree(qos->resume_latency.notifiers);
        kfree(qos);
 
  out:
index 404d94c6c8bc6a4531b0666a77c5b86daab207a6..ae0429827f31052fff58362131e171f33ff27a17 100644 (file)
@@ -141,6 +141,13 @@ static irqreturn_t handle_threaded_wake_irq(int irq, void *_wirq)
        struct wake_irq *wirq = _wirq;
        int res;
 
+       /* Maybe abort suspend? */
+       if (irqd_is_wakeup_set(irq_get_irq_data(irq))) {
+               pm_wakeup_event(wirq->dev, 0);
+
+               return IRQ_HANDLED;
+       }
+
        /* We don't want RPM_ASYNC or RPM_NOWAIT here */
        res = pm_runtime_resume(wirq->dev);
        if (res < 0)
@@ -183,6 +190,9 @@ int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq)
        wirq->irq = irq;
        irq_set_status_flags(irq, IRQ_NOAUTOEN);
 
+       /* Prevent deferred spurious wakeirqs with disable_irq_nosync() */
+       irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY);
+
        /*
         * Consumer device may need to power up and restore state
         * so we use a threaded irq.
@@ -312,8 +322,12 @@ void dev_pm_arm_wake_irq(struct wake_irq *wirq)
        if (!wirq)
                return;
 
-       if (device_may_wakeup(wirq->dev))
+       if (device_may_wakeup(wirq->dev)) {
+               if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED)
+                       enable_irq(wirq->irq);
+
                enable_irq_wake(wirq->irq);
+       }
 }
 
 /**
@@ -328,6 +342,10 @@ void dev_pm_disarm_wake_irq(struct wake_irq *wirq)
        if (!wirq)
                return;
 
-       if (device_may_wakeup(wirq->dev))
+       if (device_may_wakeup(wirq->dev)) {
                disable_irq_wake(wirq->irq);
+
+               if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED)
+                       disable_irq_nosync(wirq->irq);
+       }
 }
index 43a36d68c3fded1602c9e8ce97358264c9f33c8a..c458c63e353f1d62f5c73ef0c91f826d5323088a 100644 (file)
@@ -21,7 +21,7 @@
 
 struct property_set {
        struct fwnode_handle fwnode;
-       struct property_entry *properties;
+       const struct property_entry *properties;
 };
 
 static inline bool is_pset_node(struct fwnode_handle *fwnode)
@@ -35,10 +35,10 @@ static inline struct property_set *to_pset_node(struct fwnode_handle *fwnode)
                container_of(fwnode, struct property_set, fwnode) : NULL;
 }
 
-static struct property_entry *pset_prop_get(struct property_set *pset,
-                                           const char *name)
+static const struct property_entry *pset_prop_get(struct property_set *pset,
+                                                 const char *name)
 {
-       struct property_entry *prop;
+       const struct property_entry *prop;
 
        if (!pset || !pset->properties)
                return NULL;
@@ -50,11 +50,11 @@ static struct property_entry *pset_prop_get(struct property_set *pset,
        return NULL;
 }
 
-static void *pset_prop_find(struct property_set *pset, const char *propname,
-                           size_t length)
+static const void *pset_prop_find(struct property_set *pset,
+                                 const char *propname, size_t length)
 {
-       struct property_entry *prop;
-       void *pointer;
+       const struct property_entry *prop;
+       const void *pointer;
 
        prop = pset_prop_get(pset, propname);
        if (!prop)
@@ -74,7 +74,7 @@ static int pset_prop_read_u8_array(struct property_set *pset,
                                   const char *propname,
                                   u8 *values, size_t nval)
 {
-       void *pointer;
+       const void *pointer;
        size_t length = nval * sizeof(*values);
 
        pointer = pset_prop_find(pset, propname, length);
@@ -89,7 +89,7 @@ static int pset_prop_read_u16_array(struct property_set *pset,
                                    const char *propname,
                                    u16 *values, size_t nval)
 {
-       void *pointer;
+       const void *pointer;
        size_t length = nval * sizeof(*values);
 
        pointer = pset_prop_find(pset, propname, length);
@@ -104,7 +104,7 @@ static int pset_prop_read_u32_array(struct property_set *pset,
                                    const char *propname,
                                    u32 *values, size_t nval)
 {
-       void *pointer;
+       const void *pointer;
        size_t length = nval * sizeof(*values);
 
        pointer = pset_prop_find(pset, propname, length);
@@ -119,7 +119,7 @@ static int pset_prop_read_u64_array(struct property_set *pset,
                                    const char *propname,
                                    u64 *values, size_t nval)
 {
-       void *pointer;
+       const void *pointer;
        size_t length = nval * sizeof(*values);
 
        pointer = pset_prop_find(pset, propname, length);
@@ -133,7 +133,7 @@ static int pset_prop_read_u64_array(struct property_set *pset,
 static int pset_prop_count_elems_of_size(struct property_set *pset,
                                         const char *propname, size_t length)
 {
-       struct property_entry *prop;
+       const struct property_entry *prop;
 
        prop = pset_prop_get(pset, propname);
        if (!prop)
@@ -146,7 +146,7 @@ static int pset_prop_read_string_array(struct property_set *pset,
                                       const char *propname,
                                       const char **strings, size_t nval)
 {
-       void *pointer;
+       const void *pointer;
        size_t length = nval * sizeof(*strings);
 
        pointer = pset_prop_find(pset, propname, length);
@@ -160,8 +160,8 @@ static int pset_prop_read_string_array(struct property_set *pset,
 static int pset_prop_read_string(struct property_set *pset,
                                 const char *propname, const char **strings)
 {
-       struct property_entry *prop;
-       const char **pointer;
+       const struct property_entry *prop;
+       const char * const *pointer;
 
        prop = pset_prop_get(pset, propname);
        if (!prop)
@@ -682,77 +682,64 @@ out:
 }
 EXPORT_SYMBOL_GPL(fwnode_property_match_string);
 
-/**
- * pset_free_set - releases memory allocated for copied property set
- * @pset: Property set to release
- *
- * Function takes previously copied property set and releases all the
- * memory allocated to it.
- */
-static void pset_free_set(struct property_set *pset)
+static int property_copy_string_array(struct property_entry *dst,
+                                     const struct property_entry *src)
 {
-       const struct property_entry *prop;
-       size_t i, nval;
+       char **d;
+       size_t nval = src->length / sizeof(*d);
+       int i;
 
-       if (!pset)
-               return;
+       d = kcalloc(nval, sizeof(*d), GFP_KERNEL);
+       if (!d)
+               return -ENOMEM;
 
-       for (prop = pset->properties; prop->name; prop++) {
-               if (prop->is_array) {
-                       if (prop->is_string && prop->pointer.str) {
-                               nval = prop->length / sizeof(const char *);
-                               for (i = 0; i < nval; i++)
-                                       kfree(prop->pointer.str[i]);
-                       }
-                       kfree(prop->pointer.raw_data);
-               } else if (prop->is_string) {
-                       kfree(prop->value.str);
+       for (i = 0; i < nval; i++) {
+               d[i] = kstrdup(src->pointer.str[i], GFP_KERNEL);
+               if (!d[i] && src->pointer.str[i]) {
+                       while (--i >= 0)
+                               kfree(d[i]);
+                       kfree(d);
+                       return -ENOMEM;
                }
-               kfree(prop->name);
        }
 
-       kfree(pset->properties);
-       kfree(pset);
+       dst->pointer.raw_data = d;
+       return 0;
 }
 
-static int pset_copy_entry(struct property_entry *dst,
-                          const struct property_entry *src)
+static int property_entry_copy_data(struct property_entry *dst,
+                                   const struct property_entry *src)
 {
-       const char **d, **s;
-       size_t i, nval;
+       int error;
 
        dst->name = kstrdup(src->name, GFP_KERNEL);
        if (!dst->name)
                return -ENOMEM;
 
        if (src->is_array) {
-               if (!src->length)
-                       return -ENODATA;
+               if (!src->length) {
+                       error = -ENODATA;
+                       goto out_free_name;
+               }
 
                if (src->is_string) {
-                       nval = src->length / sizeof(const char *);
-                       dst->pointer.str = kcalloc(nval, sizeof(const char *),
-                                                  GFP_KERNEL);
-                       if (!dst->pointer.str)
-                               return -ENOMEM;
-
-                       d = dst->pointer.str;
-                       s = src->pointer.str;
-                       for (i = 0; i < nval; i++) {
-                               d[i] = kstrdup(s[i], GFP_KERNEL);
-                               if (!d[i] && s[i])
-                                       return -ENOMEM;
-                       }
+                       error = property_copy_string_array(dst, src);
+                       if (error)
+                               goto out_free_name;
                } else {
                        dst->pointer.raw_data = kmemdup(src->pointer.raw_data,
                                                        src->length, GFP_KERNEL);
-                       if (!dst->pointer.raw_data)
-                               return -ENOMEM;
+                       if (!dst->pointer.raw_data) {
+                               error = -ENOMEM;
+                               goto out_free_name;
+                       }
                }
        } else if (src->is_string) {
                dst->value.str = kstrdup(src->value.str, GFP_KERNEL);
-               if (!dst->value.str && src->value.str)
-                       return -ENOMEM;
+               if (!dst->value.str && src->value.str) {
+                       error = -ENOMEM;
+                       goto out_free_name;
+               }
        } else {
                dst->value.raw_data = src->value.raw_data;
        }
@@ -762,6 +749,95 @@ static int pset_copy_entry(struct property_entry *dst,
        dst->is_string = src->is_string;
 
        return 0;
+
+out_free_name:
+       kfree(dst->name);
+       return error;
+}
+
+static void property_entry_free_data(const struct property_entry *p)
+{
+       size_t i, nval;
+
+       if (p->is_array) {
+               if (p->is_string && p->pointer.str) {
+                       nval = p->length / sizeof(const char *);
+                       for (i = 0; i < nval; i++)
+                               kfree(p->pointer.str[i]);
+               }
+               kfree(p->pointer.raw_data);
+       } else if (p->is_string) {
+               kfree(p->value.str);
+       }
+       kfree(p->name);
+}
+
+/**
+ * property_entries_dup - duplicate array of properties
+ * @properties: array of properties to copy
+ *
+ * This function creates a deep copy of the given NULL-terminated array
+ * of property entries.
+ */
+struct property_entry *
+property_entries_dup(const struct property_entry *properties)
+{
+       struct property_entry *p;
+       int i, n = 0;
+
+       while (properties[n].name)
+               n++;
+
+       p = kcalloc(n + 1, sizeof(*p), GFP_KERNEL);
+       if (!p)
+               return ERR_PTR(-ENOMEM);
+
+       for (i = 0; i < n; i++) {
+               int ret = property_entry_copy_data(&p[i], &properties[i]);
+               if (ret) {
+                       while (--i >= 0)
+                               property_entry_free_data(&p[i]);
+                       kfree(p);
+                       return ERR_PTR(ret);
+               }
+       }
+
+       return p;
+}
+EXPORT_SYMBOL_GPL(property_entries_dup);
+
+/**
+ * property_entries_free - free previously allocated array of properties
+ * @properties: array of properties to destroy
+ *
+ * This function frees given NULL-terminated array of property entries,
+ * along with their data.
+ */
+void property_entries_free(const struct property_entry *properties)
+{
+       const struct property_entry *p;
+
+       for (p = properties; p->name; p++)
+               property_entry_free_data(p);
+
+       kfree(properties);
+}
+EXPORT_SYMBOL_GPL(property_entries_free);
+
+/**
+ * pset_free_set - releases memory allocated for copied property set
+ * @pset: Property set to release
+ *
+ * Function takes previously copied property set and releases all the
+ * memory allocated to it.
+ */
+static void pset_free_set(struct property_set *pset)
+{
+       if (!pset)
+               return;
+
+       property_entries_free(pset->properties);
+       kfree(pset);
 }
 
 /**
@@ -776,32 +852,20 @@ static int pset_copy_entry(struct property_entry *dst,
  */
 static struct property_set *pset_copy_set(const struct property_set *pset)
 {
-       const struct property_entry *entry;
+       struct property_entry *properties;
        struct property_set *p;
-       size_t i, n = 0;
 
        p = kzalloc(sizeof(*p), GFP_KERNEL);
        if (!p)
                return ERR_PTR(-ENOMEM);
 
-       while (pset->properties[n].name)
-               n++;
-
-       p->properties = kcalloc(n + 1, sizeof(*entry), GFP_KERNEL);
-       if (!p->properties) {
+       properties = property_entries_dup(pset->properties);
+       if (IS_ERR(properties)) {
                kfree(p);
-               return ERR_PTR(-ENOMEM);
-       }
-
-       for (i = 0; i < n; i++) {
-               int ret = pset_copy_entry(&p->properties[i],
-                                         &pset->properties[i]);
-               if (ret) {
-                       pset_free_set(p);
-                       return ERR_PTR(ret);
-               }
+               return ERR_CAST(properties);
        }
 
+       p->properties = properties;
        return p;
 }
 
@@ -847,7 +911,8 @@ EXPORT_SYMBOL_GPL(device_remove_properties);
  * @dev as its secondary firmware node. The function takes a copy of
  * @properties.
  */
-int device_add_properties(struct device *dev, struct property_entry *properties)
+int device_add_properties(struct device *dev,
+                         const struct property_entry *properties)
 {
        struct property_set *p, pset;
 
index b11af3f2c1dbf2e1d6faf31cb7bc38e663b2285c..b1e9aae9a5d0be6e035c39472e8e3cdbbdc3abfb 100644 (file)
@@ -81,7 +81,7 @@ static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map,
 
        node = rbtree_ctx->root.rb_node;
        while (node) {
-               rbnode = container_of(node, struct regcache_rbtree_node, node);
+               rbnode = rb_entry(node, struct regcache_rbtree_node, node);
                regcache_rbtree_get_base_top_reg(map, rbnode, &base_reg,
                                                 &top_reg);
                if (reg >= base_reg && reg <= top_reg) {
@@ -108,8 +108,7 @@ static int regcache_rbtree_insert(struct regmap *map, struct rb_root *root,
        parent = NULL;
        new = &root->rb_node;
        while (*new) {
-               rbnode_tmp = container_of(*new, struct regcache_rbtree_node,
-                                         node);
+               rbnode_tmp = rb_entry(*new, struct regcache_rbtree_node, node);
                /* base and top registers of the current rbnode */
                regcache_rbtree_get_base_top_reg(map, rbnode_tmp, &base_reg_tmp,
                                                 &top_reg_tmp);
@@ -152,7 +151,7 @@ static int rbtree_show(struct seq_file *s, void *ignored)
 
        for (node = rb_first(&rbtree_ctx->root); node != NULL;
             node = rb_next(node)) {
-               n = container_of(node, struct regcache_rbtree_node, node);
+               n = rb_entry(node, struct regcache_rbtree_node, node);
                mem_size += sizeof(*n);
                mem_size += (n->blklen * map->cache_word_size);
                mem_size += BITS_TO_LONGS(n->blklen) * sizeof(long);
index 4e582561e1e7a0cdffeaf8b3901d3a56d66a37ad..b0a0dcf32fb7d05a0abdf725c158c47453652e34 100644 (file)
@@ -224,7 +224,7 @@ void regcache_exit(struct regmap *map)
 }
 
 /**
- * regcache_read: Fetch the value of a given register from the cache.
+ * regcache_read - Fetch the value of a given register from the cache.
  *
  * @map: map to configure.
  * @reg: The register index.
@@ -255,7 +255,7 @@ int regcache_read(struct regmap *map,
 }
 
 /**
- * regcache_write: Set the value of a given register in the cache.
+ * regcache_write - Set the value of a given register in the cache.
  *
  * @map: map to configure.
  * @reg: The register index.
@@ -328,7 +328,7 @@ static int regcache_default_sync(struct regmap *map, unsigned int min,
 }
 
 /**
- * regcache_sync: Sync the register cache with the hardware.
+ * regcache_sync - Sync the register cache with the hardware.
  *
  * @map: map to configure.
  *
@@ -396,7 +396,7 @@ out:
 EXPORT_SYMBOL_GPL(regcache_sync);
 
 /**
- * regcache_sync_region: Sync part  of the register cache with the hardware.
+ * regcache_sync_region - Sync part  of the register cache with the hardware.
  *
  * @map: map to sync.
  * @min: first register to sync
@@ -452,7 +452,7 @@ out:
 EXPORT_SYMBOL_GPL(regcache_sync_region);
 
 /**
- * regcache_drop_region: Discard part of the register cache
+ * regcache_drop_region - Discard part of the register cache
  *
  * @map: map to operate on
  * @min: first register to discard
@@ -483,10 +483,10 @@ int regcache_drop_region(struct regmap *map, unsigned int min,
 EXPORT_SYMBOL_GPL(regcache_drop_region);
 
 /**
- * regcache_cache_only: Put a register map into cache only mode
+ * regcache_cache_only - Put a register map into cache only mode
  *
  * @map: map to configure
- * @cache_only: flag if changes should be written to the hardware
+ * @enable: flag if changes should be written to the hardware
  *
  * When a register map is marked as cache only writes to the register
  * map API will only update the register cache, they will not cause
@@ -505,7 +505,7 @@ void regcache_cache_only(struct regmap *map, bool enable)
 EXPORT_SYMBOL_GPL(regcache_cache_only);
 
 /**
- * regcache_mark_dirty: Indicate that HW registers were reset to default values
+ * regcache_mark_dirty - Indicate that HW registers were reset to default values
  *
  * @map: map to mark
  *
@@ -527,10 +527,10 @@ void regcache_mark_dirty(struct regmap *map)
 EXPORT_SYMBOL_GPL(regcache_mark_dirty);
 
 /**
- * regcache_cache_bypass: Put a register map into cache bypass mode
+ * regcache_cache_bypass - Put a register map into cache bypass mode
  *
  * @map: map to configure
- * @cache_bypass: flag if changes should not be written to the cache
+ * @enable: flag if changes should not be written to the cache
  *
  * When a register map is marked with the cache bypass option, writes
  * to the register map API will only update the hardware and not the
index ec262476d04387053ffc091b6c24993f5ce15415..cd54189f2b1d4d18dd62172385848a75887bbc87 100644 (file)
@@ -398,13 +398,14 @@ static const struct irq_domain_ops regmap_domain_ops = {
 };
 
 /**
- * regmap_add_irq_chip(): Use standard regmap IRQ controller handling
+ * regmap_add_irq_chip() - Use standard regmap IRQ controller handling
  *
- * map:       The regmap for the device.
- * irq:       The IRQ the device uses to signal interrupts
- * irq_flags: The IRQF_ flags to use for the primary interrupt.
- * chip:      Configuration for the interrupt controller.
- * data:      Runtime data structure for the controller, allocated on success
+ * @map: The regmap for the device.
+ * @irq: The IRQ the device uses to signal interrupts.
+ * @irq_flags: The IRQF_ flags to use for the primary interrupt.
+ * @irq_base: Allocate at specific IRQ number if irq_base > 0.
+ * @chip: Configuration for the interrupt controller.
+ * @data: Runtime data structure for the controller, allocated on success.
  *
  * Returns 0 on success or an errno on failure.
  *
@@ -659,12 +660,12 @@ err_alloc:
 EXPORT_SYMBOL_GPL(regmap_add_irq_chip);
 
 /**
- * regmap_del_irq_chip(): Stop interrupt handling for a regmap IRQ chip
+ * regmap_del_irq_chip() - Stop interrupt handling for a regmap IRQ chip
  *
  * @irq: Primary IRQ for the device
- * @d:   regmap_irq_chip_data allocated by regmap_add_irq_chip()
+ * @d: &regmap_irq_chip_data allocated by regmap_add_irq_chip()
  *
- * This function also dispose all mapped irq on chip.
+ * This function also disposes of all mapped IRQs on the chip.
  */
 void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
 {
@@ -723,18 +724,19 @@ static int devm_regmap_irq_chip_match(struct device *dev, void *res, void *data)
 }
 
 /**
- * devm_regmap_add_irq_chip(): Resource manager regmap_add_irq_chip()
+ * devm_regmap_add_irq_chip() - Resource manager regmap_add_irq_chip()
  *
- * @dev:       The device pointer on which irq_chip belongs to.
- * @map:       The regmap for the device.
- * @irq:       The IRQ the device uses to signal interrupts
+ * @dev: The device pointer on which irq_chip belongs to.
+ * @map: The regmap for the device.
+ * @irq: The IRQ the device uses to signal interrupts
  * @irq_flags: The IRQF_ flags to use for the primary interrupt.
- * @chip:      Configuration for the interrupt controller.
- * @data:      Runtime data structure for the controller, allocated on success
+ * @irq_base: Allocate at specific IRQ number if irq_base > 0.
+ * @chip: Configuration for the interrupt controller.
+ * @data: Runtime data structure for the controller, allocated on success
  *
  * Returns 0 on success or an errno on failure.
  *
- * The regmap_irq_chip data automatically be released when the device is
+ * The &regmap_irq_chip_data will be automatically released when the device is
  * unbound.
  */
 int devm_regmap_add_irq_chip(struct device *dev, struct regmap *map, int irq,
@@ -765,11 +767,13 @@ int devm_regmap_add_irq_chip(struct device *dev, struct regmap *map, int irq,
 EXPORT_SYMBOL_GPL(devm_regmap_add_irq_chip);
 
 /**
- * devm_regmap_del_irq_chip(): Resource managed regmap_del_irq_chip()
+ * devm_regmap_del_irq_chip() - Resource managed regmap_del_irq_chip()
  *
  * @dev: Device for which which resource was allocated.
- * @irq: Primary IRQ for the device
- * @d:   regmap_irq_chip_data allocated by regmap_add_irq_chip()
+ * @irq: Primary IRQ for the device.
+ * @data: &regmap_irq_chip_data allocated by regmap_add_irq_chip().
+ *
+ * A resource managed version of regmap_del_irq_chip().
  */
 void devm_regmap_del_irq_chip(struct device *dev, int irq,
                              struct regmap_irq_chip_data *data)
@@ -786,11 +790,11 @@ void devm_regmap_del_irq_chip(struct device *dev, int irq,
 EXPORT_SYMBOL_GPL(devm_regmap_del_irq_chip);
 
 /**
- * regmap_irq_chip_get_base(): Retrieve interrupt base for a regmap IRQ chip
+ * regmap_irq_chip_get_base() - Retrieve interrupt base for a regmap IRQ chip
  *
- * Useful for drivers to request their own IRQs.
+ * @data: regmap irq controller to operate on.
  *
- * @data: regmap_irq controller to operate on.
+ * Useful for drivers to request their own IRQs.
  */
 int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data)
 {
@@ -800,12 +804,12 @@ int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data)
 EXPORT_SYMBOL_GPL(regmap_irq_chip_get_base);
 
 /**
- * regmap_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ
+ * regmap_irq_get_virq() - Map an interrupt on a chip to a virtual IRQ
  *
- * Useful for drivers to request their own IRQs.
+ * @data: regmap irq controller to operate on.
+ * @irq: index of the interrupt requested in the chip IRQs.
  *
- * @data: regmap_irq controller to operate on.
- * @irq: index of the interrupt requested in the chip IRQs
+ * Useful for drivers to request their own IRQs.
  */
 int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq)
 {
@@ -818,14 +822,14 @@ int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq)
 EXPORT_SYMBOL_GPL(regmap_irq_get_virq);
 
 /**
- * regmap_irq_get_domain(): Retrieve the irq_domain for the chip
+ * regmap_irq_get_domain() - Retrieve the irq_domain for the chip
+ *
+ * @data: regmap_irq controller to operate on.
  *
  * Useful for drivers to request their own IRQs and for integration
  * with subsystems.  For ease of integration NULL is accepted as a
  * domain, allowing devices to just call this even if no domain is
  * allocated.
- *
- * @data: regmap_irq controller to operate on.
  */
 struct irq_domain *regmap_irq_get_domain(struct regmap_irq_chip_data *data)
 {
index ae63bb0875ea8388227b0b2285fc61993e34a367..b9a779a4a739cda497351be2b2dc51d69f35c022 100644 (file)
@@ -459,7 +459,7 @@ static bool _regmap_range_add(struct regmap *map,
 
        while (*new) {
                struct regmap_range_node *this =
-                       container_of(*new, struct regmap_range_node, node);
+                       rb_entry(*new, struct regmap_range_node, node);
 
                parent = *new;
                if (data->range_max < this->range_min)
@@ -483,7 +483,7 @@ static struct regmap_range_node *_regmap_range_lookup(struct regmap *map,
 
        while (node) {
                struct regmap_range_node *this =
-                       container_of(node, struct regmap_range_node, node);
+                       rb_entry(node, struct regmap_range_node, node);
 
                if (reg < this->range_min)
                        node = node->rb_left;
@@ -1091,8 +1091,7 @@ static void regmap_field_init(struct regmap_field *rm_field,
 }
 
 /**
- * devm_regmap_field_alloc(): Allocate and initialise a register field
- * in a register map.
+ * devm_regmap_field_alloc() - Allocate and initialise a register field.
  *
  * @dev: Device that will be interacted with
  * @regmap: regmap bank in which this register field is located.
@@ -1118,13 +1117,15 @@ struct regmap_field *devm_regmap_field_alloc(struct device *dev,
 EXPORT_SYMBOL_GPL(devm_regmap_field_alloc);
 
 /**
- * devm_regmap_field_free(): Free register field allocated using
- * devm_regmap_field_alloc. Usally drivers need not call this function,
- * as the memory allocated via devm will be freed as per device-driver
- * life-cyle.
+ * devm_regmap_field_free() - Free a register field allocated using
+ *                            devm_regmap_field_alloc.
  *
  * @dev: Device that will be interacted with
  * @field: regmap field which should be freed.
+ *
+ * Free register field allocated using devm_regmap_field_alloc(). Usually
+ * drivers need not call this function, as the memory allocated via devm
+ * will be freed as per device-driver life-cyle.
  */
 void devm_regmap_field_free(struct device *dev,
        struct regmap_field *field)
@@ -1134,8 +1135,7 @@ void devm_regmap_field_free(struct device *dev,
 EXPORT_SYMBOL_GPL(devm_regmap_field_free);
 
 /**
- * regmap_field_alloc(): Allocate and initialise a register field
- * in a register map.
+ * regmap_field_alloc() - Allocate and initialise a register field.
  *
  * @regmap: regmap bank in which this register field is located.
  * @reg_field: Register field with in the bank.
@@ -1159,7 +1159,8 @@ struct regmap_field *regmap_field_alloc(struct regmap *regmap,
 EXPORT_SYMBOL_GPL(regmap_field_alloc);
 
 /**
- * regmap_field_free(): Free register field allocated using regmap_field_alloc
+ * regmap_field_free() - Free register field allocated using
+ *                       regmap_field_alloc.
  *
  * @field: regmap field which should be freed.
  */
@@ -1170,7 +1171,7 @@ void regmap_field_free(struct regmap_field *field)
 EXPORT_SYMBOL_GPL(regmap_field_free);
 
 /**
- * regmap_reinit_cache(): Reinitialise the current register cache
+ * regmap_reinit_cache() - Reinitialise the current register cache
  *
  * @map: Register map to operate on.
  * @config: New configuration.  Only the cache data will be used.
@@ -1205,7 +1206,9 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
 EXPORT_SYMBOL_GPL(regmap_reinit_cache);
 
 /**
- * regmap_exit(): Free a previously allocated register map
+ * regmap_exit() - Free a previously allocated register map
+ *
+ * @map: Register map to operate on.
  */
 void regmap_exit(struct regmap *map)
 {
@@ -1245,7 +1248,7 @@ static int dev_get_regmap_match(struct device *dev, void *res, void *data)
 }
 
 /**
- * dev_get_regmap(): Obtain the regmap (if any) for a device
+ * dev_get_regmap() - Obtain the regmap (if any) for a device
  *
  * @dev: Device to retrieve the map for
  * @name: Optional name for the register map, usually NULL.
@@ -1268,7 +1271,7 @@ struct regmap *dev_get_regmap(struct device *dev, const char *name)
 EXPORT_SYMBOL_GPL(dev_get_regmap);
 
 /**
- * regmap_get_device(): Obtain the device from a regmap
+ * regmap_get_device() - Obtain the device from a regmap
  *
  * @map: Register map to operate on.
  *
@@ -1654,7 +1657,7 @@ int _regmap_write(struct regmap *map, unsigned int reg,
 }
 
 /**
- * regmap_write(): Write a value to a single register
+ * regmap_write() - Write a value to a single register
  *
  * @map: Register map to write to
  * @reg: Register to write to
@@ -1681,7 +1684,7 @@ int regmap_write(struct regmap *map, unsigned int reg, unsigned int val)
 EXPORT_SYMBOL_GPL(regmap_write);
 
 /**
- * regmap_write_async(): Write a value to a single register asynchronously
+ * regmap_write_async() - Write a value to a single register asynchronously
  *
  * @map: Register map to write to
  * @reg: Register to write to
@@ -1712,7 +1715,7 @@ int regmap_write_async(struct regmap *map, unsigned int reg, unsigned int val)
 EXPORT_SYMBOL_GPL(regmap_write_async);
 
 /**
- * regmap_raw_write(): Write raw values to one or more registers
+ * regmap_raw_write() - Write raw values to one or more registers
  *
  * @map: Register map to write to
  * @reg: Initial register to write to
@@ -1750,9 +1753,8 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
 EXPORT_SYMBOL_GPL(regmap_raw_write);
 
 /**
- * regmap_field_update_bits_base():
- *     Perform a read/modify/write cycle on the register field
- *     with change, async, force option
+ * regmap_field_update_bits_base() - Perform a read/modify/write cycle a
+ *                                   register field.
  *
  * @field: Register field to write to
  * @mask: Bitmask to change
@@ -1761,6 +1763,9 @@ EXPORT_SYMBOL_GPL(regmap_raw_write);
  * @async: Boolean indicating asynchronously
  * @force: Boolean indicating use force update
  *
+ * Perform a read/modify/write cycle on the register field with change,
+ * async, force option.
+ *
  * A value of zero will be returned on success, a negative errno will
  * be returned in error cases.
  */
@@ -1777,9 +1782,8 @@ int regmap_field_update_bits_base(struct regmap_field *field,
 EXPORT_SYMBOL_GPL(regmap_field_update_bits_base);
 
 /**
- * regmap_fields_update_bits_base():
- *     Perform a read/modify/write cycle on the register field
- *     with change, async, force option
+ * regmap_fields_update_bits_base() - Perform a read/modify/write cycle a
+ *                                    register field with port ID
  *
  * @field: Register field to write to
  * @id: port ID
@@ -1808,8 +1812,8 @@ int regmap_fields_update_bits_base(struct regmap_field *field,  unsigned int id,
 }
 EXPORT_SYMBOL_GPL(regmap_fields_update_bits_base);
 
-/*
- * regmap_bulk_write(): Write multiple registers to the device
+/**
+ * regmap_bulk_write() - Write multiple registers to the device
  *
  * @map: Register map to write to
  * @reg: First register to be write from
@@ -2174,18 +2178,18 @@ static int _regmap_multi_reg_write(struct regmap *map,
        return _regmap_raw_multi_reg_write(map, regs, num_regs);
 }
 
-/*
- * regmap_multi_reg_write(): Write multiple registers to the device
- *
- * where the set of register,value pairs are supplied in any order,
- * possibly not all in a single range.
+/**
+ * regmap_multi_reg_write() - Write multiple registers to the device
  *
  * @map: Register map to write to
  * @regs: Array of structures containing register,value to be written
  * @num_regs: Number of registers to write
  *
+ * Write multiple registers to the device where the set of register, value
+ * pairs are supplied in any order, possibly not all in a single range.
+ *
  * The 'normal' block write mode will send ultimately send data on the
- * target bus as R,V1,V2,V3,..,Vn where successively higer registers are
+ * target bus as R,V1,V2,V3,..,Vn where successively higher registers are
  * addressed. However, this alternative block multi write mode will send
  * the data as R1,V1,R2,V2,..,Rn,Vn on the target bus. The target device
  * must of course support the mode.
@@ -2208,16 +2212,17 @@ int regmap_multi_reg_write(struct regmap *map, const struct reg_sequence *regs,
 }
 EXPORT_SYMBOL_GPL(regmap_multi_reg_write);
 
-/*
- * regmap_multi_reg_write_bypassed(): Write multiple registers to the
- *                                    device but not the cache
- *
- * where the set of register are supplied in any order
+/**
+ * regmap_multi_reg_write_bypassed() - Write multiple registers to the
+ *                                     device but not the cache
  *
  * @map: Register map to write to
  * @regs: Array of structures containing register,value to be written
  * @num_regs: Number of registers to write
  *
+ * Write multiple registers to the device but not the cache where the set
+ * of register are supplied in any order.
+ *
  * This function is intended to be used for writing a large block of data
  * atomically to the device in single transfer for those I2C client devices
  * that implement this alternative block write mode.
@@ -2248,8 +2253,8 @@ int regmap_multi_reg_write_bypassed(struct regmap *map,
 EXPORT_SYMBOL_GPL(regmap_multi_reg_write_bypassed);
 
 /**
- * regmap_raw_write_async(): Write raw values to one or more registers
- *                           asynchronously
+ * regmap_raw_write_async() - Write raw values to one or more registers
+ *                            asynchronously
  *
  * @map: Register map to write to
  * @reg: Initial register to write to
@@ -2385,7 +2390,7 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
 }
 
 /**
- * regmap_read(): Read a value from a single register
+ * regmap_read() - Read a value from a single register
  *
  * @map: Register map to read from
  * @reg: Register to be read from
@@ -2412,7 +2417,7 @@ int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val)
 EXPORT_SYMBOL_GPL(regmap_read);
 
 /**
- * regmap_raw_read(): Read raw data from the device
+ * regmap_raw_read() - Read raw data from the device
  *
  * @map: Register map to read from
  * @reg: First register to be read from
@@ -2477,7 +2482,7 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
 EXPORT_SYMBOL_GPL(regmap_raw_read);
 
 /**
- * regmap_field_read(): Read a value to a single register field
+ * regmap_field_read() - Read a value to a single register field
  *
  * @field: Register field to read from
  * @val: Pointer to store read value
@@ -2502,7 +2507,7 @@ int regmap_field_read(struct regmap_field *field, unsigned int *val)
 EXPORT_SYMBOL_GPL(regmap_field_read);
 
 /**
- * regmap_fields_read(): Read a value to a single register field with port ID
+ * regmap_fields_read() - Read a value to a single register field with port ID
  *
  * @field: Register field to read from
  * @id: port ID
@@ -2535,7 +2540,7 @@ int regmap_fields_read(struct regmap_field *field, unsigned int id,
 EXPORT_SYMBOL_GPL(regmap_fields_read);
 
 /**
- * regmap_bulk_read(): Read multiple registers from the device
+ * regmap_bulk_read() - Read multiple registers from the device
  *
  * @map: Register map to read from
  * @reg: First register to be read from
@@ -2692,9 +2697,7 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
 }
 
 /**
- * regmap_update_bits_base:
- *     Perform a read/modify/write cycle on the
- *     register map with change, async, force option
+ * regmap_update_bits_base() - Perform a read/modify/write cycle on a register
  *
  * @map: Register map to update
  * @reg: Register to update
@@ -2704,10 +2707,14 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
  * @async: Boolean indicating asynchronously
  * @force: Boolean indicating use force update
  *
- * if async was true,
- * With most buses the read must be done synchronously so this is most
- * useful for devices with a cache which do not need to interact with
- * the hardware to determine the current register value.
+ * Perform a read/modify/write cycle on a register map with change, async, force
+ * options.
+ *
+ * If async is true:
+ *
+ * With most buses the read must be done synchronously so this is most useful
+ * for devices with a cache which do not need to interact with the hardware to
+ * determine the current register value.
  *
  * Returns zero for success, a negative number on error.
  */
@@ -2765,7 +2772,7 @@ static int regmap_async_is_done(struct regmap *map)
 }
 
 /**
- * regmap_async_complete: Ensure all asynchronous I/O has completed.
+ * regmap_async_complete - Ensure all asynchronous I/O has completed.
  *
  * @map: Map to operate on.
  *
@@ -2797,8 +2804,8 @@ int regmap_async_complete(struct regmap *map)
 EXPORT_SYMBOL_GPL(regmap_async_complete);
 
 /**
- * regmap_register_patch: Register and apply register updates to be applied
- *                        on device initialistion
+ * regmap_register_patch - Register and apply register updates to be applied
+ *                         on device initialistion
  *
  * @map: Register map to apply updates to.
  * @regs: Values to update.
@@ -2855,8 +2862,10 @@ int regmap_register_patch(struct regmap *map, const struct reg_sequence *regs,
 }
 EXPORT_SYMBOL_GPL(regmap_register_patch);
 
-/*
- * regmap_get_val_bytes(): Report the size of a register value
+/**
+ * regmap_get_val_bytes() - Report the size of a register value
+ *
+ * @map: Register map to operate on.
  *
  * Report the size of a register value, mainly intended to for use by
  * generic infrastructure built on top of regmap.
@@ -2871,7 +2880,9 @@ int regmap_get_val_bytes(struct regmap *map)
 EXPORT_SYMBOL_GPL(regmap_get_val_bytes);
 
 /**
- * regmap_get_max_register(): Report the max register value
+ * regmap_get_max_register() - Report the max register value
+ *
+ * @map: Register map to operate on.
  *
  * Report the max register value, mainly intended to for use by
  * generic infrastructure built on top of regmap.
@@ -2883,7 +2894,9 @@ int regmap_get_max_register(struct regmap *map)
 EXPORT_SYMBOL_GPL(regmap_get_max_register);
 
 /**
- * regmap_get_reg_stride(): Report the register address stride
+ * regmap_get_reg_stride() - Report the register address stride
+ *
+ * @map: Register map to operate on.
  *
  * Report the register address stride, mainly intended to for use by
  * generic infrastructure built on top of regmap.
index 223ff2fcae7e06d6abc8e8e1d2472ac707828278..f744de7a0f9b27744b52a565becff82707d0274e 100644 (file)
@@ -69,6 +69,7 @@ config AMIGA_Z2RAM
 config GDROM
        tristate "SEGA Dreamcast GD-ROM drive"
        depends on SH_DREAMCAST
+       select BLK_SCSI_REQUEST # only for the generic cdrom code
        help
          A standard SEGA Dreamcast comes with a modified CD ROM drive called a
          "GD-ROM" by SEGA to signify it is capable of reading special disks
@@ -114,6 +115,7 @@ config BLK_CPQ_CISS_DA
        tristate "Compaq Smart Array 5xxx support"
        depends on PCI
        select CHECK_SIGNATURE
+       select BLK_SCSI_REQUEST
        help
          This is the driver for Compaq Smart Array 5xxx controllers.
          Everyone using these boards should say Y here.
@@ -386,6 +388,7 @@ config BLK_DEV_RAM_DAX
 config CDROM_PKTCDVD
        tristate "Packet writing on CD/DVD media (DEPRECATED)"
        depends on !UML
+       select BLK_SCSI_REQUEST
        help
          Note: This driver is deprecated and will be removed from the
          kernel in the near future!
@@ -501,6 +504,16 @@ config VIRTIO_BLK
          This is the virtual block driver for virtio.  It can be used with
           lguest or QEMU based VMMs (like KVM or Xen).  Say Y or M.
 
+config VIRTIO_BLK_SCSI
+       bool "SCSI passthrough request for the Virtio block driver"
+       depends on VIRTIO_BLK
+       select BLK_SCSI_REQUEST
+       ---help---
+         Enable support for SCSI passthrough (e.g. the SG_IO ioctl) on
+         virtio-blk devices.  This is only supported for the legacy
+         virtio protocol and not enabled by default by any hypervisor.
+         Your probably want to virtio-scsi instead.
+
 config BLK_DEV_HD
        bool "Very old hard disk (MFM/RLL/IDE) driver"
        depends on HAVE_IDE
index ec9d8610b25f772eefe20917cc8921db17c29016..027b876370bc9a04b5601b78f644fd947e6c87c5 100644 (file)
@@ -396,8 +396,8 @@ aoeblk_gdalloc(void *vp)
        WARN_ON(d->gd);
        WARN_ON(d->flags & DEVFL_UP);
        blk_queue_max_hw_sectors(q, BLK_DEF_MAX_SECTORS);
-       q->backing_dev_info.name = "aoe";
-       q->backing_dev_info.ra_pages = READ_AHEAD / PAGE_SIZE;
+       q->backing_dev_info->name = "aoe";
+       q->backing_dev_info->ra_pages = READ_AHEAD / PAGE_SIZE;
        d->bufpool = mp;
        d->blkq = gd->queue = q;
        q->queuedata = d;
index e5c5b8eb14a9bc4aaea939b955cd89c91946e98c..27d613795653bd39c38d49f68a983b325f57b470 100644 (file)
@@ -52,6 +52,7 @@
 #include <scsi/scsi.h>
 #include <scsi/sg.h>
 #include <scsi/scsi_ioctl.h>
+#include <scsi/scsi_request.h>
 #include <linux/cdrom.h>
 #include <linux/scatterlist.h>
 #include <linux/kthread.h>
@@ -1853,8 +1854,8 @@ static void cciss_softirq_done(struct request *rq)
        dev_dbg(&h->pdev->dev, "Done with %p\n", rq);
 
        /* set the residual count for pc requests */
-       if (rq->cmd_type == REQ_TYPE_BLOCK_PC)
-               rq->resid_len = c->err_info->ResidualCnt;
+       if (blk_rq_is_passthrough(rq))
+               scsi_req(rq)->resid_len = c->err_info->ResidualCnt;
 
        blk_end_request_all(rq, (rq->errors == 0) ? 0 : -EIO);
 
@@ -1941,9 +1942,16 @@ static void cciss_get_serial_no(ctlr_info_t *h, int logvol,
 static int cciss_add_disk(ctlr_info_t *h, struct gendisk *disk,
                                int drv_index)
 {
-       disk->queue = blk_init_queue(do_cciss_request, &h->lock);
+       disk->queue = blk_alloc_queue(GFP_KERNEL);
        if (!disk->queue)
                goto init_queue_failure;
+
+       disk->queue->cmd_size = sizeof(struct scsi_request);
+       disk->queue->request_fn = do_cciss_request;
+       disk->queue->queue_lock = &h->lock;
+       if (blk_init_allocated_queue(disk->queue) < 0)
+               goto cleanup_queue;
+
        sprintf(disk->disk_name, "cciss/c%dd%d", h->ctlr, drv_index);
        disk->major = h->major;
        disk->first_minor = drv_index << NWD_SHIFT;
@@ -3075,7 +3083,7 @@ static inline int evaluate_target_status(ctlr_info_t *h,
        driver_byte = DRIVER_OK;
        msg_byte = cmd->err_info->CommandStatus; /* correct?  seems too device specific */
 
-       if (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC)
+       if (blk_rq_is_passthrough(cmd->rq))
                host_byte = DID_PASSTHROUGH;
        else
                host_byte = DID_OK;
@@ -3084,7 +3092,7 @@ static inline int evaluate_target_status(ctlr_info_t *h,
                host_byte, driver_byte);
 
        if (cmd->err_info->ScsiStatus != SAM_STAT_CHECK_CONDITION) {
-               if (cmd->rq->cmd_type != REQ_TYPE_BLOCK_PC)
+               if (!blk_rq_is_passthrough(cmd->rq))
                        dev_warn(&h->pdev->dev, "cmd %p "
                               "has SCSI Status 0x%x\n",
                               cmd, cmd->err_info->ScsiStatus);
@@ -3095,31 +3103,23 @@ static inline int evaluate_target_status(ctlr_info_t *h,
        sense_key = 0xf & cmd->err_info->SenseInfo[2];
        /* no status or recovered error */
        if (((sense_key == 0x0) || (sense_key == 0x1)) &&
-           (cmd->rq->cmd_type != REQ_TYPE_BLOCK_PC))
+           !blk_rq_is_passthrough(cmd->rq))
                error_value = 0;
 
        if (check_for_unit_attention(h, cmd)) {
-               *retry_cmd = !(cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC);
+               *retry_cmd = !blk_rq_is_passthrough(cmd->rq);
                return 0;
        }
 
        /* Not SG_IO or similar? */
-       if (cmd->rq->cmd_type != REQ_TYPE_BLOCK_PC) {
+       if (!blk_rq_is_passthrough(cmd->rq)) {
                if (error_value != 0)
                        dev_warn(&h->pdev->dev, "cmd %p has CHECK CONDITION"
                               " sense key = 0x%x\n", cmd, sense_key);
                return error_value;
        }
 
-       /* SG_IO or similar, copy sense data back */
-       if (cmd->rq->sense) {
-               if (cmd->rq->sense_len > cmd->err_info->SenseLen)
-                       cmd->rq->sense_len = cmd->err_info->SenseLen;
-               memcpy(cmd->rq->sense, cmd->err_info->SenseInfo,
-                       cmd->rq->sense_len);
-       } else
-               cmd->rq->sense_len = 0;
-
+       scsi_req(cmd->rq)->sense_len = cmd->err_info->SenseLen;
        return error_value;
 }
 
@@ -3146,15 +3146,14 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
                rq->errors = evaluate_target_status(h, cmd, &retry_cmd);
                break;
        case CMD_DATA_UNDERRUN:
-               if (cmd->rq->cmd_type == REQ_TYPE_FS) {
+               if (!blk_rq_is_passthrough(cmd->rq)) {
                        dev_warn(&h->pdev->dev, "cmd %p has"
                               " completed with data underrun "
                               "reported\n", cmd);
-                       cmd->rq->resid_len = cmd->err_info->ResidualCnt;
                }
                break;
        case CMD_DATA_OVERRUN:
-               if (cmd->rq->cmd_type == REQ_TYPE_FS)
+               if (!blk_rq_is_passthrough(cmd->rq))
                        dev_warn(&h->pdev->dev, "cciss: cmd %p has"
                               " completed with data overrun "
                               "reported\n", cmd);
@@ -3164,7 +3163,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
                       "reported invalid\n", cmd);
                rq->errors = make_status_bytes(SAM_STAT_GOOD,
                        cmd->err_info->CommandStatus, DRIVER_OK,
-                       (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
+                       blk_rq_is_passthrough(cmd->rq) ?
                                DID_PASSTHROUGH : DID_ERROR);
                break;
        case CMD_PROTOCOL_ERR:
@@ -3172,7 +3171,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
                       "protocol error\n", cmd);
                rq->errors = make_status_bytes(SAM_STAT_GOOD,
                        cmd->err_info->CommandStatus, DRIVER_OK,
-                       (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
+                       blk_rq_is_passthrough(cmd->rq) ?
                                DID_PASSTHROUGH : DID_ERROR);
                break;
        case CMD_HARDWARE_ERR:
@@ -3180,7 +3179,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
                       " hardware error\n", cmd);
                rq->errors = make_status_bytes(SAM_STAT_GOOD,
                        cmd->err_info->CommandStatus, DRIVER_OK,
-                       (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
+                       blk_rq_is_passthrough(cmd->rq) ?
                                DID_PASSTHROUGH : DID_ERROR);
                break;
        case CMD_CONNECTION_LOST:
@@ -3188,7 +3187,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
                       "connection lost\n", cmd);
                rq->errors = make_status_bytes(SAM_STAT_GOOD,
                        cmd->err_info->CommandStatus, DRIVER_OK,
-                       (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
+                       blk_rq_is_passthrough(cmd->rq) ?
                                DID_PASSTHROUGH : DID_ERROR);
                break;
        case CMD_ABORTED:
@@ -3196,7 +3195,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
                       "aborted\n", cmd);
                rq->errors = make_status_bytes(SAM_STAT_GOOD,
                        cmd->err_info->CommandStatus, DRIVER_OK,
-                       (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
+                       blk_rq_is_passthrough(cmd->rq) ?
                                DID_PASSTHROUGH : DID_ABORT);
                break;
        case CMD_ABORT_FAILED:
@@ -3204,7 +3203,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
                       "abort failed\n", cmd);
                rq->errors = make_status_bytes(SAM_STAT_GOOD,
                        cmd->err_info->CommandStatus, DRIVER_OK,
-                       (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
+                       blk_rq_is_passthrough(cmd->rq) ?
                                DID_PASSTHROUGH : DID_ERROR);
                break;
        case CMD_UNSOLICITED_ABORT:
@@ -3219,21 +3218,21 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
                                "%p retried too many times\n", cmd);
                rq->errors = make_status_bytes(SAM_STAT_GOOD,
                        cmd->err_info->CommandStatus, DRIVER_OK,
-                       (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
+                       blk_rq_is_passthrough(cmd->rq) ?
                                DID_PASSTHROUGH : DID_ABORT);
                break;
        case CMD_TIMEOUT:
                dev_warn(&h->pdev->dev, "cmd %p timedout\n", cmd);
                rq->errors = make_status_bytes(SAM_STAT_GOOD,
                        cmd->err_info->CommandStatus, DRIVER_OK,
-                       (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
+                       blk_rq_is_passthrough(cmd->rq) ?
                                DID_PASSTHROUGH : DID_ERROR);
                break;
        case CMD_UNABORTABLE:
                dev_warn(&h->pdev->dev, "cmd %p unabortable\n", cmd);
                rq->errors = make_status_bytes(SAM_STAT_GOOD,
                        cmd->err_info->CommandStatus, DRIVER_OK,
-                       cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC ?
+                       blk_rq_is_passthrough(cmd->rq) ?
                                DID_PASSTHROUGH : DID_ERROR);
                break;
        default:
@@ -3242,7 +3241,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
                       cmd->err_info->CommandStatus);
                rq->errors = make_status_bytes(SAM_STAT_GOOD,
                        cmd->err_info->CommandStatus, DRIVER_OK,
-                       (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
+                       blk_rq_is_passthrough(cmd->rq) ?
                                DID_PASSTHROUGH : DID_ERROR);
        }
 
@@ -3395,7 +3394,9 @@ static void do_cciss_request(struct request_queue *q)
                c->Header.SGList = h->max_cmd_sgentries;
        set_performant_mode(h, c);
 
-       if (likely(creq->cmd_type == REQ_TYPE_FS)) {
+       switch (req_op(creq)) {
+       case REQ_OP_READ:
+       case REQ_OP_WRITE:
                if(h->cciss_read == CCISS_READ_10) {
                        c->Request.CDB[1] = 0;
                        c->Request.CDB[2] = (start_blk >> 24) & 0xff; /* MSB */
@@ -3425,12 +3426,16 @@ static void do_cciss_request(struct request_queue *q)
                        c->Request.CDB[13]= blk_rq_sectors(creq) & 0xff;
                        c->Request.CDB[14] = c->Request.CDB[15] = 0;
                }
-       } else if (creq->cmd_type == REQ_TYPE_BLOCK_PC) {
-               c->Request.CDBLen = creq->cmd_len;
-               memcpy(c->Request.CDB, creq->cmd, BLK_MAX_CDB);
-       } else {
+               break;
+       case REQ_OP_SCSI_IN:
+       case REQ_OP_SCSI_OUT:
+               c->Request.CDBLen = scsi_req(creq)->cmd_len;
+               memcpy(c->Request.CDB, scsi_req(creq)->cmd, BLK_MAX_CDB);
+               scsi_req(creq)->sense = c->err_info->SenseInfo;
+               break;
+       default:
                dev_warn(&h->pdev->dev, "bad request type %d\n",
-                       creq->cmd_type);
+                       creq->cmd_flags);
                BUG();
        }
 
@@ -4074,41 +4079,27 @@ clean_up:
 
 static void cciss_interrupt_mode(ctlr_info_t *h)
 {
-#ifdef CONFIG_PCI_MSI
-       int err;
-       struct msix_entry cciss_msix_entries[4] = { {0, 0}, {0, 1},
-       {0, 2}, {0, 3}
-       };
+       int ret;
 
        /* Some boards advertise MSI but don't really support it */
        if ((h->board_id == 0x40700E11) || (h->board_id == 0x40800E11) ||
            (h->board_id == 0x40820E11) || (h->board_id == 0x40830E11))
                goto default_int_mode;
 
-       if (pci_find_capability(h->pdev, PCI_CAP_ID_MSIX)) {
-               err = pci_enable_msix_exact(h->pdev, cciss_msix_entries, 4);
-               if (!err) {
-                       h->intr[0] = cciss_msix_entries[0].vector;
-                       h->intr[1] = cciss_msix_entries[1].vector;
-                       h->intr[2] = cciss_msix_entries[2].vector;
-                       h->intr[3] = cciss_msix_entries[3].vector;
-                       h->msix_vector = 1;
-                       return;
-               } else {
-                       dev_warn(&h->pdev->dev,
-                               "MSI-X init failed %d\n", err);
-               }
-       }
-       if (pci_find_capability(h->pdev, PCI_CAP_ID_MSI)) {
-               if (!pci_enable_msi(h->pdev))
-                       h->msi_vector = 1;
-               else
-                       dev_warn(&h->pdev->dev, "MSI init failed\n");
+       ret = pci_alloc_irq_vectors(h->pdev, 4, 4, PCI_IRQ_MSIX);
+       if (ret >= 0)   {
+               h->intr[0] = pci_irq_vector(h->pdev, 0);
+               h->intr[1] = pci_irq_vector(h->pdev, 1);
+               h->intr[2] = pci_irq_vector(h->pdev, 2);
+               h->intr[3] = pci_irq_vector(h->pdev, 3);
+               return;
        }
+
+       ret = pci_alloc_irq_vectors(h->pdev, 1, 1, PCI_IRQ_MSI);
+
 default_int_mode:
-#endif                         /* CONFIG_PCI_MSI */
        /* if we get here we're going to use the default interrupt mode */
-       h->intr[h->intr_mode] = h->pdev->irq;
+       h->intr[h->intr_mode] = pci_irq_vector(h->pdev, 0);
        return;
 }
 
@@ -4888,7 +4879,7 @@ static int cciss_request_irq(ctlr_info_t *h,
        irqreturn_t (*msixhandler)(int, void *),
        irqreturn_t (*intxhandler)(int, void *))
 {
-       if (h->msix_vector || h->msi_vector) {
+       if (h->pdev->msi_enabled || h->pdev->msix_enabled) {
                if (!request_irq(h->intr[h->intr_mode], msixhandler,
                                0, h->devname, h))
                        return 0;
@@ -4934,12 +4925,7 @@ static void cciss_undo_allocations_after_kdump_soft_reset(ctlr_info_t *h)
        int ctlr = h->ctlr;
 
        free_irq(h->intr[h->intr_mode], h);
-#ifdef CONFIG_PCI_MSI
-       if (h->msix_vector)
-               pci_disable_msix(h->pdev);
-       else if (h->msi_vector)
-               pci_disable_msi(h->pdev);
-#endif /* CONFIG_PCI_MSI */
+       pci_free_irq_vectors(h->pdev);
        cciss_free_sg_chain_blocks(h->cmd_sg_list, h->nr_cmds);
        cciss_free_scatterlists(h);
        cciss_free_cmd_pool(h);
@@ -5295,12 +5281,7 @@ static void cciss_remove_one(struct pci_dev *pdev)
 
        cciss_shutdown(pdev);
 
-#ifdef CONFIG_PCI_MSI
-       if (h->msix_vector)
-               pci_disable_msix(h->pdev);
-       else if (h->msi_vector)
-               pci_disable_msi(h->pdev);
-#endif                         /* CONFIG_PCI_MSI */
+       pci_free_irq_vectors(h->pdev);
 
        iounmap(h->transtable);
        iounmap(h->cfgtable);
index 7fda30e4a2416195696b6a4eebd560d74fca6917..24b5fd75501a60b450c6f349f1230711b022d725 100644 (file)
@@ -90,8 +90,6 @@ struct ctlr_info
 #      define SIMPLE_MODE_INT  2
 #      define MEMQ_MODE_INT    3
        unsigned int intr[4];
-       unsigned int msix_vector;
-       unsigned int msi_vector;
        int     intr_mode;
        int     cciss_max_sectors;
        BYTE    cciss_read;
@@ -333,7 +331,7 @@ static unsigned long SA5_performant_completed(ctlr_info_t *h)
         */
        register_value = readl(h->vaddr + SA5_OUTDB_STATUS);
        /* msi auto clears the interrupt pending bit. */
-       if (!(h->msi_vector || h->msix_vector)) {
+       if (!(h->pdev->msi_enabled || h->pdev->msix_enabled)) {
                writel(SA5_OUTDB_CLEAR_PERF_BIT, h->vaddr + SA5_OUTDB_CLEAR);
                /* Do a read in order to flush the write to the controller
                 * (as per spec.)
@@ -393,7 +391,7 @@ static bool SA5_performant_intr_pending(ctlr_info_t *h)
        if (!register_value)
                return false;
 
-       if (h->msi_vector || h->msix_vector)
+       if (h->pdev->msi_enabled || h->pdev->msix_enabled)
                return true;
 
        /* Read outbound doorbell to flush */
@@ -402,27 +400,27 @@ static bool SA5_performant_intr_pending(ctlr_info_t *h)
 }
 
 static struct access_method SA5_access = {
-       SA5_submit_command,
-       SA5_intr_mask,
-       SA5_fifo_full,
-       SA5_intr_pending,
-       SA5_completed,
+       .submit_command = SA5_submit_command,
+       .set_intr_mask = SA5_intr_mask,
+       .fifo_full = SA5_fifo_full,
+       .intr_pending = SA5_intr_pending,
+       .command_completed = SA5_completed,
 };
 
 static struct access_method SA5B_access = {
-        SA5_submit_command,
-        SA5B_intr_mask,
-        SA5_fifo_full,
-        SA5B_intr_pending,
-        SA5_completed,
+       .submit_command = SA5_submit_command,
+       .set_intr_mask = SA5B_intr_mask,
+       .fifo_full = SA5_fifo_full,
+       .intr_pending = SA5B_intr_pending,
+       .command_completed = SA5_completed,
 };
 
 static struct access_method SA5_performant_access = {
-       SA5_submit_command,
-       SA5_performant_intr_mask,
-       SA5_fifo_full,
-       SA5_performant_intr_pending,
-       SA5_performant_completed,
+       .submit_command = SA5_submit_command,
+       .set_intr_mask = SA5_performant_intr_mask,
+       .fifo_full = SA5_fifo_full,
+       .intr_pending = SA5_performant_intr_pending,
+       .command_completed = SA5_performant_completed,
 };
 
 struct board_type {
index c3ff60c30dde06c5ac3f8efa4636806cb24c682c..615e5b5178a0541852820e67698d7a8b41cc268d 100644 (file)
@@ -2462,7 +2462,7 @@ static int drbd_congested(void *congested_data, int bdi_bits)
 
        if (get_ldev(device)) {
                q = bdev_get_queue(device->ldev->backing_bdev);
-               r = bdi_congested(&q->backing_dev_info, bdi_bits);
+               r = bdi_congested(q->backing_dev_info, bdi_bits);
                put_ldev(device);
                if (r)
                        reason = 'b';
@@ -2834,8 +2834,8 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig
        /* we have no partitions. we contain only ourselves. */
        device->this_bdev->bd_contains = device->this_bdev;
 
-       q->backing_dev_info.congested_fn = drbd_congested;
-       q->backing_dev_info.congested_data = device;
+       q->backing_dev_info->congested_fn = drbd_congested;
+       q->backing_dev_info->congested_data = device;
 
        blk_queue_make_request(q, drbd_make_request);
        blk_queue_write_cache(q, true, true);
index f35db29cac76f5b23edc9e3affccc6d7b5a23745..908c704e20aa7ba57be68849b96b7797e848d9e4 100644 (file)
@@ -1328,11 +1328,13 @@ static void drbd_setup_queue_param(struct drbd_device *device, struct drbd_backi
        if (b) {
                blk_queue_stack_limits(q, b);
 
-               if (q->backing_dev_info.ra_pages != b->backing_dev_info.ra_pages) {
+               if (q->backing_dev_info->ra_pages !=
+                   b->backing_dev_info->ra_pages) {
                        drbd_info(device, "Adjusting my ra_pages to backing device's (%lu -> %lu)\n",
-                                q->backing_dev_info.ra_pages,
-                                b->backing_dev_info.ra_pages);
-                       q->backing_dev_info.ra_pages = b->backing_dev_info.ra_pages;
+                                q->backing_dev_info->ra_pages,
+                                b->backing_dev_info->ra_pages);
+                       q->backing_dev_info->ra_pages =
+                                               b->backing_dev_info->ra_pages;
                }
        }
        fixup_discard_if_not_supported(q);
@@ -3345,7 +3347,7 @@ static void device_to_statistics(struct device_statistics *s,
                s->dev_disk_flags = md->flags;
                q = bdev_get_queue(device->ldev->backing_bdev);
                s->dev_lower_blocked =
-                       bdi_congested(&q->backing_dev_info,
+                       bdi_congested(q->backing_dev_info,
                                      (1 << WB_async_congested) |
                                      (1 << WB_sync_congested));
                put_ldev(device);
index be2b93fd2c11a23ca2f293db92460446f926c114..8378142f7a55182d748b2b0ec4e1ae9699ff5eac 100644 (file)
@@ -288,7 +288,7 @@ static int drbd_seq_show(struct seq_file *seq, void *v)
                        seq_printf(seq, "%2d: cs:Unconfigured\n", i);
                } else {
                        /* reset device->congestion_reason */
-                       bdi_rw_congested(&device->rq_queue->backing_dev_info);
+                       bdi_rw_congested(device->rq_queue->backing_dev_info);
 
                        nc = rcu_dereference(first_peer_device(device)->connection->net_conf);
                        wp = nc ? nc->wire_protocol - DRBD_PROT_A + 'A' : ' ';
index b489ac2e9c4446d74f1bfeb5b7230b152c17ce55..652114ae1a8aeba3abe05899e95139a2cd21753d 100644 (file)
@@ -927,7 +927,7 @@ static bool remote_due_to_read_balancing(struct drbd_device *device, sector_t se
 
        switch (rbm) {
        case RB_CONGESTED_REMOTE:
-               bdi = &device->ldev->backing_bdev->bd_disk->queue->backing_dev_info;
+               bdi = device->ldev->backing_bdev->bd_disk->queue->backing_dev_info;
                return bdi_read_congested(bdi);
        case RB_LEAST_PENDING:
                return atomic_read(&device->local_cnt) >
index a391a3cfb3fe6ef7c7b065cd9160671d58318ae5..45b4384f650ccedeed20c2b4718fa1be49b87b06 100644 (file)
@@ -2900,8 +2900,8 @@ static void do_fd_request(struct request_queue *q)
                return;
 
        if (WARN(atomic_read(&usage_count) == 0,
-                "warning: usage count=0, current_req=%p sect=%ld type=%x flags=%llx\n",
-                current_req, (long)blk_rq_pos(current_req), current_req->cmd_type,
+                "warning: usage count=0, current_req=%p sect=%ld flags=%llx\n",
+                current_req, (long)blk_rq_pos(current_req),
                 (unsigned long long) current_req->cmd_flags))
                return;
 
@@ -3119,7 +3119,7 @@ static int raw_cmd_copyin(int cmd, void __user *param,
        *rcmd = NULL;
 
 loop:
-       ptr = kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER);
+       ptr = kmalloc(sizeof(struct floppy_raw_cmd), GFP_KERNEL);
        if (!ptr)
                return -ENOMEM;
        *rcmd = ptr;
index a9b48ed7a3cd258c1314b23aa77502c9a4fbbfc1..6043648da1e85581135e16169210219aecbd5285 100644 (file)
@@ -626,30 +626,29 @@ repeat:
                req_data_dir(req) == READ ? "read" : "writ",
                cyl, head, sec, nsect, bio_data(req->bio));
 #endif
-       if (req->cmd_type == REQ_TYPE_FS) {
-               switch (rq_data_dir(req)) {
-               case READ:
-                       hd_out(disk, nsect, sec, head, cyl, ATA_CMD_PIO_READ,
-                               &read_intr);
-                       if (reset)
-                               goto repeat;
-                       break;
-               case WRITE:
-                       hd_out(disk, nsect, sec, head, cyl, ATA_CMD_PIO_WRITE,
-                               &write_intr);
-                       if (reset)
-                               goto repeat;
-                       if (wait_DRQ()) {
-                               bad_rw_intr();
-                               goto repeat;
-                       }
-                       outsw(HD_DATA, bio_data(req->bio), 256);
-                       break;
-               default:
-                       printk("unknown hd-command\n");
-                       hd_end_request_cur(-EIO);
-                       break;
+
+       switch (req_op(req)) {
+       case REQ_OP_READ:
+               hd_out(disk, nsect, sec, head, cyl, ATA_CMD_PIO_READ,
+                       &read_intr);
+               if (reset)
+                       goto repeat;
+               break;
+       case REQ_OP_WRITE:
+               hd_out(disk, nsect, sec, head, cyl, ATA_CMD_PIO_WRITE,
+                       &write_intr);
+               if (reset)
+                       goto repeat;
+               if (wait_DRQ()) {
+                       bad_rw_intr();
+                       goto repeat;
                }
+               outsw(HD_DATA, bio_data(req->bio), 256);
+               break;
+       default:
+               printk("unknown hd-command\n");
+               hd_end_request_cur(-EIO);
+               break;
        }
 }
 
index f347285c67ec1151d0d725842eed84ba2231f760..304377182c1ad462b9832b7a5e9b1fb930ca62fa 100644 (file)
@@ -1097,9 +1097,12 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
        if ((unsigned int) info->lo_encrypt_key_size > LO_KEY_SIZE)
                return -EINVAL;
 
+       /* I/O need to be drained during transfer transition */
+       blk_mq_freeze_queue(lo->lo_queue);
+
        err = loop_release_xfer(lo);
        if (err)
-               return err;
+               goto exit;
 
        if (info->lo_encrypt_type) {
                unsigned int type = info->lo_encrypt_type;
@@ -1114,12 +1117,14 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
 
        err = loop_init_xfer(lo, xfer, info);
        if (err)
-               return err;
+               goto exit;
 
        if (lo->lo_offset != info->lo_offset ||
            lo->lo_sizelimit != info->lo_sizelimit)
-               if (figure_loop_size(lo, info->lo_offset, info->lo_sizelimit))
-                       return -EFBIG;
+               if (figure_loop_size(lo, info->lo_offset, info->lo_sizelimit)) {
+                       err = -EFBIG;
+                       goto exit;
+               }
 
        loop_config_discard(lo);
 
@@ -1156,7 +1161,9 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
        /* update dio if lo_offset or transfer is changed */
        __loop_update_dio(lo, lo->use_dio);
 
-       return 0;
+ exit:
+       blk_mq_unfreeze_queue(lo->lo_queue);
+       return err;
 }
 
 static int
index e937fcf717690fa5a6ec2d4e7915908fbe001836..286f276f586e4674e323dafd3a1a60ababcc9088 100644 (file)
@@ -670,15 +670,17 @@ static void mg_request_poll(struct request_queue *q)
                                break;
                }
 
-               if (unlikely(host->req->cmd_type != REQ_TYPE_FS)) {
-                       mg_end_request_cur(host, -EIO);
-                       continue;
-               }
-
-               if (rq_data_dir(host->req) == READ)
+               switch (req_op(host->req)) {
+               case REQ_OP_READ:
                        mg_read(host->req);
-               else
+                       break;
+               case REQ_OP_WRITE:
                        mg_write(host->req);
+                       break;
+               default:
+                       mg_end_request_cur(host, -EIO);
+                       break;
+               }
        }
 }
 
@@ -687,13 +689,15 @@ static unsigned int mg_issue_req(struct request *req,
                unsigned int sect_num,
                unsigned int sect_cnt)
 {
-       if (rq_data_dir(req) == READ) {
+       switch (req_op(host->req)) {
+       case REQ_OP_READ:
                if (mg_out(host, sect_num, sect_cnt, MG_CMD_RD, &mg_read_intr)
                                != MG_ERR_NONE) {
                        mg_bad_rw_intr(host);
                        return host->error;
                }
-       } else {
+               break;
+       case REQ_OP_WRITE:
                /* TODO : handler */
                outb(ATA_NIEN, (unsigned long)host->dev_base + MG_REG_DRV_CTRL);
                if (mg_out(host, sect_num, sect_cnt, MG_CMD_WR, &mg_write_intr)
@@ -712,6 +716,10 @@ static unsigned int mg_issue_req(struct request *req,
                mod_timer(&host->timer, jiffies + 3 * HZ);
                outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base +
                                MG_REG_COMMAND);
+               break;
+       default:
+               mg_end_request_cur(host, -EIO);
+               break;
        }
        return MG_ERR_NONE;
 }
@@ -753,11 +761,6 @@ static void mg_request(struct request_queue *q)
                        continue;
                }
 
-               if (unlikely(req->cmd_type != REQ_TYPE_FS)) {
-                       mg_end_request_cur(host, -EIO);
-                       continue;
-               }
-
                if (!mg_issue_req(req, host, sect_num, sect_cnt))
                        return;
        }
index 9fd06eeb1a17b3880e2ad574f4ca081903a67961..0be84a3cb6d7bbb605a252ff5666c1642a1c201a 100644 (file)
@@ -41,6 +41,9 @@
 
 #include <linux/nbd.h>
 
+static DEFINE_IDR(nbd_index_idr);
+static DEFINE_MUTEX(nbd_index_mutex);
+
 struct nbd_sock {
        struct socket *sock;
        struct mutex tx_lock;
@@ -89,8 +92,9 @@ static struct dentry *nbd_dbg_dir;
 #define NBD_MAGIC 0x68797548
 
 static unsigned int nbds_max = 16;
-static struct nbd_device *nbd_dev;
 static int max_part;
+static struct workqueue_struct *recv_workqueue;
+static int part_shift;
 
 static inline struct device *nbd_to_dev(struct nbd_device *nbd)
 {
@@ -193,13 +197,6 @@ static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req,
        set_bit(NBD_TIMEDOUT, &nbd->runtime_flags);
        req->errors++;
 
-       /*
-        * If our disconnect packet times out then we're already holding the
-        * config_lock and could deadlock here, so just set an error and return,
-        * we'll handle shutting everything down later.
-        */
-       if (req->cmd_type == REQ_TYPE_DRV_PRIV)
-               return BLK_EH_HANDLED;
        mutex_lock(&nbd->config_lock);
        sock_shutdown(nbd);
        mutex_unlock(&nbd->config_lock);
@@ -278,14 +275,29 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index)
        u32 type;
        u32 tag = blk_mq_unique_tag(req);
 
-       if (req_op(req) == REQ_OP_DISCARD)
+       switch (req_op(req)) {
+       case REQ_OP_DISCARD:
                type = NBD_CMD_TRIM;
-       else if (req_op(req) == REQ_OP_FLUSH)
+               break;
+       case REQ_OP_FLUSH:
                type = NBD_CMD_FLUSH;
-       else if (rq_data_dir(req) == WRITE)
+               break;
+       case REQ_OP_WRITE:
                type = NBD_CMD_WRITE;
-       else
+               break;
+       case REQ_OP_READ:
                type = NBD_CMD_READ;
+               break;
+       default:
+               return -EIO;
+       }
+
+       if (rq_data_dir(req) == WRITE &&
+           (nbd->flags & NBD_FLAG_READ_ONLY)) {
+               dev_err_ratelimited(disk_to_dev(nbd->disk),
+                                   "Write on read-only\n");
+               return -EIO;
+       }
 
        memset(&request, 0, sizeof(request));
        request.magic = htonl(NBD_REQUEST_MAGIC);
@@ -510,18 +522,6 @@ static void nbd_handle_cmd(struct nbd_cmd *cmd, int index)
                goto error_out;
        }
 
-       if (req->cmd_type != REQ_TYPE_FS &&
-           req->cmd_type != REQ_TYPE_DRV_PRIV)
-               goto error_out;
-
-       if (req->cmd_type == REQ_TYPE_FS &&
-           rq_data_dir(req) == WRITE &&
-           (nbd->flags & NBD_FLAG_READ_ONLY)) {
-               dev_err_ratelimited(disk_to_dev(nbd->disk),
-                                   "Write on read-only\n");
-               goto error_out;
-       }
-
        req->errors = 0;
 
        nsock = nbd->socks[index];
@@ -785,7 +785,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
                        INIT_WORK(&args[i].work, recv_work);
                        args[i].nbd = nbd;
                        args[i].index = i;
-                       queue_work(system_long_wq, &args[i].work);
+                       queue_work(recv_workqueue, &args[i].work);
                }
                wait_event_interruptible(nbd->recv_wq,
                                         atomic_read(&nbd->recv_threads) == 0);
@@ -996,6 +996,103 @@ static struct blk_mq_ops nbd_mq_ops = {
        .timeout        = nbd_xmit_timeout,
 };
 
+static void nbd_dev_remove(struct nbd_device *nbd)
+{
+       struct gendisk *disk = nbd->disk;
+       nbd->magic = 0;
+       if (disk) {
+               del_gendisk(disk);
+               blk_cleanup_queue(disk->queue);
+               blk_mq_free_tag_set(&nbd->tag_set);
+               put_disk(disk);
+       }
+       kfree(nbd);
+}
+
+static int nbd_dev_add(int index)
+{
+       struct nbd_device *nbd;
+       struct gendisk *disk;
+       struct request_queue *q;
+       int err = -ENOMEM;
+
+       nbd = kzalloc(sizeof(struct nbd_device), GFP_KERNEL);
+       if (!nbd)
+               goto out;
+
+       disk = alloc_disk(1 << part_shift);
+       if (!disk)
+               goto out_free_nbd;
+
+       if (index >= 0) {
+               err = idr_alloc(&nbd_index_idr, nbd, index, index + 1,
+                               GFP_KERNEL);
+               if (err == -ENOSPC)
+                       err = -EEXIST;
+       } else {
+               err = idr_alloc(&nbd_index_idr, nbd, 0, 0, GFP_KERNEL);
+               if (err >= 0)
+                       index = err;
+       }
+       if (err < 0)
+               goto out_free_disk;
+
+       nbd->disk = disk;
+       nbd->tag_set.ops = &nbd_mq_ops;
+       nbd->tag_set.nr_hw_queues = 1;
+       nbd->tag_set.queue_depth = 128;
+       nbd->tag_set.numa_node = NUMA_NO_NODE;
+       nbd->tag_set.cmd_size = sizeof(struct nbd_cmd);
+       nbd->tag_set.flags = BLK_MQ_F_SHOULD_MERGE |
+               BLK_MQ_F_SG_MERGE | BLK_MQ_F_BLOCKING;
+       nbd->tag_set.driver_data = nbd;
+
+       err = blk_mq_alloc_tag_set(&nbd->tag_set);
+       if (err)
+               goto out_free_idr;
+
+       q = blk_mq_init_queue(&nbd->tag_set);
+       if (IS_ERR(q)) {
+               err = PTR_ERR(q);
+               goto out_free_tags;
+       }
+       disk->queue = q;
+
+       /*
+        * Tell the block layer that we are not a rotational device
+        */
+       queue_flag_set_unlocked(QUEUE_FLAG_NONROT, disk->queue);
+       queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, disk->queue);
+       disk->queue->limits.discard_granularity = 512;
+       blk_queue_max_discard_sectors(disk->queue, UINT_MAX);
+       disk->queue->limits.discard_zeroes_data = 0;
+       blk_queue_max_hw_sectors(disk->queue, 65536);
+       disk->queue->limits.max_sectors = 256;
+
+       nbd->magic = NBD_MAGIC;
+       mutex_init(&nbd->config_lock);
+       disk->major = NBD_MAJOR;
+       disk->first_minor = index << part_shift;
+       disk->fops = &nbd_fops;
+       disk->private_data = nbd;
+       sprintf(disk->disk_name, "nbd%d", index);
+       init_waitqueue_head(&nbd->recv_wq);
+       nbd_reset(nbd);
+       add_disk(disk);
+       return index;
+
+out_free_tags:
+       blk_mq_free_tag_set(&nbd->tag_set);
+out_free_idr:
+       idr_remove(&nbd_index_idr, index);
+out_free_disk:
+       put_disk(disk);
+out_free_nbd:
+       kfree(nbd);
+out:
+       return err;
+}
+
 /*
  * And here should be modules and kernel interface 
  *  (Just smiley confuses emacs :-)
@@ -1003,9 +1100,7 @@ static struct blk_mq_ops nbd_mq_ops = {
 
 static int __init nbd_init(void)
 {
-       int err = -ENOMEM;
        int i;
-       int part_shift;
 
        BUILD_BUG_ON(sizeof(struct nbd_request) != 28);
 
@@ -1034,111 +1129,38 @@ static int __init nbd_init(void)
 
        if (nbds_max > 1UL << (MINORBITS - part_shift))
                return -EINVAL;
-
-       nbd_dev = kcalloc(nbds_max, sizeof(*nbd_dev), GFP_KERNEL);
-       if (!nbd_dev)
+       recv_workqueue = alloc_workqueue("knbd-recv",
+                                        WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
+       if (!recv_workqueue)
                return -ENOMEM;
 
-       for (i = 0; i < nbds_max; i++) {
-               struct request_queue *q;
-               struct gendisk *disk = alloc_disk(1 << part_shift);
-               if (!disk)
-                       goto out;
-               nbd_dev[i].disk = disk;
-
-               nbd_dev[i].tag_set.ops = &nbd_mq_ops;
-               nbd_dev[i].tag_set.nr_hw_queues = 1;
-               nbd_dev[i].tag_set.queue_depth = 128;
-               nbd_dev[i].tag_set.numa_node = NUMA_NO_NODE;
-               nbd_dev[i].tag_set.cmd_size = sizeof(struct nbd_cmd);
-               nbd_dev[i].tag_set.flags = BLK_MQ_F_SHOULD_MERGE |
-                       BLK_MQ_F_SG_MERGE | BLK_MQ_F_BLOCKING;
-               nbd_dev[i].tag_set.driver_data = &nbd_dev[i];
-
-               err = blk_mq_alloc_tag_set(&nbd_dev[i].tag_set);
-               if (err) {
-                       put_disk(disk);
-                       goto out;
-               }
-
-               /*
-                * The new linux 2.5 block layer implementation requires
-                * every gendisk to have its very own request_queue struct.
-                * These structs are big so we dynamically allocate them.
-                */
-               q = blk_mq_init_queue(&nbd_dev[i].tag_set);
-               if (IS_ERR(q)) {
-                       blk_mq_free_tag_set(&nbd_dev[i].tag_set);
-                       put_disk(disk);
-                       goto out;
-               }
-               disk->queue = q;
-
-               /*
-                * Tell the block layer that we are not a rotational device
-                */
-               queue_flag_set_unlocked(QUEUE_FLAG_NONROT, disk->queue);
-               queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, disk->queue);
-               disk->queue->limits.discard_granularity = 512;
-               blk_queue_max_discard_sectors(disk->queue, UINT_MAX);
-               disk->queue->limits.discard_zeroes_data = 0;
-               blk_queue_max_hw_sectors(disk->queue, 65536);
-               disk->queue->limits.max_sectors = 256;
-       }
-
-       if (register_blkdev(NBD_MAJOR, "nbd")) {
-               err = -EIO;
-               goto out;
-       }
-
-       printk(KERN_INFO "nbd: registered device at major %d\n", NBD_MAJOR);
+       if (register_blkdev(NBD_MAJOR, "nbd"))
+               return -EIO;
 
        nbd_dbg_init();
 
-       for (i = 0; i < nbds_max; i++) {
-               struct gendisk *disk = nbd_dev[i].disk;
-               nbd_dev[i].magic = NBD_MAGIC;
-               mutex_init(&nbd_dev[i].config_lock);
-               disk->major = NBD_MAJOR;
-               disk->first_minor = i << part_shift;
-               disk->fops = &nbd_fops;
-               disk->private_data = &nbd_dev[i];
-               sprintf(disk->disk_name, "nbd%d", i);
-               init_waitqueue_head(&nbd_dev[i].recv_wq);
-               nbd_reset(&nbd_dev[i]);
-               add_disk(disk);
-       }
+       mutex_lock(&nbd_index_mutex);
+       for (i = 0; i < nbds_max; i++)
+               nbd_dev_add(i);
+       mutex_unlock(&nbd_index_mutex);
+       return 0;
+}
 
+static int nbd_exit_cb(int id, void *ptr, void *data)
+{
+       struct nbd_device *nbd = ptr;
+       nbd_dev_remove(nbd);
        return 0;
-out:
-       while (i--) {
-               blk_mq_free_tag_set(&nbd_dev[i].tag_set);
-               blk_cleanup_queue(nbd_dev[i].disk->queue);
-               put_disk(nbd_dev[i].disk);
-       }
-       kfree(nbd_dev);
-       return err;
 }
 
 static void __exit nbd_cleanup(void)
 {
-       int i;
-
        nbd_dbg_close();
 
-       for (i = 0; i < nbds_max; i++) {
-               struct gendisk *disk = nbd_dev[i].disk;
-               nbd_dev[i].magic = 0;
-               if (disk) {
-                       del_gendisk(disk);
-                       blk_cleanup_queue(disk->queue);
-                       blk_mq_free_tag_set(&nbd_dev[i].tag_set);
-                       put_disk(disk);
-               }
-       }
+       idr_for_each(&nbd_index_idr, &nbd_exit_cb, NULL);
+       idr_destroy(&nbd_index_idr);
+       destroy_workqueue(recv_workqueue);
        unregister_blkdev(NBD_MAJOR, "nbd");
-       kfree(nbd_dev);
-       printk(KERN_INFO "nbd: unregistered device at major %d\n", NBD_MAJOR);
 }
 
 module_init(nbd_init);
index c0e14e54909b41b8f8e2f916be0d1169464ff643..6f2e565bccc59e8f3610f1651a385de885443e4c 100644 (file)
@@ -420,7 +420,8 @@ static void null_lnvm_end_io(struct request *rq, int error)
 {
        struct nvm_rq *rqd = rq->end_io_data;
 
-       nvm_end_io(rqd, error);
+       rqd->error = error;
+       nvm_end_io(rqd);
 
        blk_put_request(rq);
 }
@@ -431,11 +432,11 @@ static int null_lnvm_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd)
        struct request *rq;
        struct bio *bio = rqd->bio;
 
-       rq = blk_mq_alloc_request(q, bio_data_dir(bio), 0);
+       rq = blk_mq_alloc_request(q,
+               op_is_write(bio_op(bio)) ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0);
        if (IS_ERR(rq))
                return -ENOMEM;
 
-       rq->cmd_type = REQ_TYPE_DRV_PRIV;
        rq->__sector = bio->bi_iter.bi_sector;
        rq->ioprio = bio_prio(bio);
 
@@ -460,7 +461,6 @@ static int null_lnvm_id(struct nvm_dev *dev, struct nvm_id *id)
 
        id->ver_id = 0x1;
        id->vmnt = 0;
-       id->cgrps = 1;
        id->cap = 0x2;
        id->dom = 0x1;
 
@@ -479,7 +479,7 @@ static int null_lnvm_id(struct nvm_dev *dev, struct nvm_id *id)
 
        sector_div(size, bs); /* convert size to pages */
        size >>= 8; /* concert size to pgs pr blk */
-       grp = &id->groups[0];
+       grp = &id->grp;
        grp->mtype = 0;
        grp->fmtype = 0;
        grp->num_ch = 1;
index 92900f5f0b4725ebc1d1edbf3da30138a3e2979b..8127b8201a011a2b26d9b2665ae11233e5799179 100644 (file)
@@ -308,12 +308,6 @@ static void osdblk_rq_fn(struct request_queue *q)
                if (!rq)
                        break;
 
-               /* filter out block requests we don't understand */
-               if (rq->cmd_type != REQ_TYPE_FS) {
-                       blk_end_request_all(rq, 0);
-                       continue;
-               }
-
                /* deduce our operation (read, write, flush) */
                /* I wish the block layer simplified cmd_type/cmd_flags/cmd[]
                 * into a clearly defined set of RPC commands:
index efefb5ac300452dbf3ac7af14989d465102ee29f..3a15247942e41119bd26822a8e5b636b9a8a01e0 100644 (file)
@@ -25,6 +25,7 @@ config PARIDE_PD
 config PARIDE_PCD
        tristate "Parallel port ATAPI CD-ROMs"
        depends on PARIDE
+       select BLK_SCSI_REQUEST # only for the generic cdrom code
        ---help---
          This option enables the high-level driver for ATAPI CD-ROM devices
          connected through a parallel port. If you chose to build PARIDE
index 5fd2d0e25567dca15c9edb91f9a1a4f27bec8f75..10aed84244f51854305ff7e0c59277731ab826f2 100644 (file)
@@ -273,7 +273,7 @@ static const struct block_device_operations pcd_bdops = {
        .check_events   = pcd_block_check_events,
 };
 
-static struct cdrom_device_ops pcd_dops = {
+static const struct cdrom_device_ops pcd_dops = {
        .open           = pcd_open,
        .release        = pcd_release,
        .drive_status   = pcd_drive_status,
index c3ed2fc72daae449f354867cb50e3eb111ec9c75..644ba0888bd41bb5e54f4ab58345b6af9519e0c2 100644 (file)
@@ -439,18 +439,16 @@ static int pd_retries = 0;        /* i/o error retry count */
 static int pd_block;           /* address of next requested block */
 static int pd_count;           /* number of blocks still to do */
 static int pd_run;             /* sectors in current cluster */
-static int pd_cmd;             /* current command READ/WRITE */
 static char *pd_buf;           /* buffer for request in progress */
 
 static enum action do_pd_io_start(void)
 {
-       if (pd_req->cmd_type == REQ_TYPE_DRV_PRIV) {
+       switch (req_op(pd_req)) {
+       case REQ_OP_DRV_IN:
                phase = pd_special;
                return pd_special();
-       }
-
-       pd_cmd = rq_data_dir(pd_req);
-       if (pd_cmd == READ || pd_cmd == WRITE) {
+       case REQ_OP_READ:
+       case REQ_OP_WRITE:
                pd_block = blk_rq_pos(pd_req);
                pd_count = blk_rq_cur_sectors(pd_req);
                if (pd_block + pd_count > get_capacity(pd_req->rq_disk))
@@ -458,7 +456,7 @@ static enum action do_pd_io_start(void)
                pd_run = blk_rq_sectors(pd_req);
                pd_buf = bio_data(pd_req->bio);
                pd_retries = 0;
-               if (pd_cmd == READ)
+               if (req_op(pd_req) == REQ_OP_READ)
                        return do_pd_read_start();
                else
                        return do_pd_write_start();
@@ -723,11 +721,10 @@ static int pd_special_command(struct pd_unit *disk,
        struct request *rq;
        int err = 0;
 
-       rq = blk_get_request(disk->gd->queue, READ, __GFP_RECLAIM);
+       rq = blk_get_request(disk->gd->queue, REQ_OP_DRV_IN, __GFP_RECLAIM);
        if (IS_ERR(rq))
                return PTR_ERR(rq);
 
-       rq->cmd_type = REQ_TYPE_DRV_PRIV;
        rq->special = func;
 
        err = blk_execute_rq(disk->gd->queue, disk->gd, rq, 0);
index 1b94c1ca5c5f1ee1bc00e0fe5103cf6ef0a4dafe..66d846ba85a9774c226dc92a85cc1c19b8c1ca9d 100644 (file)
@@ -704,10 +704,10 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *
        int ret = 0;
 
        rq = blk_get_request(q, (cgc->data_direction == CGC_DATA_WRITE) ?
-                            WRITE : READ, __GFP_RECLAIM);
+                            REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, __GFP_RECLAIM);
        if (IS_ERR(rq))
                return PTR_ERR(rq);
-       blk_rq_set_block_pc(rq);
+       scsi_req_init(rq);
 
        if (cgc->buflen) {
                ret = blk_rq_map_kern(q, rq, cgc->buffer, cgc->buflen,
@@ -716,8 +716,8 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *
                        goto out;
        }
 
-       rq->cmd_len = COMMAND_SIZE(cgc->cmd[0]);
-       memcpy(rq->cmd, cgc->cmd, CDROM_PACKET_SIZE);
+       scsi_req(rq)->cmd_len = COMMAND_SIZE(cgc->cmd[0]);
+       memcpy(scsi_req(rq)->cmd, cgc->cmd, CDROM_PACKET_SIZE);
 
        rq->timeout = 60*HZ;
        if (cgc->quiet)
@@ -1243,7 +1243,7 @@ try_next_bio:
                        && pd->bio_queue_size <= pd->write_congestion_off);
        spin_unlock(&pd->lock);
        if (wakeup) {
-               clear_bdi_congested(&pd->disk->queue->backing_dev_info,
+               clear_bdi_congested(pd->disk->queue->backing_dev_info,
                                        BLK_RW_ASYNC);
        }
 
@@ -2370,7 +2370,7 @@ static void pkt_make_request_write(struct request_queue *q, struct bio *bio)
        spin_lock(&pd->lock);
        if (pd->write_congestion_on > 0
            && pd->bio_queue_size >= pd->write_congestion_on) {
-               set_bdi_congested(&q->backing_dev_info, BLK_RW_ASYNC);
+               set_bdi_congested(q->backing_dev_info, BLK_RW_ASYNC);
                do {
                        spin_unlock(&pd->lock);
                        congestion_wait(BLK_RW_ASYNC, HZ);
index 76f33c84ce3dfb2eb6228d7bc5afdecb284e6ba9..a809e3e9feb8b885af9cd439de909c7e2e27f220 100644 (file)
@@ -196,16 +196,19 @@ static void ps3disk_do_request(struct ps3_storage_device *dev,
        dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__);
 
        while ((req = blk_fetch_request(q))) {
-               if (req_op(req) == REQ_OP_FLUSH) {
+               switch (req_op(req)) {
+               case REQ_OP_FLUSH:
                        if (ps3disk_submit_flush_request(dev, req))
-                               break;
-               } else if (req->cmd_type == REQ_TYPE_FS) {
+                               return;
+                       break;
+               case REQ_OP_READ:
+               case REQ_OP_WRITE:
                        if (ps3disk_submit_request_sg(dev, req))
-                               break;
-               } else {
+                               return;
+                       break;
+               default:
                        blk_dump_rq_flags(req, DEVICE_NAME " bad request");
                        __blk_end_request_all(req, -EIO);
-                       continue;
                }
        }
 }
index 436baa66f701c8ee88519047016c7525c2d390e6..362cecc77130260459d81d18d8853f39a7eb35eb 100644 (file)
@@ -4099,19 +4099,21 @@ static void rbd_queue_workfn(struct work_struct *work)
        bool must_be_locked;
        int result;
 
-       if (rq->cmd_type != REQ_TYPE_FS) {
-               dout("%s: non-fs request type %d\n", __func__,
-                       (int) rq->cmd_type);
-               result = -EIO;
-               goto err;
-       }
-
-       if (req_op(rq) == REQ_OP_DISCARD)
+       switch (req_op(rq)) {
+       case REQ_OP_DISCARD:
                op_type = OBJ_OP_DISCARD;
-       else if (req_op(rq) == REQ_OP_WRITE)
+               break;
+       case REQ_OP_WRITE:
                op_type = OBJ_OP_WRITE;
-       else
+               break;
+       case REQ_OP_READ:
                op_type = OBJ_OP_READ;
+               break;
+       default:
+               dout("%s: non-fs request type %d\n", __func__, req_op(rq));
+               result = -EIO;
+               goto err;
+       }
 
        /* Ignore/skip any zero-length requests */
 
@@ -4524,7 +4526,7 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
        q->limits.discard_zeroes_data = 1;
 
        if (!ceph_test_opt(rbd_dev->rbd_client->client, NOCRC))
-               q->backing_dev_info.capabilities |= BDI_CAP_STABLE_WRITES;
+               q->backing_dev_info->capabilities |= BDI_CAP_STABLE_WRITES;
 
        disk->queue = q;
 
index abf805e332e2a11e55e628c0f2e419e782ba03a9..27833e4dae2adffca5eec7714272459cd0a29bb7 100644 (file)
@@ -1204,10 +1204,11 @@ static void skd_complete_special(struct skd_device *skdev,
 static int skd_bdev_ioctl(struct block_device *bdev, fmode_t mode,
                          uint cmd_in, ulong arg)
 {
-       int rc = 0;
+       static const int sg_version_num = 30527;
+       int rc = 0, timeout;
        struct gendisk *disk = bdev->bd_disk;
        struct skd_device *skdev = disk->private_data;
-       void __user *p = (void *)arg;
+       int __user *p = (int __user *)arg;
 
        pr_debug("%s:%s:%d %s: CMD[%s] ioctl  mode 0x%x, cmd 0x%x arg %0lx\n",
                 skdev->name, __func__, __LINE__,
@@ -1218,12 +1219,18 @@ static int skd_bdev_ioctl(struct block_device *bdev, fmode_t mode,
 
        switch (cmd_in) {
        case SG_SET_TIMEOUT:
+               rc = get_user(timeout, p);
+               if (!rc)
+                       disk->queue->sg_timeout = clock_t_to_jiffies(timeout);
+               break;
        case SG_GET_TIMEOUT:
+               rc = jiffies_to_clock_t(disk->queue->sg_timeout);
+               break;
        case SG_GET_VERSION_NUM:
-               rc = scsi_cmd_ioctl(disk->queue, disk, mode, cmd_in, p);
+               rc = put_user(sg_version_num, p);
                break;
        case SG_IO:
-               rc = skd_ioctl_sg_io(skdev, mode, p);
+               rc = skd_ioctl_sg_io(skdev, mode, (void __user *)arg);
                break;
 
        default:
index 0e93ad7b851160540b25c068e5314f107dad2964..c8e072caf56ffcd9678b850ffab9886f6ac9b5c6 100644 (file)
@@ -567,7 +567,7 @@ static struct carm_request *carm_get_special(struct carm_host *host)
        if (!crq)
                return NULL;
 
-       rq = blk_get_request(host->oob_q, WRITE /* bogus */, GFP_KERNEL);
+       rq = blk_get_request(host->oob_q, REQ_OP_DRV_OUT, GFP_KERNEL);
        if (IS_ERR(rq)) {
                spin_lock_irqsave(&host->lock, flags);
                carm_put_request(host, crq);
@@ -620,7 +620,6 @@ static int carm_array_info (struct carm_host *host, unsigned int array_idx)
        spin_unlock_irq(&host->lock);
 
        DPRINTK("blk_execute_rq_nowait, tag == %u\n", idx);
-       crq->rq->cmd_type = REQ_TYPE_DRV_PRIV;
        crq->rq->special = crq;
        blk_execute_rq_nowait(host->oob_q, NULL, crq->rq, true, NULL);
 
@@ -661,7 +660,6 @@ static int carm_send_special (struct carm_host *host, carm_sspc_t func)
        crq->msg_bucket = (u32) rc;
 
        DPRINTK("blk_execute_rq_nowait, tag == %u\n", idx);
-       crq->rq->cmd_type = REQ_TYPE_DRV_PRIV;
        crq->rq->special = crq;
        blk_execute_rq_nowait(host->oob_q, NULL, crq->rq, true, NULL);
 
index 264c5eac12b028eab2d30d2e35bd05e1fa968745..024b473524c09615768050743bd482a048b3de27 100644 (file)
@@ -52,11 +52,13 @@ struct virtio_blk {
 };
 
 struct virtblk_req {
-       struct request *req;
-       struct virtio_blk_outhdr out_hdr;
+#ifdef CONFIG_VIRTIO_BLK_SCSI
+       struct scsi_request sreq;       /* for SCSI passthrough, must be first */
+       u8 sense[SCSI_SENSE_BUFFERSIZE];
        struct virtio_scsi_inhdr in_hdr;
+#endif
+       struct virtio_blk_outhdr out_hdr;
        u8 status;
-       u8 sense[SCSI_SENSE_BUFFERSIZE];
        struct scatterlist sg[];
 };
 
@@ -72,28 +74,88 @@ static inline int virtblk_result(struct virtblk_req *vbr)
        }
 }
 
-static int __virtblk_add_req(struct virtqueue *vq,
-                            struct virtblk_req *vbr,
-                            struct scatterlist *data_sg,
-                            bool have_data)
+/*
+ * If this is a packet command we need a couple of additional headers.  Behind
+ * the normal outhdr we put a segment with the scsi command block, and before
+ * the normal inhdr we put the sense data and the inhdr with additional status
+ * information.
+ */
+#ifdef CONFIG_VIRTIO_BLK_SCSI
+static int virtblk_add_req_scsi(struct virtqueue *vq, struct virtblk_req *vbr,
+               struct scatterlist *data_sg, bool have_data)
 {
        struct scatterlist hdr, status, cmd, sense, inhdr, *sgs[6];
        unsigned int num_out = 0, num_in = 0;
-       __virtio32 type = vbr->out_hdr.type & ~cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_OUT);
 
        sg_init_one(&hdr, &vbr->out_hdr, sizeof(vbr->out_hdr));
        sgs[num_out++] = &hdr;
+       sg_init_one(&cmd, vbr->sreq.cmd, vbr->sreq.cmd_len);
+       sgs[num_out++] = &cmd;
+
+       if (have_data) {
+               if (vbr->out_hdr.type & cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_OUT))
+                       sgs[num_out++] = data_sg;
+               else
+                       sgs[num_out + num_in++] = data_sg;
+       }
+
+       sg_init_one(&sense, vbr->sense, SCSI_SENSE_BUFFERSIZE);
+       sgs[num_out + num_in++] = &sense;
+       sg_init_one(&inhdr, &vbr->in_hdr, sizeof(vbr->in_hdr));
+       sgs[num_out + num_in++] = &inhdr;
+       sg_init_one(&status, &vbr->status, sizeof(vbr->status));
+       sgs[num_out + num_in++] = &status;
+
+       return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC);
+}
+
+static inline void virtblk_scsi_reques_done(struct request *req)
+{
+       struct virtblk_req *vbr = blk_mq_rq_to_pdu(req);
+       struct virtio_blk *vblk = req->q->queuedata;
+       struct scsi_request *sreq = &vbr->sreq;
+
+       sreq->resid_len = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.residual);
+       sreq->sense_len = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.sense_len);
+       req->errors = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.errors);
+}
+
+static int virtblk_ioctl(struct block_device *bdev, fmode_t mode,
+                            unsigned int cmd, unsigned long data)
+{
+       struct gendisk *disk = bdev->bd_disk;
+       struct virtio_blk *vblk = disk->private_data;
 
        /*
-        * If this is a packet command we need a couple of additional headers.
-        * Behind the normal outhdr we put a segment with the scsi command
-        * block, and before the normal inhdr we put the sense data and the
-        * inhdr with additional status information.
+        * Only allow the generic SCSI ioctls if the host can support it.
         */
-       if (type == cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_SCSI_CMD)) {
-               sg_init_one(&cmd, vbr->req->cmd, vbr->req->cmd_len);
-               sgs[num_out++] = &cmd;
-       }
+       if (!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_SCSI))
+               return -ENOTTY;
+
+       return scsi_cmd_blk_ioctl(bdev, mode, cmd,
+                                 (void __user *)data);
+}
+#else
+static inline int virtblk_add_req_scsi(struct virtqueue *vq,
+               struct virtblk_req *vbr, struct scatterlist *data_sg,
+               bool have_data)
+{
+       return -EIO;
+}
+static inline void virtblk_scsi_reques_done(struct request *req)
+{
+}
+#define virtblk_ioctl  NULL
+#endif /* CONFIG_VIRTIO_BLK_SCSI */
+
+static int virtblk_add_req(struct virtqueue *vq, struct virtblk_req *vbr,
+               struct scatterlist *data_sg, bool have_data)
+{
+       struct scatterlist hdr, status, *sgs[3];
+       unsigned int num_out = 0, num_in = 0;
+
+       sg_init_one(&hdr, &vbr->out_hdr, sizeof(vbr->out_hdr));
+       sgs[num_out++] = &hdr;
 
        if (have_data) {
                if (vbr->out_hdr.type & cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_OUT))
@@ -102,14 +164,6 @@ static int __virtblk_add_req(struct virtqueue *vq,
                        sgs[num_out + num_in++] = data_sg;
        }
 
-       if (type == cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_SCSI_CMD)) {
-               memcpy(vbr->sense, vbr->req->sense, SCSI_SENSE_BUFFERSIZE);
-               sg_init_one(&sense, vbr->sense, SCSI_SENSE_BUFFERSIZE);
-               sgs[num_out + num_in++] = &sense;
-               sg_init_one(&inhdr, &vbr->in_hdr, sizeof(vbr->in_hdr));
-               sgs[num_out + num_in++] = &inhdr;
-       }
-
        sg_init_one(&status, &vbr->status, sizeof(vbr->status));
        sgs[num_out + num_in++] = &status;
 
@@ -119,15 +173,16 @@ static int __virtblk_add_req(struct virtqueue *vq,
 static inline void virtblk_request_done(struct request *req)
 {
        struct virtblk_req *vbr = blk_mq_rq_to_pdu(req);
-       struct virtio_blk *vblk = req->q->queuedata;
        int error = virtblk_result(vbr);
 
-       if (req->cmd_type == REQ_TYPE_BLOCK_PC) {
-               req->resid_len = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.residual);
-               req->sense_len = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.sense_len);
-               req->errors = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.errors);
-       } else if (req->cmd_type == REQ_TYPE_DRV_PRIV) {
+       switch (req_op(req)) {
+       case REQ_OP_SCSI_IN:
+       case REQ_OP_SCSI_OUT:
+               virtblk_scsi_reques_done(req);
+               break;
+       case REQ_OP_DRV_IN:
                req->errors = (error != 0);
+               break;
        }
 
        blk_mq_end_request(req, error);
@@ -146,7 +201,9 @@ static void virtblk_done(struct virtqueue *vq)
        do {
                virtqueue_disable_cb(vq);
                while ((vbr = virtqueue_get_buf(vblk->vqs[qid].vq, &len)) != NULL) {
-                       blk_mq_complete_request(vbr->req, vbr->req->errors);
+                       struct request *req = blk_mq_rq_from_pdu(vbr);
+
+                       blk_mq_complete_request(req, req->errors);
                        req_done = true;
                }
                if (unlikely(virtqueue_is_broken(vq)))
@@ -170,49 +227,50 @@ static int virtio_queue_rq(struct blk_mq_hw_ctx *hctx,
        int qid = hctx->queue_num;
        int err;
        bool notify = false;
+       u32 type;
 
        BUG_ON(req->nr_phys_segments + 2 > vblk->sg_elems);
 
-       vbr->req = req;
-       if (req_op(req) == REQ_OP_FLUSH) {
-               vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_FLUSH);
-               vbr->out_hdr.sector = 0;
-               vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(vbr->req));
-       } else {
-               switch (req->cmd_type) {
-               case REQ_TYPE_FS:
-                       vbr->out_hdr.type = 0;
-                       vbr->out_hdr.sector = cpu_to_virtio64(vblk->vdev, blk_rq_pos(vbr->req));
-                       vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(vbr->req));
-                       break;
-               case REQ_TYPE_BLOCK_PC:
-                       vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_SCSI_CMD);
-                       vbr->out_hdr.sector = 0;
-                       vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(vbr->req));
-                       break;
-               case REQ_TYPE_DRV_PRIV:
-                       vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_GET_ID);
-                       vbr->out_hdr.sector = 0;
-                       vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(vbr->req));
-                       break;
-               default:
-                       /* We don't put anything else in the queue. */
-                       BUG();
-               }
+       switch (req_op(req)) {
+       case REQ_OP_READ:
+       case REQ_OP_WRITE:
+               type = 0;
+               break;
+       case REQ_OP_FLUSH:
+               type = VIRTIO_BLK_T_FLUSH;
+               break;
+       case REQ_OP_SCSI_IN:
+       case REQ_OP_SCSI_OUT:
+               type = VIRTIO_BLK_T_SCSI_CMD;
+               break;
+       case REQ_OP_DRV_IN:
+               type = VIRTIO_BLK_T_GET_ID;
+               break;
+       default:
+               WARN_ON_ONCE(1);
+               return BLK_MQ_RQ_QUEUE_ERROR;
        }
 
+       vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, type);
+       vbr->out_hdr.sector = type ?
+               0 : cpu_to_virtio64(vblk->vdev, blk_rq_pos(req));
+       vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(req));
+
        blk_mq_start_request(req);
 
-       num = blk_rq_map_sg(hctx->queue, vbr->req, vbr->sg);
+       num = blk_rq_map_sg(hctx->queue, req, vbr->sg);
        if (num) {
-               if (rq_data_dir(vbr->req) == WRITE)
+               if (rq_data_dir(req) == WRITE)
                        vbr->out_hdr.type |= cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_OUT);
                else
                        vbr->out_hdr.type |= cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_IN);
        }
 
        spin_lock_irqsave(&vblk->vqs[qid].lock, flags);
-       err = __virtblk_add_req(vblk->vqs[qid].vq, vbr, vbr->sg, num);
+       if (req_op(req) == REQ_OP_SCSI_IN || req_op(req) == REQ_OP_SCSI_OUT)
+               err = virtblk_add_req_scsi(vblk->vqs[qid].vq, vbr, vbr->sg, num);
+       else
+               err = virtblk_add_req(vblk->vqs[qid].vq, vbr, vbr->sg, num);
        if (err) {
                virtqueue_kick(vblk->vqs[qid].vq);
                blk_mq_stop_hw_queue(hctx);
@@ -242,10 +300,9 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str)
        struct request *req;
        int err;
 
-       req = blk_get_request(q, READ, GFP_KERNEL);
+       req = blk_get_request(q, REQ_OP_DRV_IN, GFP_KERNEL);
        if (IS_ERR(req))
                return PTR_ERR(req);
-       req->cmd_type = REQ_TYPE_DRV_PRIV;
 
        err = blk_rq_map_kern(q, req, id_str, VIRTIO_BLK_ID_BYTES, GFP_KERNEL);
        if (err)
@@ -257,22 +314,6 @@ out:
        return err;
 }
 
-static int virtblk_ioctl(struct block_device *bdev, fmode_t mode,
-                            unsigned int cmd, unsigned long data)
-{
-       struct gendisk *disk = bdev->bd_disk;
-       struct virtio_blk *vblk = disk->private_data;
-
-       /*
-        * Only allow the generic SCSI ioctls if the host can support it.
-        */
-       if (!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_SCSI))
-               return -ENOTTY;
-
-       return scsi_cmd_blk_ioctl(bdev, mode, cmd,
-                                 (void __user *)data);
-}
-
 /* We provide getgeo only to please some old bootloader/partitioning tools */
 static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
 {
@@ -538,6 +579,9 @@ static int virtblk_init_request(void *data, struct request *rq,
        struct virtio_blk *vblk = data;
        struct virtblk_req *vbr = blk_mq_rq_to_pdu(rq);
 
+#ifdef CONFIG_VIRTIO_BLK_SCSI
+       vbr->sreq.sense = vbr->sense;
+#endif
        sg_init_table(vbr->sg, vblk->sg_elems);
        return 0;
 }
@@ -821,7 +865,10 @@ static const struct virtio_device_id id_table[] = {
 
 static unsigned int features_legacy[] = {
        VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_GEOMETRY,
-       VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, VIRTIO_BLK_F_SCSI,
+       VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE,
+#ifdef CONFIG_VIRTIO_BLK_SCSI
+       VIRTIO_BLK_F_SCSI,
+#endif
        VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE,
        VIRTIO_BLK_F_MQ,
 }
index 415e79b69d347b207f4e1caeecc7e4ce482356d4..8fe61b5dc5a6553d141950506344fe90bbfde2c8 100644 (file)
@@ -38,8 +38,8 @@ struct backend_info {
 static struct kmem_cache *xen_blkif_cachep;
 static void connect(struct backend_info *);
 static int connect_ring(struct backend_info *);
-static void backend_changed(struct xenbus_watch *, const char **,
-                           unsigned int);
+static void backend_changed(struct xenbus_watch *, const char *,
+                           const char *);
 static void xen_blkif_free(struct xen_blkif *blkif);
 static void xen_vbd_free(struct xen_vbd *vbd);
 
@@ -661,7 +661,7 @@ fail:
  * ready, connect.
  */
 static void backend_changed(struct xenbus_watch *watch,
-                           const char **vec, unsigned int len)
+                           const char *path, const char *token)
 {
        int err;
        unsigned major;
index 265f1a7072e9a1fed8212520d509adaecdbef04b..5067a0a952cb2161aec7da6168adfcb874aa02bc 100644 (file)
@@ -865,7 +865,7 @@ static inline void flush_requests(struct blkfront_ring_info *rinfo)
 static inline bool blkif_request_flush_invalid(struct request *req,
                                               struct blkfront_info *info)
 {
-       return ((req->cmd_type != REQ_TYPE_FS) ||
+       return (blk_rq_is_passthrough(req) ||
                ((req_op(req) == REQ_OP_FLUSH) &&
                 !info->feature_flush) ||
                ((req->cmd_flags & REQ_FUA) &&
index c4328d9d9981ed18c8d5c5decc5af9efe00338ee..757dce2147e005a4b2bcb16881a19e226ab75743 100644 (file)
@@ -468,7 +468,7 @@ static struct request *ace_get_next_request(struct request_queue *q)
        struct request *req;
 
        while ((req = blk_peek_request(q)) != NULL) {
-               if (req->cmd_type == REQ_TYPE_FS)
+               if (!blk_rq_is_passthrough(req))
                        break;
                blk_start_request(req);
                __blk_end_request_all(req, -EIO);
index e5ab7d9e8c452f2feac3e2f374c6e1639317756b..3cd7856156b42de033b8e18db918542219026152 100644 (file)
@@ -117,7 +117,7 @@ static void zram_revalidate_disk(struct zram *zram)
 {
        revalidate_disk(zram->disk);
        /* revalidate_disk reset the BDI_CAP_STABLE_WRITES so set again */
-       zram->disk->queue->backing_dev_info.capabilities |=
+       zram->disk->queue->backing_dev_info->capabilities |=
                BDI_CAP_STABLE_WRITES;
 }
 
index 59cca72647a623dad42465c08021bb9f818933b8..87739649eac21a6c3688c5c60956280746babd70 100644 (file)
 #include <linux/fcntl.h>
 #include <linux/blkdev.h>
 #include <linux/times.h>
-
 #include <linux/uaccess.h>
+#include <scsi/scsi_request.h>
 
 /* used to tell the module to turn on full debugging messages */
 static bool debug;
@@ -342,8 +342,8 @@ static void cdrom_sysctl_register(void);
 
 static LIST_HEAD(cdrom_list);
 
-static int cdrom_dummy_generic_packet(struct cdrom_device_info *cdi,
-                                     struct packet_command *cgc)
+int cdrom_dummy_generic_packet(struct cdrom_device_info *cdi,
+                              struct packet_command *cgc)
 {
        if (cgc->sense) {
                cgc->sense->sense_key = 0x05;
@@ -354,6 +354,7 @@ static int cdrom_dummy_generic_packet(struct cdrom_device_info *cdi,
        cgc->stat = -EIO;
        return -EIO;
 }
+EXPORT_SYMBOL(cdrom_dummy_generic_packet);
 
 static int cdrom_flush_cache(struct cdrom_device_info *cdi)
 {
@@ -371,7 +372,7 @@ static int cdrom_flush_cache(struct cdrom_device_info *cdi)
 static int cdrom_get_disc_info(struct cdrom_device_info *cdi,
                               disc_information *di)
 {
-       struct cdrom_device_ops *cdo = cdi->ops;
+       const struct cdrom_device_ops *cdo = cdi->ops;
        struct packet_command cgc;
        int ret, buflen;
 
@@ -586,7 +587,7 @@ static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space)
 int register_cdrom(struct cdrom_device_info *cdi)
 {
        static char banner_printed;
-       struct cdrom_device_ops *cdo = cdi->ops;
+       const struct cdrom_device_ops *cdo = cdi->ops;
        int *change_capability = (int *)&cdo->capability; /* hack */
 
        cd_dbg(CD_OPEN, "entering register_cdrom\n");
@@ -610,7 +611,6 @@ int register_cdrom(struct cdrom_device_info *cdi)
        ENSURE(reset, CDC_RESET);
        ENSURE(generic_packet, CDC_GENERIC_PACKET);
        cdi->mc_flags = 0;
-       cdo->n_minors = 0;
        cdi->options = CDO_USE_FFLAGS;
 
        if (autoclose == 1 && CDROM_CAN(CDC_CLOSE_TRAY))
@@ -630,8 +630,7 @@ int register_cdrom(struct cdrom_device_info *cdi)
        else
                cdi->cdda_method = CDDA_OLD;
 
-       if (!cdo->generic_packet)
-               cdo->generic_packet = cdrom_dummy_generic_packet;
+       WARN_ON(!cdo->generic_packet);
 
        cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name);
        mutex_lock(&cdrom_mutex);
@@ -652,7 +651,6 @@ void unregister_cdrom(struct cdrom_device_info *cdi)
        if (cdi->exit)
                cdi->exit(cdi);
 
-       cdi->ops->n_minors--;
        cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" unregistered\n", cdi->name);
 }
 
@@ -1036,7 +1034,7 @@ static
 int open_for_data(struct cdrom_device_info *cdi)
 {
        int ret;
-       struct cdrom_device_ops *cdo = cdi->ops;
+       const struct cdrom_device_ops *cdo = cdi->ops;
        tracktype tracks;
        cd_dbg(CD_OPEN, "entering open_for_data\n");
        /* Check if the driver can report drive status.  If it can, we
@@ -1198,8 +1196,8 @@ err:
 /* This code is similar to that in open_for_data. The routine is called
    whenever an audio play operation is requested.
 */
-static int check_for_audio_disc(struct cdrom_device_info * cdi,
-                               struct cdrom_device_ops * cdo)
+static int check_for_audio_disc(struct cdrom_device_info *cdi,
+                               const struct cdrom_device_ops *cdo)
 {
         int ret;
        tracktype tracks;
@@ -1254,7 +1252,7 @@ static int check_for_audio_disc(struct cdrom_device_info * cdi,
 
 void cdrom_release(struct cdrom_device_info *cdi, fmode_t mode)
 {
-       struct cdrom_device_ops *cdo = cdi->ops;
+       const struct cdrom_device_ops *cdo = cdi->ops;
        int opened_for_data;
 
        cd_dbg(CD_CLOSE, "entering cdrom_release\n");
@@ -1294,7 +1292,7 @@ static int cdrom_read_mech_status(struct cdrom_device_info *cdi,
                                  struct cdrom_changer_info *buf)
 {
        struct packet_command cgc;
-       struct cdrom_device_ops *cdo = cdi->ops;
+       const struct cdrom_device_ops *cdo = cdi->ops;
        int length;
 
        /*
@@ -1643,7 +1641,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
        int ret;
        u_char buf[20];
        struct packet_command cgc;
-       struct cdrom_device_ops *cdo = cdi->ops;
+       const struct cdrom_device_ops *cdo = cdi->ops;
        rpc_state_t rpc_state;
 
        memset(buf, 0, sizeof(buf));
@@ -1791,7 +1789,7 @@ static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s,
 {
        unsigned char buf[21], *base;
        struct dvd_layer *layer;
-       struct cdrom_device_ops *cdo = cdi->ops;
+       const struct cdrom_device_ops *cdo = cdi->ops;
        int ret, layer_num = s->physical.layer_num;
 
        if (layer_num >= DVD_LAYERS)
@@ -1842,7 +1840,7 @@ static int dvd_read_copyright(struct cdrom_device_info *cdi, dvd_struct *s,
 {
        int ret;
        u_char buf[8];
-       struct cdrom_device_ops *cdo = cdi->ops;
+       const struct cdrom_device_ops *cdo = cdi->ops;
 
        init_cdrom_command(cgc, buf, sizeof(buf), CGC_DATA_READ);
        cgc->cmd[0] = GPCMD_READ_DVD_STRUCTURE;
@@ -1866,7 +1864,7 @@ static int dvd_read_disckey(struct cdrom_device_info *cdi, dvd_struct *s,
 {
        int ret, size;
        u_char *buf;
-       struct cdrom_device_ops *cdo = cdi->ops;
+       const struct cdrom_device_ops *cdo = cdi->ops;
 
        size = sizeof(s->disckey.value) + 4;
 
@@ -1894,7 +1892,7 @@ static int dvd_read_bca(struct cdrom_device_info *cdi, dvd_struct *s,
 {
        int ret, size = 4 + 188;
        u_char *buf;
-       struct cdrom_device_ops *cdo = cdi->ops;
+       const struct cdrom_device_ops *cdo = cdi->ops;
 
        buf = kmalloc(size, GFP_KERNEL);
        if (!buf)
@@ -1928,7 +1926,7 @@ static int dvd_read_manufact(struct cdrom_device_info *cdi, dvd_struct *s,
 {
        int ret = 0, size;
        u_char *buf;
-       struct cdrom_device_ops *cdo = cdi->ops;
+       const struct cdrom_device_ops *cdo = cdi->ops;
 
        size = sizeof(s->manufact.value) + 4;
 
@@ -1995,7 +1993,7 @@ int cdrom_mode_sense(struct cdrom_device_info *cdi,
                     struct packet_command *cgc,
                     int page_code, int page_control)
 {
-       struct cdrom_device_ops *cdo = cdi->ops;
+       const struct cdrom_device_ops *cdo = cdi->ops;
 
        memset(cgc->cmd, 0, sizeof(cgc->cmd));
 
@@ -2010,7 +2008,7 @@ int cdrom_mode_sense(struct cdrom_device_info *cdi,
 int cdrom_mode_select(struct cdrom_device_info *cdi,
                      struct packet_command *cgc)
 {
-       struct cdrom_device_ops *cdo = cdi->ops;
+       const struct cdrom_device_ops *cdo = cdi->ops;
 
        memset(cgc->cmd, 0, sizeof(cgc->cmd));
        memset(cgc->buffer, 0, 2);
@@ -2025,7 +2023,7 @@ int cdrom_mode_select(struct cdrom_device_info *cdi,
 static int cdrom_read_subchannel(struct cdrom_device_info *cdi,
                                 struct cdrom_subchnl *subchnl, int mcn)
 {
-       struct cdrom_device_ops *cdo = cdi->ops;
+       const struct cdrom_device_ops *cdo = cdi->ops;
        struct packet_command cgc;
        char buffer[32];
        int ret;
@@ -2073,7 +2071,7 @@ static int cdrom_read_cd(struct cdrom_device_info *cdi,
                         struct packet_command *cgc, int lba,
                         int blocksize, int nblocks)
 {
-       struct cdrom_device_ops *cdo = cdi->ops;
+       const struct cdrom_device_ops *cdo = cdi->ops;
 
        memset(&cgc->cmd, 0, sizeof(cgc->cmd));
        cgc->cmd[0] = GPCMD_READ_10;
@@ -2093,7 +2091,7 @@ static int cdrom_read_block(struct cdrom_device_info *cdi,
                            struct packet_command *cgc,
                            int lba, int nblocks, int format, int blksize)
 {
-       struct cdrom_device_ops *cdo = cdi->ops;
+       const struct cdrom_device_ops *cdo = cdi->ops;
 
        memset(&cgc->cmd, 0, sizeof(cgc->cmd));
        cgc->cmd[0] = GPCMD_READ_CD;
@@ -2172,6 +2170,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
 {
        struct request_queue *q = cdi->disk->queue;
        struct request *rq;
+       struct scsi_request *req;
        struct bio *bio;
        unsigned int len;
        int nr, ret = 0;
@@ -2190,12 +2189,13 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
 
                len = nr * CD_FRAMESIZE_RAW;
 
-               rq = blk_get_request(q, READ, GFP_KERNEL);
+               rq = blk_get_request(q, REQ_OP_SCSI_IN, GFP_KERNEL);
                if (IS_ERR(rq)) {
                        ret = PTR_ERR(rq);
                        break;
                }
-               blk_rq_set_block_pc(rq);
+               req = scsi_req(rq);
+               scsi_req_init(rq);
 
                ret = blk_rq_map_user(q, rq, NULL, ubuf, len, GFP_KERNEL);
                if (ret) {
@@ -2203,23 +2203,23 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
                        break;
                }
 
-               rq->cmd[0] = GPCMD_READ_CD;
-               rq->cmd[1] = 1 << 2;
-               rq->cmd[2] = (lba >> 24) & 0xff;
-               rq->cmd[3] = (lba >> 16) & 0xff;
-               rq->cmd[4] = (lba >>  8) & 0xff;
-               rq->cmd[5] = lba & 0xff;
-               rq->cmd[6] = (nr >> 16) & 0xff;
-               rq->cmd[7] = (nr >>  8) & 0xff;
-               rq->cmd[8] = nr & 0xff;
-               rq->cmd[9] = 0xf8;
-
-               rq->cmd_len = 12;
+               req->cmd[0] = GPCMD_READ_CD;
+               req->cmd[1] = 1 << 2;
+               req->cmd[2] = (lba >> 24) & 0xff;
+               req->cmd[3] = (lba >> 16) & 0xff;
+               req->cmd[4] = (lba >>  8) & 0xff;
+               req->cmd[5] = lba & 0xff;
+               req->cmd[6] = (nr >> 16) & 0xff;
+               req->cmd[7] = (nr >>  8) & 0xff;
+               req->cmd[8] = nr & 0xff;
+               req->cmd[9] = 0xf8;
+
+               req->cmd_len = 12;
                rq->timeout = 60 * HZ;
                bio = rq->bio;
 
                if (blk_execute_rq(q, cdi->disk, rq, 0)) {
-                       struct request_sense *s = rq->sense;
+                       struct request_sense *s = req->sense;
                        ret = -EIO;
                        cdi->last_sense = s->sense_key;
                }
@@ -2764,7 +2764,7 @@ static int cdrom_ioctl_audioctl(struct cdrom_device_info *cdi,
  */
 static int cdrom_switch_blocksize(struct cdrom_device_info *cdi, int size)
 {
-       struct cdrom_device_ops *cdo = cdi->ops;
+       const struct cdrom_device_ops *cdo = cdi->ops;
        struct packet_command cgc;
        struct modesel_head mh;
 
@@ -2790,7 +2790,7 @@ static int cdrom_switch_blocksize(struct cdrom_device_info *cdi, int size)
 static int cdrom_get_track_info(struct cdrom_device_info *cdi,
                                __u16 track, __u8 type, track_information *ti)
 {
-       struct cdrom_device_ops *cdo = cdi->ops;
+       const struct cdrom_device_ops *cdo = cdi->ops;
        struct packet_command cgc;
        int ret, buflen;
 
@@ -3049,7 +3049,7 @@ static noinline int mmc_ioctl_cdrom_play_msf(struct cdrom_device_info *cdi,
                                             void __user *arg,
                                             struct packet_command *cgc)
 {
-       struct cdrom_device_ops *cdo = cdi->ops;
+       const struct cdrom_device_ops *cdo = cdi->ops;
        struct cdrom_msf msf;
        cd_dbg(CD_DO_IOCTL, "entering CDROMPLAYMSF\n");
        if (copy_from_user(&msf, (struct cdrom_msf __user *)arg, sizeof(msf)))
@@ -3069,7 +3069,7 @@ static noinline int mmc_ioctl_cdrom_play_blk(struct cdrom_device_info *cdi,
                                             void __user *arg,
                                             struct packet_command *cgc)
 {
-       struct cdrom_device_ops *cdo = cdi->ops;
+       const struct cdrom_device_ops *cdo = cdi->ops;
        struct cdrom_blk blk;
        cd_dbg(CD_DO_IOCTL, "entering CDROMPLAYBLK\n");
        if (copy_from_user(&blk, (struct cdrom_blk __user *)arg, sizeof(blk)))
@@ -3164,7 +3164,7 @@ static noinline int mmc_ioctl_cdrom_start_stop(struct cdrom_device_info *cdi,
                                               struct packet_command *cgc,
                                               int cmd)
 {
-       struct cdrom_device_ops *cdo = cdi->ops;
+       const struct cdrom_device_ops *cdo = cdi->ops;
        cd_dbg(CD_DO_IOCTL, "entering CDROMSTART/CDROMSTOP\n");
        cgc->cmd[0] = GPCMD_START_STOP_UNIT;
        cgc->cmd[1] = 1;
@@ -3177,7 +3177,7 @@ static noinline int mmc_ioctl_cdrom_pause_resume(struct cdrom_device_info *cdi,
                                                 struct packet_command *cgc,
                                                 int cmd)
 {
-       struct cdrom_device_ops *cdo = cdi->ops;
+       const struct cdrom_device_ops *cdo = cdi->ops;
        cd_dbg(CD_DO_IOCTL, "entering CDROMPAUSE/CDROMRESUME\n");
        cgc->cmd[0] = GPCMD_PAUSE_RESUME;
        cgc->cmd[8] = (cmd == CDROMRESUME) ? 1 : 0;
index 584bc3126403d58955a915db2117fcd1d16de5a2..1372763a948f48e81af667748df01d850e6859af 100644 (file)
@@ -481,7 +481,7 @@ static int gdrom_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
        return -EINVAL;
 }
 
-static struct cdrom_device_ops gdrom_ops = {
+static const struct cdrom_device_ops gdrom_ops = {
        .open                   = gdrom_open,
        .release                = gdrom_release,
        .drive_status           = gdrom_drivestatus,
@@ -489,9 +489,9 @@ static struct cdrom_device_ops gdrom_ops = {
        .get_last_session       = gdrom_get_last_session,
        .reset                  = gdrom_hardreset,
        .audio_ioctl            = gdrom_audio_ioctl,
+       .generic_packet         = cdrom_dummy_generic_packet,
        .capability             = CDC_MULTI_SESSION | CDC_MEDIA_CHANGED |
                                  CDC_RESET | CDC_DRIVE_STATUS | CDC_CD_R,
-       .n_minors               = 1,
 };
 
 static int gdrom_bdops_open(struct block_device *bdev, fmode_t mode)
@@ -659,23 +659,24 @@ static void gdrom_request(struct request_queue *rq)
        struct request *req;
 
        while ((req = blk_fetch_request(rq)) != NULL) {
-               if (req->cmd_type != REQ_TYPE_FS) {
-                       printk(KERN_DEBUG "gdrom: Non-fs request ignored\n");
-                       __blk_end_request_all(req, -EIO);
-                       continue;
-               }
-               if (rq_data_dir(req) != READ) {
+               switch (req_op(req)) {
+               case REQ_OP_READ:
+                       /*
+                        * Add to list of deferred work and then schedule
+                        * workqueue.
+                        */
+                       list_add_tail(&req->queuelist, &gdrom_deferred);
+                       schedule_work(&work);
+                       break;
+               case REQ_OP_WRITE:
                        pr_notice("Read only device - write request ignored\n");
                        __blk_end_request_all(req, -EIO);
-                       continue;
+                       break;
+               default:
+                       printk(KERN_DEBUG "gdrom: Non-fs request ignored\n");
+                       __blk_end_request_all(req, -EIO);
+                       break;
                }
-
-               /*
-                * Add to list of deferred work and then schedule
-                * workqueue.
-                */
-               list_add_tail(&req->queuelist, &gdrom_deferred);
-               schedule_work(&work);
        }
 }
 
@@ -807,16 +808,20 @@ static int probe_gdrom(struct platform_device *devptr)
        if (err)
                goto probe_fail_cmdirq_register;
        gd.gdrom_rq = blk_init_queue(gdrom_request, &gdrom_lock);
-       if (!gd.gdrom_rq)
+       if (!gd.gdrom_rq) {
+               err = -ENOMEM;
                goto probe_fail_requestq;
+       }
 
        err = probe_gdrom_setupqueue();
        if (err)
                goto probe_fail_toc;
 
        gd.toc = kzalloc(sizeof(struct gdromtoc), GFP_KERNEL);
-       if (!gd.toc)
+       if (!gd.toc) {
+               err = -ENOMEM;
                goto probe_fail_toc;
+       }
        add_disk(gd.disk);
        return 0;
 
index 277186d3b668fbbd7b0c49861288f9a3ae854662..af985cca413cbfef089f88aea1767c3e26bb18e1 100644 (file)
@@ -6,6 +6,7 @@ menuconfig TCG_TPM
        tristate "TPM Hardware Support"
        depends on HAS_IOMEM
        select SECURITYFS
+       select CRYPTO_HASH_INFO
        ---help---
          If you have a TPM security chip in your system, which
          implements the Trusted Computing Group's specification,
index a05b1ebd0b261d0b81c328de008cd5ffced3e70b..3d386a8c579f0961ac0b38ab438f3352084a1649 100644 (file)
@@ -3,7 +3,7 @@
 #
 obj-$(CONFIG_TCG_TPM) += tpm.o
 tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o \
-               tpm_eventlog.o
+               tpm1_eventlog.o tpm2_eventlog.o
 tpm-$(CONFIG_ACPI) += tpm_ppi.o tpm_acpi.o
 tpm-$(CONFIG_OF) += tpm_of.o
 obj-$(CONFIG_TCG_TIS_CORE) += tpm_tis_core.o
index 6f060c76217b9a7ea02ab19b8909e7d708578bd5..e8e0f7c0268690145b1dcf5e4b0411909483fe1a 100644 (file)
@@ -18,7 +18,6 @@
 
 #include <linux/module.h>
 #include <linux/fs.h>
-#include <linux/miscdevice.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/wait.h>
index a77262d31911a1dc65c227f7d237fd3c61300bea..c406343848dac66223da77c901342da362a12d1b 100644 (file)
@@ -141,7 +141,7 @@ static void tpm_dev_release(struct device *dev)
  * Allocates a new struct tpm_chip instance and assigns a free
  * device number for it. Must be paired with put_device(&chip->dev).
  */
-struct tpm_chip *tpm_chip_alloc(struct device *dev,
+struct tpm_chip *tpm_chip_alloc(struct device *pdev,
                                const struct tpm_class_ops *ops)
 {
        struct tpm_chip *chip;
@@ -160,7 +160,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *dev,
        rc = idr_alloc(&dev_nums_idr, NULL, 0, TPM_NUM_DEVICES, GFP_KERNEL);
        mutex_unlock(&idr_lock);
        if (rc < 0) {
-               dev_err(dev, "No available tpm device numbers\n");
+               dev_err(pdev, "No available tpm device numbers\n");
                kfree(chip);
                return ERR_PTR(rc);
        }
@@ -170,7 +170,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *dev,
 
        chip->dev.class = tpm_class;
        chip->dev.release = tpm_dev_release;
-       chip->dev.parent = dev;
+       chip->dev.parent = pdev;
        chip->dev.groups = chip->groups;
 
        if (chip->dev_num == 0)
@@ -182,7 +182,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *dev,
        if (rc)
                goto out;
 
-       if (!dev)
+       if (!pdev)
                chip->flags |= TPM_CHIP_FLAG_VIRTUAL;
 
        cdev_init(&chip->cdev, &tpm_fops);
index 912ad30be5852f8a2145d0c1e56c03257bbbb211..02a8850d3a69022dcf58346c7e69413e9f34ea27 100644 (file)
@@ -38,6 +38,9 @@ static void user_reader_timeout(unsigned long ptr)
 {
        struct file_priv *priv = (struct file_priv *)ptr;
 
+       pr_warn("TPM user space timeout is deprecated (pid=%d)\n",
+               task_tgid_nr(current));
+
        schedule_work(&priv->work);
 }
 
@@ -157,7 +160,7 @@ static ssize_t tpm_write(struct file *file, const char __user *buf,
        mutex_unlock(&priv->buffer_mutex);
 
        /* Set a timeout by which the reader must come claim the result */
-       mod_timer(&priv->user_read_timer, jiffies + (60 * HZ));
+       mod_timer(&priv->user_read_timer, jiffies + (120 * HZ));
 
        return in_size;
 }
index a2688ac2b48f3ce1d06a151ddc4ee03a6984a7ae..bd2128e0b56cc8c4774acdd2adec682847d911f0 100644 (file)
@@ -47,7 +47,7 @@
 static int tpm_suspend_pcr;
 module_param_named(suspend_pcr, tpm_suspend_pcr, uint, 0644);
 MODULE_PARM_DESC(suspend_pcr,
-                "PCR to use for dummy writes to faciltate flush on suspend.");
+                "PCR to use for dummy writes to facilitate flush on suspend.");
 
 /*
  * Array with one entry per ordinal defining the maximum amount
@@ -328,8 +328,17 @@ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip,
 }
 EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration);
 
-/*
- * Internal kernel interface to transmit TPM commands
+/**
+ * tmp_transmit - Internal kernel interface to transmit TPM commands.
+ *
+ * @chip: TPM chip to use
+ * @buf: TPM command buffer
+ * @bufsiz: length of the TPM command buffer
+ * @flags: tpm transmit flags - bitmap
+ *
+ * Return:
+ *     0 when the operation is successful.
+ *     A negative number for system errors (errno).
  */
 ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz,
                     unsigned int flags)
@@ -409,31 +418,55 @@ out:
        return rc;
 }
 
-#define TPM_DIGEST_SIZE 20
-#define TPM_RET_CODE_IDX 6
-
-ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *cmd,
-                        int len, unsigned int flags, const char *desc)
+/**
+ * tmp_transmit_cmd - send a tpm command to the device
+ *    The function extracts tpm out header return code
+ *
+ * @chip: TPM chip to use
+ * @buf: TPM command buffer
+ * @bufsiz: length of the buffer
+ * @min_rsp_body_length: minimum expected length of response body
+ * @flags: tpm transmit flags - bitmap
+ * @desc: command description used in the error message
+ *
+ * Return:
+ *     0 when the operation is successful.
+ *     A negative number for system errors (errno).
+ *     A positive number for a TPM error.
+ */
+ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *buf,
+                        size_t bufsiz, size_t min_rsp_body_length,
+                        unsigned int flags, const char *desc)
 {
        const struct tpm_output_header *header;
        int err;
+       ssize_t len;
 
-       len = tpm_transmit(chip, (const u8 *)cmd, len, flags);
+       len = tpm_transmit(chip, (const u8 *)buf, bufsiz, flags);
        if (len <  0)
                return len;
        else if (len < TPM_HEADER_SIZE)
                return -EFAULT;
 
-       header = cmd;
+       header = buf;
+       if (len != be32_to_cpu(header->length))
+               return -EFAULT;
 
        err = be32_to_cpu(header->return_code);
        if (err != 0 && desc)
                dev_err(&chip->dev, "A TPM error (%d) occurred %s\n", err,
                        desc);
+       if (err)
+               return err;
+
+       if (len < min_rsp_body_length + TPM_HEADER_SIZE)
+               return -EFAULT;
 
-       return err;
+       return 0;
 }
 
+#define TPM_DIGEST_SIZE 20
+#define TPM_RET_CODE_IDX 6
 #define TPM_INTERNAL_RESULT_SIZE 200
 #define TPM_ORD_GET_CAP cpu_to_be32(101)
 #define TPM_ORD_GET_RANDOM cpu_to_be32(70)
@@ -445,7 +478,7 @@ static const struct tpm_input_header tpm_getcap_header = {
 };
 
 ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
-                  const char *desc)
+                  const char *desc, size_t min_cap_length)
 {
        struct tpm_cmd_t tpm_cmd;
        int rc;
@@ -468,8 +501,8 @@ ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
                tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
                tpm_cmd.params.getcap_in.subcap = cpu_to_be32(subcap_id);
        }
-       rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0,
-                             desc);
+       rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
+                             min_cap_length, 0, desc);
        if (!rc)
                *cap = tpm_cmd.params.getcap_out.cap;
        return rc;
@@ -493,14 +526,13 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
 
        start_cmd.params.startup_in.startup_type = startup_type;
        return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE, 0,
-                               "attempting to start the TPM");
+                               0, "attempting to start the TPM");
 }
 
 int tpm_get_timeouts(struct tpm_chip *chip)
 {
        cap_t cap;
-       unsigned long new_timeout[4];
-       unsigned long old_timeout[4];
+       unsigned long timeout_old[4], timeout_chip[4], timeout_eff[4];
        ssize_t rc;
 
        if (chip->flags & TPM_CHIP_FLAG_HAVE_TIMEOUTS)
@@ -523,8 +555,8 @@ int tpm_get_timeouts(struct tpm_chip *chip)
                return 0;
        }
 
-       rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap,
-                       "attempting to determine the timeouts");
+       rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, NULL,
+                       sizeof(cap.timeout));
        if (rc == TPM_ERR_INVALID_POSTINIT) {
                /* The TPM is not started, we are the first to talk to it.
                   Execute a startup command. */
@@ -533,16 +565,26 @@ int tpm_get_timeouts(struct tpm_chip *chip)
                        return rc;
 
                rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap,
-                               "attempting to determine the timeouts");
+                               "attempting to determine the timeouts",
+                               sizeof(cap.timeout));
        }
-       if (rc)
+
+       if (rc) {
+               dev_err(&chip->dev,
+                       "A TPM error (%zd) occurred attempting to determine the timeouts\n",
+                       rc);
                return rc;
+       }
 
-       old_timeout[0] = be32_to_cpu(cap.timeout.a);
-       old_timeout[1] = be32_to_cpu(cap.timeout.b);
-       old_timeout[2] = be32_to_cpu(cap.timeout.c);
-       old_timeout[3] = be32_to_cpu(cap.timeout.d);
-       memcpy(new_timeout, old_timeout, sizeof(new_timeout));
+       timeout_old[0] = jiffies_to_usecs(chip->timeout_a);
+       timeout_old[1] = jiffies_to_usecs(chip->timeout_b);
+       timeout_old[2] = jiffies_to_usecs(chip->timeout_c);
+       timeout_old[3] = jiffies_to_usecs(chip->timeout_d);
+       timeout_chip[0] = be32_to_cpu(cap.timeout.a);
+       timeout_chip[1] = be32_to_cpu(cap.timeout.b);
+       timeout_chip[2] = be32_to_cpu(cap.timeout.c);
+       timeout_chip[3] = be32_to_cpu(cap.timeout.d);
+       memcpy(timeout_eff, timeout_chip, sizeof(timeout_eff));
 
        /*
         * Provide ability for vendor overrides of timeout values in case
@@ -550,16 +592,24 @@ int tpm_get_timeouts(struct tpm_chip *chip)
         */
        if (chip->ops->update_timeouts != NULL)
                chip->timeout_adjusted =
-                       chip->ops->update_timeouts(chip, new_timeout);
+                       chip->ops->update_timeouts(chip, timeout_eff);
 
        if (!chip->timeout_adjusted) {
-               /* Don't overwrite default if value is 0 */
-               if (new_timeout[0] != 0 && new_timeout[0] < 1000) {
-                       int i;
+               /* Restore default if chip reported 0 */
+               int i;
 
+               for (i = 0; i < ARRAY_SIZE(timeout_eff); i++) {
+                       if (timeout_eff[i])
+                               continue;
+
+                       timeout_eff[i] = timeout_old[i];
+                       chip->timeout_adjusted = true;
+               }
+
+               if (timeout_eff[0] != 0 && timeout_eff[0] < 1000) {
                        /* timeouts in msec rather usec */
-                       for (i = 0; i != ARRAY_SIZE(new_timeout); i++)
-                               new_timeout[i] *= 1000;
+                       for (i = 0; i != ARRAY_SIZE(timeout_eff); i++)
+                               timeout_eff[i] *= 1000;
                        chip->timeout_adjusted = true;
                }
        }
@@ -568,19 +618,20 @@ int tpm_get_timeouts(struct tpm_chip *chip)
        if (chip->timeout_adjusted) {
                dev_info(&chip->dev,
                         HW_ERR "Adjusting reported timeouts: A %lu->%luus B %lu->%luus C %lu->%luus D %lu->%luus\n",
-                        old_timeout[0], new_timeout[0],
-                        old_timeout[1], new_timeout[1],
-                        old_timeout[2], new_timeout[2],
-                        old_timeout[3], new_timeout[3]);
+                        timeout_chip[0], timeout_eff[0],
+                        timeout_chip[1], timeout_eff[1],
+                        timeout_chip[2], timeout_eff[2],
+                        timeout_chip[3], timeout_eff[3]);
        }
 
-       chip->timeout_a = usecs_to_jiffies(new_timeout[0]);
-       chip->timeout_b = usecs_to_jiffies(new_timeout[1]);
-       chip->timeout_c = usecs_to_jiffies(new_timeout[2]);
-       chip->timeout_d = usecs_to_jiffies(new_timeout[3]);
+       chip->timeout_a = usecs_to_jiffies(timeout_eff[0]);
+       chip->timeout_b = usecs_to_jiffies(timeout_eff[1]);
+       chip->timeout_c = usecs_to_jiffies(timeout_eff[2]);
+       chip->timeout_d = usecs_to_jiffies(timeout_eff[3]);
 
        rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_DURATION, &cap,
-                       "attempting to determine the durations");
+                       "attempting to determine the durations",
+                       sizeof(cap.duration));
        if (rc)
                return rc;
 
@@ -631,13 +682,14 @@ static int tpm_continue_selftest(struct tpm_chip *chip)
        struct tpm_cmd_t cmd;
 
        cmd.header.in = continue_selftest_header;
-       rc = tpm_transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE, 0,
+       rc = tpm_transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE, 0, 0,
                              "continue selftest");
        return rc;
 }
 
 #define TPM_ORDINAL_PCRREAD cpu_to_be32(21)
 #define READ_PCR_RESULT_SIZE 30
+#define READ_PCR_RESULT_BODY_SIZE 20
 static const struct tpm_input_header pcrread_header = {
        .tag = TPM_TAG_RQU_COMMAND,
        .length = cpu_to_be32(14),
@@ -651,7 +703,8 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
 
        cmd.header.in = pcrread_header;
        cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx);
-       rc = tpm_transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE, 0,
+       rc = tpm_transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE,
+                             READ_PCR_RESULT_BODY_SIZE, 0,
                              "attempting to read a pcr value");
 
        if (rc == 0)
@@ -714,6 +767,7 @@ EXPORT_SYMBOL_GPL(tpm_pcr_read);
 
 #define TPM_ORD_PCR_EXTEND cpu_to_be32(20)
 #define EXTEND_PCR_RESULT_SIZE 34
+#define EXTEND_PCR_RESULT_BODY_SIZE 20
 static const struct tpm_input_header pcrextend_header = {
        .tag = TPM_TAG_RQU_COMMAND,
        .length = cpu_to_be32(34),
@@ -735,13 +789,25 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
        struct tpm_cmd_t cmd;
        int rc;
        struct tpm_chip *chip;
+       struct tpm2_digest digest_list[ARRAY_SIZE(chip->active_banks)];
+       u32 count = 0;
+       int i;
 
        chip = tpm_chip_find_get(chip_num);
        if (chip == NULL)
                return -ENODEV;
 
        if (chip->flags & TPM_CHIP_FLAG_TPM2) {
-               rc = tpm2_pcr_extend(chip, pcr_idx, hash);
+               memset(digest_list, 0, sizeof(digest_list));
+
+               for (i = 0; i < ARRAY_SIZE(chip->active_banks) &&
+                           chip->active_banks[i] != TPM2_ALG_ERROR; i++) {
+                       digest_list[i].alg_id = chip->active_banks[i];
+                       memcpy(digest_list[i].digest, hash, TPM_DIGEST_SIZE);
+                       count++;
+               }
+
+               rc = tpm2_pcr_extend(chip, pcr_idx, count, digest_list);
                tpm_put_ops(chip);
                return rc;
        }
@@ -749,7 +815,8 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
        cmd.header.in = pcrextend_header;
        cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
        memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE);
-       rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, 0,
+       rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
+                             EXTEND_PCR_RESULT_BODY_SIZE, 0,
                              "attempting extend a PCR value");
 
        tpm_put_ops(chip);
@@ -853,7 +920,7 @@ int tpm_send(u32 chip_num, void *cmd, size_t buflen)
        if (chip == NULL)
                return -ENODEV;
 
-       rc = tpm_transmit_cmd(chip, cmd, buflen, 0, "attempting tpm_cmd");
+       rc = tpm_transmit_cmd(chip, cmd, buflen, 0, 0, "attempting tpm_cmd");
 
        tpm_put_ops(chip);
        return rc;
@@ -955,7 +1022,8 @@ int tpm_pm_suspend(struct device *dev)
                cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr);
                memcpy(cmd.params.pcrextend_in.hash, dummy_hash,
                       TPM_DIGEST_SIZE);
-               rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, 0,
+               rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
+                                    EXTEND_PCR_RESULT_BODY_SIZE, 0,
                                      "extending dummy pcr before suspend");
        }
 
@@ -963,7 +1031,7 @@ int tpm_pm_suspend(struct device *dev)
        for (try = 0; try < TPM_RETRY; try++) {
                cmd.header.in = savestate_header;
                rc = tpm_transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, 0,
-                                     NULL);
+                                     0, NULL);
 
                /*
                 * If the TPM indicates that it is too busy to respond to
@@ -1025,7 +1093,7 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
 {
        struct tpm_chip *chip;
        struct tpm_cmd_t tpm_cmd;
-       u32 recd, num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA);
+       u32 recd, num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA), rlength;
        int err, total = 0, retries = 5;
        u8 *dest = out;
 
@@ -1048,11 +1116,20 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
 
                err = tpm_transmit_cmd(chip, &tpm_cmd,
                                       TPM_GETRANDOM_RESULT_SIZE + num_bytes,
+                                      offsetof(struct tpm_getrandom_out,
+                                               rng_data),
                                       0, "attempting get random");
                if (err)
                        break;
 
                recd = be32_to_cpu(tpm_cmd.params.getrandom_out.rng_data_len);
+
+               rlength = be32_to_cpu(tpm_cmd.header.out.length);
+               if (rlength < offsetof(struct tpm_getrandom_out, rng_data) +
+                             recd) {
+                       total = -EFAULT;
+                       break;
+               }
                memcpy(dest, tpm_cmd.params.getrandom_out.rng_data, recd);
 
                dest += recd;
index 848ad6580b46d942d5600bd4b8285d65f1aaa9df..2f596d74f80c4e9a9a0d27a644b885407a76fbf4 100644 (file)
@@ -21,6 +21,7 @@
 #include "tpm.h"
 
 #define READ_PUBEK_RESULT_SIZE 314
+#define READ_PUBEK_RESULT_MIN_BODY_SIZE (28 + 256)
 #define TPM_ORD_READPUBEK cpu_to_be32(124)
 static const struct tpm_input_header tpm_readpubek_header = {
        .tag = TPM_TAG_RQU_COMMAND,
@@ -39,7 +40,8 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
        struct tpm_chip *chip = to_tpm_chip(dev);
 
        tpm_cmd.header.in = tpm_readpubek_header;
-       err = tpm_transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE, 0,
+       err = tpm_transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
+                              READ_PUBEK_RESULT_MIN_BODY_SIZE, 0,
                               "attempting to read the PUBEK");
        if (err)
                goto out;
@@ -95,7 +97,8 @@ static ssize_t pcrs_show(struct device *dev, struct device_attribute *attr,
        struct tpm_chip *chip = to_tpm_chip(dev);
 
        rc = tpm_getcap(chip, TPM_CAP_PROP_PCR, &cap,
-                       "attempting to determine the number of PCRS");
+                       "attempting to determine the number of PCRS",
+                       sizeof(cap.num_pcrs));
        if (rc)
                return 0;
 
@@ -120,7 +123,8 @@ static ssize_t enabled_show(struct device *dev, struct device_attribute *attr,
        ssize_t rc;
 
        rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_PERM, &cap,
-                       "attempting to determine the permanent enabled state");
+                       "attempting to determine the permanent enabled state",
+                       sizeof(cap.perm_flags));
        if (rc)
                return 0;
 
@@ -136,7 +140,8 @@ static ssize_t active_show(struct device *dev, struct device_attribute *attr,
        ssize_t rc;
 
        rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_PERM, &cap,
-                       "attempting to determine the permanent active state");
+                       "attempting to determine the permanent active state",
+                       sizeof(cap.perm_flags));
        if (rc)
                return 0;
 
@@ -152,7 +157,8 @@ static ssize_t owned_show(struct device *dev, struct device_attribute *attr,
        ssize_t rc;
 
        rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_PROP_OWNER, &cap,
-                       "attempting to determine the owner state");
+                       "attempting to determine the owner state",
+                       sizeof(cap.owned));
        if (rc)
                return 0;
 
@@ -168,7 +174,8 @@ static ssize_t temp_deactivated_show(struct device *dev,
        ssize_t rc;
 
        rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_VOL, &cap,
-                       "attempting to determine the temporary state");
+                       "attempting to determine the temporary state",
+                       sizeof(cap.stclear_flags));
        if (rc)
                return 0;
 
@@ -186,7 +193,8 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr,
        char *str = buf;
 
        rc = tpm_getcap(chip, TPM_CAP_PROP_MANUFACTURER, &cap,
-                       "attempting to determine the manufacturer");
+                       "attempting to determine the manufacturer",
+                       sizeof(cap.manufacturer_id));
        if (rc)
                return 0;
        str += sprintf(str, "Manufacturer: 0x%x\n",
@@ -194,7 +202,8 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr,
 
        /* Try to get a TPM version 1.2 TPM_CAP_VERSION_INFO */
        rc = tpm_getcap(chip, TPM_CAP_VERSION_1_2, &cap,
-                       "attempting to determine the 1.2 version");
+                       "attempting to determine the 1.2 version",
+                       sizeof(cap.tpm_version_1_2));
        if (!rc) {
                str += sprintf(str,
                               "TCG version: %d.%d\nFirmware version: %d.%d\n",
@@ -205,7 +214,8 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr,
        } else {
                /* Otherwise just use TPM_STRUCT_VER */
                rc = tpm_getcap(chip, TPM_CAP_VERSION_1_1, &cap,
-                               "attempting to determine the 1.1 version");
+                               "attempting to determine the 1.1 version",
+                               sizeof(cap.tpm_version));
                if (rc)
                        return 0;
                str += sprintf(str,
index 1ae976894257f54e525e2f8791e98343b957a053..4937b56a275cf28a90d4f96789ee94b541caf54f 100644 (file)
@@ -34,8 +34,7 @@
 #include <linux/acpi.h>
 #include <linux/cdev.h>
 #include <linux/highmem.h>
-
-#include "tpm_eventlog.h"
+#include <crypto/hash_info.h>
 
 enum tpm_const {
        TPM_MINOR = 224,        /* officially assigned */
@@ -97,6 +96,7 @@ enum tpm2_return_codes {
 };
 
 enum tpm2_algorithms {
+       TPM2_ALG_ERROR          = 0x0000,
        TPM2_ALG_SHA1           = 0x0004,
        TPM2_ALG_KEYEDHASH      = 0x0008,
        TPM2_ALG_SHA256         = 0x000B,
@@ -127,6 +127,7 @@ enum tpm2_permanent_handles {
 };
 
 enum tpm2_capabilities {
+       TPM2_CAP_PCRS           = 5,
        TPM2_CAP_TPM_PROPERTIES = 6,
 };
 
@@ -148,6 +149,11 @@ enum tpm_chip_flags {
        TPM_CHIP_FLAG_HAVE_TIMEOUTS     = BIT(4),
 };
 
+struct tpm_bios_log {
+       void *bios_event_log;
+       void *bios_event_log_end;
+};
+
 struct tpm_chip_seqops {
        struct tpm_chip *chip;
        const struct seq_operations *seqops;
@@ -187,6 +193,8 @@ struct tpm_chip {
 
        const struct attribute_group *groups[3];
        unsigned int groups_cnt;
+
+       u16 active_banks[7];
 #ifdef CONFIG_ACPI
        acpi_handle acpi_dev_handle;
        char ppi_version[TPM_PPI_VERSION_LEN + 1];
@@ -195,17 +203,6 @@ struct tpm_chip {
 
 #define to_tpm_chip(d) container_of(d, struct tpm_chip, dev)
 
-static inline int tpm_read_index(int base, int index)
-{
-       outb(index, base);
-       return inb(base+1) & 0xFF;
-}
-
-static inline void tpm_write_index(int base, int index, int value)
-{
-       outb(index, base);
-       outb(value & 0xFF, base+1);
-}
 struct tpm_input_header {
        __be16  tag;
        __be32  length;
@@ -284,7 +281,7 @@ struct permanent_flags_t {
 typedef union {
        struct  permanent_flags_t perm_flags;
        struct  stclear_flags_t stclear_flags;
-       bool    owned;
+       __u8    owned;
        __be32  num_pcrs;
        struct  tpm_version_t   tpm_version;
        struct  tpm_version_1_2_t tpm_version_1_2;
@@ -387,6 +384,11 @@ struct tpm_cmd_t {
        tpm_cmd_params  params;
 } __packed;
 
+struct tpm2_digest {
+       u16 alg_id;
+       u8 digest[SHA512_DIGEST_SIZE];
+} __packed;
+
 /* A string buffer type for constructing TPM commands. This is based on the
  * ideas of string buffer code in security/keys/trusted.h but is heap based
  * in order to keep the stack usage minimal.
@@ -493,10 +495,11 @@ enum tpm_transmit_flags {
 
 ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz,
                     unsigned int flags);
-ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *cmd, int len,
-                        unsigned int flags, const char *desc);
+ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *buf, size_t bufsiz,
+                        size_t min_rsp_body_len, unsigned int flags,
+                        const char *desc);
 ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
-                  const char *desc);
+                  const char *desc, size_t min_cap_length);
 int tpm_get_timeouts(struct tpm_chip *);
 int tpm1_auto_startup(struct tpm_chip *chip);
 int tpm_do_selftest(struct tpm_chip *chip);
@@ -529,8 +532,14 @@ static inline void tpm_add_ppi(struct tpm_chip *chip)
 }
 #endif
 
+static inline inline u32 tpm2_rc_value(u32 rc)
+{
+       return (rc & BIT(7)) ? rc & 0xff : rc;
+}
+
 int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf);
-int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash);
+int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, u32 count,
+                   struct tpm2_digest *digests);
 int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max);
 int tpm2_seal_trusted(struct tpm_chip *chip,
                      struct trusted_key_payload *payload,
diff --git a/drivers/char/tpm/tpm1_eventlog.c b/drivers/char/tpm/tpm1_eventlog.c
new file mode 100644 (file)
index 0000000..9a8605e
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+ * Copyright (C) 2005, 2012 IBM Corporation
+ *
+ * Authors:
+ *     Kent Yoder <key@linux.vnet.ibm.com>
+ *     Seiji Munetoh <munetoh@jp.ibm.com>
+ *     Stefan Berger <stefanb@us.ibm.com>
+ *     Reiner Sailer <sailer@watson.ibm.com>
+ *     Kylene Hall <kjhall@us.ibm.com>
+ *     Nayna Jain <nayna@linux.vnet.ibm.com>
+ *
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
+ *
+ * Access to the event log created by a system's firmware / BIOS
+ *
+ * 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/seq_file.h>
+#include <linux/fs.h>
+#include <linux/security.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "tpm.h"
+#include "tpm_eventlog.h"
+
+
+static const char* tcpa_event_type_strings[] = {
+       "PREBOOT",
+       "POST CODE",
+       "",
+       "NO ACTION",
+       "SEPARATOR",
+       "ACTION",
+       "EVENT TAG",
+       "S-CRTM Contents",
+       "S-CRTM Version",
+       "CPU Microcode",
+       "Platform Config Flags",
+       "Table of Devices",
+       "Compact Hash",
+       "IPL",
+       "IPL Partition Data",
+       "Non-Host Code",
+       "Non-Host Config",
+       "Non-Host Info"
+};
+
+static const char* tcpa_pc_event_id_strings[] = {
+       "",
+       "SMBIOS",
+       "BIS Certificate",
+       "POST BIOS ",
+       "ESCD ",
+       "CMOS",
+       "NVRAM",
+       "Option ROM",
+       "Option ROM config",
+       "",
+       "Option ROM microcode ",
+       "S-CRTM Version",
+       "S-CRTM Contents ",
+       "POST Contents ",
+       "Table of Devices",
+};
+
+/* returns pointer to start of pos. entry of tcg log */
+static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos)
+{
+       loff_t i;
+       struct tpm_chip *chip = m->private;
+       struct tpm_bios_log *log = &chip->log;
+       void *addr = log->bios_event_log;
+       void *limit = log->bios_event_log_end;
+       struct tcpa_event *event;
+       u32 converted_event_size;
+       u32 converted_event_type;
+
+
+       /* read over *pos measurements */
+       for (i = 0; i < *pos; i++) {
+               event = addr;
+
+               converted_event_size =
+                   do_endian_conversion(event->event_size);
+               converted_event_type =
+                   do_endian_conversion(event->event_type);
+
+               if ((addr + sizeof(struct tcpa_event)) < limit) {
+                       if ((converted_event_type == 0) &&
+                           (converted_event_size == 0))
+                               return NULL;
+                       addr += (sizeof(struct tcpa_event) +
+                                converted_event_size);
+               }
+       }
+
+       /* now check if current entry is valid */
+       if ((addr + sizeof(struct tcpa_event)) >= limit)
+               return NULL;
+
+       event = addr;
+
+       converted_event_size = do_endian_conversion(event->event_size);
+       converted_event_type = do_endian_conversion(event->event_type);
+
+       if (((converted_event_type == 0) && (converted_event_size == 0))
+           || ((addr + sizeof(struct tcpa_event) + converted_event_size)
+               >= limit))
+               return NULL;
+
+       return addr;
+}
+
+static void *tpm_bios_measurements_next(struct seq_file *m, void *v,
+                                       loff_t *pos)
+{
+       struct tcpa_event *event = v;
+       struct tpm_chip *chip = m->private;
+       struct tpm_bios_log *log = &chip->log;
+       void *limit = log->bios_event_log_end;
+       u32 converted_event_size;
+       u32 converted_event_type;
+
+       converted_event_size = do_endian_conversion(event->event_size);
+
+       v += sizeof(struct tcpa_event) + converted_event_size;
+
+       /* now check if current entry is valid */
+       if ((v + sizeof(struct tcpa_event)) >= limit)
+               return NULL;
+
+       event = v;
+
+       converted_event_size = do_endian_conversion(event->event_size);
+       converted_event_type = do_endian_conversion(event->event_type);
+
+       if (((converted_event_type == 0) && (converted_event_size == 0)) ||
+           ((v + sizeof(struct tcpa_event) + converted_event_size) >= limit))
+               return NULL;
+
+       (*pos)++;
+       return v;
+}
+
+static void tpm_bios_measurements_stop(struct seq_file *m, void *v)
+{
+}
+
+static int get_event_name(char *dest, struct tcpa_event *event,
+                       unsigned char * event_entry)
+{
+       const char *name = "";
+       /* 41 so there is room for 40 data and 1 nul */
+       char data[41] = "";
+       int i, n_len = 0, d_len = 0;
+       struct tcpa_pc_event *pc_event;
+
+       switch (do_endian_conversion(event->event_type)) {
+       case PREBOOT:
+       case POST_CODE:
+       case UNUSED:
+       case NO_ACTION:
+       case SCRTM_CONTENTS:
+       case SCRTM_VERSION:
+       case CPU_MICROCODE:
+       case PLATFORM_CONFIG_FLAGS:
+       case TABLE_OF_DEVICES:
+       case COMPACT_HASH:
+       case IPL:
+       case IPL_PARTITION_DATA:
+       case NONHOST_CODE:
+       case NONHOST_CONFIG:
+       case NONHOST_INFO:
+               name = tcpa_event_type_strings[do_endian_conversion
+                                               (event->event_type)];
+               n_len = strlen(name);
+               break;
+       case SEPARATOR:
+       case ACTION:
+               if (MAX_TEXT_EVENT >
+                   do_endian_conversion(event->event_size)) {
+                       name = event_entry;
+                       n_len = do_endian_conversion(event->event_size);
+               }
+               break;
+       case EVENT_TAG:
+               pc_event = (struct tcpa_pc_event *)event_entry;
+
+               /* ToDo Row data -> Base64 */
+
+               switch (do_endian_conversion(pc_event->event_id)) {
+               case SMBIOS:
+               case BIS_CERT:
+               case CMOS:
+               case NVRAM:
+               case OPTION_ROM_EXEC:
+               case OPTION_ROM_CONFIG:
+               case S_CRTM_VERSION:
+                       name = tcpa_pc_event_id_strings[do_endian_conversion
+                                                       (pc_event->event_id)];
+                       n_len = strlen(name);
+                       break;
+               /* hash data */
+               case POST_BIOS_ROM:
+               case ESCD:
+               case OPTION_ROM_MICROCODE:
+               case S_CRTM_CONTENTS:
+               case POST_CONTENTS:
+                       name = tcpa_pc_event_id_strings[do_endian_conversion
+                                                       (pc_event->event_id)];
+                       n_len = strlen(name);
+                       for (i = 0; i < 20; i++)
+                               d_len += sprintf(&data[2*i], "%02x",
+                                               pc_event->event_data[i]);
+                       break;
+               default:
+                       break;
+               }
+       default:
+               break;
+       }
+
+       return snprintf(dest, MAX_TEXT_EVENT, "[%.*s%.*s]",
+                       n_len, name, d_len, data);
+
+}
+
+static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v)
+{
+       struct tcpa_event *event = v;
+       struct tcpa_event temp_event;
+       char *temp_ptr;
+       int i;
+
+       memcpy(&temp_event, event, sizeof(struct tcpa_event));
+
+       /* convert raw integers for endianness */
+       temp_event.pcr_index = do_endian_conversion(event->pcr_index);
+       temp_event.event_type = do_endian_conversion(event->event_type);
+       temp_event.event_size = do_endian_conversion(event->event_size);
+
+       temp_ptr = (char *) &temp_event;
+
+       for (i = 0; i < (sizeof(struct tcpa_event) - 1) ; i++)
+               seq_putc(m, temp_ptr[i]);
+
+       temp_ptr = (char *) v;
+
+       for (i = (sizeof(struct tcpa_event) - 1);
+            i < (sizeof(struct tcpa_event) + temp_event.event_size); i++)
+               seq_putc(m, temp_ptr[i]);
+
+       return 0;
+
+}
+
+static int tpm_bios_measurements_release(struct inode *inode,
+                                        struct file *file)
+{
+       struct seq_file *seq = (struct seq_file *)file->private_data;
+       struct tpm_chip *chip = (struct tpm_chip *)seq->private;
+
+       put_device(&chip->dev);
+
+       return seq_release(inode, file);
+}
+
+static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v)
+{
+       int len = 0;
+       char *eventname;
+       struct tcpa_event *event = v;
+       unsigned char *event_entry =
+           (unsigned char *)(v + sizeof(struct tcpa_event));
+
+       eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
+       if (!eventname) {
+               printk(KERN_ERR "%s: ERROR - No Memory for event name\n ",
+                      __func__);
+               return -EFAULT;
+       }
+
+       /* 1st: PCR */
+       seq_printf(m, "%2d ", do_endian_conversion(event->pcr_index));
+
+       /* 2nd: SHA1 */
+       seq_printf(m, "%20phN", event->pcr_value);
+
+       /* 3rd: event type identifier */
+       seq_printf(m, " %02x", do_endian_conversion(event->event_type));
+
+       len += get_event_name(eventname, event, event_entry);
+
+       /* 4th: eventname <= max + \'0' delimiter */
+       seq_printf(m, " %s\n", eventname);
+
+       kfree(eventname);
+       return 0;
+}
+
+static const struct seq_operations tpm_ascii_b_measurements_seqops = {
+       .start = tpm_bios_measurements_start,
+       .next = tpm_bios_measurements_next,
+       .stop = tpm_bios_measurements_stop,
+       .show = tpm_ascii_bios_measurements_show,
+};
+
+static const struct seq_operations tpm_binary_b_measurements_seqops = {
+       .start = tpm_bios_measurements_start,
+       .next = tpm_bios_measurements_next,
+       .stop = tpm_bios_measurements_stop,
+       .show = tpm_binary_bios_measurements_show,
+};
+
+static int tpm_bios_measurements_open(struct inode *inode,
+                                           struct file *file)
+{
+       int err;
+       struct seq_file *seq;
+       struct tpm_chip_seqops *chip_seqops;
+       const struct seq_operations *seqops;
+       struct tpm_chip *chip;
+
+       inode_lock(inode);
+       if (!inode->i_private) {
+               inode_unlock(inode);
+               return -ENODEV;
+       }
+       chip_seqops = (struct tpm_chip_seqops *)inode->i_private;
+       seqops = chip_seqops->seqops;
+       chip = chip_seqops->chip;
+       get_device(&chip->dev);
+       inode_unlock(inode);
+
+       /* now register seq file */
+       err = seq_open(file, seqops);
+       if (!err) {
+               seq = file->private_data;
+               seq->private = chip;
+       }
+
+       return err;
+}
+
+static const struct file_operations tpm_bios_measurements_ops = {
+       .owner = THIS_MODULE,
+       .open = tpm_bios_measurements_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = tpm_bios_measurements_release,
+};
+
+static int tpm_read_log(struct tpm_chip *chip)
+{
+       int rc;
+
+       if (chip->log.bios_event_log != NULL) {
+               dev_dbg(&chip->dev,
+                       "%s: ERROR - event log already initialized\n",
+                       __func__);
+               return -EFAULT;
+       }
+
+       rc = tpm_read_log_acpi(chip);
+       if (rc != -ENODEV)
+               return rc;
+
+       return tpm_read_log_of(chip);
+}
+
+/*
+ * tpm_bios_log_setup() - Read the event log from the firmware
+ * @chip: TPM chip to use.
+ *
+ * If an event log is found then the securityfs files are setup to
+ * export it to userspace, otherwise nothing is done.
+ *
+ * Returns -ENODEV if the firmware has no event log or securityfs is not
+ * supported.
+ */
+int tpm_bios_log_setup(struct tpm_chip *chip)
+{
+       const char *name = dev_name(&chip->dev);
+       unsigned int cnt;
+       int rc = 0;
+
+       rc = tpm_read_log(chip);
+       if (rc)
+               return rc;
+
+       cnt = 0;
+       chip->bios_dir[cnt] = securityfs_create_dir(name, NULL);
+       /* NOTE: securityfs_create_dir can return ENODEV if securityfs is
+        * compiled out. The caller should ignore the ENODEV return code.
+        */
+       if (IS_ERR(chip->bios_dir[cnt]))
+               goto err;
+       cnt++;
+
+       chip->bin_log_seqops.chip = chip;
+       if (chip->flags & TPM_CHIP_FLAG_TPM2)
+               chip->bin_log_seqops.seqops =
+                       &tpm2_binary_b_measurements_seqops;
+       else
+               chip->bin_log_seqops.seqops =
+                       &tpm_binary_b_measurements_seqops;
+
+
+       chip->bios_dir[cnt] =
+           securityfs_create_file("binary_bios_measurements",
+                                  0440, chip->bios_dir[0],
+                                  (void *)&chip->bin_log_seqops,
+                                  &tpm_bios_measurements_ops);
+       if (IS_ERR(chip->bios_dir[cnt]))
+               goto err;
+       cnt++;
+
+       if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
+
+               chip->ascii_log_seqops.chip = chip;
+               chip->ascii_log_seqops.seqops =
+                       &tpm_ascii_b_measurements_seqops;
+
+               chip->bios_dir[cnt] =
+                       securityfs_create_file("ascii_bios_measurements",
+                                              0440, chip->bios_dir[0],
+                                              (void *)&chip->ascii_log_seqops,
+                                              &tpm_bios_measurements_ops);
+               if (IS_ERR(chip->bios_dir[cnt]))
+                       goto err;
+               cnt++;
+       }
+
+       return 0;
+
+err:
+       rc = PTR_ERR(chip->bios_dir[cnt]);
+       chip->bios_dir[cnt] = NULL;
+       tpm_bios_log_teardown(chip);
+       return rc;
+}
+
+void tpm_bios_log_teardown(struct tpm_chip *chip)
+{
+       int i;
+       struct inode *inode;
+
+       /* securityfs_remove currently doesn't take care of handling sync
+        * between removal and opening of pseudo files. To handle this, a
+        * workaround is added by making i_private = NULL here during removal
+        * and to check it during open(), both within inode_lock()/unlock().
+        * This design ensures that open() either safely gets kref or fails.
+        */
+       for (i = (TPM_NUM_EVENT_LOG_FILES - 1); i >= 0; i--) {
+               if (chip->bios_dir[i]) {
+                       inode = d_inode(chip->bios_dir[i]);
+                       inode_lock(inode);
+                       inode->i_private = NULL;
+                       inode_unlock(inode);
+                       securityfs_remove(chip->bios_dir[i]);
+               }
+       }
+}
index da5b782a97316e777fdcda2ea46c9681d2340b82..881aea9732bf1805d2c41a2ce6e218286bab335a 100644 (file)
@@ -53,22 +53,6 @@ struct tpm2_pcr_read_out {
        u8      digest[TPM_DIGEST_SIZE];
 } __packed;
 
-struct tpm2_null_auth_area {
-       __be32                  handle;
-       __be16                  nonce_size;
-       u8                      attributes;
-       __be16                  auth_size;
-} __packed;
-
-struct tpm2_pcr_extend_in {
-       __be32                          pcr_idx;
-       __be32                          auth_area_size;
-       struct tpm2_null_auth_area      auth_area;
-       __be32                          digest_cnt;
-       __be16                          hash_alg;
-       u8                              digest[TPM_DIGEST_SIZE];
-} __packed;
-
 struct tpm2_get_tpm_pt_in {
        __be32  cap_id;
        __be32  property_id;
@@ -97,7 +81,6 @@ union tpm2_cmd_params {
        struct  tpm2_self_test_in       selftest_in;
        struct  tpm2_pcr_read_in        pcrread_in;
        struct  tpm2_pcr_read_out       pcrread_out;
-       struct  tpm2_pcr_extend_in      pcrextend_in;
        struct  tpm2_get_tpm_pt_in      get_tpm_pt_in;
        struct  tpm2_get_tpm_pt_out     get_tpm_pt_out;
        struct  tpm2_get_random_in      getrandom_in;
@@ -248,6 +231,9 @@ static const u8 tpm2_ordinal_duration[TPM2_CC_LAST - TPM2_CC_FIRST + 1] = {
        (sizeof(struct tpm_input_header) + \
         sizeof(struct tpm2_pcr_read_in))
 
+#define TPM2_PCR_READ_RESP_BODY_SIZE \
+        sizeof(struct tpm2_pcr_read_out)
+
 static const struct tpm_input_header tpm2_pcrread_header = {
        .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
        .length = cpu_to_be32(TPM2_PCR_READ_IN_SIZE),
@@ -258,11 +244,9 @@ static const struct tpm_input_header tpm2_pcrread_header = {
  * tpm2_pcr_read() - read a PCR value
  * @chip:      TPM chip to use.
  * @pcr_idx:   index of the PCR to read.
- * @ref_buf:   buffer to store the resulting hash,
+ * @res_buf:   buffer to store the resulting hash.
  *
- * 0 is returned when the operation is successful. If a negative number is
- * returned it remarks a POSIX error code. If a positive number is returned
- * it remarks a TPM error.
+ * Return: Same as with tpm_transmit_cmd.
  */
 int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
 {
@@ -282,8 +266,9 @@ int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
               sizeof(cmd.params.pcrread_in.pcr_select));
        cmd.params.pcrread_in.pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7);
 
-       rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0,
-                             "attempting to read a pcr value");
+       rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
+                             TPM2_PCR_READ_RESP_BODY_SIZE,
+                             0, "attempting to read a pcr value");
        if (rc == 0) {
                buf = cmd.params.pcrread_out.digest;
                memcpy(res_buf, buf, TPM_DIGEST_SIZE);
@@ -292,50 +277,71 @@ int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
        return rc;
 }
 
-#define TPM2_GET_PCREXTEND_IN_SIZE \
-       (sizeof(struct tpm_input_header) + \
-        sizeof(struct tpm2_pcr_extend_in))
-
-static const struct tpm_input_header tpm2_pcrextend_header = {
-       .tag = cpu_to_be16(TPM2_ST_SESSIONS),
-       .length = cpu_to_be32(TPM2_GET_PCREXTEND_IN_SIZE),
-       .ordinal = cpu_to_be32(TPM2_CC_PCR_EXTEND)
-};
+struct tpm2_null_auth_area {
+       __be32  handle;
+       __be16  nonce_size;
+       u8  attributes;
+       __be16  auth_size;
+} __packed;
 
 /**
  * tpm2_pcr_extend() - extend a PCR value
+ *
  * @chip:      TPM chip to use.
  * @pcr_idx:   index of the PCR.
- * @hash:      hash value to use for the extend operation.
+ * @count:     number of digests passed.
+ * @digests:   list of pcr banks and corresponding digest values to extend.
  *
- * 0 is returned when the operation is successful. If a negative number is
- * returned it remarks a POSIX error code. If a positive number is returned
- * it remarks a TPM error.
+ * Return: Same as with tpm_transmit_cmd.
  */
-int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash)
+int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, u32 count,
+                   struct tpm2_digest *digests)
 {
-       struct tpm2_cmd cmd;
+       struct tpm_buf buf;
+       struct tpm2_null_auth_area auth_area;
        int rc;
+       int i;
+       int j;
+
+       if (count > ARRAY_SIZE(chip->active_banks))
+               return -EINVAL;
+
+       rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
+       if (rc)
+               return rc;
+
+       tpm_buf_append_u32(&buf, pcr_idx);
+
+       auth_area.handle = cpu_to_be32(TPM2_RS_PW);
+       auth_area.nonce_size = 0;
+       auth_area.attributes = 0;
+       auth_area.auth_size = 0;
+
+       tpm_buf_append_u32(&buf, sizeof(struct tpm2_null_auth_area));
+       tpm_buf_append(&buf, (const unsigned char *)&auth_area,
+                      sizeof(auth_area));
+       tpm_buf_append_u32(&buf, count);
+
+       for (i = 0; i < count; i++) {
+               for (j = 0; j < ARRAY_SIZE(tpm2_hash_map); j++) {
+                       if (digests[i].alg_id != tpm2_hash_map[j].tpm_id)
+                               continue;
+                       tpm_buf_append_u16(&buf, digests[i].alg_id);
+                       tpm_buf_append(&buf, (const unsigned char
+                                             *)&digests[i].digest,
+                              hash_digest_size[tpm2_hash_map[j].crypto_id]);
+               }
+       }
 
-       cmd.header.in = tpm2_pcrextend_header;
-       cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
-       cmd.params.pcrextend_in.auth_area_size =
-               cpu_to_be32(sizeof(struct tpm2_null_auth_area));
-       cmd.params.pcrextend_in.auth_area.handle =
-               cpu_to_be32(TPM2_RS_PW);
-       cmd.params.pcrextend_in.auth_area.nonce_size = 0;
-       cmd.params.pcrextend_in.auth_area.attributes = 0;
-       cmd.params.pcrextend_in.auth_area.auth_size = 0;
-       cmd.params.pcrextend_in.digest_cnt = cpu_to_be32(1);
-       cmd.params.pcrextend_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1);
-       memcpy(cmd.params.pcrextend_in.digest, hash, TPM_DIGEST_SIZE);
-
-       rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0,
+       rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 0, 0,
                              "attempting extend a PCR value");
 
+       tpm_buf_destroy(&buf);
+
        return rc;
 }
 
+
 #define TPM2_GETRANDOM_IN_SIZE \
        (sizeof(struct tpm_input_header) + \
         sizeof(struct tpm2_get_random_in))
@@ -348,18 +354,18 @@ static const struct tpm_input_header tpm2_getrandom_header = {
 
 /**
  * tpm2_get_random() - get random bytes from the TPM RNG
+ *
  * @chip: TPM chip to use
  * @out: destination buffer for the random bytes
  * @max: the max number of bytes to write to @out
  *
- * 0 is returned when the operation is successful. If a negative number is
- * returned it remarks a POSIX error code. If a positive number is returned
- * it remarks a TPM error.
+ * Return:
+ *    Size of the output buffer, or -EIO on error.
  */
 int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max)
 {
        struct tpm2_cmd cmd;
-       u32 recd;
+       u32 recd, rlength;
        u32 num_bytes;
        int err;
        int total = 0;
@@ -376,13 +382,19 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max)
                cmd.header.in = tpm2_getrandom_header;
                cmd.params.getrandom_in.size = cpu_to_be16(num_bytes);
 
-               err = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0,
-                                      "attempting get random");
+               err = tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
+                                      offsetof(struct tpm2_get_random_out,
+                                               buffer),
+                                      0, "attempting get random");
                if (err)
                        break;
 
                recd = min_t(u32, be16_to_cpu(cmd.params.getrandom_out.size),
                             num_bytes);
+               rlength = be32_to_cpu(cmd.header.out.length);
+               if (rlength < offsetof(struct tpm2_get_random_out, buffer) +
+                             recd)
+                       return -EFAULT;
                memcpy(dest, cmd.params.getrandom_out.buffer, recd);
 
                dest += recd;
@@ -397,6 +409,9 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max)
        (sizeof(struct tpm_input_header) + \
         sizeof(struct tpm2_get_tpm_pt_in))
 
+#define TPM2_GET_TPM_PT_OUT_BODY_SIZE \
+        sizeof(struct tpm2_get_tpm_pt_out)
+
 static const struct tpm_input_header tpm2_get_tpm_pt_header = {
        .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
        .length = cpu_to_be32(TPM2_GET_TPM_PT_IN_SIZE),
@@ -404,15 +419,15 @@ static const struct tpm_input_header tpm2_get_tpm_pt_header = {
 };
 
 /**
- * Append TPMS_AUTH_COMMAND to the buffer. The buffer must be allocated with
- * tpm_buf_alloc().
- *
- * @param buf: an allocated tpm_buf instance
- * @param nonce: the session nonce, may be NULL if not used
- * @param nonce_len: the session nonce length, may be 0 if not used
- * @param attributes: the session attributes
- * @param hmac: the session HMAC or password, may be NULL if not used
- * @param hmac_len: the session HMAC or password length, maybe 0 if not used
+ * tpm_buf_append_auth() - append TPMS_AUTH_COMMAND to the buffer.
+ *
+ * @buf: an allocated tpm_buf instance
+ * @session_handle: session handle
+ * @nonce: the session nonce, may be NULL if not used
+ * @nonce_len: the session nonce length, may be 0 if not used
+ * @attributes: the session attributes
+ * @hmac: the session HMAC or password, may be NULL if not used
+ * @hmac_len: the session HMAC or password length, maybe 0 if not used
  */
 static void tpm2_buf_append_auth(struct tpm_buf *buf, u32 session_handle,
                                 const u8 *nonce, u16 nonce_len,
@@ -435,7 +450,8 @@ static void tpm2_buf_append_auth(struct tpm_buf *buf, u32 session_handle,
 
 /**
  * tpm2_seal_trusted() - seal the payload of a trusted key
- * @chip_num: TPM chip to use
+ *
+ * @chip: TPM chip to use
  * @payload: the key data in clear and encrypted form
  * @options: authentication values and other options
  *
@@ -447,7 +463,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
 {
        unsigned int blob_len;
        struct tpm_buf buf;
-       u32 hash;
+       u32 hash, rlength;
        int i;
        int rc;
 
@@ -512,7 +528,8 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
                goto out;
        }
 
-       rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 0, "sealing data");
+       rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 4, 0,
+                             "sealing data");
        if (rc)
                goto out;
 
@@ -521,6 +538,11 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
                rc = -E2BIG;
                goto out;
        }
+       rlength = be32_to_cpu(((struct tpm2_cmd *)&buf)->header.out.length);
+       if (rlength < TPM_HEADER_SIZE + 4 + blob_len) {
+               rc = -EFAULT;
+               goto out;
+       }
 
        memcpy(payload->blob, &buf.data[TPM_HEADER_SIZE + 4], blob_len);
        payload->blob_len = blob_len;
@@ -529,7 +551,7 @@ out:
        tpm_buf_destroy(&buf);
 
        if (rc > 0) {
-               if ((rc & TPM2_RC_HASH) == TPM2_RC_HASH)
+               if (tpm2_rc_value(rc) == TPM2_RC_HASH)
                        rc = -EINVAL;
                else
                        rc = -EPERM;
@@ -540,11 +562,17 @@ out:
 
 /**
  * tpm2_load_cmd() - execute a TPM2_Load command
- * @chip_num: TPM chip to use
+ *
+ * @chip: TPM chip to use
  * @payload: the key data in clear and encrypted form
  * @options: authentication values and other options
+ * @blob_handle: returned blob handle
+ * @flags: tpm transmit flags
  *
- * Return: same as with tpm_transmit_cmd
+ * Return: 0 on success.
+ *        -E2BIG on wrong payload size.
+ *        -EPERM on tpm error status.
+ *        < 0 error from tpm_transmit_cmd.
  */
 static int tpm2_load_cmd(struct tpm_chip *chip,
                         struct trusted_key_payload *payload,
@@ -584,7 +612,8 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
                goto out;
        }
 
-       rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, flags, "loading blob");
+       rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 4, flags,
+                             "loading blob");
        if (!rc)
                *blob_handle = be32_to_cpup(
                        (__be32 *) &buf.data[TPM_HEADER_SIZE]);
@@ -600,11 +629,12 @@ out:
 
 /**
  * tpm2_flush_context_cmd() - execute a TPM2_FlushContext command
- * @chip_num: TPM chip to use
- * @payload: the key data in clear and encrypted form
- * @options: authentication values and other options
  *
- * Return: same as with tpm_transmit_cmd
+ * @chip: TPM chip to use
+ * @handle: the key data in clear and encrypted form
+ * @flags: tpm transmit flags
+ *
+ * Return: Same as with tpm_transmit_cmd.
  */
 static void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle,
                                   unsigned int flags)
@@ -621,7 +651,7 @@ static void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle,
 
        tpm_buf_append_u32(&buf, handle);
 
-       rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, flags,
+       rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 0, flags,
                              "flushing context");
        if (rc)
                dev_warn(&chip->dev, "0x%08x was not flushed, rc=%d\n", handle,
@@ -632,11 +662,16 @@ static void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle,
 
 /**
  * tpm2_unseal_cmd() - execute a TPM2_Unload command
- * @chip_num: TPM chip to use
+ *
+ * @chip: TPM chip to use
  * @payload: the key data in clear and encrypted form
  * @options: authentication values and other options
+ * @blob_handle: blob handle
+ * @flags: tpm_transmit_cmd flags
  *
- * Return: same as with tpm_transmit_cmd
+ * Return: 0 on success
+ *         -EPERM on tpm error status
+ *         < 0 error from tpm_transmit_cmd
  */
 static int tpm2_unseal_cmd(struct tpm_chip *chip,
                           struct trusted_key_payload *payload,
@@ -647,6 +682,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
        u16 data_len;
        u8 *data;
        int rc;
+       u32 rlength;
 
        rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
        if (rc)
@@ -661,13 +697,21 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
                             options->blobauth /* hmac */,
                             TPM_DIGEST_SIZE);
 
-       rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, flags, "unsealing");
+       rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 6, flags,
+                             "unsealing");
        if (rc > 0)
                rc = -EPERM;
 
        if (!rc) {
                data_len = be16_to_cpup(
                        (__be16 *) &buf.data[TPM_HEADER_SIZE + 4]);
+
+               rlength = be32_to_cpu(((struct tpm2_cmd *)&buf)
+                                       ->header.out.length);
+               if (rlength < TPM_HEADER_SIZE + 6 + data_len) {
+                       rc = -EFAULT;
+                       goto out;
+               }
                data = &buf.data[TPM_HEADER_SIZE + 6];
 
                memcpy(payload->key, data, data_len - 1);
@@ -675,17 +719,19 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
                payload->migratable = data[data_len - 1];
        }
 
+out:
        tpm_buf_destroy(&buf);
        return rc;
 }
 
 /**
  * tpm2_unseal_trusted() - unseal the payload of a trusted key
- * @chip_num: TPM chip to use
+ *
+ * @chip: TPM chip to use
  * @payload: the key data in clear and encrypted form
  * @options: authentication values and other options
  *
- * Return: < 0 on error and 0 on success.
+ * Return: Same as with tpm_transmit_cmd.
  */
 int tpm2_unseal_trusted(struct tpm_chip *chip,
                        struct trusted_key_payload *payload,
@@ -715,9 +761,7 @@ out:
  * @value:             output variable.
  * @desc:              passed to tpm_transmit_cmd()
  *
- * 0 is returned when the operation is successful. If a negative number is
- * returned it remarks a POSIX error code. If a positive number is returned
- * it remarks a TPM error.
+ * Return: Same as with tpm_transmit_cmd.
  */
 ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id,  u32 *value,
                        const char *desc)
@@ -730,7 +774,8 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id,  u32 *value,
        cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(property_id);
        cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1);
 
-       rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, desc);
+       rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
+                             TPM2_GET_TPM_PT_OUT_BODY_SIZE, 0, desc);
        if (!rc)
                *value = be32_to_cpu(cmd.params.get_tpm_pt_out.value);
 
@@ -750,13 +795,12 @@ static const struct tpm_input_header tpm2_startup_header = {
 
 /**
  * tpm2_startup() - send startup command to the TPM chip
+ *
  * @chip:              TPM chip to use.
- * @startup_type       startup type. The value is either
+ * @startup_type:      startup type. The value is either
  *                     TPM_SU_CLEAR or TPM_SU_STATE.
  *
- * 0 is returned when the operation is successful. If a negative number is
- * returned it remarks a POSIX error code. If a positive number is returned
- * it remarks a TPM error.
+ * Return: Same as with tpm_transmit_cmd.
  */
 static int tpm2_startup(struct tpm_chip *chip, u16 startup_type)
 {
@@ -765,7 +809,7 @@ static int tpm2_startup(struct tpm_chip *chip, u16 startup_type)
        cmd.header.in = tpm2_startup_header;
 
        cmd.params.startup_in.startup_type = cpu_to_be16(startup_type);
-       return tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0,
+       return tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, 0,
                                "attempting to start the TPM");
 }
 
@@ -781,8 +825,9 @@ static const struct tpm_input_header tpm2_shutdown_header = {
 
 /**
  * tpm2_shutdown() - send shutdown command to the TPM chip
+ *
  * @chip:              TPM chip to use.
- * @shutdown_type      shutdown type. The value is either
+ * @shutdown_type:     shutdown type. The value is either
  *                     TPM_SU_CLEAR or TPM_SU_STATE.
  */
 void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
@@ -793,7 +838,8 @@ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
        cmd.header.in = tpm2_shutdown_header;
        cmd.params.startup_in.startup_type = cpu_to_be16(shutdown_type);
 
-       rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, "stopping the TPM");
+       rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, 0,
+                             "stopping the TPM");
 
        /* In places where shutdown command is sent there's no much we can do
         * except print the error code on a system failure.
@@ -805,12 +851,11 @@ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
 
 /*
  * tpm2_calc_ordinal_duration() - maximum duration for a command
+ *
  * @chip:      TPM chip to use.
  * @ordinal:   command code number.
  *
- * 0 is returned when the operation is successful. If a negative number is
- * returned it remarks a POSIX error code. If a positive number is returned
- * it remarks a TPM error.
+ * Return: maximum duration for a command
  */
 unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
 {
@@ -842,13 +887,12 @@ static const struct tpm_input_header tpm2_selftest_header = {
 
 /**
  * tpm2_continue_selftest() - start a self test
+ *
  * @chip: TPM chip to use
  * @full: test all commands instead of testing only those that were not
  *        previously tested.
  *
- * 0 is returned when the operation is successful. If a negative number is
- * returned it remarks a POSIX error code. If a positive number is returned
- * it remarks a TPM error.
+ * Return: Same as with tpm_transmit_cmd with exception of RC_TESTING.
  */
 static int tpm2_start_selftest(struct tpm_chip *chip, bool full)
 {
@@ -858,7 +902,7 @@ static int tpm2_start_selftest(struct tpm_chip *chip, bool full)
        cmd.header.in = tpm2_selftest_header;
        cmd.params.selftest_in.full_test = full;
 
-       rc = tpm_transmit_cmd(chip, &cmd, TPM2_SELF_TEST_IN_SIZE, 0,
+       rc = tpm_transmit_cmd(chip, &cmd, TPM2_SELF_TEST_IN_SIZE, 0, 0,
                              "continue selftest");
 
        /* At least some prototype chips seem to give RC_TESTING error
@@ -874,14 +918,13 @@ static int tpm2_start_selftest(struct tpm_chip *chip, bool full)
 
 /**
  * tpm2_do_selftest() - run a full self test
+ *
  * @chip: TPM chip to use
  *
+ * Return: Same as with tpm_transmit_cmd.
+ *
  * During the self test TPM2 commands return with the error code RC_TESTING.
  * Waiting is done by issuing PCR read until it executes successfully.
- *
- * 0 is returned when the operation is successful. If a negative number is
- * returned it remarks a POSIX error code. If a positive number is returned
- * it remarks a TPM error.
  */
 static int tpm2_do_selftest(struct tpm_chip *chip)
 {
@@ -910,7 +953,7 @@ static int tpm2_do_selftest(struct tpm_chip *chip)
                cmd.params.pcrread_in.pcr_select[1] = 0x00;
                cmd.params.pcrread_in.pcr_select[2] = 0x00;
 
-               rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, NULL);
+               rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, 0, NULL);
                if (rc < 0)
                        break;
 
@@ -928,6 +971,8 @@ static int tpm2_do_selftest(struct tpm_chip *chip)
  * tpm2_probe() - probe TPM 2.0
  * @chip: TPM chip to use
  *
+ * Return: < 0 error and 0 on success.
+ *
  * Send idempotent TPM 2.0 command and see whether TPM 2.0 chip replied based on
  * the reply tag.
  */
@@ -941,7 +986,7 @@ int tpm2_probe(struct tpm_chip *chip)
        cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(0x100);
        cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1);
 
-       rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd),  0, NULL);
+       rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, 0, NULL);
        if (rc <  0)
                return rc;
 
@@ -952,12 +997,85 @@ int tpm2_probe(struct tpm_chip *chip)
 }
 EXPORT_SYMBOL_GPL(tpm2_probe);
 
+struct tpm2_pcr_selection {
+       __be16  hash_alg;
+       u8  size_of_select;
+       u8  pcr_select[3];
+} __packed;
+
+static ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip)
+{
+       struct tpm2_pcr_selection pcr_selection;
+       struct tpm_buf buf;
+       void *marker;
+       void *end;
+       void *pcr_select_offset;
+       unsigned int count;
+       u32 sizeof_pcr_selection;
+       u32 rsp_len;
+       int rc;
+       int i = 0;
+
+       rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY);
+       if (rc)
+               return rc;
+
+       tpm_buf_append_u32(&buf, TPM2_CAP_PCRS);
+       tpm_buf_append_u32(&buf, 0);
+       tpm_buf_append_u32(&buf, 1);
+
+       rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 9, 0,
+                             "get tpm pcr allocation");
+       if (rc)
+               goto out;
+
+       count = be32_to_cpup(
+               (__be32 *)&buf.data[TPM_HEADER_SIZE + 5]);
+
+       if (count > ARRAY_SIZE(chip->active_banks)) {
+               rc = -ENODEV;
+               goto out;
+       }
+
+       marker = &buf.data[TPM_HEADER_SIZE + 9];
+
+       rsp_len = be32_to_cpup((__be32 *)&buf.data[2]);
+       end = &buf.data[rsp_len];
+
+       for (i = 0; i < count; i++) {
+               pcr_select_offset = marker +
+                       offsetof(struct tpm2_pcr_selection, size_of_select);
+               if (pcr_select_offset >= end) {
+                       rc = -EFAULT;
+                       break;
+               }
+
+               memcpy(&pcr_selection, marker, sizeof(pcr_selection));
+               chip->active_banks[i] = be16_to_cpu(pcr_selection.hash_alg);
+               sizeof_pcr_selection = sizeof(pcr_selection.hash_alg) +
+                       sizeof(pcr_selection.size_of_select) +
+                       pcr_selection.size_of_select;
+               marker = marker + sizeof_pcr_selection;
+       }
+
+out:
+       if (i < ARRAY_SIZE(chip->active_banks))
+               chip->active_banks[i] = TPM2_ALG_ERROR;
+
+       tpm_buf_destroy(&buf);
+
+       return rc;
+}
+
 /**
  * tpm2_auto_startup - Perform the standard automatic TPM initialization
  *                     sequence
  * @chip: TPM chip to use
  *
- * Returns 0 on success, < 0 in case of fatal error.
+ * Initializes timeout values for operation and command durations, conducts
+ * a self-test and reads the list of active PCR banks.
+ *
+ * Return: 0 on success. Otherwise, a system error code is returned.
  */
 int tpm2_auto_startup(struct tpm_chip *chip)
 {
@@ -985,6 +1103,8 @@ int tpm2_auto_startup(struct tpm_chip *chip)
                }
        }
 
+       rc = tpm2_get_pcr_allocation(chip);
+
 out:
        if (rc > 0)
                rc = -ENODEV;
diff --git a/drivers/char/tpm/tpm2_eventlog.c b/drivers/char/tpm/tpm2_eventlog.c
new file mode 100644 (file)
index 0000000..513897c
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2016 IBM Corporation
+ *
+ * Authors:
+ *      Nayna Jain <nayna@linux.vnet.ibm.com>
+ *
+ * Access to TPM 2.0 event log as written by Firmware.
+ * It assumes that writer of event log has followed TCG Specification
+ * for Family "2.0" and written the event data in little endian.
+ * With that, it doesn't need any endian conversion for structure
+ * content.
+ *
+ * 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/seq_file.h>
+#include <linux/fs.h>
+#include <linux/security.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "tpm.h"
+#include "tpm_eventlog.h"
+
+/*
+ * calc_tpm2_event_size() - calculate the event size, where event
+ * is an entry in the TPM 2.0 event log. The event is of type Crypto
+ * Agile Log Entry Format as defined in TCG EFI Protocol Specification
+ * Family "2.0".
+
+ * @event: event whose size is to be calculated.
+ * @event_header: the first event in the event log.
+ *
+ * Returns size of the event. If it is an invalid event, returns 0.
+ */
+static int calc_tpm2_event_size(struct tcg_pcr_event2 *event,
+                               struct tcg_pcr_event *event_header)
+{
+       struct tcg_efi_specid_event *efispecid;
+       struct tcg_event_field *event_field;
+       void *marker;
+       void *marker_start;
+       u32 halg_size;
+       size_t size;
+       u16 halg;
+       int i;
+       int j;
+
+       marker = event;
+       marker_start = marker;
+       marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type)
+               + sizeof(event->count);
+
+       efispecid = (struct tcg_efi_specid_event *)event_header->event;
+
+       for (i = 0; (i < event->count) && (i < TPM2_ACTIVE_PCR_BANKS);
+            i++) {
+               halg_size = sizeof(event->digests[i].alg_id);
+               memcpy(&halg, marker, halg_size);
+               marker = marker + halg_size;
+               for (j = 0; (j < efispecid->num_algs); j++) {
+                       if (halg == efispecid->digest_sizes[j].alg_id) {
+                               marker = marker +
+                                       efispecid->digest_sizes[j].digest_size;
+                               break;
+                       }
+               }
+       }
+
+       event_field = (struct tcg_event_field *)marker;
+       marker = marker + sizeof(event_field->event_size)
+               + event_field->event_size;
+       size = marker - marker_start;
+
+       if ((event->event_type == 0) && (event_field->event_size == 0))
+               return 0;
+
+       return size;
+}
+
+static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos)
+{
+       struct tpm_chip *chip = m->private;
+       struct tpm_bios_log *log = &chip->log;
+       void *addr = log->bios_event_log;
+       void *limit = log->bios_event_log_end;
+       struct tcg_pcr_event *event_header;
+       struct tcg_pcr_event2 *event;
+       size_t size;
+       int i;
+
+       event_header = addr;
+       size = sizeof(struct tcg_pcr_event) - sizeof(event_header->event)
+               + event_header->event_size;
+
+       if (*pos == 0) {
+               if (addr + size < limit) {
+                       if ((event_header->event_type == 0) &&
+                           (event_header->event_size == 0))
+                               return NULL;
+                       return SEQ_START_TOKEN;
+               }
+       }
+
+       if (*pos > 0) {
+               addr += size;
+               event = addr;
+               size = calc_tpm2_event_size(event, event_header);
+               if ((addr + size >=  limit) || (size == 0))
+                       return NULL;
+       }
+
+       for (i = 0; i < (*pos - 1); i++) {
+               event = addr;
+               size = calc_tpm2_event_size(event, event_header);
+
+               if ((addr + size >= limit) || (size == 0))
+                       return NULL;
+               addr += size;
+       }
+
+       return addr;
+}
+
+static void *tpm2_bios_measurements_next(struct seq_file *m, void *v,
+                                        loff_t *pos)
+{
+       struct tcg_pcr_event *event_header;
+       struct tcg_pcr_event2 *event;
+       struct tpm_chip *chip = m->private;
+       struct tpm_bios_log *log = &chip->log;
+       void *limit = log->bios_event_log_end;
+       size_t event_size;
+       void *marker;
+
+       event_header = log->bios_event_log;
+
+       if (v == SEQ_START_TOKEN) {
+               event_size = sizeof(struct tcg_pcr_event) -
+                       sizeof(event_header->event) + event_header->event_size;
+               marker = event_header;
+       } else {
+               event = v;
+               event_size = calc_tpm2_event_size(event, event_header);
+               if (event_size == 0)
+                       return NULL;
+               marker = event;
+       }
+
+       marker = marker + event_size;
+       if (marker >= limit)
+               return NULL;
+       v = marker;
+       event = v;
+
+       event_size = calc_tpm2_event_size(event, event_header);
+       if (((v + event_size) >= limit) || (event_size == 0))
+               return NULL;
+
+       (*pos)++;
+       return v;
+}
+
+static void tpm2_bios_measurements_stop(struct seq_file *m, void *v)
+{
+}
+
+static int tpm2_binary_bios_measurements_show(struct seq_file *m, void *v)
+{
+       struct tpm_chip *chip = m->private;
+       struct tpm_bios_log *log = &chip->log;
+       struct tcg_pcr_event *event_header = log->bios_event_log;
+       struct tcg_pcr_event2 *event = v;
+       void *temp_ptr;
+       size_t size;
+
+       if (v == SEQ_START_TOKEN) {
+               size = sizeof(struct tcg_pcr_event) -
+                       sizeof(event_header->event) + event_header->event_size;
+
+               temp_ptr = event_header;
+
+               if (size > 0)
+                       seq_write(m, temp_ptr, size);
+       } else {
+               size = calc_tpm2_event_size(event, event_header);
+               temp_ptr = event;
+               if (size > 0)
+                       seq_write(m, temp_ptr, size);
+       }
+
+       return 0;
+}
+
+const struct seq_operations tpm2_binary_b_measurements_seqops = {
+       .start = tpm2_bios_measurements_start,
+       .next = tpm2_bios_measurements_next,
+       .stop = tpm2_bios_measurements_stop,
+       .show = tpm2_binary_bios_measurements_show,
+};
index b7718c95fd0b48cdd0abf074b462568ed22f57b9..169edf3ce86d9df8a5c2b923ab94d08f60439060 100644 (file)
@@ -54,6 +54,9 @@ int tpm_read_log_acpi(struct tpm_chip *chip)
        u64 len, start;
        struct tpm_bios_log *log;
 
+       if (chip->flags & TPM_CHIP_FLAG_TPM2)
+               return -ENODEV;
+
        log = &chip->log;
 
        /* Unfortuntely ACPI does not associate the event log with a specific
index 4f96d80cdce997f1a031a323b70ba60d6b1d0954..5c82eb47665e0783ca07a444ec7b2ba659127da4 100644 (file)
@@ -96,6 +96,12 @@ enum tpm_atmel_addr {
        TPM_ATMEL_BASE_ADDR_HI = 0x09
 };
 
+static inline int tpm_read_index(int base, int index)
+{
+       outb(index, base);
+       return inb(base+1) & 0xFF;
+}
+
 /* Verify this is a 1.1 Atmel TPM */
 static int atmel_verify_tpm11(void)
 {
index 717b6b47c042760fe4db4f6834e8d40af5d2a117..86f355b6df1d345ff9cf0874c40a29f5f986b0f2 100644 (file)
@@ -264,10 +264,12 @@ static const struct tpm_class_ops tpm_crb = {
 static int crb_check_resource(struct acpi_resource *ares, void *data)
 {
        struct resource *io_res = data;
-       struct resource res;
+       struct resource_win win;
+       struct resource *res = &(win.res);
 
-       if (acpi_dev_resource_memory(ares, &res)) {
-               *io_res = res;
+       if (acpi_dev_resource_memory(ares, res) ||
+           acpi_dev_resource_address_space(ares, &win)) {
+               *io_res = *res;
                io_res->name = NULL;
        }
 
diff --git a/drivers/char/tpm/tpm_eventlog.c b/drivers/char/tpm/tpm_eventlog.c
deleted file mode 100644 (file)
index 11bb113..0000000
+++ /dev/null
@@ -1,462 +0,0 @@
-/*
- * Copyright (C) 2005, 2012 IBM Corporation
- *
- * Authors:
- *     Kent Yoder <key@linux.vnet.ibm.com>
- *     Seiji Munetoh <munetoh@jp.ibm.com>
- *     Stefan Berger <stefanb@us.ibm.com>
- *     Reiner Sailer <sailer@watson.ibm.com>
- *     Kylene Hall <kjhall@us.ibm.com>
- *     Nayna Jain <nayna@linux.vnet.ibm.com>
- *
- * Maintained by: <tpmdd-devel@lists.sourceforge.net>
- *
- * Access to the event log created by a system's firmware / BIOS
- *
- * 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/seq_file.h>
-#include <linux/fs.h>
-#include <linux/security.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-
-#include "tpm.h"
-#include "tpm_eventlog.h"
-
-
-static const char* tcpa_event_type_strings[] = {
-       "PREBOOT",
-       "POST CODE",
-       "",
-       "NO ACTION",
-       "SEPARATOR",
-       "ACTION",
-       "EVENT TAG",
-       "S-CRTM Contents",
-       "S-CRTM Version",
-       "CPU Microcode",
-       "Platform Config Flags",
-       "Table of Devices",
-       "Compact Hash",
-       "IPL",
-       "IPL Partition Data",
-       "Non-Host Code",
-       "Non-Host Config",
-       "Non-Host Info"
-};
-
-static const char* tcpa_pc_event_id_strings[] = {
-       "",
-       "SMBIOS",
-       "BIS Certificate",
-       "POST BIOS ",
-       "ESCD ",
-       "CMOS",
-       "NVRAM",
-       "Option ROM",
-       "Option ROM config",
-       "",
-       "Option ROM microcode ",
-       "S-CRTM Version",
-       "S-CRTM Contents ",
-       "POST Contents ",
-       "Table of Devices",
-};
-
-/* returns pointer to start of pos. entry of tcg log */
-static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos)
-{
-       loff_t i;
-       struct tpm_chip *chip = m->private;
-       struct tpm_bios_log *log = &chip->log;
-       void *addr = log->bios_event_log;
-       void *limit = log->bios_event_log_end;
-       struct tcpa_event *event;
-       u32 converted_event_size;
-       u32 converted_event_type;
-
-
-       /* read over *pos measurements */
-       for (i = 0; i < *pos; i++) {
-               event = addr;
-
-               converted_event_size =
-                   do_endian_conversion(event->event_size);
-               converted_event_type =
-                   do_endian_conversion(event->event_type);
-
-               if ((addr + sizeof(struct tcpa_event)) < limit) {
-                       if ((converted_event_type == 0) &&
-                           (converted_event_size == 0))
-                               return NULL;
-                       addr += (sizeof(struct tcpa_event) +
-                                converted_event_size);
-               }
-       }
-
-       /* now check if current entry is valid */
-       if ((addr + sizeof(struct tcpa_event)) >= limit)
-               return NULL;
-
-       event = addr;
-
-       converted_event_size = do_endian_conversion(event->event_size);
-       converted_event_type = do_endian_conversion(event->event_type);
-
-       if (((converted_event_type == 0) && (converted_event_size == 0))
-           || ((addr + sizeof(struct tcpa_event) + converted_event_size)
-               >= limit))
-               return NULL;
-
-       return addr;
-}
-
-static void *tpm_bios_measurements_next(struct seq_file *m, void *v,
-                                       loff_t *pos)
-{
-       struct tcpa_event *event = v;
-       struct tpm_chip *chip = m->private;
-       struct tpm_bios_log *log = &chip->log;
-       void *limit = log->bios_event_log_end;
-       u32 converted_event_size;
-       u32 converted_event_type;
-
-       converted_event_size = do_endian_conversion(event->event_size);
-
-       v += sizeof(struct tcpa_event) + converted_event_size;
-
-       /* now check if current entry is valid */
-       if ((v + sizeof(struct tcpa_event)) >= limit)
-               return NULL;
-
-       event = v;
-
-       converted_event_size = do_endian_conversion(event->event_size);
-       converted_event_type = do_endian_conversion(event->event_type);
-
-       if (((converted_event_type == 0) && (converted_event_size == 0)) ||
-           ((v + sizeof(struct tcpa_event) + converted_event_size) >= limit))
-               return NULL;
-
-       (*pos)++;
-       return v;
-}
-
-static void tpm_bios_measurements_stop(struct seq_file *m, void *v)
-{
-}
-
-static int get_event_name(char *dest, struct tcpa_event *event,
-                       unsigned char * event_entry)
-{
-       const char *name = "";
-       /* 41 so there is room for 40 data and 1 nul */
-       char data[41] = "";
-       int i, n_len = 0, d_len = 0;
-       struct tcpa_pc_event *pc_event;
-
-       switch (do_endian_conversion(event->event_type)) {
-       case PREBOOT:
-       case POST_CODE:
-       case UNUSED:
-       case NO_ACTION:
-       case SCRTM_CONTENTS:
-       case SCRTM_VERSION:
-       case CPU_MICROCODE:
-       case PLATFORM_CONFIG_FLAGS:
-       case TABLE_OF_DEVICES:
-       case COMPACT_HASH:
-       case IPL:
-       case IPL_PARTITION_DATA:
-       case NONHOST_CODE:
-       case NONHOST_CONFIG:
-       case NONHOST_INFO:
-               name = tcpa_event_type_strings[do_endian_conversion
-                                               (event->event_type)];
-               n_len = strlen(name);
-               break;
-       case SEPARATOR:
-       case ACTION:
-               if (MAX_TEXT_EVENT >
-                   do_endian_conversion(event->event_size)) {
-                       name = event_entry;
-                       n_len = do_endian_conversion(event->event_size);
-               }
-               break;
-       case EVENT_TAG:
-               pc_event = (struct tcpa_pc_event *)event_entry;
-
-               /* ToDo Row data -> Base64 */
-
-               switch (do_endian_conversion(pc_event->event_id)) {
-               case SMBIOS:
-               case BIS_CERT:
-               case CMOS:
-               case NVRAM:
-               case OPTION_ROM_EXEC:
-               case OPTION_ROM_CONFIG:
-               case S_CRTM_VERSION:
-                       name = tcpa_pc_event_id_strings[do_endian_conversion
-                                                       (pc_event->event_id)];
-                       n_len = strlen(name);
-                       break;
-               /* hash data */
-               case POST_BIOS_ROM:
-               case ESCD:
-               case OPTION_ROM_MICROCODE:
-               case S_CRTM_CONTENTS:
-               case POST_CONTENTS:
-                       name = tcpa_pc_event_id_strings[do_endian_conversion
-                                                       (pc_event->event_id)];
-                       n_len = strlen(name);
-                       for (i = 0; i < 20; i++)
-                               d_len += sprintf(&data[2*i], "%02x",
-                                               pc_event->event_data[i]);
-                       break;
-               default:
-                       break;
-               }
-       default:
-               break;
-       }
-
-       return snprintf(dest, MAX_TEXT_EVENT, "[%.*s%.*s]",
-                       n_len, name, d_len, data);
-
-}
-
-static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v)
-{
-       struct tcpa_event *event = v;
-       struct tcpa_event temp_event;
-       char *temp_ptr;
-       int i;
-
-       memcpy(&temp_event, event, sizeof(struct tcpa_event));
-
-       /* convert raw integers for endianness */
-       temp_event.pcr_index = do_endian_conversion(event->pcr_index);
-       temp_event.event_type = do_endian_conversion(event->event_type);
-       temp_event.event_size = do_endian_conversion(event->event_size);
-
-       temp_ptr = (char *) &temp_event;
-
-       for (i = 0; i < (sizeof(struct tcpa_event) - 1) ; i++)
-               seq_putc(m, temp_ptr[i]);
-
-       temp_ptr = (char *) v;
-
-       for (i = (sizeof(struct tcpa_event) - 1);
-            i < (sizeof(struct tcpa_event) + temp_event.event_size); i++)
-               seq_putc(m, temp_ptr[i]);
-
-       return 0;
-
-}
-
-static int tpm_bios_measurements_release(struct inode *inode,
-                                        struct file *file)
-{
-       struct seq_file *seq = (struct seq_file *)file->private_data;
-       struct tpm_chip *chip = (struct tpm_chip *)seq->private;
-
-       put_device(&chip->dev);
-
-       return seq_release(inode, file);
-}
-
-static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v)
-{
-       int len = 0;
-       char *eventname;
-       struct tcpa_event *event = v;
-       unsigned char *event_entry =
-           (unsigned char *)(v + sizeof(struct tcpa_event));
-
-       eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
-       if (!eventname) {
-               printk(KERN_ERR "%s: ERROR - No Memory for event name\n ",
-                      __func__);
-               return -EFAULT;
-       }
-
-       /* 1st: PCR */
-       seq_printf(m, "%2d ", do_endian_conversion(event->pcr_index));
-
-       /* 2nd: SHA1 */
-       seq_printf(m, "%20phN", event->pcr_value);
-
-       /* 3rd: event type identifier */
-       seq_printf(m, " %02x", do_endian_conversion(event->event_type));
-
-       len += get_event_name(eventname, event, event_entry);
-
-       /* 4th: eventname <= max + \'0' delimiter */
-       seq_printf(m, " %s\n", eventname);
-
-       kfree(eventname);
-       return 0;
-}
-
-static const struct seq_operations tpm_ascii_b_measurements_seqops = {
-       .start = tpm_bios_measurements_start,
-       .next = tpm_bios_measurements_next,
-       .stop = tpm_bios_measurements_stop,
-       .show = tpm_ascii_bios_measurements_show,
-};
-
-static const struct seq_operations tpm_binary_b_measurements_seqops = {
-       .start = tpm_bios_measurements_start,
-       .next = tpm_bios_measurements_next,
-       .stop = tpm_bios_measurements_stop,
-       .show = tpm_binary_bios_measurements_show,
-};
-
-static int tpm_bios_measurements_open(struct inode *inode,
-                                           struct file *file)
-{
-       int err;
-       struct seq_file *seq;
-       struct tpm_chip_seqops *chip_seqops;
-       const struct seq_operations *seqops;
-       struct tpm_chip *chip;
-
-       inode_lock(inode);
-       if (!inode->i_private) {
-               inode_unlock(inode);
-               return -ENODEV;
-       }
-       chip_seqops = (struct tpm_chip_seqops *)inode->i_private;
-       seqops = chip_seqops->seqops;
-       chip = chip_seqops->chip;
-       get_device(&chip->dev);
-       inode_unlock(inode);
-
-       /* now register seq file */
-       err = seq_open(file, seqops);
-       if (!err) {
-               seq = file->private_data;
-               seq->private = chip;
-       }
-
-       return err;
-}
-
-static const struct file_operations tpm_bios_measurements_ops = {
-       .owner = THIS_MODULE,
-       .open = tpm_bios_measurements_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = tpm_bios_measurements_release,
-};
-
-static int tpm_read_log(struct tpm_chip *chip)
-{
-       int rc;
-
-       if (chip->log.bios_event_log != NULL) {
-               dev_dbg(&chip->dev,
-                       "%s: ERROR - event log already initialized\n",
-                       __func__);
-               return -EFAULT;
-       }
-
-       rc = tpm_read_log_acpi(chip);
-       if (rc != -ENODEV)
-               return rc;
-
-       return tpm_read_log_of(chip);
-}
-
-/*
- * tpm_bios_log_setup() - Read the event log from the firmware
- * @chip: TPM chip to use.
- *
- * If an event log is found then the securityfs files are setup to
- * export it to userspace, otherwise nothing is done.
- *
- * Returns -ENODEV if the firmware has no event log or securityfs is not
- * supported.
- */
-int tpm_bios_log_setup(struct tpm_chip *chip)
-{
-       const char *name = dev_name(&chip->dev);
-       unsigned int cnt;
-       int rc = 0;
-
-       if (chip->flags & TPM_CHIP_FLAG_TPM2)
-               return 0;
-
-       rc = tpm_read_log(chip);
-       if (rc)
-               return rc;
-
-       cnt = 0;
-       chip->bios_dir[cnt] = securityfs_create_dir(name, NULL);
-       /* NOTE: securityfs_create_dir can return ENODEV if securityfs is
-        * compiled out. The caller should ignore the ENODEV return code.
-        */
-       if (IS_ERR(chip->bios_dir[cnt]))
-               goto err;
-       cnt++;
-
-       chip->bin_log_seqops.chip = chip;
-       chip->bin_log_seqops.seqops = &tpm_binary_b_measurements_seqops;
-
-       chip->bios_dir[cnt] =
-           securityfs_create_file("binary_bios_measurements",
-                                  0440, chip->bios_dir[0],
-                                  (void *)&chip->bin_log_seqops,
-                                  &tpm_bios_measurements_ops);
-       if (IS_ERR(chip->bios_dir[cnt]))
-               goto err;
-       cnt++;
-
-       chip->ascii_log_seqops.chip = chip;
-       chip->ascii_log_seqops.seqops = &tpm_ascii_b_measurements_seqops;
-
-       chip->bios_dir[cnt] =
-           securityfs_create_file("ascii_bios_measurements",
-                                  0440, chip->bios_dir[0],
-                                  (void *)&chip->ascii_log_seqops,
-                                  &tpm_bios_measurements_ops);
-       if (IS_ERR(chip->bios_dir[cnt]))
-               goto err;
-       cnt++;
-
-       return 0;
-
-err:
-       rc = PTR_ERR(chip->bios_dir[cnt]);
-       chip->bios_dir[cnt] = NULL;
-       tpm_bios_log_teardown(chip);
-       return rc;
-}
-
-void tpm_bios_log_teardown(struct tpm_chip *chip)
-{
-       int i;
-       struct inode *inode;
-
-       /* securityfs_remove currently doesn't take care of handling sync
-        * between removal and opening of pseudo files. To handle this, a
-        * workaround is added by making i_private = NULL here during removal
-        * and to check it during open(), both within inode_lock()/unlock().
-        * This design ensures that open() either safely gets kref or fails.
-        */
-       for (i = (TPM_NUM_EVENT_LOG_FILES - 1); i >= 0; i--) {
-               if (chip->bios_dir[i]) {
-                       inode = d_inode(chip->bios_dir[i]);
-                       inode_lock(inode);
-                       inode->i_private = NULL;
-                       inode_unlock(inode);
-                       securityfs_remove(chip->bios_dir[i]);
-               }
-       }
-}
index 1660d74ea79a3a436ef5a1bc8a293f5d52f1e771..b4b5495592035bbc2996be216404b12c5c9287c5 100644 (file)
@@ -2,9 +2,12 @@
 #ifndef __TPM_EVENTLOG_H__
 #define __TPM_EVENTLOG_H__
 
+#include <crypto/hash_info.h>
+
 #define TCG_EVENT_NAME_LEN_MAX 255
 #define MAX_TEXT_EVENT         1000    /* Max event string length */
 #define ACPI_TCPA_SIG          "TCPA"  /* 0x41504354 /'TCPA' */
+#define TPM2_ACTIVE_PCR_BANKS  3
 
 #ifdef CONFIG_PPC64
 #define do_endian_conversion(x) be32_to_cpu(x)
@@ -17,11 +20,6 @@ enum bios_platform_class {
        BIOS_SERVER = 0x01,
 };
 
-struct tpm_bios_log {
-       void *bios_event_log;
-       void *bios_event_log_end;
-};
-
 struct tcpa_event {
        u32 pcr_index;
        u32 event_type;
@@ -73,6 +71,49 @@ enum tcpa_pc_event_ids {
        HOST_TABLE_OF_DEVICES,
 };
 
+/* http://www.trustedcomputinggroup.org/tcg-efi-protocol-specification/ */
+
+struct tcg_efi_specid_event_algs {
+       u16 alg_id;
+       u16 digest_size;
+} __packed;
+
+struct tcg_efi_specid_event {
+       u8 signature[16];
+       u32 platform_class;
+       u8 spec_version_minor;
+       u8 spec_version_major;
+       u8 spec_errata;
+       u8 uintnsize;
+       u32 num_algs;
+       struct tcg_efi_specid_event_algs digest_sizes[TPM2_ACTIVE_PCR_BANKS];
+       u8 vendor_info_size;
+       u8 vendor_info[0];
+} __packed;
+
+struct tcg_pcr_event {
+       u32 pcr_idx;
+       u32 event_type;
+       u8 digest[20];
+       u32 event_size;
+       u8 event[0];
+} __packed;
+
+struct tcg_event_field {
+       u32 event_size;
+       u8 event[0];
+} __packed;
+
+struct tcg_pcr_event2 {
+       u32 pcr_idx;
+       u32 event_type;
+       u32 count;
+       struct tpm2_digest digests[TPM2_ACTIVE_PCR_BANKS];
+       struct tcg_event_field event;
+} __packed;
+
+extern const struct seq_operations tpm2_binary_b_measurements_seqops;
+
 #if defined(CONFIG_ACPI)
 int tpm_read_log_acpi(struct tpm_chip *chip);
 #else
index 946025a7413b6b6e771e54a66a7bb42d75ed803e..1b9d61ffe9912d67c283cb8a53909c1d41887c4f 100644 (file)
@@ -40,11 +40,12 @@ MODULE_DEVICE_TABLE(vio, tpm_ibmvtpm_device_table);
 
 /**
  * ibmvtpm_send_crq - Send a CRQ request
+ *
  * @vdev:      vio device struct
  * @w1:                first word
  * @w2:                second word
  *
- * Return value:
+ * Return:
  *     0 -Sucess
  *     Non-zero - Failure
  */
@@ -55,11 +56,12 @@ static int ibmvtpm_send_crq(struct vio_dev *vdev, u64 w1, u64 w2)
 
 /**
  * tpm_ibmvtpm_recv - Receive data after send
+ *
  * @chip:      tpm chip struct
  * @buf:       buffer to read
- * count:      size of buffer
+ * @count:     size of buffer
  *
- * Return value:
+ * Return:
  *     Number of bytes read
  */
 static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
@@ -96,12 +98,13 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 
 /**
  * tpm_ibmvtpm_send - Send tpm request
+ *
  * @chip:      tpm chip struct
  * @buf:       buffer contains data to send
- * count:      size of buffer
+ * @count:     size of buffer
  *
- * Return value:
- *     Number of bytes sent
+ * Return:
+ *     Number of bytes sent or < 0 on error.
  */
 static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
 {
@@ -170,11 +173,12 @@ static u8 tpm_ibmvtpm_status(struct tpm_chip *chip)
 
 /**
  * ibmvtpm_crq_get_rtce_size - Send a CRQ request to get rtce size
+ *
  * @ibmvtpm:   vtpm device struct
  *
- * Return value:
- *     0 - Success
- *     Non-zero - Failure
+ * Return:
+ *     0 on success.
+ *     Non-zero on failure.
  */
 static int ibmvtpm_crq_get_rtce_size(struct ibmvtpm_dev *ibmvtpm)
 {
@@ -197,11 +201,12 @@ static int ibmvtpm_crq_get_rtce_size(struct ibmvtpm_dev *ibmvtpm)
 /**
  * ibmvtpm_crq_get_version - Send a CRQ request to get vtpm version
  *                        - Note that this is vtpm version and not tpm version
+ *
  * @ibmvtpm:   vtpm device struct
  *
- * Return value:
- *     0 - Success
- *     Non-zero - Failure
+ * Return:
+ *     0 on success.
+ *     Non-zero on failure.
  */
 static int ibmvtpm_crq_get_version(struct ibmvtpm_dev *ibmvtpm)
 {
@@ -225,9 +230,9 @@ static int ibmvtpm_crq_get_version(struct ibmvtpm_dev *ibmvtpm)
  * ibmvtpm_crq_send_init_complete - Send a CRQ initialize complete message
  * @ibmvtpm:   vtpm device struct
  *
- * Return value:
- *     0 - Success
- *     Non-zero - Failure
+ * Return:
+ *     0 on success.
+ *     Non-zero on failure.
  */
 static int ibmvtpm_crq_send_init_complete(struct ibmvtpm_dev *ibmvtpm)
 {
@@ -245,9 +250,9 @@ static int ibmvtpm_crq_send_init_complete(struct ibmvtpm_dev *ibmvtpm)
  * ibmvtpm_crq_send_init - Send a CRQ initialize message
  * @ibmvtpm:   vtpm device struct
  *
- * Return value:
- *     0 - Success
- *     Non-zero - Failure
+ * Return:
+ *     0 on success.
+ *     Non-zero on failure.
  */
 static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm)
 {
@@ -265,8 +270,7 @@ static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm)
  * tpm_ibmvtpm_remove - ibm vtpm remove entry point
  * @vdev:      vio device struct
  *
- * Return value:
- *     0
+ * Return: Always 0.
  */
 static int tpm_ibmvtpm_remove(struct vio_dev *vdev)
 {
@@ -303,18 +307,19 @@ static int tpm_ibmvtpm_remove(struct vio_dev *vdev)
  * tpm_ibmvtpm_get_desired_dma - Get DMA size needed by this driver
  * @vdev:      vio device struct
  *
- * Return value:
- *     Number of bytes the driver needs to DMA map
+ * Return:
+ *     Number of bytes the driver needs to DMA map.
  */
 static unsigned long tpm_ibmvtpm_get_desired_dma(struct vio_dev *vdev)
 {
        struct tpm_chip *chip = dev_get_drvdata(&vdev->dev);
        struct ibmvtpm_dev *ibmvtpm = dev_get_drvdata(&chip->dev);
 
-       /* ibmvtpm initializes at probe time, so the data we are
-       * asking for may not be set yet. Estimate that 4K required
-       * for TCE-mapped buffer in addition to CRQ.
-       */
+       /*
+        * ibmvtpm initializes at probe time, so the data we are
+        * asking for may not be set yet. Estimate that 4K required
+        * for TCE-mapped buffer in addition to CRQ.
+        */
        if (!ibmvtpm)
                return CRQ_RES_BUF_SIZE + PAGE_SIZE;
 
@@ -325,8 +330,7 @@ static unsigned long tpm_ibmvtpm_get_desired_dma(struct vio_dev *vdev)
  * tpm_ibmvtpm_suspend - Suspend
  * @dev:       device struct
  *
- * Return value:
- *     0
+ * Return: Always 0.
  */
 static int tpm_ibmvtpm_suspend(struct device *dev)
 {
@@ -350,11 +354,12 @@ static int tpm_ibmvtpm_suspend(struct device *dev)
 
 /**
  * ibmvtpm_reset_crq - Reset CRQ
+ *
  * @ibmvtpm:   ibm vtpm struct
  *
- * Return value:
- *     0 - Success
- *     Non-zero - Failure
+ * Return:
+ *     0 on success.
+ *     Non-zero on failure.
  */
 static int ibmvtpm_reset_crq(struct ibmvtpm_dev *ibmvtpm)
 {
@@ -376,10 +381,10 @@ static int ibmvtpm_reset_crq(struct ibmvtpm_dev *ibmvtpm)
 
 /**
  * tpm_ibmvtpm_resume - Resume from suspend
+ *
  * @dev:       device struct
  *
- * Return value:
- *     0
+ * Return: Always 0.
  */
 static int tpm_ibmvtpm_resume(struct device *dev)
 {
@@ -434,10 +439,10 @@ static const struct dev_pm_ops tpm_ibmvtpm_pm_ops = {
 
 /**
  * ibmvtpm_crq_get_next - Get next responded crq
- * @ibmvtpm    vtpm device struct
  *
- * Return value:
- *     vtpm crq pointer
+ * @ibmvtpm:   vtpm device struct
+ *
+ * Return: vtpm crq pointer or NULL.
  */
 static struct ibmvtpm_crq *ibmvtpm_crq_get_next(struct ibmvtpm_dev *ibmvtpm)
 {
@@ -455,11 +460,10 @@ static struct ibmvtpm_crq *ibmvtpm_crq_get_next(struct ibmvtpm_dev *ibmvtpm)
 
 /**
  * ibmvtpm_crq_process - Process responded crq
- * @crq                crq to be processed
- * @ibmvtpm    vtpm device struct
  *
- * Return value:
- *     Nothing
+ * @crq:       crq to be processed
+ * @ibmvtpm:   vtpm device struct
+ *
  */
 static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq,
                                struct ibmvtpm_dev *ibmvtpm)
@@ -528,6 +532,7 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq,
 
 /**
  * ibmvtpm_interrupt - Interrupt handler
+ *
  * @irq:               irq number to handle
  * @vtpm_instance:     vtpm that received interrupt
  *
@@ -554,12 +559,13 @@ static irqreturn_t ibmvtpm_interrupt(int irq, void *vtpm_instance)
 
 /**
  * tpm_ibmvtpm_probe - ibm vtpm initialize entry point
+ *
  * @vio_dev:   vio device struct
  * @id:                vio device id struct
  *
- * Return value:
- *     0 - Success
- *     Non-zero - Failure
+ * Return:
+ *     0 on success.
+ *     Non-zero on failure.
  */
 static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
                                   const struct vio_device_id *id)
@@ -671,11 +677,12 @@ static struct vio_driver ibmvtpm_driver = {
 };
 
 /**
- * ibmvtpm_module_init - Initialize ibm vtpm module
+ * ibmvtpm_module_init - Initialize ibm vtpm module.
  *
- * Return value:
- *     0 -Success
- *     Non-zero - Failure
+ *
+ * Return:
+ *     0 on success.
+ *     Non-zero on failure.
  */
 static int __init ibmvtpm_module_init(void)
 {
@@ -683,10 +690,7 @@ static int __init ibmvtpm_module_init(void)
 }
 
 /**
- * ibmvtpm_module_exit - Teardown ibm vtpm module
- *
- * Return value:
- *     Nothing
+ * ibmvtpm_module_exit - Tear down ibm vtpm module.
  */
 static void __exit ibmvtpm_module_exit(void)
 {
index 9ff0e072c4760a12d637fd9914cef50f43ddc18c..5d6cce74cd3fa3e7f71cf207454dd1e5e492e560 100644 (file)
@@ -278,6 +278,18 @@ static struct platform_driver nsc_drv = {
        },
 };
 
+static inline int tpm_read_index(int base, int index)
+{
+       outb(index, base);
+       return inb(base+1) & 0xFF;
+}
+
+static inline void tpm_write_index(int base, int index, int value)
+{
+       outb(index, base);
+       outb(value & 0xFF, base+1);
+}
+
 static int __init init_nsc(void)
 {
        int rc = 0;
index 7dee42d7b5e05c03f7d01c3ea3554ba89921f5c1..de57d4ac8901df9b2c2f5585db825efc0ae3587c 100644 (file)
@@ -27,6 +27,8 @@ int tpm_read_log_of(struct tpm_chip *chip)
        const u32 *sizep;
        const u64 *basep;
        struct tpm_bios_log *log;
+       u32 size;
+       u64 base;
 
        log = &chip->log;
        if (chip->dev.parent && chip->dev.parent->of_node)
@@ -41,18 +43,35 @@ int tpm_read_log_of(struct tpm_chip *chip)
        if (sizep == NULL || basep == NULL)
                return -EIO;
 
-       if (*sizep == 0) {
+       /*
+        * For both vtpm/tpm, firmware has log addr and log size in big
+        * endian format. But in case of vtpm, there is a method called
+        * sml-handover which is run during kernel init even before
+        * device tree is setup. This sml-handover function takes care
+        * of endianness and writes to sml-base and sml-size in little
+        * endian format. For this reason, vtpm doesn't need conversion
+        * but physical tpm needs the conversion.
+        */
+       if (of_property_match_string(np, "compatible", "IBM,vtpm") < 0) {
+               size = be32_to_cpup(sizep);
+               base = be64_to_cpup(basep);
+       } else {
+               size = *sizep;
+               base = *basep;
+       }
+
+       if (size == 0) {
                dev_warn(&chip->dev, "%s: Event log area empty\n", __func__);
                return -EIO;
        }
 
-       log->bios_event_log = kmalloc(*sizep, GFP_KERNEL);
+       log->bios_event_log = kmalloc(size, GFP_KERNEL);
        if (!log->bios_event_log)
                return -ENOMEM;
 
-       log->bios_event_log_end = log->bios_event_log + *sizep;
+       log->bios_event_log_end = log->bios_event_log + size;
 
-       memcpy(log->bios_event_log, __va(*basep), *sizep);
+       memcpy(log->bios_event_log, __va(base), size);
 
        return 0;
 }
index 0127af130cb12eef911e0f296e8b885e1f391723..c7e1384f1b08023d6470308a91f9210063861c14 100644 (file)
@@ -159,7 +159,7 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
                irq = tpm_info->irq;
 
        if (itpm)
-               phy->priv.flags |= TPM_TIS_ITPM_POSSIBLE;
+               phy->priv.flags |= TPM_TIS_ITPM_WORKAROUND;
 
        return tpm_tis_core_init(dev, &phy->priv, irq, &tpm_tcg,
                                 acpi_dev_handle);
@@ -432,7 +432,7 @@ err_pnp:
        acpi_bus_unregister_driver(&tis_acpi_driver);
 err_acpi:
 #endif
-       platform_device_unregister(force_pdev);
+       platform_driver_unregister(&tis_drv);
 err_platform:
        if (force_pdev)
                platform_device_unregister(force_pdev);
index 7993678954a2b7c2910233f77c6af1b5070af9cc..c0f296b5d41344c84f85a6a6a4c7040d91cb819c 100644 (file)
@@ -264,7 +264,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
        struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
        int rc, status, burstcnt;
        size_t count = 0;
-       bool itpm = priv->flags & TPM_TIS_ITPM_POSSIBLE;
+       bool itpm = priv->flags & TPM_TIS_ITPM_WORKAROUND;
 
        if (request_locality(chip, 0) < 0)
                return -EBUSY;
@@ -464,6 +464,9 @@ static int probe_itpm(struct tpm_chip *chip)
        size_t len = sizeof(cmd_getticks);
        u16 vendor;
 
+       if (priv->flags & TPM_TIS_ITPM_WORKAROUND)
+               return 0;
+
        rc = tpm_tis_read16(priv, TPM_DID_VID(0), &vendor);
        if (rc < 0)
                return rc;
@@ -479,12 +482,15 @@ static int probe_itpm(struct tpm_chip *chip)
        tpm_tis_ready(chip);
        release_locality(chip, priv->locality, 0);
 
+       priv->flags |= TPM_TIS_ITPM_WORKAROUND;
+
        rc = tpm_tis_send_data(chip, cmd_getticks, len);
-       if (rc == 0) {
+       if (rc == 0)
                dev_info(&chip->dev, "Detected an iTPM.\n");
-               rc = 1;
-       } else
+       else {
+               priv->flags &= ~TPM_TIS_ITPM_WORKAROUND;
                rc = -EFAULT;
+       }
 
 out:
        tpm_tis_ready(chip);
@@ -552,7 +558,8 @@ static int tpm_tis_gen_interrupt(struct tpm_chip *chip)
        if (chip->flags & TPM_CHIP_FLAG_TPM2)
                return tpm2_get_tpm_pt(chip, 0x100, &cap2, desc);
        else
-               return tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, desc);
+               return tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, desc,
+                                 0);
 }
 
 /* Register the IRQ and issue a command that will cause an interrupt. If an
@@ -740,15 +747,10 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
                 (chip->flags & TPM_CHIP_FLAG_TPM2) ? "2.0" : "1.2",
                 vendor >> 16, rid);
 
-       if (!(priv->flags & TPM_TIS_ITPM_POSSIBLE)) {
-               probe = probe_itpm(chip);
-               if (probe < 0) {
-                       rc = -ENODEV;
-                       goto out_err;
-               }
-
-               if (!!probe)
-                       priv->flags |= TPM_TIS_ITPM_POSSIBLE;
+       probe = probe_itpm(chip);
+       if (probe < 0) {
+               rc = -ENODEV;
+               goto out_err;
        }
 
        /* Figure out the capabilities */
index 9191aabbf9c2d9031fae874d720c7510480a59fb..e2212f021a02eb67db9be8bf479edaa97d8b516d 100644 (file)
@@ -80,7 +80,7 @@ enum tis_defaults {
 #define        TPM_RID(l)                      (0x0F04 | ((l) << 12))
 
 enum tpm_tis_flags {
-       TPM_TIS_ITPM_POSSIBLE           = BIT(0),
+       TPM_TIS_ITPM_WORKAROUND         = BIT(0),
 };
 
 struct tpm_tis_data {
index dbaad9c681e37c119831a63d20b71c43ac7078d2..5292e5768a7ebc16257edb9459f95fb2fdd3322b 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/acpi.h>
 #include <linux/freezer.h>
 
-#include <linux/module.h>
 #include <linux/spi/spi.h>
 #include <linux/gpio.h>
 #include <linux/of_irq.h>
index 5463b58af26e852d394bc4794e6522857fa16546..751059d2140a90dd1b8b4d00a50acc5b05f55004 100644 (file)
@@ -65,7 +65,12 @@ static void vtpm_proxy_delete_device(struct proxy_dev *proxy_dev);
 /**
  * vtpm_proxy_fops_read - Read TPM commands on 'server side'
  *
- * Return value:
+ * @filp: file pointer
+ * @buf: read buffer
+ * @count: number of bytes to read
+ * @off: offset
+ *
+ * Return:
  *     Number of bytes read or negative error code
  */
 static ssize_t vtpm_proxy_fops_read(struct file *filp, char __user *buf,
@@ -115,7 +120,12 @@ static ssize_t vtpm_proxy_fops_read(struct file *filp, char __user *buf,
 /**
  * vtpm_proxy_fops_write - Write TPM responses on 'server side'
  *
- * Return value:
+ * @filp: file pointer
+ * @buf: write buffer
+ * @count: number of bytes to write
+ * @off: offset
+ *
+ * Return:
  *     Number of bytes read or negative error value
  */
 static ssize_t vtpm_proxy_fops_write(struct file *filp, const char __user *buf,
@@ -155,10 +165,12 @@ static ssize_t vtpm_proxy_fops_write(struct file *filp, const char __user *buf,
 }
 
 /*
- * vtpm_proxy_fops_poll: Poll status on 'server side'
+ * vtpm_proxy_fops_poll - Poll status on 'server side'
+ *
+ * @filp: file pointer
+ * @wait: poll table
  *
- * Return value:
- *      Poll flags
+ * Return: Poll flags
  */
 static unsigned int vtpm_proxy_fops_poll(struct file *filp, poll_table *wait)
 {
@@ -185,6 +197,8 @@ static unsigned int vtpm_proxy_fops_poll(struct file *filp, poll_table *wait)
 /*
  * vtpm_proxy_fops_open - Open vTPM device on 'server side'
  *
+ * @filp: file pointer
+ *
  * Called when setting up the anonymous file descriptor
  */
 static void vtpm_proxy_fops_open(struct file *filp)
@@ -196,8 +210,9 @@ static void vtpm_proxy_fops_open(struct file *filp)
 
 /**
  * vtpm_proxy_fops_undo_open - counter-part to vtpm_fops_open
+ *       Call to undo vtpm_proxy_fops_open
  *
- * Call to undo vtpm_proxy_fops_open
+ *@proxy_dev: tpm proxy device
  */
 static void vtpm_proxy_fops_undo_open(struct proxy_dev *proxy_dev)
 {
@@ -212,9 +227,11 @@ static void vtpm_proxy_fops_undo_open(struct proxy_dev *proxy_dev)
 }
 
 /*
- * vtpm_proxy_fops_release: Close 'server side'
+ * vtpm_proxy_fops_release - Close 'server side'
  *
- * Return value:
+ * @inode: inode
+ * @filp: file pointer
+ * Return:
  *      Always returns 0.
  */
 static int vtpm_proxy_fops_release(struct inode *inode, struct file *filp)
@@ -245,7 +262,10 @@ static const struct file_operations vtpm_proxy_fops = {
 /*
  * Called when core TPM driver reads TPM responses from 'server side'
  *
- * Return value:
+ * @chip: tpm chip to use
+ * @buf: receive buffer
+ * @count: bytes to read
+ * Return:
  *      Number of TPM response bytes read, negative error value otherwise
  */
 static int vtpm_proxy_tpm_op_recv(struct tpm_chip *chip, u8 *buf, size_t count)
@@ -282,7 +302,11 @@ out:
 /*
  * Called when core TPM driver forwards TPM requests to 'server side'.
  *
- * Return value:
+ * @chip: tpm chip to use
+ * @buf: send buffer
+ * @count: bytes to send
+ *
+ * Return:
  *      0 in case of success, negative error value otherwise.
  */
 static int vtpm_proxy_tpm_op_send(struct tpm_chip *chip, u8 *buf, size_t count)
@@ -442,7 +466,7 @@ static inline void vtpm_proxy_delete_proxy_dev(struct proxy_dev *proxy_dev)
 /*
  * Create a /dev/tpm%d and 'server side' file descriptor pair
  *
- * Return value:
+ * Return:
  *      Returns file pointer on success, an error value otherwise
  */
 static struct file *vtpm_proxy_create_device(
@@ -571,7 +595,7 @@ static long vtpmx_ioc_new_dev(struct file *file, unsigned int ioctl,
 /*
  * vtpmx_fops_ioctl: ioctl on /dev/vtpmx
  *
- * Return value:
+ * Return:
  *      Returns 0 on success, a negative error code otherwise.
  */
 static long vtpmx_fops_ioctl(struct file *f, unsigned int ioctl,
index 5aaa268f3a784a8aa0eb8a2889deeef6d071cccb..656e8af95d5282f8dbce5e4bd6e277c368092a81 100644 (file)
@@ -289,7 +289,6 @@ static int tpmfront_probe(struct xenbus_device *dev,
                const struct xenbus_device_id *id)
 {
        struct tpm_private *priv;
-       struct tpm_chip *chip;
        int rv;
 
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
@@ -306,7 +305,6 @@ static int tpmfront_probe(struct xenbus_device *dev,
 
        rv = setup_ring(dev, priv);
        if (rv) {
-               chip = dev_get_drvdata(&dev->dev);
                ring_free(priv);
                return rv;
        }
index f010562534ebe056bc67ed57bad8f9a48c9458ff..2c44aeb0b97c7b437fa79b2cdf82f8ee9df577b0 100644 (file)
@@ -633,16 +633,12 @@ static int find_lut_index_for_rate(struct tegra_dfll *td, unsigned long rate)
        struct dev_pm_opp *opp;
        int i, uv;
 
-       rcu_read_lock();
-
        opp = dev_pm_opp_find_freq_ceil(td->soc->dev, &rate);
-       if (IS_ERR(opp)) {
-               rcu_read_unlock();
+       if (IS_ERR(opp))
                return PTR_ERR(opp);
-       }
-       uv = dev_pm_opp_get_voltage(opp);
 
-       rcu_read_unlock();
+       uv = dev_pm_opp_get_voltage(opp);
+       dev_pm_opp_put(opp);
 
        for (i = 0; i < td->i2c_lut_size; i++) {
                if (regulator_list_voltage(td->vdd_reg, td->i2c_lut[i]) == uv)
@@ -1440,8 +1436,6 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td)
        struct dev_pm_opp *opp;
        int lut;
 
-       rcu_read_lock();
-
        rate = ULONG_MAX;
        opp = dev_pm_opp_find_freq_floor(td->soc->dev, &rate);
        if (IS_ERR(opp)) {
@@ -1449,6 +1443,7 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td)
                goto out;
        }
        v_max = dev_pm_opp_get_voltage(opp);
+       dev_pm_opp_put(opp);
 
        v = td->soc->cvb->min_millivolts * 1000;
        lut = find_vdd_map_entry_exact(td, v);
@@ -1465,6 +1460,8 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td)
                if (v_opp <= td->soc->cvb->min_millivolts * 1000)
                        td->dvco_rate_min = dev_pm_opp_get_freq(opp);
 
+               dev_pm_opp_put(opp);
+
                for (;;) {
                        v += max(1, (v_max - v) / (MAX_DFLL_VOLTAGES - j));
                        if (v >= v_opp)
@@ -1496,8 +1493,6 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td)
                ret = 0;
 
 out:
-       rcu_read_unlock();
-
        return ret;
 }
 
index d8b164a7c4e517f8da42507ecaf979043dace3d8..4ebae43118effe98f4763618cbd0777060e8e134 100644 (file)
@@ -37,14 +37,6 @@ config CPU_FREQ_STAT
 
          If in doubt, say N.
 
-config CPU_FREQ_STAT_DETAILS
-       bool "CPU frequency transition statistics details"
-       depends on CPU_FREQ_STAT
-       help
-         Show detailed CPU frequency transition table in sysfs.
-
-         If in doubt, say N.
-
 choice
        prompt "Default CPUFreq governor"
        default CPU_FREQ_DEFAULT_GOV_USERSPACE if ARM_SA1100_CPUFREQ || ARM_SA1110_CPUFREQ
@@ -271,6 +263,16 @@ config IA64_ACPI_CPUFREQ
 endif
 
 if MIPS
+config BMIPS_CPUFREQ
+       tristate "BMIPS CPUfreq Driver"
+       help
+         This option adds a CPUfreq driver for BMIPS processors with
+         support for configurable CPU frequency.
+
+         For now, BMIPS5 chips are supported (such as the Broadcom 7425).
+
+         If in doubt, say N.
+
 config LOONGSON2_CPUFREQ
        tristate "Loongson2 CPUFreq Driver"
        help
@@ -332,7 +334,7 @@ endif
 
 config QORIQ_CPUFREQ
        tristate "CPU frequency scaling driver for Freescale QorIQ SoCs"
-       depends on OF && COMMON_CLK && (PPC_E500MC || ARM)
+       depends on OF && COMMON_CLK && (PPC_E500MC || ARM || ARM64)
        depends on !CPU_THERMAL || THERMAL
        select CLK_QORIQ
        help
index 920c469f3953e890bd747413750be8ad6a4352e2..74fa5c5904d388444f357bc7b7e9e1737a45fd29 100644 (file)
@@ -247,6 +247,17 @@ config ARM_TEGRA124_CPUFREQ
        help
          This adds the CPUFreq driver support for Tegra124 SOCs.
 
+config ARM_TI_CPUFREQ
+       bool "Texas Instruments CPUFreq support"
+       depends on ARCH_OMAP2PLUS
+       help
+         This driver enables valid OPPs on the running platform based on
+         values contained within the SoC in use. Enable this in order to
+         use the cpufreq-dt driver on all Texas Instruments platforms that
+         provide dt based operating-points-v2 tables with opp-supported-hw
+         data provided. Required for cpufreq support on AM335x, AM437x,
+         DRA7x, and AM57x platforms.
+
 config ARM_PXA2xx_CPUFREQ
        tristate "Intel PXA2xx CPUfreq driver"
        depends on PXA27x || PXA25x
@@ -257,7 +268,7 @@ config ARM_PXA2xx_CPUFREQ
 
 config ACPI_CPPC_CPUFREQ
        tristate "CPUFreq driver based on the ACPI CPPC spec"
-       depends on ACPI
+       depends on ACPI_PROCESSOR
        select ACPI_CPPC_LIB
        default n
        help
index 1e46c3918e7a630647d744549a46c184e5e8fd80..9f5a8045f36d37710c8196e8ddf1145817664f05 100644 (file)
@@ -77,6 +77,7 @@ obj-$(CONFIG_ARM_SPEAR_CPUFREQ)               += spear-cpufreq.o
 obj-$(CONFIG_ARM_STI_CPUFREQ)          += sti-cpufreq.o
 obj-$(CONFIG_ARM_TEGRA20_CPUFREQ)      += tegra20-cpufreq.o
 obj-$(CONFIG_ARM_TEGRA124_CPUFREQ)     += tegra124-cpufreq.o
+obj-$(CONFIG_ARM_TI_CPUFREQ)           += ti-cpufreq.o
 obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o
 obj-$(CONFIG_ACPI_CPPC_CPUFREQ) += cppc_cpufreq.o
 obj-$(CONFIG_MACH_MVEBU_V7)            += mvebu-cpufreq.o
@@ -98,6 +99,7 @@ obj-$(CONFIG_POWERNV_CPUFREQ)         += powernv-cpufreq.o
 # Other platform drivers
 obj-$(CONFIG_AVR32_AT32AP_CPUFREQ)     += at32ap-cpufreq.o
 obj-$(CONFIG_BFIN_CPU_FREQ)            += blackfin-cpufreq.o
+obj-$(CONFIG_BMIPS_CPUFREQ)            += bmips-cpufreq.o
 obj-$(CONFIG_CRIS_MACH_ARTPEC3)                += cris-artpec3-cpufreq.o
 obj-$(CONFIG_ETRAXFS)                  += cris-etraxfs-cpufreq.o
 obj-$(CONFIG_IA64_ACPI_CPUFREQ)                += ia64-acpi-cpufreq.o
diff --git a/drivers/cpufreq/bmips-cpufreq.c b/drivers/cpufreq/bmips-cpufreq.c
new file mode 100644 (file)
index 0000000..1653151
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * CPU frequency scaling for Broadcom BMIPS SoCs
+ *
+ * Copyright (c) 2017 Broadcom
+ *
+ * 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 "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/cpufreq.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+
+/* for mips_hpt_frequency */
+#include <asm/time.h>
+
+#define BMIPS_CPUFREQ_PREFIX   "bmips"
+#define BMIPS_CPUFREQ_NAME     BMIPS_CPUFREQ_PREFIX "-cpufreq"
+
+#define TRANSITION_LATENCY     (25 * 1000)     /* 25 us */
+
+#define BMIPS5_CLK_DIV_SET_SHIFT       0x7
+#define BMIPS5_CLK_DIV_SHIFT           0x4
+#define BMIPS5_CLK_DIV_MASK            0xf
+
+enum bmips_type {
+       BMIPS5000,
+       BMIPS5200,
+};
+
+struct cpufreq_compat {
+       const char *compatible;
+       unsigned int bmips_type;
+       unsigned int clk_mult;
+       unsigned int max_freqs;
+};
+
+#define BMIPS(c, t, m, f) { \
+       .compatible = c, \
+       .bmips_type = (t), \
+       .clk_mult = (m), \
+       .max_freqs = (f), \
+}
+
+static struct cpufreq_compat bmips_cpufreq_compat[] = {
+       BMIPS("brcm,bmips5000", BMIPS5000, 8, 4),
+       BMIPS("brcm,bmips5200", BMIPS5200, 8, 4),
+       { }
+};
+
+static struct cpufreq_compat *priv;
+
+static int htp_freq_to_cpu_freq(unsigned int clk_mult)
+{
+       return mips_hpt_frequency * clk_mult / 1000;
+}
+
+static struct cpufreq_frequency_table *
+bmips_cpufreq_get_freq_table(const struct cpufreq_policy *policy)
+{
+       struct cpufreq_frequency_table *table;
+       unsigned long cpu_freq;
+       int i;
+
+       cpu_freq = htp_freq_to_cpu_freq(priv->clk_mult);
+
+       table = kmalloc((priv->max_freqs + 1) * sizeof(*table), GFP_KERNEL);
+       if (!table)
+               return ERR_PTR(-ENOMEM);
+
+       for (i = 0; i < priv->max_freqs; i++) {
+               table[i].frequency = cpu_freq / (1 << i);
+               table[i].driver_data = i;
+       }
+       table[i].frequency = CPUFREQ_TABLE_END;
+
+       return table;
+}
+
+static unsigned int bmips_cpufreq_get(unsigned int cpu)
+{
+       unsigned int div;
+       uint32_t mode;
+
+       switch (priv->bmips_type) {
+       case BMIPS5200:
+       case BMIPS5000:
+               mode = read_c0_brcm_mode();
+               div = ((mode >> BMIPS5_CLK_DIV_SHIFT) & BMIPS5_CLK_DIV_MASK);
+               break;
+       default:
+               div = 0;
+       }
+
+       return htp_freq_to_cpu_freq(priv->clk_mult) / (1 << div);
+}
+
+static int bmips_cpufreq_target_index(struct cpufreq_policy *policy,
+                                     unsigned int index)
+{
+       unsigned int div = policy->freq_table[index].driver_data;
+
+       switch (priv->bmips_type) {
+       case BMIPS5200:
+       case BMIPS5000:
+               change_c0_brcm_mode(BMIPS5_CLK_DIV_MASK << BMIPS5_CLK_DIV_SHIFT,
+                                   (1 << BMIPS5_CLK_DIV_SET_SHIFT) |
+                                   (div << BMIPS5_CLK_DIV_SHIFT));
+               break;
+       default:
+               return -ENOTSUPP;
+       }
+
+       return 0;
+}
+
+static int bmips_cpufreq_exit(struct cpufreq_policy *policy)
+{
+       kfree(policy->freq_table);
+
+       return 0;
+}
+
+static int bmips_cpufreq_init(struct cpufreq_policy *policy)
+{
+       struct cpufreq_frequency_table *freq_table;
+       int ret;
+
+       freq_table = bmips_cpufreq_get_freq_table(policy);
+       if (IS_ERR(freq_table)) {
+               ret = PTR_ERR(freq_table);
+               pr_err("%s: couldn't determine frequency table (%d).\n",
+                       BMIPS_CPUFREQ_NAME, ret);
+               return ret;
+       }
+
+       ret = cpufreq_generic_init(policy, freq_table, TRANSITION_LATENCY);
+       if (ret)
+               bmips_cpufreq_exit(policy);
+       else
+               pr_info("%s: registered\n", BMIPS_CPUFREQ_NAME);
+
+       return ret;
+}
+
+static struct cpufreq_driver bmips_cpufreq_driver = {
+       .flags          = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
+       .verify         = cpufreq_generic_frequency_table_verify,
+       .target_index   = bmips_cpufreq_target_index,
+       .get            = bmips_cpufreq_get,
+       .init           = bmips_cpufreq_init,
+       .exit           = bmips_cpufreq_exit,
+       .attr           = cpufreq_generic_attr,
+       .name           = BMIPS_CPUFREQ_PREFIX,
+};
+
+static int __init bmips_cpufreq_probe(void)
+{
+       struct cpufreq_compat *cc;
+       struct device_node *np;
+
+       for (cc = bmips_cpufreq_compat; cc->compatible; cc++) {
+               np = of_find_compatible_node(NULL, "cpu", cc->compatible);
+               if (np) {
+                       of_node_put(np);
+                       priv = cc;
+                       break;
+               }
+       }
+
+       /* We hit the guard element of the array. No compatible CPU found. */
+       if (!cc->compatible)
+               return -ENODEV;
+
+       return cpufreq_register_driver(&bmips_cpufreq_driver);
+}
+device_initcall(bmips_cpufreq_probe);
+
+MODULE_AUTHOR("Markus Mayer <mmayer@broadcom.com>");
+MODULE_DESCRIPTION("CPUfreq driver for Broadcom BMIPS SoCs");
+MODULE_LICENSE("GPL");
index c94360671f41e54db9861a8ca86a8da7ddc2e5fe..7281a2c19c362177a57a962f8d587ef40764b92e 100644 (file)
@@ -878,7 +878,6 @@ unmap_intr_base:
        iounmap(priv->avs_intr_base);
 unmap_base:
        iounmap(priv->base);
-       platform_set_drvdata(pdev, NULL);
 
        return ret;
 }
@@ -1042,7 +1041,6 @@ static int brcm_avs_cpufreq_remove(struct platform_device *pdev)
        priv = platform_get_drvdata(pdev);
        iounmap(priv->base);
        iounmap(priv->avs_intr_base);
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
index 7fcaf26e8f819b7665f6e9bf83c07a1b705b1d65..921b4a6c3d16bece3177b1e407883c8df9bcfa4a 100644 (file)
@@ -87,8 +87,6 @@ static const struct of_device_id machines[] __initconst = {
        { .compatible = "socionext,uniphier-ld11", },
        { .compatible = "socionext,uniphier-ld20", },
 
-       { .compatible = "ti,am33xx", },
-       { .compatible = "ti,dra7", },
        { .compatible = "ti,omap2", },
        { .compatible = "ti,omap3", },
        { .compatible = "ti,omap4", },
index 269013311e791484dc5272cd6b5d38623fc3757c..c943787d761ee4e3172a661fb5a15ce7bae4002a 100644 (file)
@@ -148,7 +148,6 @@ static int cpufreq_init(struct cpufreq_policy *policy)
        struct private_data *priv;
        struct device *cpu_dev;
        struct clk *cpu_clk;
-       struct dev_pm_opp *suspend_opp;
        unsigned int transition_latency;
        bool fallback = false;
        const char *name;
@@ -252,11 +251,7 @@ static int cpufreq_init(struct cpufreq_policy *policy)
        policy->driver_data = priv;
        policy->clk = cpu_clk;
 
-       rcu_read_lock();
-       suspend_opp = dev_pm_opp_get_suspend_opp(cpu_dev);
-       if (suspend_opp)
-               policy->suspend_freq = dev_pm_opp_get_freq(suspend_opp) / 1000;
-       rcu_read_unlock();
+       policy->suspend_freq = dev_pm_opp_get_suspend_opp_freq(cpu_dev) / 1000;
 
        ret = cpufreq_table_validate_and_show(policy, freq_table);
        if (ret) {
index 3e9b319a2e79a50aa19fe12f62c7e16e2a92cafa..a475432818642fee4547699011ba4cf5aa619f3a 100644 (file)
@@ -1078,15 +1078,11 @@ err_free_policy:
        return NULL;
 }
 
-static void cpufreq_policy_put_kobj(struct cpufreq_policy *policy, bool notify)
+static void cpufreq_policy_put_kobj(struct cpufreq_policy *policy)
 {
        struct kobject *kobj;
        struct completion *cmp;
 
-       if (notify)
-               blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
-                                            CPUFREQ_REMOVE_POLICY, policy);
-
        down_write(&policy->rwsem);
        cpufreq_stats_free_table(policy);
        kobj = &policy->kobj;
@@ -1104,7 +1100,7 @@ static void cpufreq_policy_put_kobj(struct cpufreq_policy *policy, bool notify)
        pr_debug("wait complete\n");
 }
 
-static void cpufreq_policy_free(struct cpufreq_policy *policy, bool notify)
+static void cpufreq_policy_free(struct cpufreq_policy *policy)
 {
        unsigned long flags;
        int cpu;
@@ -1117,7 +1113,7 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy, bool notify)
                per_cpu(cpufreq_cpu_data, cpu) = NULL;
        write_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
-       cpufreq_policy_put_kobj(policy, notify);
+       cpufreq_policy_put_kobj(policy);
        free_cpumask_var(policy->real_cpus);
        free_cpumask_var(policy->related_cpus);
        free_cpumask_var(policy->cpus);
@@ -1170,8 +1166,6 @@ static int cpufreq_online(unsigned int cpu)
        if (new_policy) {
                /* related_cpus should at least include policy->cpus. */
                cpumask_copy(policy->related_cpus, policy->cpus);
-               /* Clear mask of registered CPUs */
-               cpumask_clear(policy->real_cpus);
        }
 
        /*
@@ -1244,17 +1238,12 @@ static int cpufreq_online(unsigned int cpu)
                        goto out_exit_policy;
 
                cpufreq_stats_create_table(policy);
-               blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
-                               CPUFREQ_CREATE_POLICY, policy);
 
                write_lock_irqsave(&cpufreq_driver_lock, flags);
                list_add(&policy->policy_list, &cpufreq_policy_list);
                write_unlock_irqrestore(&cpufreq_driver_lock, flags);
        }
 
-       blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
-                                    CPUFREQ_START, policy);
-
        ret = cpufreq_init_policy(policy);
        if (ret) {
                pr_err("%s: Failed to initialize policy for cpu: %d (%d)\n",
@@ -1282,7 +1271,7 @@ out_exit_policy:
        if (cpufreq_driver->exit)
                cpufreq_driver->exit(policy);
 out_free_policy:
-       cpufreq_policy_free(policy, !new_policy);
+       cpufreq_policy_free(policy);
        return ret;
 }
 
@@ -1403,7 +1392,7 @@ static void cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
        remove_cpu_dev_symlink(policy, dev);
 
        if (cpumask_empty(policy->real_cpus))
-               cpufreq_policy_free(policy, true);
+               cpufreq_policy_free(policy);
 }
 
 /**
index 17048bbec287f5b8307197d765b73b6cafe633b1..f570ead624547e111d74911e722b31aabcfce117 100644 (file)
@@ -24,9 +24,7 @@ struct cpufreq_stats {
        unsigned int last_index;
        u64 *time_in_state;
        unsigned int *freq_table;
-#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
        unsigned int *trans_table;
-#endif
 };
 
 static int cpufreq_stats_update(struct cpufreq_stats *stats)
@@ -45,9 +43,7 @@ static void cpufreq_stats_clear_table(struct cpufreq_stats *stats)
        unsigned int count = stats->max_state;
 
        memset(stats->time_in_state, 0, count * sizeof(u64));
-#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
        memset(stats->trans_table, 0, count * count * sizeof(int));
-#endif
        stats->last_time = get_jiffies_64();
        stats->total_trans = 0;
 }
@@ -83,7 +79,6 @@ static ssize_t store_reset(struct cpufreq_policy *policy, const char *buf,
        return count;
 }
 
-#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
 static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf)
 {
        struct cpufreq_stats *stats = policy->stats;
@@ -128,7 +123,6 @@ static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf)
        return len;
 }
 cpufreq_freq_attr_ro(trans_table);
-#endif
 
 cpufreq_freq_attr_ro(total_trans);
 cpufreq_freq_attr_ro(time_in_state);
@@ -138,9 +132,7 @@ static struct attribute *default_attrs[] = {
        &total_trans.attr,
        &time_in_state.attr,
        &reset.attr,
-#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
        &trans_table.attr,
-#endif
        NULL
 };
 static struct attribute_group stats_attr_group = {
@@ -199,9 +191,7 @@ void cpufreq_stats_create_table(struct cpufreq_policy *policy)
 
        alloc_size = count * sizeof(int) + count * sizeof(u64);
 
-#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
        alloc_size += count * count * sizeof(int);
-#endif
 
        /* Allocate memory for time_in_state/freq_table/trans_table in one go */
        stats->time_in_state = kzalloc(alloc_size, GFP_KERNEL);
@@ -210,9 +200,7 @@ void cpufreq_stats_create_table(struct cpufreq_policy *policy)
 
        stats->freq_table = (unsigned int *)(stats->time_in_state + count);
 
-#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
        stats->trans_table = stats->freq_table + count;
-#endif
 
        stats->max_state = count;
 
@@ -258,8 +246,6 @@ void cpufreq_stats_record_transition(struct cpufreq_policy *policy,
        cpufreq_stats_update(stats);
 
        stats->last_index = new_index;
-#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
        stats->trans_table[old_index * stats->max_state + new_index]++;
-#endif
        stats->total_trans++;
 }
index c0f3373706f4f04cd6ec197cb0791c2b3b7765de..9180d34cc9fce09be6255559e8d85b03be5c35a6 100644 (file)
@@ -118,12 +118,10 @@ static int init_div_table(void)
        unsigned int tmp, clk_div, ema_div, freq, volt_id;
        struct dev_pm_opp *opp;
 
-       rcu_read_lock();
        cpufreq_for_each_entry(pos, freq_tbl) {
                opp = dev_pm_opp_find_freq_exact(dvfs_info->dev,
                                        pos->frequency * 1000, true);
                if (IS_ERR(opp)) {
-                       rcu_read_unlock();
                        dev_err(dvfs_info->dev,
                                "failed to find valid OPP for %u KHZ\n",
                                pos->frequency);
@@ -140,6 +138,7 @@ static int init_div_table(void)
 
                /* Calculate EMA */
                volt_id = dev_pm_opp_get_voltage(opp);
+
                volt_id = (MAX_VOLTAGE - volt_id) / VOLTAGE_STEP;
                if (volt_id < PMIC_HIGH_VOLT) {
                        ema_div = (CPUEMA_HIGH << P0_7_CPUEMA_SHIFT) |
@@ -157,9 +156,9 @@ static int init_div_table(void)
 
                __raw_writel(tmp, dvfs_info->base + XMU_PMU_P0_7 + 4 *
                                                (pos - freq_tbl));
+               dev_pm_opp_put(opp);
        }
 
-       rcu_read_unlock();
        return 0;
 }
 
index ef1fa8145419cd1d2aa277f3dd20c9645e698203..7719b02e04f50f433e52bf4764461d4df6c2017b 100644 (file)
@@ -53,16 +53,15 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
        freq_hz = new_freq * 1000;
        old_freq = clk_get_rate(arm_clk) / 1000;
 
-       rcu_read_lock();
        opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
        if (IS_ERR(opp)) {
-               rcu_read_unlock();
                dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz);
                return PTR_ERR(opp);
        }
 
        volt = dev_pm_opp_get_voltage(opp);
-       rcu_read_unlock();
+       dev_pm_opp_put(opp);
+
        volt_old = regulator_get_voltage(arm_reg);
 
        dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n",
@@ -321,14 +320,15 @@ soc_opp_out:
         * freq_table initialised from OPP is therefore sorted in the
         * same order.
         */
-       rcu_read_lock();
        opp = dev_pm_opp_find_freq_exact(cpu_dev,
                                  freq_table[0].frequency * 1000, true);
        min_volt = dev_pm_opp_get_voltage(opp);
+       dev_pm_opp_put(opp);
        opp = dev_pm_opp_find_freq_exact(cpu_dev,
                                  freq_table[--num].frequency * 1000, true);
        max_volt = dev_pm_opp_get_voltage(opp);
-       rcu_read_unlock();
+       dev_pm_opp_put(opp);
+
        ret = regulator_set_voltage_time(arm_reg, min_volt, max_volt);
        if (ret > 0)
                transition_latency += ret * 1000;
index 50bd6d987fc3a0bf2e1a344a44b9b41d084899cb..eb0f7fb716858992f00bb4a02285b3d0189b1f07 100644 (file)
@@ -358,6 +358,8 @@ static struct pstate_funcs pstate_funcs __read_mostly;
 static int hwp_active __read_mostly;
 static bool per_cpu_limits __read_mostly;
 
+static bool driver_registered __read_mostly;
+
 #ifdef CONFIG_ACPI
 static bool acpi_ppc;
 #endif
@@ -394,6 +396,7 @@ static struct perf_limits *limits = &performance_limits;
 static struct perf_limits *limits = &powersave_limits;
 #endif
 
+static DEFINE_MUTEX(intel_pstate_driver_lock);
 static DEFINE_MUTEX(intel_pstate_limits_lock);
 
 #ifdef CONFIG_ACPI
@@ -538,7 +541,6 @@ static void intel_pstate_exit_perf_limits(struct cpufreq_policy *policy)
 
        acpi_processor_unregister_performance(policy->cpu);
 }
-
 #else
 static inline void intel_pstate_init_acpi_perf_limits(struct cpufreq_policy *policy)
 {
@@ -873,7 +875,10 @@ static void intel_pstate_hwp_set(struct cpufreq_policy *policy)
 
                rdmsrl_on_cpu(cpu, MSR_HWP_CAPABILITIES, &cap);
                hw_min = HWP_LOWEST_PERF(cap);
-               hw_max = HWP_HIGHEST_PERF(cap);
+               if (limits->no_turbo)
+                       hw_max = HWP_GUARANTEED_PERF(cap);
+               else
+                       hw_max = HWP_HIGHEST_PERF(cap);
                range = hw_max - hw_min;
 
                max_perf_pct = perf_limits->max_perf_pct;
@@ -887,11 +892,6 @@ static void intel_pstate_hwp_set(struct cpufreq_policy *policy)
 
                adj_range = max_perf_pct * range / 100;
                max = hw_min + adj_range;
-               if (limits->no_turbo) {
-                       hw_max = HWP_GUARANTEED_PERF(cap);
-                       if (hw_max < max)
-                               max = hw_max;
-               }
 
                value &= ~HWP_MAX_PERF(~0L);
                value |= HWP_MAX_PERF(max);
@@ -1007,35 +1007,57 @@ static int pid_param_get(void *data, u64 *val)
 }
 DEFINE_SIMPLE_ATTRIBUTE(fops_pid_param, pid_param_get, pid_param_set, "%llu\n");
 
+static struct dentry *debugfs_parent;
+
 struct pid_param {
        char *name;
        void *value;
+       struct dentry *dentry;
 };
 
 static struct pid_param pid_files[] = {
-       {"sample_rate_ms", &pid_params.sample_rate_ms},
-       {"d_gain_pct", &pid_params.d_gain_pct},
-       {"i_gain_pct", &pid_params.i_gain_pct},
-       {"deadband", &pid_params.deadband},
-       {"setpoint", &pid_params.setpoint},
-       {"p_gain_pct", &pid_params.p_gain_pct},
-       {NULL, NULL}
+       {"sample_rate_ms", &pid_params.sample_rate_ms},
+       {"d_gain_pct", &pid_params.d_gain_pct},
+       {"i_gain_pct", &pid_params.i_gain_pct},
+       {"deadband", &pid_params.deadband},
+       {"setpoint", &pid_params.setpoint},
+       {"p_gain_pct", &pid_params.p_gain_pct},
+       {NULL, NULL}
 };
 
-static void __init intel_pstate_debug_expose_params(void)
+static void intel_pstate_debug_expose_params(void)
 {
-       struct dentry *debugfs_parent;
-       int i = 0;
+       int i;
 
        debugfs_parent = debugfs_create_dir("pstate_snb", NULL);
        if (IS_ERR_OR_NULL(debugfs_parent))
                return;
-       while (pid_files[i].name) {
-               debugfs_create_file(pid_files[i].name, 0660,
-                                   debugfs_parent, pid_files[i].value,
-                                   &fops_pid_param);
-               i++;
+
+       for (i = 0; pid_files[i].name; i++) {
+               struct dentry *dentry;
+
+               dentry = debugfs_create_file(pid_files[i].name, 0660,
+                                            debugfs_parent, pid_files[i].value,
+                                            &fops_pid_param);
+               if (!IS_ERR(dentry))
+                       pid_files[i].dentry = dentry;
+       }
+}
+
+static void intel_pstate_debug_hide_params(void)
+{
+       int i;
+
+       if (IS_ERR_OR_NULL(debugfs_parent))
+               return;
+
+       for (i = 0; pid_files[i].name; i++) {
+               debugfs_remove(pid_files[i].dentry);
+               pid_files[i].dentry = NULL;
        }
+
+       debugfs_remove(debugfs_parent);
+       debugfs_parent = NULL;
 }
 
 /************************** debugfs end ************************/
@@ -1048,6 +1070,34 @@ static void __init intel_pstate_debug_expose_params(void)
                return sprintf(buf, "%u\n", limits->object);            \
        }
 
+static ssize_t intel_pstate_show_status(char *buf);
+static int intel_pstate_update_status(const char *buf, size_t size);
+
+static ssize_t show_status(struct kobject *kobj,
+                          struct attribute *attr, char *buf)
+{
+       ssize_t ret;
+
+       mutex_lock(&intel_pstate_driver_lock);
+       ret = intel_pstate_show_status(buf);
+       mutex_unlock(&intel_pstate_driver_lock);
+
+       return ret;
+}
+
+static ssize_t store_status(struct kobject *a, struct attribute *b,
+                           const char *buf, size_t count)
+{
+       char *p = memchr(buf, '\n', count);
+       int ret;
+
+       mutex_lock(&intel_pstate_driver_lock);
+       ret = intel_pstate_update_status(buf, p ? p - buf : count);
+       mutex_unlock(&intel_pstate_driver_lock);
+
+       return ret < 0 ? ret : count;
+}
+
 static ssize_t show_turbo_pct(struct kobject *kobj,
                                struct attribute *attr, char *buf)
 {
@@ -1055,12 +1105,22 @@ static ssize_t show_turbo_pct(struct kobject *kobj,
        int total, no_turbo, turbo_pct;
        uint32_t turbo_fp;
 
+       mutex_lock(&intel_pstate_driver_lock);
+
+       if (!driver_registered) {
+               mutex_unlock(&intel_pstate_driver_lock);
+               return -EAGAIN;
+       }
+
        cpu = all_cpu_data[0];
 
        total = cpu->pstate.turbo_pstate - cpu->pstate.min_pstate + 1;
        no_turbo = cpu->pstate.max_pstate - cpu->pstate.min_pstate + 1;
        turbo_fp = div_fp(no_turbo, total);
        turbo_pct = 100 - fp_toint(mul_fp(turbo_fp, int_tofp(100)));
+
+       mutex_unlock(&intel_pstate_driver_lock);
+
        return sprintf(buf, "%u\n", turbo_pct);
 }
 
@@ -1070,8 +1130,18 @@ static ssize_t show_num_pstates(struct kobject *kobj,
        struct cpudata *cpu;
        int total;
 
+       mutex_lock(&intel_pstate_driver_lock);
+
+       if (!driver_registered) {
+               mutex_unlock(&intel_pstate_driver_lock);
+               return -EAGAIN;
+       }
+
        cpu = all_cpu_data[0];
        total = cpu->pstate.turbo_pstate - cpu->pstate.min_pstate + 1;
+
+       mutex_unlock(&intel_pstate_driver_lock);
+
        return sprintf(buf, "%u\n", total);
 }
 
@@ -1080,12 +1150,21 @@ static ssize_t show_no_turbo(struct kobject *kobj,
 {
        ssize_t ret;
 
+       mutex_lock(&intel_pstate_driver_lock);
+
+       if (!driver_registered) {
+               mutex_unlock(&intel_pstate_driver_lock);
+               return -EAGAIN;
+       }
+
        update_turbo_state();
        if (limits->turbo_disabled)
                ret = sprintf(buf, "%u\n", limits->turbo_disabled);
        else
                ret = sprintf(buf, "%u\n", limits->no_turbo);
 
+       mutex_unlock(&intel_pstate_driver_lock);
+
        return ret;
 }
 
@@ -1099,12 +1178,20 @@ static ssize_t store_no_turbo(struct kobject *a, struct attribute *b,
        if (ret != 1)
                return -EINVAL;
 
+       mutex_lock(&intel_pstate_driver_lock);
+
+       if (!driver_registered) {
+               mutex_unlock(&intel_pstate_driver_lock);
+               return -EAGAIN;
+       }
+
        mutex_lock(&intel_pstate_limits_lock);
 
        update_turbo_state();
        if (limits->turbo_disabled) {
                pr_warn("Turbo disabled by BIOS or unavailable on processor\n");
                mutex_unlock(&intel_pstate_limits_lock);
+               mutex_unlock(&intel_pstate_driver_lock);
                return -EPERM;
        }
 
@@ -1114,6 +1201,8 @@ static ssize_t store_no_turbo(struct kobject *a, struct attribute *b,
 
        intel_pstate_update_policies();
 
+       mutex_unlock(&intel_pstate_driver_lock);
+
        return count;
 }
 
@@ -1127,6 +1216,13 @@ static ssize_t store_max_perf_pct(struct kobject *a, struct attribute *b,
        if (ret != 1)
                return -EINVAL;
 
+       mutex_lock(&intel_pstate_driver_lock);
+
+       if (!driver_registered) {
+               mutex_unlock(&intel_pstate_driver_lock);
+               return -EAGAIN;
+       }
+
        mutex_lock(&intel_pstate_limits_lock);
 
        limits->max_sysfs_pct = clamp_t(int, input, 0 , 100);
@@ -1142,6 +1238,8 @@ static ssize_t store_max_perf_pct(struct kobject *a, struct attribute *b,
 
        intel_pstate_update_policies();
 
+       mutex_unlock(&intel_pstate_driver_lock);
+
        return count;
 }
 
@@ -1155,6 +1253,13 @@ static ssize_t store_min_perf_pct(struct kobject *a, struct attribute *b,
        if (ret != 1)
                return -EINVAL;
 
+       mutex_lock(&intel_pstate_driver_lock);
+
+       if (!driver_registered) {
+               mutex_unlock(&intel_pstate_driver_lock);
+               return -EAGAIN;
+       }
+
        mutex_lock(&intel_pstate_limits_lock);
 
        limits->min_sysfs_pct = clamp_t(int, input, 0 , 100);
@@ -1170,12 +1275,15 @@ static ssize_t store_min_perf_pct(struct kobject *a, struct attribute *b,
 
        intel_pstate_update_policies();
 
+       mutex_unlock(&intel_pstate_driver_lock);
+
        return count;
 }
 
 show_one(max_perf_pct, max_perf_pct);
 show_one(min_perf_pct, min_perf_pct);
 
+define_one_global_rw(status);
 define_one_global_rw(no_turbo);
 define_one_global_rw(max_perf_pct);
 define_one_global_rw(min_perf_pct);
@@ -1183,6 +1291,7 @@ define_one_global_ro(turbo_pct);
 define_one_global_ro(num_pstates);
 
 static struct attribute *intel_pstate_attributes[] = {
+       &status.attr,
        &no_turbo.attr,
        &turbo_pct.attr,
        &num_pstates.attr,
@@ -1364,48 +1473,71 @@ static int core_get_max_pstate_physical(void)
        return (value >> 8) & 0xFF;
 }
 
+static int core_get_tdp_ratio(u64 plat_info)
+{
+       /* Check how many TDP levels present */
+       if (plat_info & 0x600000000) {
+               u64 tdp_ctrl;
+               u64 tdp_ratio;
+               int tdp_msr;
+               int err;
+
+               /* Get the TDP level (0, 1, 2) to get ratios */
+               err = rdmsrl_safe(MSR_CONFIG_TDP_CONTROL, &tdp_ctrl);
+               if (err)
+                       return err;
+
+               /* TDP MSR are continuous starting at 0x648 */
+               tdp_msr = MSR_CONFIG_TDP_NOMINAL + (tdp_ctrl & 0x03);
+               err = rdmsrl_safe(tdp_msr, &tdp_ratio);
+               if (err)
+                       return err;
+
+               /* For level 1 and 2, bits[23:16] contain the ratio */
+               if (tdp_ctrl & 0x03)
+                       tdp_ratio >>= 16;
+
+               tdp_ratio &= 0xff; /* ratios are only 8 bits long */
+               pr_debug("tdp_ratio %x\n", (int)tdp_ratio);
+
+               return (int)tdp_ratio;
+       }
+
+       return -ENXIO;
+}
+
 static int core_get_max_pstate(void)
 {
        u64 tar;
        u64 plat_info;
        int max_pstate;
+       int tdp_ratio;
        int err;
 
        rdmsrl(MSR_PLATFORM_INFO, plat_info);
        max_pstate = (plat_info >> 8) & 0xFF;
 
+       tdp_ratio = core_get_tdp_ratio(plat_info);
+       if (tdp_ratio <= 0)
+               return max_pstate;
+
+       if (hwp_active) {
+               /* Turbo activation ratio is not used on HWP platforms */
+               return tdp_ratio;
+       }
+
        err = rdmsrl_safe(MSR_TURBO_ACTIVATION_RATIO, &tar);
        if (!err) {
+               int tar_levels;
+
                /* Do some sanity checking for safety */
-               if (plat_info & 0x600000000) {
-                       u64 tdp_ctrl;
-                       u64 tdp_ratio;
-                       int tdp_msr;
-
-                       err = rdmsrl_safe(MSR_CONFIG_TDP_CONTROL, &tdp_ctrl);
-                       if (err)
-                               goto skip_tar;
-
-                       tdp_msr = MSR_CONFIG_TDP_NOMINAL + (tdp_ctrl & 0x3);
-                       err = rdmsrl_safe(tdp_msr, &tdp_ratio);
-                       if (err)
-                               goto skip_tar;
-
-                       /* For level 1 and 2, bits[23:16] contain the ratio */
-                       if (tdp_ctrl)
-                               tdp_ratio >>= 16;
-
-                       tdp_ratio &= 0xff; /* ratios are only 8 bits long */
-                       if (tdp_ratio - 1 == tar) {
-                               max_pstate = tar;
-                               pr_debug("max_pstate=TAC %x\n", max_pstate);
-                       } else {
-                               goto skip_tar;
-                       }
+               tar_levels = tar & 0xff;
+               if (tdp_ratio - 1 == tar_levels) {
+                       max_pstate = tar_levels;
+                       pr_debug("max_pstate=TAC %x\n", max_pstate);
                }
        }
 
-skip_tar:
        return max_pstate;
 }
 
@@ -2072,6 +2204,20 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
 
 static int intel_pstate_verify_policy(struct cpufreq_policy *policy)
 {
+       struct cpudata *cpu = all_cpu_data[policy->cpu];
+       struct perf_limits *perf_limits;
+
+       if (policy->policy == CPUFREQ_POLICY_PERFORMANCE)
+               perf_limits = &performance_limits;
+       else
+               perf_limits = &powersave_limits;
+
+       update_turbo_state();
+       policy->cpuinfo.max_freq = perf_limits->turbo_disabled ||
+                                       perf_limits->no_turbo ?
+                                       cpu->pstate.max_freq :
+                                       cpu->pstate.turbo_freq;
+
        cpufreq_verify_within_cpu_limits(policy);
 
        if (policy->policy != CPUFREQ_POLICY_POWERSAVE &&
@@ -2299,6 +2445,111 @@ static struct cpufreq_driver intel_cpufreq = {
 
 static struct cpufreq_driver *intel_pstate_driver = &intel_pstate;
 
+static void intel_pstate_driver_cleanup(void)
+{
+       unsigned int cpu;
+
+       get_online_cpus();
+       for_each_online_cpu(cpu) {
+               if (all_cpu_data[cpu]) {
+                       if (intel_pstate_driver == &intel_pstate)
+                               intel_pstate_clear_update_util_hook(cpu);
+
+                       kfree(all_cpu_data[cpu]);
+                       all_cpu_data[cpu] = NULL;
+               }
+       }
+       put_online_cpus();
+}
+
+static int intel_pstate_register_driver(void)
+{
+       int ret;
+
+       ret = cpufreq_register_driver(intel_pstate_driver);
+       if (ret) {
+               intel_pstate_driver_cleanup();
+               return ret;
+       }
+
+       mutex_lock(&intel_pstate_limits_lock);
+       driver_registered = true;
+       mutex_unlock(&intel_pstate_limits_lock);
+
+       if (intel_pstate_driver == &intel_pstate && !hwp_active &&
+           pstate_funcs.get_target_pstate != get_target_pstate_use_cpu_load)
+               intel_pstate_debug_expose_params();
+
+       return 0;
+}
+
+static int intel_pstate_unregister_driver(void)
+{
+       if (hwp_active)
+               return -EBUSY;
+
+       if (intel_pstate_driver == &intel_pstate && !hwp_active &&
+           pstate_funcs.get_target_pstate != get_target_pstate_use_cpu_load)
+               intel_pstate_debug_hide_params();
+
+       mutex_lock(&intel_pstate_limits_lock);
+       driver_registered = false;
+       mutex_unlock(&intel_pstate_limits_lock);
+
+       cpufreq_unregister_driver(intel_pstate_driver);
+       intel_pstate_driver_cleanup();
+
+       return 0;
+}
+
+static ssize_t intel_pstate_show_status(char *buf)
+{
+       if (!driver_registered)
+               return sprintf(buf, "off\n");
+
+       return sprintf(buf, "%s\n", intel_pstate_driver == &intel_pstate ?
+                                       "active" : "passive");
+}
+
+static int intel_pstate_update_status(const char *buf, size_t size)
+{
+       int ret;
+
+       if (size == 3 && !strncmp(buf, "off", size))
+               return driver_registered ?
+                       intel_pstate_unregister_driver() : -EINVAL;
+
+       if (size == 6 && !strncmp(buf, "active", size)) {
+               if (driver_registered) {
+                       if (intel_pstate_driver == &intel_pstate)
+                               return 0;
+
+                       ret = intel_pstate_unregister_driver();
+                       if (ret)
+                               return ret;
+               }
+
+               intel_pstate_driver = &intel_pstate;
+               return intel_pstate_register_driver();
+       }
+
+       if (size == 7 && !strncmp(buf, "passive", size)) {
+               if (driver_registered) {
+                       if (intel_pstate_driver != &intel_pstate)
+                               return 0;
+
+                       ret = intel_pstate_unregister_driver();
+                       if (ret)
+                               return ret;
+               }
+
+               intel_pstate_driver = &intel_cpufreq;
+               return intel_pstate_register_driver();
+       }
+
+       return -EINVAL;
+}
+
 static int no_load __initdata;
 static int no_hwp __initdata;
 static int hwp_only __initdata;
@@ -2486,9 +2737,9 @@ static const struct x86_cpu_id hwp_support_ids[] __initconst = {
 
 static int __init intel_pstate_init(void)
 {
-       int cpu, rc = 0;
        const struct x86_cpu_id *id;
        struct cpu_defaults *cpu_def;
+       int rc = 0;
 
        if (no_load)
                return -ENODEV;
@@ -2520,45 +2771,29 @@ hwp_cpu_matched:
        if (intel_pstate_platform_pwr_mgmt_exists())
                return -ENODEV;
 
+       if (!hwp_active && hwp_only)
+               return -ENOTSUPP;
+
        pr_info("Intel P-state driver initializing\n");
 
        all_cpu_data = vzalloc(sizeof(void *) * num_possible_cpus());
        if (!all_cpu_data)
                return -ENOMEM;
 
-       if (!hwp_active && hwp_only)
-               goto out;
-
        intel_pstate_request_control_from_smm();
 
-       rc = cpufreq_register_driver(intel_pstate_driver);
-       if (rc)
-               goto out;
-
-       if (intel_pstate_driver == &intel_pstate && !hwp_active &&
-           pstate_funcs.get_target_pstate != get_target_pstate_use_cpu_load)
-               intel_pstate_debug_expose_params();
-
        intel_pstate_sysfs_expose_params();
 
+       mutex_lock(&intel_pstate_driver_lock);
+       rc = intel_pstate_register_driver();
+       mutex_unlock(&intel_pstate_driver_lock);
+       if (rc)
+               return rc;
+
        if (hwp_active)
                pr_info("HWP enabled\n");
 
-       return rc;
-out:
-       get_online_cpus();
-       for_each_online_cpu(cpu) {
-               if (all_cpu_data[cpu]) {
-                       if (intel_pstate_driver == &intel_pstate)
-                               intel_pstate_clear_update_util_hook(cpu);
-
-                       kfree(all_cpu_data[cpu]);
-               }
-       }
-
-       put_online_cpus();
-       vfree(all_cpu_data);
-       return -ENODEV;
+       return 0;
 }
 device_initcall(intel_pstate_init);
 
index 643f43179df16c1a56efc2930d61f31c7d7a79db..ab25b1235a5eadc32cbc7cf904e11665e786f878 100644 (file)
@@ -232,16 +232,14 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
 
        freq_hz = freq_table[index].frequency * 1000;
 
-       rcu_read_lock();
        opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
        if (IS_ERR(opp)) {
-               rcu_read_unlock();
                pr_err("cpu%d: failed to find OPP for %ld\n",
                       policy->cpu, freq_hz);
                return PTR_ERR(opp);
        }
        vproc = dev_pm_opp_get_voltage(opp);
-       rcu_read_unlock();
+       dev_pm_opp_put(opp);
 
        /*
         * If the new voltage or the intermediate voltage is higher than the
@@ -411,16 +409,14 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
 
        /* Search a safe voltage for intermediate frequency. */
        rate = clk_get_rate(inter_clk);
-       rcu_read_lock();
        opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate);
        if (IS_ERR(opp)) {
-               rcu_read_unlock();
                pr_err("failed to get intermediate opp for cpu%d\n", cpu);
                ret = PTR_ERR(opp);
                goto out_free_opp_table;
        }
        info->intermediate_voltage = dev_pm_opp_get_voltage(opp);
-       rcu_read_unlock();
+       dev_pm_opp_put(opp);
 
        info->cpu_dev = cpu_dev;
        info->proc_reg = proc_reg;
index 376e63ca94e840e5334ae4d803dc9a173a69ab15..71e81bbf031b22cdc0ca6a227102ffeb7f01271f 100644 (file)
@@ -63,16 +63,14 @@ static int omap_target(struct cpufreq_policy *policy, unsigned int index)
        freq = ret;
 
        if (mpu_reg) {
-               rcu_read_lock();
                opp = dev_pm_opp_find_freq_ceil(mpu_dev, &freq);
                if (IS_ERR(opp)) {
-                       rcu_read_unlock();
                        dev_err(mpu_dev, "%s: unable to find MPU OPP for %d\n",
                                __func__, new_freq);
                        return -EINVAL;
                }
                volt = dev_pm_opp_get_voltage(opp);
-               rcu_read_unlock();
+               dev_pm_opp_put(opp);
                tol = volt * OPP_TOLERANCE / 100;
                volt_old = regulator_get_voltage(mpu_reg);
        }
index 37671b54588030aae885e04c29b5076556223529..3ff5160451b436ec48511a9428ab611b2291b1f9 100644 (file)
@@ -144,6 +144,7 @@ static struct powernv_pstate_info {
        unsigned int max;
        unsigned int nominal;
        unsigned int nr_pstates;
+       bool wof_enabled;
 } powernv_pstate_info;
 
 /* Use following macros for conversions between pstate_id and index */
@@ -203,6 +204,7 @@ static int init_powernv_pstates(void)
        const __be32 *pstate_ids, *pstate_freqs;
        u32 len_ids, len_freqs;
        u32 pstate_min, pstate_max, pstate_nominal;
+       u32 pstate_turbo, pstate_ultra_turbo;
 
        power_mgt = of_find_node_by_path("/ibm,opal/power-mgt");
        if (!power_mgt) {
@@ -225,8 +227,29 @@ static int init_powernv_pstates(void)
                pr_warn("ibm,pstate-nominal not found\n");
                return -ENODEV;
        }
+
+       if (of_property_read_u32(power_mgt, "ibm,pstate-ultra-turbo",
+                                &pstate_ultra_turbo)) {
+               powernv_pstate_info.wof_enabled = false;
+               goto next;
+       }
+
+       if (of_property_read_u32(power_mgt, "ibm,pstate-turbo",
+                                &pstate_turbo)) {
+               powernv_pstate_info.wof_enabled = false;
+               goto next;
+       }
+
+       if (pstate_turbo == pstate_ultra_turbo)
+               powernv_pstate_info.wof_enabled = false;
+       else
+               powernv_pstate_info.wof_enabled = true;
+
+next:
        pr_info("cpufreq pstate min %d nominal %d max %d\n", pstate_min,
                pstate_nominal, pstate_max);
+       pr_info("Workload Optimized Frequency is %s in the platform\n",
+               (powernv_pstate_info.wof_enabled) ? "enabled" : "disabled");
 
        pstate_ids = of_get_property(power_mgt, "ibm,pstate-ids", &len_ids);
        if (!pstate_ids) {
@@ -268,6 +291,13 @@ static int init_powernv_pstates(void)
                        powernv_pstate_info.nominal = i;
                else if (id == pstate_min)
                        powernv_pstate_info.min = i;
+
+               if (powernv_pstate_info.wof_enabled && id == pstate_turbo) {
+                       int j;
+
+                       for (j = i - 1; j >= (int)powernv_pstate_info.max; j--)
+                               powernv_freqs[j].flags = CPUFREQ_BOOST_FREQ;
+               }
        }
 
        /* End of list marker entry */
@@ -305,9 +335,12 @@ static ssize_t cpuinfo_nominal_freq_show(struct cpufreq_policy *policy,
 struct freq_attr cpufreq_freq_attr_cpuinfo_nominal_freq =
        __ATTR_RO(cpuinfo_nominal_freq);
 
+#define SCALING_BOOST_FREQS_ATTR_INDEX         2
+
 static struct freq_attr *powernv_cpu_freq_attr[] = {
        &cpufreq_freq_attr_scaling_available_freqs,
        &cpufreq_freq_attr_cpuinfo_nominal_freq,
+       &cpufreq_freq_attr_scaling_boost_freqs,
        NULL,
 };
 
@@ -1013,11 +1046,22 @@ static int __init powernv_cpufreq_init(void)
        register_reboot_notifier(&powernv_cpufreq_reboot_nb);
        opal_message_notifier_register(OPAL_MSG_OCC, &powernv_cpufreq_opal_nb);
 
+       if (powernv_pstate_info.wof_enabled)
+               powernv_cpufreq_driver.boost_enabled = true;
+       else
+               powernv_cpu_freq_attr[SCALING_BOOST_FREQS_ATTR_INDEX] = NULL;
+
        rc = cpufreq_register_driver(&powernv_cpufreq_driver);
-       if (!rc)
-               return 0;
+       if (rc) {
+               pr_info("Failed to register the cpufreq driver (%d)\n", rc);
+               goto cleanup_notifiers;
+       }
 
-       pr_info("Failed to register the cpufreq driver (%d)\n", rc);
+       if (powernv_pstate_info.wof_enabled)
+               cpufreq_enable_boost_support();
+
+       return 0;
+cleanup_notifiers:
        unregister_all_notifiers();
        clean_chip_info();
 out:
index dc112481a40841e67fdc5c9ffbed0effc5d54ce1..eeaa92251512d45bfdfb8b1313d0165818b32aed 100644 (file)
@@ -100,9 +100,6 @@ static int pmi_notifier(struct notifier_block *nb,
        /* Should this really be called for CPUFREQ_ADJUST and CPUFREQ_NOTIFY
         * policy events?)
         */
-       if (event == CPUFREQ_START)
-               return 0;
-
        node = cbe_cpu_to_node(policy->cpu);
 
        pr_debug("got notified, event=%lu, node=%u\n", event, node);
index 53d8c3fb16f67bfc5a4cba5065c32a5503be4328..a6fefac8afe49a38ccc613bc0c015e3e8f5d6cdc 100644 (file)
@@ -11,6 +11,7 @@
 #define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
 
 #include <linux/clk.h>
+#include <linux/clk-provider.h>
 #include <linux/cpufreq.h>
 #include <linux/cpu_cooling.h>
 #include <linux/errno.h>
@@ -37,53 +38,20 @@ struct cpu_data {
        struct thermal_cooling_device *cdev;
 };
 
+/*
+ * Don't use cpufreq on this SoC -- used when the SoC would have otherwise
+ * matched a more generic compatible.
+ */
+#define SOC_BLACKLIST          1
+
 /**
  * struct soc_data - SoC specific data
- * @freq_mask: mask the disallowed frequencies
- * @flag: unique flags
+ * @flags: SOC_xxx
  */
 struct soc_data {
-       u32 freq_mask[4];
-       u32 flag;
-};
-
-#define FREQ_MASK      1
-/* see hardware specification for the allowed frqeuencies */
-static const struct soc_data sdata[] = {
-       { /* used by p2041 and p3041 */
-               .freq_mask = {0x8, 0x8, 0x2, 0x2},
-               .flag = FREQ_MASK,
-       },
-       { /* used by p5020 */
-               .freq_mask = {0x8, 0x2},
-               .flag = FREQ_MASK,
-       },
-       { /* used by p4080, p5040 */
-               .freq_mask = {0},
-               .flag = 0,
-       },
+       u32 flags;
 };
 
-/*
- * the minimum allowed core frequency, in Hz
- * for chassis v1.0, >= platform frequency
- * for chassis v2.0, >= platform frequency / 2
- */
-static u32 min_cpufreq;
-static const u32 *fmask;
-
-#if defined(CONFIG_ARM)
-static int get_cpu_physical_id(int cpu)
-{
-       return topology_core_id(cpu);
-}
-#else
-static int get_cpu_physical_id(int cpu)
-{
-       return get_hard_smp_processor_id(cpu);
-}
-#endif
-
 static u32 get_bus_freq(void)
 {
        struct device_node *soc;
@@ -101,9 +69,10 @@ static u32 get_bus_freq(void)
        return sysfreq;
 }
 
-static struct device_node *cpu_to_clk_node(int cpu)
+static struct clk *cpu_to_clk(int cpu)
 {
-       struct device_node *np, *clk_np;
+       struct device_node *np;
+       struct clk *clk;
 
        if (!cpu_present(cpu))
                return NULL;
@@ -112,37 +81,28 @@ static struct device_node *cpu_to_clk_node(int cpu)
        if (!np)
                return NULL;
 
-       clk_np = of_parse_phandle(np, "clocks", 0);
-       if (!clk_np)
-               return NULL;
-
+       clk = of_clk_get(np, 0);
        of_node_put(np);
-
-       return clk_np;
+       return clk;
 }
 
 /* traverse cpu nodes to get cpu mask of sharing clock wire */
 static void set_affected_cpus(struct cpufreq_policy *policy)
 {
-       struct device_node *np, *clk_np;
        struct cpumask *dstp = policy->cpus;
+       struct clk *clk;
        int i;
 
-       np = cpu_to_clk_node(policy->cpu);
-       if (!np)
-               return;
-
        for_each_present_cpu(i) {
-               clk_np = cpu_to_clk_node(i);
-               if (!clk_np)
+               clk = cpu_to_clk(i);
+               if (IS_ERR(clk)) {
+                       pr_err("%s: no clock for cpu %d\n", __func__, i);
                        continue;
+               }
 
-               if (clk_np == np)
+               if (clk_is_match(policy->clk, clk))
                        cpumask_set_cpu(i, dstp);
-
-               of_node_put(clk_np);
        }
-       of_node_put(np);
 }
 
 /* reduce the duplicated frequencies in frequency table */
@@ -198,10 +158,11 @@ static void freq_table_sort(struct cpufreq_frequency_table *freq_table,
 
 static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy)
 {
-       struct device_node *np, *pnode;
+       struct device_node *np;
        int i, count, ret;
-       u32 freq, mask;
+       u32 freq;
        struct clk *clk;
+       const struct clk_hw *hwclk;
        struct cpufreq_frequency_table *table;
        struct cpu_data *data;
        unsigned int cpu = policy->cpu;
@@ -221,17 +182,13 @@ static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy)
                goto err_nomem2;
        }
 
-       pnode = of_parse_phandle(np, "clocks", 0);
-       if (!pnode) {
-               pr_err("%s: could not get clock information\n", __func__);
-               goto err_nomem2;
-       }
+       hwclk = __clk_get_hw(policy->clk);
+       count = clk_hw_get_num_parents(hwclk);
 
-       count = of_property_count_strings(pnode, "clock-names");
        data->pclk = kcalloc(count, sizeof(struct clk *), GFP_KERNEL);
        if (!data->pclk) {
                pr_err("%s: no memory\n", __func__);
-               goto err_node;
+               goto err_nomem2;
        }
 
        table = kcalloc(count + 1, sizeof(*table), GFP_KERNEL);
@@ -240,23 +197,11 @@ static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy)
                goto err_pclk;
        }
 
-       if (fmask)
-               mask = fmask[get_cpu_physical_id(cpu)];
-       else
-               mask = 0x0;
-
        for (i = 0; i < count; i++) {
-               clk = of_clk_get(pnode, i);
+               clk = clk_hw_get_parent_by_index(hwclk, i)->clk;
                data->pclk[i] = clk;
                freq = clk_get_rate(clk);
-               /*
-                * the clock is valid if its frequency is not masked
-                * and large than minimum allowed frequency.
-                */
-               if (freq < min_cpufreq || (mask & (1 << i)))
-                       table[i].frequency = CPUFREQ_ENTRY_INVALID;
-               else
-                       table[i].frequency = freq / 1000;
+               table[i].frequency = freq / 1000;
                table[i].driver_data = i;
        }
        freq_table_redup(table, count);
@@ -282,7 +227,6 @@ static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy)
        policy->cpuinfo.transition_latency = u64temp + 1;
 
        of_node_put(np);
-       of_node_put(pnode);
 
        return 0;
 
@@ -290,10 +234,7 @@ err_nomem1:
        kfree(table);
 err_pclk:
        kfree(data->pclk);
-err_node:
-       of_node_put(pnode);
 err_nomem2:
-       policy->driver_data = NULL;
        kfree(data);
 err_np:
        of_node_put(np);
@@ -357,12 +298,25 @@ static struct cpufreq_driver qoriq_cpufreq_driver = {
        .attr           = cpufreq_generic_attr,
 };
 
+static const struct soc_data blacklist = {
+       .flags = SOC_BLACKLIST,
+};
+
 static const struct of_device_id node_matches[] __initconst = {
-       { .compatible = "fsl,p2041-clockgen", .data = &sdata[0], },
-       { .compatible = "fsl,p3041-clockgen", .data = &sdata[0], },
-       { .compatible = "fsl,p5020-clockgen", .data = &sdata[1], },
-       { .compatible = "fsl,p4080-clockgen", .data = &sdata[2], },
-       { .compatible = "fsl,p5040-clockgen", .data = &sdata[2], },
+       /* e6500 cannot use cpufreq due to erratum A-008083 */
+       { .compatible = "fsl,b4420-clockgen", &blacklist },
+       { .compatible = "fsl,b4860-clockgen", &blacklist },
+       { .compatible = "fsl,t2080-clockgen", &blacklist },
+       { .compatible = "fsl,t4240-clockgen", &blacklist },
+
+       { .compatible = "fsl,ls1012a-clockgen", },
+       { .compatible = "fsl,ls1021a-clockgen", },
+       { .compatible = "fsl,ls1043a-clockgen", },
+       { .compatible = "fsl,ls1046a-clockgen", },
+       { .compatible = "fsl,ls1088a-clockgen", },
+       { .compatible = "fsl,ls2080a-clockgen", },
+       { .compatible = "fsl,p4080-clockgen", },
+       { .compatible = "fsl,qoriq-clockgen-1.0", },
        { .compatible = "fsl,qoriq-clockgen-2.0", },
        {}
 };
@@ -380,16 +334,12 @@ static int __init qoriq_cpufreq_init(void)
 
        match = of_match_node(node_matches, np);
        data = match->data;
-       if (data) {
-               if (data->flag)
-                       fmask = data->freq_mask;
-               min_cpufreq = get_bus_freq();
-       } else {
-               min_cpufreq = get_bus_freq() / 2;
-       }
 
        of_node_put(np);
 
+       if (data && data->flags & SOC_BLACKLIST)
+               return -ENODEV;
+
        ret = cpufreq_register_driver(&qoriq_cpufreq_driver);
        if (!ret)
                pr_info("Freescale QorIQ CPU frequency scaling driver\n");
index d6d425773fa497274301eaa88f247fb8dd770e89..5b2db3c6568f691429fce3d636ac955e06b0bec9 100644 (file)
@@ -400,7 +400,6 @@ static int s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy)
        rate = clk_get_rate(s3c_freq->hclk);
        if (rate < 133 * 1000 * 1000) {
                pr_err("cpufreq: HCLK not at 133MHz\n");
-               clk_put(s3c_freq->hclk);
                ret = -EINVAL;
                goto err_armclk;
        }
index b366e6d830ea30d4bef9e823defa5bf82047af82..a7db9011d5fec57fbf71849fce133a37f88d4a94 100644 (file)
@@ -160,6 +160,7 @@ static int sti_cpufreq_set_opp_info(void)
        int pcode, substrate, major, minor;
        int ret;
        char name[MAX_PCODE_NAME_LEN];
+       struct opp_table *opp_table;
 
        reg_fields = sti_cpufreq_match();
        if (!reg_fields) {
@@ -211,20 +212,20 @@ use_defaults:
 
        snprintf(name, MAX_PCODE_NAME_LEN, "pcode%d", pcode);
 
-       ret = dev_pm_opp_set_prop_name(dev, name);
-       if (ret) {
+       opp_table = dev_pm_opp_set_prop_name(dev, name);
+       if (IS_ERR(opp_table)) {
                dev_err(dev, "Failed to set prop name\n");
-               return ret;
+               return PTR_ERR(opp_table);
        }
 
        version[0] = BIT(major);
        version[1] = BIT(minor);
        version[2] = BIT(substrate);
 
-       ret = dev_pm_opp_set_supported_hw(dev, version, VERSION_ELEMENTS);
-       if (ret) {
+       opp_table = dev_pm_opp_set_supported_hw(dev, version, VERSION_ELEMENTS);
+       if (IS_ERR(opp_table)) {
                dev_err(dev, "Failed to set supported hardware\n");
-               return ret;
+               return PTR_ERR(opp_table);
        }
 
        dev_dbg(dev, "pcode: %d major: %d minor: %d substrate: %d\n",
diff --git a/drivers/cpufreq/ti-cpufreq.c b/drivers/cpufreq/ti-cpufreq.c
new file mode 100644 (file)
index 0000000..a7b5658
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * TI CPUFreq/OPP hw-supported driver
+ *
+ * Copyright (C) 2016-2017 Texas Instruments, Inc.
+ *      Dave Gerlach <d-gerlach@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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/cpu.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/pm_opp.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define REVISION_MASK                          0xF
+#define REVISION_SHIFT                         28
+
+#define AM33XX_800M_ARM_MPU_MAX_FREQ           0x1E2F
+#define AM43XX_600M_ARM_MPU_MAX_FREQ           0xFFA
+
+#define DRA7_EFUSE_HAS_OD_MPU_OPP              11
+#define DRA7_EFUSE_HAS_HIGH_MPU_OPP            15
+#define DRA7_EFUSE_HAS_ALL_MPU_OPP             23
+
+#define DRA7_EFUSE_NOM_MPU_OPP                 BIT(0)
+#define DRA7_EFUSE_OD_MPU_OPP                  BIT(1)
+#define DRA7_EFUSE_HIGH_MPU_OPP                        BIT(2)
+
+#define VERSION_COUNT                          2
+
+struct ti_cpufreq_data;
+
+struct ti_cpufreq_soc_data {
+       unsigned long (*efuse_xlate)(struct ti_cpufreq_data *opp_data,
+                                    unsigned long efuse);
+       unsigned long efuse_fallback;
+       unsigned long efuse_offset;
+       unsigned long efuse_mask;
+       unsigned long efuse_shift;
+       unsigned long rev_offset;
+};
+
+struct ti_cpufreq_data {
+       struct device *cpu_dev;
+       struct device_node *opp_node;
+       struct regmap *syscon;
+       const struct ti_cpufreq_soc_data *soc_data;
+};
+
+static unsigned long amx3_efuse_xlate(struct ti_cpufreq_data *opp_data,
+                                     unsigned long efuse)
+{
+       if (!efuse)
+               efuse = opp_data->soc_data->efuse_fallback;
+       /* AM335x and AM437x use "OPP disable" bits, so invert */
+       return ~efuse;
+}
+
+static unsigned long dra7_efuse_xlate(struct ti_cpufreq_data *opp_data,
+                                     unsigned long efuse)
+{
+       unsigned long calculated_efuse = DRA7_EFUSE_NOM_MPU_OPP;
+
+       /*
+        * The efuse on dra7 and am57 parts contains a specific
+        * value indicating the highest available OPP.
+        */
+
+       switch (efuse) {
+       case DRA7_EFUSE_HAS_ALL_MPU_OPP:
+       case DRA7_EFUSE_HAS_HIGH_MPU_OPP:
+               calculated_efuse |= DRA7_EFUSE_HIGH_MPU_OPP;
+       case DRA7_EFUSE_HAS_OD_MPU_OPP:
+               calculated_efuse |= DRA7_EFUSE_OD_MPU_OPP;
+       }
+
+       return calculated_efuse;
+}
+
+static struct ti_cpufreq_soc_data am3x_soc_data = {
+       .efuse_xlate = amx3_efuse_xlate,
+       .efuse_fallback = AM33XX_800M_ARM_MPU_MAX_FREQ,
+       .efuse_offset = 0x07fc,
+       .efuse_mask = 0x1fff,
+       .rev_offset = 0x600,
+};
+
+static struct ti_cpufreq_soc_data am4x_soc_data = {
+       .efuse_xlate = amx3_efuse_xlate,
+       .efuse_fallback = AM43XX_600M_ARM_MPU_MAX_FREQ,
+       .efuse_offset = 0x0610,
+       .efuse_mask = 0x3f,
+       .rev_offset = 0x600,
+};
+
+static struct ti_cpufreq_soc_data dra7_soc_data = {
+       .efuse_xlate = dra7_efuse_xlate,
+       .efuse_offset = 0x020c,
+       .efuse_mask = 0xf80000,
+       .efuse_shift = 19,
+       .rev_offset = 0x204,
+};
+
+/**
+ * ti_cpufreq_get_efuse() - Parse and return efuse value present on SoC
+ * @opp_data: pointer to ti_cpufreq_data context
+ * @efuse_value: Set to the value parsed from efuse
+ *
+ * Returns error code if efuse not read properly.
+ */
+static int ti_cpufreq_get_efuse(struct ti_cpufreq_data *opp_data,
+                               u32 *efuse_value)
+{
+       struct device *dev = opp_data->cpu_dev;
+       u32 efuse;
+       int ret;
+
+       ret = regmap_read(opp_data->syscon, opp_data->soc_data->efuse_offset,
+                         &efuse);
+       if (ret) {
+               dev_err(dev,
+                       "Failed to read the efuse value from syscon: %d\n",
+                       ret);
+               return ret;
+       }
+
+       efuse = (efuse & opp_data->soc_data->efuse_mask);
+       efuse >>= opp_data->soc_data->efuse_shift;
+
+       *efuse_value = opp_data->soc_data->efuse_xlate(opp_data, efuse);
+
+       return 0;
+}
+
+/**
+ * ti_cpufreq_get_rev() - Parse and return rev value present on SoC
+ * @opp_data: pointer to ti_cpufreq_data context
+ * @revision_value: Set to the value parsed from revision register
+ *
+ * Returns error code if revision not read properly.
+ */
+static int ti_cpufreq_get_rev(struct ti_cpufreq_data *opp_data,
+                             u32 *revision_value)
+{
+       struct device *dev = opp_data->cpu_dev;
+       u32 revision;
+       int ret;
+
+       ret = regmap_read(opp_data->syscon, opp_data->soc_data->rev_offset,
+                         &revision);
+       if (ret) {
+               dev_err(dev,
+                       "Failed to read the revision number from syscon: %d\n",
+                       ret);
+               return ret;
+       }
+
+       *revision_value = BIT((revision >> REVISION_SHIFT) & REVISION_MASK);
+
+       return 0;
+}
+
+static int ti_cpufreq_setup_syscon_register(struct ti_cpufreq_data *opp_data)
+{
+       struct device *dev = opp_data->cpu_dev;
+       struct device_node *np = opp_data->opp_node;
+
+       opp_data->syscon = syscon_regmap_lookup_by_phandle(np,
+                                                       "syscon");
+       if (IS_ERR(opp_data->syscon)) {
+               dev_err(dev,
+                       "\"syscon\" is missing, cannot use OPPv2 table.\n");
+               return PTR_ERR(opp_data->syscon);
+       }
+
+       return 0;
+}
+
+static const struct of_device_id ti_cpufreq_of_match[] = {
+       { .compatible = "ti,am33xx", .data = &am3x_soc_data, },
+       { .compatible = "ti,am4372", .data = &am4x_soc_data, },
+       { .compatible = "ti,dra7", .data = &dra7_soc_data },
+       {},
+};
+
+static int ti_cpufreq_init(void)
+{
+       u32 version[VERSION_COUNT];
+       struct device_node *np;
+       const struct of_device_id *match;
+       struct ti_cpufreq_data *opp_data;
+       int ret;
+
+       np = of_find_node_by_path("/");
+       match = of_match_node(ti_cpufreq_of_match, np);
+       if (!match)
+               return -ENODEV;
+
+       opp_data = kzalloc(sizeof(*opp_data), GFP_KERNEL);
+       if (!opp_data)
+               return -ENOMEM;
+
+       opp_data->soc_data = match->data;
+
+       opp_data->cpu_dev = get_cpu_device(0);
+       if (!opp_data->cpu_dev) {
+               pr_err("%s: Failed to get device for CPU0\n", __func__);
+               return -ENODEV;
+       }
+
+       opp_data->opp_node = dev_pm_opp_of_get_opp_desc_node(opp_data->cpu_dev);
+       if (!opp_data->opp_node) {
+               dev_info(opp_data->cpu_dev,
+                        "OPP-v2 not supported, cpufreq-dt will attempt to use legacy tables.\n");
+               goto register_cpufreq_dt;
+       }
+
+       ret = ti_cpufreq_setup_syscon_register(opp_data);
+       if (ret)
+               goto fail_put_node;
+
+       /*
+        * OPPs determine whether or not they are supported based on
+        * two metrics:
+        *      0 - SoC Revision
+        *      1 - eFuse value
+        */
+       ret = ti_cpufreq_get_rev(opp_data, &version[0]);
+       if (ret)
+               goto fail_put_node;
+
+       ret = ti_cpufreq_get_efuse(opp_data, &version[1]);
+       if (ret)
+               goto fail_put_node;
+
+       of_node_put(opp_data->opp_node);
+
+       ret = PTR_ERR_OR_ZERO(dev_pm_opp_set_supported_hw(opp_data->cpu_dev,
+                                                         version, VERSION_COUNT));
+       if (ret) {
+               dev_err(opp_data->cpu_dev,
+                       "Failed to set supported hardware\n");
+               goto fail_put_node;
+       }
+
+register_cpufreq_dt:
+       platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
+
+       return 0;
+
+fail_put_node:
+       of_node_put(opp_data->opp_node);
+
+       return ret;
+}
+device_initcall(ti_cpufreq_init);
index d9b5b9398a0f67938c7173fa8d4d757c0d67a3ff..8d6d25c38c020e1bcc6f6f0e68d8aab97f96bc3d 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/tick.h>
 #include <linux/sched.h>
 #include <linux/math64.h>
+#include <linux/cpu.h>
 
 /*
  * Please note when changing the tuning values:
@@ -280,17 +281,23 @@ again:
 static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
 {
        struct menu_device *data = this_cpu_ptr(&menu_devices);
+       struct device *device = get_cpu_device(dev->cpu);
        int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
        int i;
        unsigned int interactivity_req;
        unsigned int expected_interval;
        unsigned long nr_iowaiters, cpu_load;
+       int resume_latency = dev_pm_qos_read_value(device);
 
        if (data->needs_update) {
                menu_update(drv, dev);
                data->needs_update = 0;
        }
 
+       /* resume_latency is 0 means no restriction */
+       if (resume_latency && resume_latency < latency_req)
+               latency_req = resume_latency;
+
        /* Special case when user has set very strict latency requirement */
        if (unlikely(latency_req == 0))
                return 0;
@@ -357,9 +364,9 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
                if (s->disabled || su->disable)
                        continue;
                if (s->target_residency > data->predicted_us)
-                       continue;
+                       break;
                if (s->exit_latency > latency_req)
-                       continue;
+                       break;
 
                data->last_state_idx = i;
        }
index 9aea2c7ecbe6ec3cba2802502ca54181df0f3935..8648b32ebc8906c123561eaca53af6e48f655a1a 100644 (file)
@@ -306,7 +306,7 @@ struct devfreq_event_dev *devfreq_event_add_edev(struct device *dev,
                                                struct devfreq_event_desc *desc)
 {
        struct devfreq_event_dev *edev;
-       static atomic_t event_no = ATOMIC_INIT(0);
+       static atomic_t event_no = ATOMIC_INIT(-1);
        int ret;
 
        if (!dev || !desc)
@@ -329,7 +329,7 @@ struct devfreq_event_dev *devfreq_event_add_edev(struct device *dev,
        edev->dev.class = devfreq_event_class;
        edev->dev.release = devfreq_event_release_edev;
 
-       dev_set_name(&edev->dev, "event.%d", atomic_inc_return(&event_no) - 1);
+       dev_set_name(&edev->dev, "event%d", atomic_inc_return(&event_no));
        ret = device_register(&edev->dev);
        if (ret < 0) {
                put_device(&edev->dev);
index 47206a21bb901f424c4e331c9db6eaedef69d93d..551a271353d2a49f98221a03af5c235405d50fe5 100644 (file)
@@ -111,18 +111,16 @@ static void devfreq_set_freq_table(struct devfreq *devfreq)
                return;
        }
 
-       rcu_read_lock();
        for (i = 0, freq = 0; i < profile->max_state; i++, freq++) {
                opp = dev_pm_opp_find_freq_ceil(devfreq->dev.parent, &freq);
                if (IS_ERR(opp)) {
                        devm_kfree(devfreq->dev.parent, profile->freq_table);
                        profile->max_state = 0;
-                       rcu_read_unlock();
                        return;
                }
+               dev_pm_opp_put(opp);
                profile->freq_table[i] = freq;
        }
-       rcu_read_unlock();
 }
 
 /**
@@ -130,7 +128,7 @@ static void devfreq_set_freq_table(struct devfreq *devfreq)
  * @devfreq:   the devfreq instance
  * @freq:      the update target frequency
  */
-static int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
+int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
 {
        int lev, prev_lev, ret = 0;
        unsigned long cur_time;
@@ -166,6 +164,7 @@ out:
        devfreq->last_stat_updated = cur_time;
        return ret;
 }
+EXPORT_SYMBOL(devfreq_update_status);
 
 /**
  * find_devfreq_governor() - find devfreq governor from name
@@ -474,11 +473,15 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
 }
 
 /**
- * _remove_devfreq() - Remove devfreq from the list and release its resources.
- * @devfreq:   the devfreq struct
+ * devfreq_dev_release() - Callback for struct device to release the device.
+ * @dev:       the devfreq device
+ *
+ * Remove devfreq from the list and release its resources.
  */
-static void _remove_devfreq(struct devfreq *devfreq)
+static void devfreq_dev_release(struct device *dev)
 {
+       struct devfreq *devfreq = to_devfreq(dev);
+
        mutex_lock(&devfreq_list_lock);
        if (IS_ERR(find_device_devfreq(devfreq->dev.parent))) {
                mutex_unlock(&devfreq_list_lock);
@@ -499,19 +502,6 @@ static void _remove_devfreq(struct devfreq *devfreq)
        kfree(devfreq);
 }
 
-/**
- * devfreq_dev_release() - Callback for struct device to release the device.
- * @dev:       the devfreq device
- *
- * This calls _remove_devfreq() if _remove_devfreq() is not called.
- */
-static void devfreq_dev_release(struct device *dev)
-{
-       struct devfreq *devfreq = to_devfreq(dev);
-
-       _remove_devfreq(devfreq);
-}
-
 /**
  * devfreq_add_device() - Add devfreq feature to the device
  * @dev:       the device to add devfreq feature.
@@ -527,6 +517,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
 {
        struct devfreq *devfreq;
        struct devfreq_governor *governor;
+       static atomic_t devfreq_no = ATOMIC_INIT(-1);
        int err = 0;
 
        if (!dev || !profile || !governor_name) {
@@ -538,15 +529,14 @@ struct devfreq *devfreq_add_device(struct device *dev,
        devfreq = find_device_devfreq(dev);
        mutex_unlock(&devfreq_list_lock);
        if (!IS_ERR(devfreq)) {
-               dev_err(dev, "%s: Unable to create devfreq for the device. It already has one.\n", __func__);
+               dev_err(dev, "%s: Unable to create devfreq for the device.\n",
+                       __func__);
                err = -EINVAL;
                goto err_out;
        }
 
        devfreq = kzalloc(sizeof(struct devfreq), GFP_KERNEL);
        if (!devfreq) {
-               dev_err(dev, "%s: Unable to create devfreq for the device\n",
-                       __func__);
                err = -ENOMEM;
                goto err_out;
        }
@@ -569,18 +559,21 @@ struct devfreq *devfreq_add_device(struct device *dev,
                mutex_lock(&devfreq->lock);
        }
 
-       dev_set_name(&devfreq->dev, "%s", dev_name(dev));
+       dev_set_name(&devfreq->dev, "devfreq%d",
+                               atomic_inc_return(&devfreq_no));
        err = device_register(&devfreq->dev);
        if (err) {
                mutex_unlock(&devfreq->lock);
                goto err_out;
        }
 
-       devfreq->trans_table =  devm_kzalloc(&devfreq->dev, sizeof(unsigned int) *
+       devfreq->trans_table =  devm_kzalloc(&devfreq->dev,
+                                               sizeof(unsigned int) *
                                                devfreq->profile->max_state *
                                                devfreq->profile->max_state,
                                                GFP_KERNEL);
-       devfreq->time_in_state = devm_kzalloc(&devfreq->dev, sizeof(unsigned long) *
+       devfreq->time_in_state = devm_kzalloc(&devfreq->dev,
+                                               sizeof(unsigned long) *
                                                devfreq->profile->max_state,
                                                GFP_KERNEL);
        devfreq->last_stat_updated = jiffies;
@@ -939,6 +932,9 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
        if (df->governor == governor) {
                ret = 0;
                goto out;
+       } else if (df->governor->immutable || governor->immutable) {
+               ret = -EINVAL;
+               goto out;
        }
 
        if (df->governor) {
@@ -968,13 +964,33 @@ static ssize_t available_governors_show(struct device *d,
                                        struct device_attribute *attr,
                                        char *buf)
 {
-       struct devfreq_governor *tmp_governor;
+       struct devfreq *df = to_devfreq(d);
        ssize_t count = 0;
 
        mutex_lock(&devfreq_list_lock);
-       list_for_each_entry(tmp_governor, &devfreq_governor_list, node)
-               count += scnprintf(&buf[count], (PAGE_SIZE - count - 2),
-                                  "%s ", tmp_governor->name);
+
+       /*
+        * The devfreq with immutable governor (e.g., passive) shows
+        * only own governor.
+        */
+       if (df->governor->immutable) {
+               count = scnprintf(&buf[count], DEVFREQ_NAME_LEN,
+                                  "%s ", df->governor_name);
+       /*
+        * The devfreq device shows the registered governor except for
+        * immutable governors such as passive governor .
+        */
+       } else {
+               struct devfreq_governor *governor;
+
+               list_for_each_entry(governor, &devfreq_governor_list, node) {
+                       if (governor->immutable)
+                               continue;
+                       count += scnprintf(&buf[count], (PAGE_SIZE - count - 2),
+                                          "%s ", governor->name);
+               }
+       }
+
        mutex_unlock(&devfreq_list_lock);
 
        /* Truncate the trailing space */
@@ -995,7 +1011,7 @@ static ssize_t cur_freq_show(struct device *dev, struct device_attribute *attr,
 
        if (devfreq->profile->get_cur_freq &&
                !devfreq->profile->get_cur_freq(devfreq->dev.parent, &freq))
-                       return sprintf(buf, "%lu\n", freq);
+               return sprintf(buf, "%lu\n", freq);
 
        return sprintf(buf, "%lu\n", devfreq->previous_freq);
 }
@@ -1112,17 +1128,16 @@ static ssize_t available_frequencies_show(struct device *d,
        ssize_t count = 0;
        unsigned long freq = 0;
 
-       rcu_read_lock();
        do {
                opp = dev_pm_opp_find_freq_ceil(dev, &freq);
                if (IS_ERR(opp))
                        break;
 
+               dev_pm_opp_put(opp);
                count += scnprintf(&buf[count], (PAGE_SIZE - count - 2),
                                   "%lu ", freq);
                freq++;
        } while (1);
-       rcu_read_unlock();
 
        /* Truncate the trailing space */
        if (count)
@@ -1224,11 +1239,8 @@ subsys_initcall(devfreq_init);
  * @freq:      The frequency given to target function
  * @flags:     Flags handed from devfreq framework.
  *
- * Locking: This function must be called under rcu_read_lock(). opp is a rcu
- * protected pointer. The reason for the same is that the opp pointer which is
- * returned will remain valid for use with opp_get_{voltage, freq} only while
- * under the locked area. The pointer returned must be used prior to unlocking
- * with rcu_read_unlock() to maintain the integrity of the pointer.
+ * The callers are required to call dev_pm_opp_put() for the returned OPP after
+ * use.
  */
 struct dev_pm_opp *devfreq_recommended_opp(struct device *dev,
                                           unsigned long *freq,
@@ -1265,18 +1277,7 @@ EXPORT_SYMBOL(devfreq_recommended_opp);
  */
 int devfreq_register_opp_notifier(struct device *dev, struct devfreq *devfreq)
 {
-       struct srcu_notifier_head *nh;
-       int ret = 0;
-
-       rcu_read_lock();
-       nh = dev_pm_opp_get_notifier(dev);
-       if (IS_ERR(nh))
-               ret = PTR_ERR(nh);
-       rcu_read_unlock();
-       if (!ret)
-               ret = srcu_notifier_chain_register(nh, &devfreq->nb);
-
-       return ret;
+       return dev_pm_opp_register_notifier(dev, &devfreq->nb);
 }
 EXPORT_SYMBOL(devfreq_register_opp_notifier);
 
@@ -1292,18 +1293,7 @@ EXPORT_SYMBOL(devfreq_register_opp_notifier);
  */
 int devfreq_unregister_opp_notifier(struct device *dev, struct devfreq *devfreq)
 {
-       struct srcu_notifier_head *nh;
-       int ret = 0;
-
-       rcu_read_lock();
-       nh = dev_pm_opp_get_notifier(dev);
-       if (IS_ERR(nh))
-               ret = PTR_ERR(nh);
-       rcu_read_unlock();
-       if (!ret)
-               ret = srcu_notifier_chain_unregister(nh, &devfreq->nb);
-
-       return ret;
+       return dev_pm_opp_unregister_notifier(dev, &devfreq->nb);
 }
 EXPORT_SYMBOL(devfreq_unregister_opp_notifier);
 
index 107eb91a9415d26eb429bee2c47dc39ac132e648..9b7350935b73259828a897a7eea6d4fc9b2e4c4f 100644 (file)
 #include <linux/module.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
 #include <linux/suspend.h>
 #include <linux/devfreq-event.h>
 
 #include "exynos-ppmu.h"
 
 struct exynos_ppmu_data {
-       void __iomem *base;
        struct clk *clk;
 };
 
@@ -33,6 +33,7 @@ struct exynos_ppmu {
        unsigned int num_events;
 
        struct device *dev;
+       struct regmap *regmap;
 
        struct exynos_ppmu_data ppmu;
 };
@@ -107,20 +108,28 @@ static int exynos_ppmu_find_ppmu_id(struct devfreq_event_dev *edev)
 static int exynos_ppmu_disable(struct devfreq_event_dev *edev)
 {
        struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
+       int ret;
        u32 pmnc;
 
        /* Disable all counters */
-       __raw_writel(PPMU_CCNT_MASK |
-                    PPMU_PMCNT0_MASK |
-                    PPMU_PMCNT1_MASK |
-                    PPMU_PMCNT2_MASK |
-                    PPMU_PMCNT3_MASK,
-                    info->ppmu.base + PPMU_CNTENC);
+       ret = regmap_write(info->regmap, PPMU_CNTENC,
+                               PPMU_CCNT_MASK |
+                               PPMU_PMCNT0_MASK |
+                               PPMU_PMCNT1_MASK |
+                               PPMU_PMCNT2_MASK |
+                               PPMU_PMCNT3_MASK);
+       if (ret < 0)
+               return ret;
 
        /* Disable PPMU */
-       pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC);
+       ret = regmap_read(info->regmap, PPMU_PMNC, &pmnc);
+       if (ret < 0)
+               return ret;
+
        pmnc &= ~PPMU_PMNC_ENABLE_MASK;
-       __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC);
+       ret = regmap_write(info->regmap, PPMU_PMNC, pmnc);
+       if (ret < 0)
+               return ret;
 
        return 0;
 }
@@ -129,29 +138,42 @@ static int exynos_ppmu_set_event(struct devfreq_event_dev *edev)
 {
        struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
        int id = exynos_ppmu_find_ppmu_id(edev);
+       int ret;
        u32 pmnc, cntens;
 
        if (id < 0)
                return id;
 
        /* Enable specific counter */
-       cntens = __raw_readl(info->ppmu.base + PPMU_CNTENS);
+       ret = regmap_read(info->regmap, PPMU_CNTENS, &cntens);
+       if (ret < 0)
+               return ret;
+
        cntens |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id));
-       __raw_writel(cntens, info->ppmu.base + PPMU_CNTENS);
+       ret = regmap_write(info->regmap, PPMU_CNTENS, cntens);
+       if (ret < 0)
+               return ret;
 
        /* Set the event of Read/Write data count  */
-       __raw_writel(PPMU_RO_DATA_CNT | PPMU_WO_DATA_CNT,
-                       info->ppmu.base + PPMU_BEVTxSEL(id));
+       ret = regmap_write(info->regmap, PPMU_BEVTxSEL(id),
+                               PPMU_RO_DATA_CNT | PPMU_WO_DATA_CNT);
+       if (ret < 0)
+               return ret;
 
        /* Reset cycle counter/performance counter and enable PPMU */
-       pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC);
+       ret = regmap_read(info->regmap, PPMU_PMNC, &pmnc);
+       if (ret < 0)
+               return ret;
+
        pmnc &= ~(PPMU_PMNC_ENABLE_MASK
                        | PPMU_PMNC_COUNTER_RESET_MASK
                        | PPMU_PMNC_CC_RESET_MASK);
        pmnc |= (PPMU_ENABLE << PPMU_PMNC_ENABLE_SHIFT);
        pmnc |= (PPMU_ENABLE << PPMU_PMNC_COUNTER_RESET_SHIFT);
        pmnc |= (PPMU_ENABLE << PPMU_PMNC_CC_RESET_SHIFT);
-       __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC);
+       ret = regmap_write(info->regmap, PPMU_PMNC, pmnc);
+       if (ret < 0)
+               return ret;
 
        return 0;
 }
@@ -161,40 +183,64 @@ static int exynos_ppmu_get_event(struct devfreq_event_dev *edev,
 {
        struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
        int id = exynos_ppmu_find_ppmu_id(edev);
-       u32 pmnc, cntenc;
+       unsigned int total_count, load_count;
+       unsigned int pmcnt3_high, pmcnt3_low;
+       unsigned int pmnc, cntenc;
+       int ret;
 
        if (id < 0)
                return -EINVAL;
 
        /* Disable PPMU */
-       pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC);
+       ret = regmap_read(info->regmap, PPMU_PMNC, &pmnc);
+       if (ret < 0)
+               return ret;
+
        pmnc &= ~PPMU_PMNC_ENABLE_MASK;
-       __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC);
+       ret = regmap_write(info->regmap, PPMU_PMNC, pmnc);
+       if (ret < 0)
+               return ret;
 
        /* Read cycle count */
-       edata->total_count = __raw_readl(info->ppmu.base + PPMU_CCNT);
+       ret = regmap_read(info->regmap, PPMU_CCNT, &total_count);
+       if (ret < 0)
+               return ret;
+       edata->total_count = total_count;
 
        /* Read performance count */
        switch (id) {
        case PPMU_PMNCNT0:
        case PPMU_PMNCNT1:
        case PPMU_PMNCNT2:
-               edata->load_count
-                       = __raw_readl(info->ppmu.base + PPMU_PMNCT(id));
+               ret = regmap_read(info->regmap, PPMU_PMNCT(id), &load_count);
+               if (ret < 0)
+                       return ret;
+               edata->load_count = load_count;
                break;
        case PPMU_PMNCNT3:
-               edata->load_count =
-                       ((__raw_readl(info->ppmu.base + PPMU_PMCNT3_HIGH) << 8)
-                       | __raw_readl(info->ppmu.base + PPMU_PMCNT3_LOW));
+               ret = regmap_read(info->regmap, PPMU_PMCNT3_HIGH, &pmcnt3_high);
+               if (ret < 0)
+                       return ret;
+
+               ret = regmap_read(info->regmap, PPMU_PMCNT3_LOW, &pmcnt3_low);
+               if (ret < 0)
+                       return ret;
+
+               edata->load_count = ((pmcnt3_high << 8) | pmcnt3_low);
                break;
        default:
                return -EINVAL;
        }
 
        /* Disable specific counter */
-       cntenc = __raw_readl(info->ppmu.base + PPMU_CNTENC);
+       ret = regmap_read(info->regmap, PPMU_CNTENC, &cntenc);
+       if (ret < 0)
+               return ret;
+
        cntenc |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id));
-       __raw_writel(cntenc, info->ppmu.base + PPMU_CNTENC);
+       ret = regmap_write(info->regmap, PPMU_CNTENC, cntenc);
+       if (ret < 0)
+               return ret;
 
        dev_dbg(&edev->dev, "%s (event: %ld/%ld)\n", edev->desc->name,
                                        edata->load_count, edata->total_count);
@@ -214,36 +260,93 @@ static const struct devfreq_event_ops exynos_ppmu_ops = {
 static int exynos_ppmu_v2_disable(struct devfreq_event_dev *edev)
 {
        struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
+       int ret;
        u32 pmnc, clear;
 
        /* Disable all counters */
        clear = (PPMU_CCNT_MASK | PPMU_PMCNT0_MASK | PPMU_PMCNT1_MASK
                | PPMU_PMCNT2_MASK | PPMU_PMCNT3_MASK);
+       ret = regmap_write(info->regmap, PPMU_V2_FLAG, clear);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_INTENC, clear);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_CNTENC, clear);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_CNT_RESET, clear);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_CIG_CFG0, 0x0);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_CIG_CFG1, 0x0);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_CIG_CFG2, 0x0);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_CIG_RESULT, 0x0);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_CNT_AUTO, 0x0);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_CH_EV0_TYPE, 0x0);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_CH_EV1_TYPE, 0x0);
+       if (ret < 0)
+               return ret;
 
-       __raw_writel(clear, info->ppmu.base + PPMU_V2_FLAG);
-       __raw_writel(clear, info->ppmu.base + PPMU_V2_INTENC);
-       __raw_writel(clear, info->ppmu.base + PPMU_V2_CNTENC);
-       __raw_writel(clear, info->ppmu.base + PPMU_V2_CNT_RESET);
-
-       __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_CFG0);
-       __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_CFG1);
-       __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_CFG2);
-       __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_RESULT);
-       __raw_writel(0x0, info->ppmu.base + PPMU_V2_CNT_AUTO);
-       __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV0_TYPE);
-       __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV1_TYPE);
-       __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV2_TYPE);
-       __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV3_TYPE);
-       __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_ID_V);
-       __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_ID_A);
-       __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_OTHERS_V);
-       __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_OTHERS_A);
-       __raw_writel(0x0, info->ppmu.base + PPMU_V2_INTERRUPT_RESET);
+       ret = regmap_write(info->regmap, PPMU_V2_CH_EV2_TYPE, 0x0);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_CH_EV3_TYPE, 0x0);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_SM_ID_V, 0x0);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_SM_ID_A, 0x0);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_SM_OTHERS_V, 0x0);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_SM_OTHERS_A, 0x0);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(info->regmap, PPMU_V2_INTERRUPT_RESET, 0x0);
+       if (ret < 0)
+               return ret;
 
        /* Disable PPMU */
-       pmnc = __raw_readl(info->ppmu.base + PPMU_V2_PMNC);
+       ret = regmap_read(info->regmap, PPMU_V2_PMNC, &pmnc);
+       if (ret < 0)
+               return ret;
+
        pmnc &= ~PPMU_PMNC_ENABLE_MASK;
-       __raw_writel(pmnc, info->ppmu.base + PPMU_V2_PMNC);
+       ret = regmap_write(info->regmap, PPMU_V2_PMNC, pmnc);
+       if (ret < 0)
+               return ret;
 
        return 0;
 }
@@ -251,30 +354,43 @@ static int exynos_ppmu_v2_disable(struct devfreq_event_dev *edev)
 static int exynos_ppmu_v2_set_event(struct devfreq_event_dev *edev)
 {
        struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
+       unsigned int pmnc, cntens;
        int id = exynos_ppmu_find_ppmu_id(edev);
-       u32 pmnc, cntens;
+       int ret;
 
        /* Enable all counters */
-       cntens = __raw_readl(info->ppmu.base + PPMU_V2_CNTENS);
+       ret = regmap_read(info->regmap, PPMU_V2_CNTENS, &cntens);
+       if (ret < 0)
+               return ret;
+
        cntens |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id));
-       __raw_writel(cntens, info->ppmu.base + PPMU_V2_CNTENS);
+       ret = regmap_write(info->regmap, PPMU_V2_CNTENS, cntens);
+       if (ret < 0)
+               return ret;
 
        /* Set the event of Read/Write data count  */
        switch (id) {
        case PPMU_PMNCNT0:
        case PPMU_PMNCNT1:
        case PPMU_PMNCNT2:
-               __raw_writel(PPMU_V2_RO_DATA_CNT | PPMU_V2_WO_DATA_CNT,
-                               info->ppmu.base + PPMU_V2_CH_EVx_TYPE(id));
+               ret = regmap_write(info->regmap, PPMU_V2_CH_EVx_TYPE(id),
+                               PPMU_V2_RO_DATA_CNT | PPMU_V2_WO_DATA_CNT);
+               if (ret < 0)
+                       return ret;
                break;
        case PPMU_PMNCNT3:
-               __raw_writel(PPMU_V2_EVT3_RW_DATA_CNT,
-                               info->ppmu.base + PPMU_V2_CH_EVx_TYPE(id));
+               ret = regmap_write(info->regmap, PPMU_V2_CH_EVx_TYPE(id),
+                               PPMU_V2_EVT3_RW_DATA_CNT);
+               if (ret < 0)
+                       return ret;
                break;
        }
 
        /* Reset cycle counter/performance counter and enable PPMU */
-       pmnc = __raw_readl(info->ppmu.base + PPMU_V2_PMNC);
+       ret = regmap_read(info->regmap, PPMU_V2_PMNC, &pmnc);
+       if (ret < 0)
+               return ret;
+
        pmnc &= ~(PPMU_PMNC_ENABLE_MASK
                        | PPMU_PMNC_COUNTER_RESET_MASK
                        | PPMU_PMNC_CC_RESET_MASK
@@ -284,7 +400,10 @@ static int exynos_ppmu_v2_set_event(struct devfreq_event_dev *edev)
        pmnc |= (PPMU_ENABLE << PPMU_PMNC_COUNTER_RESET_SHIFT);
        pmnc |= (PPMU_ENABLE << PPMU_PMNC_CC_RESET_SHIFT);
        pmnc |= (PPMU_V2_MODE_MANUAL << PPMU_V2_PMNC_START_MODE_SHIFT);
-       __raw_writel(pmnc, info->ppmu.base + PPMU_V2_PMNC);
+
+       ret = regmap_write(info->regmap, PPMU_V2_PMNC, pmnc);
+       if (ret < 0)
+               return ret;
 
        return 0;
 }
@@ -294,37 +413,61 @@ static int exynos_ppmu_v2_get_event(struct devfreq_event_dev *edev,
 {
        struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
        int id = exynos_ppmu_find_ppmu_id(edev);
-       u32 pmnc, cntenc;
-       u32 pmcnt_high, pmcnt_low;
-       u64 load_count = 0;
+       int ret;
+       unsigned int pmnc, cntenc;
+       unsigned int pmcnt_high, pmcnt_low;
+       unsigned int total_count, count;
+       unsigned long load_count = 0;
 
        /* Disable PPMU */
-       pmnc = __raw_readl(info->ppmu.base + PPMU_V2_PMNC);
+       ret = regmap_read(info->regmap, PPMU_V2_PMNC, &pmnc);
+       if (ret < 0)
+               return ret;
+
        pmnc &= ~PPMU_PMNC_ENABLE_MASK;
-       __raw_writel(pmnc, info->ppmu.base + PPMU_V2_PMNC);
+       ret = regmap_write(info->regmap, PPMU_V2_PMNC, pmnc);
+       if (ret < 0)
+               return ret;
 
        /* Read cycle count and performance count */
-       edata->total_count = __raw_readl(info->ppmu.base + PPMU_V2_CCNT);
+       ret = regmap_read(info->regmap, PPMU_V2_CCNT, &total_count);
+       if (ret < 0)
+               return ret;
+       edata->total_count = total_count;
 
        switch (id) {
        case PPMU_PMNCNT0:
        case PPMU_PMNCNT1:
        case PPMU_PMNCNT2:
-               load_count = __raw_readl(info->ppmu.base + PPMU_V2_PMNCT(id));
+               ret = regmap_read(info->regmap, PPMU_V2_PMNCT(id), &count);
+               if (ret < 0)
+                       return ret;
+               load_count = count;
                break;
        case PPMU_PMNCNT3:
-               pmcnt_high = __raw_readl(info->ppmu.base + PPMU_V2_PMCNT3_HIGH);
-               pmcnt_low = __raw_readl(info->ppmu.base + PPMU_V2_PMCNT3_LOW);
-               load_count = ((u64)((pmcnt_high & 0xff)) << 32)
-                          + (u64)pmcnt_low;
+               ret = regmap_read(info->regmap, PPMU_V2_PMCNT3_HIGH,
+                                               &pmcnt_high);
+               if (ret < 0)
+                       return ret;
+
+               ret = regmap_read(info->regmap, PPMU_V2_PMCNT3_LOW, &pmcnt_low);
+               if (ret < 0)
+                       return ret;
+
+               load_count = ((u64)((pmcnt_high & 0xff)) << 32)+ (u64)pmcnt_low;
                break;
        }
        edata->load_count = load_count;
 
        /* Disable all counters */
-       cntenc = __raw_readl(info->ppmu.base + PPMU_V2_CNTENC);
+       ret = regmap_read(info->regmap, PPMU_V2_CNTENC, &cntenc);
+       if (ret < 0)
+               return 0;
+
        cntenc |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id));
-       __raw_writel(cntenc, info->ppmu.base + PPMU_V2_CNTENC);
+       ret = regmap_write(info->regmap, PPMU_V2_CNTENC, cntenc);
+       if (ret < 0)
+               return ret;
 
        dev_dbg(&edev->dev, "%25s (load: %ld / %ld)\n", edev->desc->name,
                                        edata->load_count, edata->total_count);
@@ -411,10 +554,19 @@ static int of_get_devfreq_events(struct device_node *np,
        return 0;
 }
 
-static int exynos_ppmu_parse_dt(struct exynos_ppmu *info)
+static struct regmap_config exynos_ppmu_regmap_config = {
+       .reg_bits = 32,
+       .val_bits = 32,
+       .reg_stride = 4,
+};
+
+static int exynos_ppmu_parse_dt(struct platform_device *pdev,
+                               struct exynos_ppmu *info)
 {
        struct device *dev = info->dev;
        struct device_node *np = dev->of_node;
+       struct resource *res;
+       void __iomem *base;
        int ret = 0;
 
        if (!np) {
@@ -423,10 +575,17 @@ static int exynos_ppmu_parse_dt(struct exynos_ppmu *info)
        }
 
        /* Maps the memory mapped IO to control PPMU register */
-       info->ppmu.base = of_iomap(np, 0);
-       if (IS_ERR_OR_NULL(info->ppmu.base)) {
-               dev_err(dev, "failed to map memory region\n");
-               return -ENOMEM;
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       exynos_ppmu_regmap_config.max_register = resource_size(res) - 4;
+       info->regmap = devm_regmap_init_mmio(dev, base,
+                                       &exynos_ppmu_regmap_config);
+       if (IS_ERR(info->regmap)) {
+               dev_err(dev, "failed to initialize regmap\n");
+               return PTR_ERR(info->regmap);
        }
 
        info->ppmu.clk = devm_clk_get(dev, "ppmu");
@@ -438,15 +597,10 @@ static int exynos_ppmu_parse_dt(struct exynos_ppmu *info)
        ret = of_get_devfreq_events(np, info);
        if (ret < 0) {
                dev_err(dev, "failed to parse exynos ppmu dt node\n");
-               goto err;
+               return ret;
        }
 
        return 0;
-
-err:
-       iounmap(info->ppmu.base);
-
-       return ret;
 }
 
 static int exynos_ppmu_probe(struct platform_device *pdev)
@@ -463,7 +617,7 @@ static int exynos_ppmu_probe(struct platform_device *pdev)
        info->dev = &pdev->dev;
 
        /* Parse dt data to get resource */
-       ret = exynos_ppmu_parse_dt(info);
+       ret = exynos_ppmu_parse_dt(pdev, info);
        if (ret < 0) {
                dev_err(&pdev->dev,
                        "failed to parse devicetree for resource\n");
@@ -476,8 +630,7 @@ static int exynos_ppmu_probe(struct platform_device *pdev)
        if (!info->edev) {
                dev_err(&pdev->dev,
                        "failed to allocate memory devfreq-event devices\n");
-               ret = -ENOMEM;
-               goto err;
+               return -ENOMEM;
        }
        edev = info->edev;
        platform_set_drvdata(pdev, info);
@@ -488,17 +641,16 @@ static int exynos_ppmu_probe(struct platform_device *pdev)
                        ret = PTR_ERR(edev[i]);
                        dev_err(&pdev->dev,
                                "failed to add devfreq-event device\n");
-                       goto err;
+                       return PTR_ERR(edev[i]);
                }
+
+               pr_info("exynos-ppmu: new PPMU device registered %s (%s)\n",
+                       dev_name(&pdev->dev), desc[i].name);
        }
 
        clk_prepare_enable(info->ppmu.clk);
 
        return 0;
-err:
-       iounmap(info->ppmu.base);
-
-       return ret;
 }
 
 static int exynos_ppmu_remove(struct platform_device *pdev)
@@ -506,7 +658,6 @@ static int exynos_ppmu_remove(struct platform_device *pdev)
        struct exynos_ppmu *info = platform_get_drvdata(pdev);
 
        clk_disable_unprepare(info->ppmu.clk);
-       iounmap(info->ppmu.base);
 
        return 0;
 }
index 9af86f46fbec0fc0779e4cf211c16227b804510d..49f68929e024fa9fc95b8f31eda07edd5218bb53 100644 (file)
@@ -103,18 +103,17 @@ static int exynos_bus_target(struct device *dev, unsigned long *freq, u32 flags)
        int ret = 0;
 
        /* Get new opp-bus instance according to new bus clock */
-       rcu_read_lock();
        new_opp = devfreq_recommended_opp(dev, freq, flags);
        if (IS_ERR(new_opp)) {
                dev_err(dev, "failed to get recommended opp instance\n");
-               rcu_read_unlock();
                return PTR_ERR(new_opp);
        }
 
        new_freq = dev_pm_opp_get_freq(new_opp);
        new_volt = dev_pm_opp_get_voltage(new_opp);
+       dev_pm_opp_put(new_opp);
+
        old_freq = bus->curr_freq;
-       rcu_read_unlock();
 
        if (old_freq == new_freq)
                return 0;
@@ -147,8 +146,8 @@ static int exynos_bus_target(struct device *dev, unsigned long *freq, u32 flags)
        }
        bus->curr_freq = new_freq;
 
-       dev_dbg(dev, "Set the frequency of bus (%lukHz -> %lukHz)\n",
-                       old_freq/1000, new_freq/1000);
+       dev_dbg(dev, "Set the frequency of bus (%luHz -> %luHz, %luHz)\n",
+                       old_freq, new_freq, clk_get_rate(bus->clk));
 out:
        mutex_unlock(&bus->lock);
 
@@ -214,17 +213,16 @@ static int exynos_bus_passive_target(struct device *dev, unsigned long *freq,
        int ret = 0;
 
        /* Get new opp-bus instance according to new bus clock */
-       rcu_read_lock();
        new_opp = devfreq_recommended_opp(dev, freq, flags);
        if (IS_ERR(new_opp)) {
                dev_err(dev, "failed to get recommended opp instance\n");
-               rcu_read_unlock();
                return PTR_ERR(new_opp);
        }
 
        new_freq = dev_pm_opp_get_freq(new_opp);
+       dev_pm_opp_put(new_opp);
+
        old_freq = bus->curr_freq;
-       rcu_read_unlock();
 
        if (old_freq == new_freq)
                return 0;
@@ -241,8 +239,8 @@ static int exynos_bus_passive_target(struct device *dev, unsigned long *freq,
        *freq = new_freq;
        bus->curr_freq = new_freq;
 
-       dev_dbg(dev, "Set the frequency of bus (%lukHz -> %lukHz)\n",
-                       old_freq/1000, new_freq/1000);
+       dev_dbg(dev, "Set the frequency of bus (%luHz -> %luHz, %luHz)\n",
+                       old_freq, new_freq, clk_get_rate(bus->clk));
 out:
        mutex_unlock(&bus->lock);
 
@@ -358,16 +356,14 @@ static int exynos_bus_parse_of(struct device_node *np,
 
        rate = clk_get_rate(bus->clk);
 
-       rcu_read_lock();
        opp = devfreq_recommended_opp(dev, &rate, 0);
        if (IS_ERR(opp)) {
                dev_err(dev, "failed to find dev_pm_opp\n");
-               rcu_read_unlock();
                ret = PTR_ERR(opp);
                goto err_opp;
        }
        bus->curr_freq = dev_pm_opp_get_freq(opp);
-       rcu_read_unlock();
+       dev_pm_opp_put(opp);
 
        return 0;
 
index fad7d63219786387e191ea4130bf5a0b7b37001b..71576b8bdfeff2f5fc5a1e5108eef21c35396949 100644 (file)
@@ -38,4 +38,6 @@ extern void devfreq_interval_update(struct devfreq *devfreq,
 extern int devfreq_add_governor(struct devfreq_governor *governor);
 extern int devfreq_remove_governor(struct devfreq_governor *governor);
 
+extern int devfreq_update_status(struct devfreq *devfreq, unsigned long freq);
+
 #endif /* _GOVERNOR_H */
index 9ef46e2592c45616cb59471c7cb2698155b56b7e..673ad8cc9a1d093e3db6e2d335742a1aee529953 100644 (file)
@@ -59,14 +59,14 @@ static int devfreq_passive_get_target_freq(struct devfreq *devfreq,
         * list of parent device. Because in this case, *freq is temporary
         * value which is decided by ondemand governor.
         */
-       rcu_read_lock();
        opp = devfreq_recommended_opp(parent_devfreq->dev.parent, freq, 0);
-       rcu_read_unlock();
        if (IS_ERR(opp)) {
                ret = PTR_ERR(opp);
                goto out;
        }
 
+       dev_pm_opp_put(opp);
+
        /*
         * Get the OPP table's index of decided freqeuncy by governor
         * of parent device.
@@ -112,6 +112,11 @@ static int update_devfreq_passive(struct devfreq *devfreq, unsigned long freq)
        if (ret < 0)
                goto out;
 
+       if (devfreq->profile->freq_table
+               && (devfreq_update_status(devfreq, freq)))
+               dev_err(&devfreq->dev,
+                       "Couldn't update frequency transition information.\n");
+
        devfreq->previous_freq = freq;
 
 out:
@@ -179,6 +184,7 @@ static int devfreq_passive_event_handler(struct devfreq *devfreq,
 
 static struct devfreq_governor devfreq_passive = {
        .name = "passive",
+       .immutable = 1,
        .get_target_freq = devfreq_passive_get_target_freq,
        .event_handler = devfreq_passive_event_handler,
 };
index 35de6e83c1febedd99f8c155e374b5d4f8bb5202..176976068bcd1552d0a625ea47ebdf72812b4c6b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/devfreq/governor_simpleondemand.c
+ *  linux/drivers/devfreq/governor_userspace.c
  *
  *  Copyright (C) 2011 Samsung Electronics
  *     MyungJoo Ham <myungjoo.ham@samsung.com>
@@ -50,7 +50,6 @@ static ssize_t store_freq(struct device *dev, struct device_attribute *attr,
        unsigned long wanted;
        int err = 0;
 
-
        mutex_lock(&devfreq->lock);
        data = devfreq->data;
 
@@ -112,7 +111,13 @@ out:
 
 static void userspace_exit(struct devfreq *devfreq)
 {
-       sysfs_remove_group(&devfreq->dev.kobj, &dev_attr_group);
+       /*
+        * Remove the sysfs entry, unless this is being called after
+        * device_del(), which should have done this already via kobject_del().
+        */
+       if (devfreq->dev.kobj.sd)
+               sysfs_remove_group(&devfreq->dev.kobj, &dev_attr_group);
+
        kfree(devfreq->data);
        devfreq->data = NULL;
 }
index 27d2f349b53c9ae7d8cd4db31681576e0dac8354..40a2499730fcb4cc635dfb9a0de2b9d50ea47869 100644 (file)
@@ -91,17 +91,13 @@ static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq,
        unsigned long target_volt, target_rate;
        int err;
 
-       rcu_read_lock();
        opp = devfreq_recommended_opp(dev, freq, flags);
-       if (IS_ERR(opp)) {
-               rcu_read_unlock();
+       if (IS_ERR(opp))
                return PTR_ERR(opp);
-       }
 
        target_rate = dev_pm_opp_get_freq(opp);
        target_volt = dev_pm_opp_get_voltage(opp);
-
-       rcu_read_unlock();
+       dev_pm_opp_put(opp);
 
        if (dmcfreq->rate == target_rate)
                return 0;
@@ -422,15 +418,13 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
 
        data->rate = clk_get_rate(data->dmc_clk);
 
-       rcu_read_lock();
        opp = devfreq_recommended_opp(dev, &data->rate, 0);
-       if (IS_ERR(opp)) {
-               rcu_read_unlock();
+       if (IS_ERR(opp))
                return PTR_ERR(opp);
-       }
+
        data->rate = dev_pm_opp_get_freq(opp);
        data->volt = dev_pm_opp_get_voltage(opp);
-       rcu_read_unlock();
+       dev_pm_opp_put(opp);
 
        rk3399_devfreq_dmc_profile.initial_freq = data->rate;
 
index fe9dce0245bf0c7d32b2c8eb3590e7f73651ae6d..214fff96fa4a6c23d92b71eb1528348e2025afb8 100644 (file)
@@ -487,15 +487,13 @@ static int tegra_devfreq_target(struct device *dev, unsigned long *freq,
        struct dev_pm_opp *opp;
        unsigned long rate = *freq * KHZ;
 
-       rcu_read_lock();
        opp = devfreq_recommended_opp(dev, &rate, flags);
        if (IS_ERR(opp)) {
-               rcu_read_unlock();
                dev_err(dev, "Failed to find opp for %lu KHz\n", *freq);
                return PTR_ERR(opp);
        }
        rate = dev_pm_opp_get_freq(opp);
-       rcu_read_unlock();
+       dev_pm_opp_put(opp);
 
        clk_set_min_rate(tegra->emc_clock, rate);
        clk_set_rate(tegra->emc_clock, 0);
index 263495d0adbdfd0a5e079c3ba5c6f71247ee7fde..d01d59812cf3ec8f171e09641ae2c1c787e0de06 100644 (file)
@@ -157,7 +157,7 @@ config DMA_SUN4I
 
 config DMA_SUN6I
        tristate "Allwinner A31 SoCs DMA support"
-       depends on MACH_SUN6I || MACH_SUN8I || COMPILE_TEST
+       depends on MACH_SUN6I || MACH_SUN8I || (ARM64 && ARCH_SUNXI) || COMPILE_TEST
        depends on RESET_CONTROLLER
        select DMA_ENGINE
        select DMA_VIRTUAL_CHANNELS
@@ -458,7 +458,7 @@ config STM32_DMA
        help
          Enable support for the on-chip DMA controller on STMicroelectronics
          STM32 MCUs.
-         If you have a board based on such a MCU and wish to use DMA say Y or M
+         If you have a board based on such a MCU and wish to use DMA say Y
          here.
 
 config S3C24XX_DMAC
@@ -571,12 +571,12 @@ config XILINX_ZYNQMP_DMA
          Enable support for Xilinx ZynqMP DMA controller.
 
 config ZX_DMA
-       tristate "ZTE ZX296702 DMA support"
+       tristate "ZTE ZX DMA support"
        depends on ARCH_ZX || COMPILE_TEST
        select DMA_ENGINE
        select DMA_VIRTUAL_CHANNELS
        help
-         Support the DMA engine for ZTE ZX296702 platform devices.
+         Support the DMA engine for ZTE ZX family platform devices.
 
 
 # driver files
index a4fa3360e609d1ef81bf89dc7086b76e6ae52048..0b723e94d9e6d3751d1ceea4509b173cbd84b458 100644 (file)
@@ -66,7 +66,7 @@ obj-$(CONFIG_TI_CPPI41) += cppi41.o
 obj-$(CONFIG_TI_DMA_CROSSBAR) += ti-dma-crossbar.o
 obj-$(CONFIG_TI_EDMA) += edma.o
 obj-$(CONFIG_XGENE_DMA) += xgene-dma.o
-obj-$(CONFIG_ZX_DMA) += zx296702_dma.o
+obj-$(CONFIG_ZX_DMA) += zx_dma.o
 obj-$(CONFIG_ST_FDMA) += st_fdma.o
 
 obj-y += qcom/
index 6b535262ac5d76972bb525b49f3cf160fcf54aa0..24e0221fd66d1ff58eead62ee9f4a865eb87da03 100644 (file)
@@ -65,7 +65,7 @@
 #include <linux/mempool.h>
 
 static DEFINE_MUTEX(dma_list_mutex);
-static DEFINE_IDR(dma_idr);
+static DEFINE_IDA(dma_ida);
 static LIST_HEAD(dma_device_list);
 static long dmaengine_ref_count;
 
@@ -162,7 +162,7 @@ static void chan_dev_release(struct device *dev)
        chan_dev = container_of(dev, typeof(*chan_dev), device);
        if (atomic_dec_and_test(chan_dev->idr_ref)) {
                mutex_lock(&dma_list_mutex);
-               idr_remove(&dma_idr, chan_dev->dev_id);
+               ida_remove(&dma_ida, chan_dev->dev_id);
                mutex_unlock(&dma_list_mutex);
                kfree(chan_dev->idr_ref);
        }
@@ -898,14 +898,15 @@ static int get_dma_id(struct dma_device *device)
 {
        int rc;
 
-       mutex_lock(&dma_list_mutex);
-
-       rc = idr_alloc(&dma_idr, NULL, 0, 0, GFP_KERNEL);
-       if (rc >= 0)
-               device->dev_id = rc;
+       do {
+               if (!ida_pre_get(&dma_ida, GFP_KERNEL))
+                       return -ENOMEM;
+               mutex_lock(&dma_list_mutex);
+               rc = ida_get_new(&dma_ida, &device->dev_id);
+               mutex_unlock(&dma_list_mutex);
+       } while (rc == -EAGAIN);
 
-       mutex_unlock(&dma_list_mutex);
-       return rc < 0 ? rc : 0;
+       return rc;
 }
 
 /**
@@ -1035,7 +1036,7 @@ err_out:
        /* if we never registered a channel just release the idr */
        if (atomic_read(idr_ref) == 0) {
                mutex_lock(&dma_list_mutex);
-               idr_remove(&dma_idr, device->dev_id);
+               ida_remove(&dma_ida, device->dev_id);
                mutex_unlock(&dma_list_mutex);
                kfree(idr_ref);
                return rc;
index e5adf5d1c34fcf53dfeab355ee647a97c2765661..e500950dad822ab84c52a6412649f740c321405b 100644 (file)
@@ -138,16 +138,32 @@ static void dwc_desc_put(struct dw_dma_chan *dwc, struct dw_desc *desc)
        dwc->descs_allocated--;
 }
 
-static void dwc_initialize(struct dw_dma_chan *dwc)
+static void dwc_initialize_chan_idma32(struct dw_dma_chan *dwc)
+{
+       u32 cfghi = 0;
+       u32 cfglo = 0;
+
+       /* Set default burst alignment */
+       cfglo |= IDMA32C_CFGL_DST_BURST_ALIGN | IDMA32C_CFGL_SRC_BURST_ALIGN;
+
+       /* Low 4 bits of the request lines */
+       cfghi |= IDMA32C_CFGH_DST_PER(dwc->dws.dst_id & 0xf);
+       cfghi |= IDMA32C_CFGH_SRC_PER(dwc->dws.src_id & 0xf);
+
+       /* Request line extension (2 bits) */
+       cfghi |= IDMA32C_CFGH_DST_PER_EXT(dwc->dws.dst_id >> 4 & 0x3);
+       cfghi |= IDMA32C_CFGH_SRC_PER_EXT(dwc->dws.src_id >> 4 & 0x3);
+
+       channel_writel(dwc, CFG_LO, cfglo);
+       channel_writel(dwc, CFG_HI, cfghi);
+}
+
+static void dwc_initialize_chan_dw(struct dw_dma_chan *dwc)
 {
-       struct dw_dma *dw = to_dw_dma(dwc->chan.device);
        u32 cfghi = DWC_CFGH_FIFO_MODE;
        u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority);
        bool hs_polarity = dwc->dws.hs_polarity;
 
-       if (test_bit(DW_DMA_IS_INITIALIZED, &dwc->flags))
-               return;
-
        cfghi |= DWC_CFGH_DST_PER(dwc->dws.dst_id);
        cfghi |= DWC_CFGH_SRC_PER(dwc->dws.src_id);
 
@@ -156,6 +172,19 @@ static void dwc_initialize(struct dw_dma_chan *dwc)
 
        channel_writel(dwc, CFG_LO, cfglo);
        channel_writel(dwc, CFG_HI, cfghi);
+}
+
+static void dwc_initialize(struct dw_dma_chan *dwc)
+{
+       struct dw_dma *dw = to_dw_dma(dwc->chan.device);
+
+       if (test_bit(DW_DMA_IS_INITIALIZED, &dwc->flags))
+               return;
+
+       if (dw->pdata->is_idma32)
+               dwc_initialize_chan_idma32(dwc);
+       else
+               dwc_initialize_chan_dw(dwc);
 
        /* Enable interrupts */
        channel_set_bit(dw, MASK.XFER, dwc->mask);
@@ -184,6 +213,37 @@ static inline void dwc_chan_disable(struct dw_dma *dw, struct dw_dma_chan *dwc)
                cpu_relax();
 }
 
+static u32 bytes2block(struct dw_dma_chan *dwc, size_t bytes,
+                         unsigned int width, size_t *len)
+{
+       struct dw_dma *dw = to_dw_dma(dwc->chan.device);
+       u32 block;
+
+       /* Always in bytes for iDMA 32-bit */
+       if (dw->pdata->is_idma32)
+               width = 0;
+
+       if ((bytes >> width) > dwc->block_size) {
+               block = dwc->block_size;
+               *len = block << width;
+       } else {
+               block = bytes >> width;
+               *len = bytes;
+       }
+
+       return block;
+}
+
+static size_t block2bytes(struct dw_dma_chan *dwc, u32 block, u32 width)
+{
+       struct dw_dma *dw = to_dw_dma(dwc->chan.device);
+
+       if (dw->pdata->is_idma32)
+               return IDMA32C_CTLH_BLOCK_TS(block);
+
+       return DWC_CTLH_BLOCK_TS(block) << width;
+}
+
 /*----------------------------------------------------------------------*/
 
 /* Perform single block transfer */
@@ -332,7 +392,7 @@ static inline u32 dwc_get_sent(struct dw_dma_chan *dwc)
        u32 ctlhi = channel_readl(dwc, CTL_HI);
        u32 ctllo = channel_readl(dwc, CTL_LO);
 
-       return (ctlhi & DWC_CTLH_BLOCK_TS_MASK) * (1 << (ctllo >> 4 & 7));
+       return block2bytes(dwc, ctlhi, ctllo >> 4 & 7);
 }
 
 static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
@@ -692,10 +752,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
                        | DWC_CTLL_FC_M2M;
        prev = first = NULL;
 
-       for (offset = 0; offset < len; offset += xfer_count << src_width) {
-               xfer_count = min_t(size_t, (len - offset) >> src_width,
-                                          dwc->block_size);
-
+       for (offset = 0; offset < len; offset += xfer_count) {
                desc = dwc_desc_get(dwc);
                if (!desc)
                        goto err_desc_get;
@@ -703,8 +760,8 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
                lli_write(desc, sar, src + offset);
                lli_write(desc, dar, dest + offset);
                lli_write(desc, ctllo, ctllo);
-               lli_write(desc, ctlhi, xfer_count);
-               desc->len = xfer_count << src_width;
+               lli_write(desc, ctlhi, bytes2block(dwc, len - offset, src_width, &xfer_count));
+               desc->len = xfer_count;
 
                if (!first) {
                        first = desc;
@@ -775,7 +832,8 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 
                for_each_sg(sgl, sg, sg_len, i) {
                        struct dw_desc  *desc;
-                       u32             len, dlen, mem;
+                       u32             len, mem;
+                       size_t          dlen;
 
                        mem = sg_dma_address(sg);
                        len = sg_dma_len(sg);
@@ -789,17 +847,8 @@ slave_sg_todev_fill_desc:
 
                        lli_write(desc, sar, mem);
                        lli_write(desc, dar, reg);
+                       lli_write(desc, ctlhi, bytes2block(dwc, len, mem_width, &dlen));
                        lli_write(desc, ctllo, ctllo | DWC_CTLL_SRC_WIDTH(mem_width));
-                       if ((len >> mem_width) > dwc->block_size) {
-                               dlen = dwc->block_size << mem_width;
-                               mem += dlen;
-                               len -= dlen;
-                       } else {
-                               dlen = len;
-                               len = 0;
-                       }
-
-                       lli_write(desc, ctlhi, dlen >> mem_width);
                        desc->len = dlen;
 
                        if (!first) {
@@ -809,6 +858,9 @@ slave_sg_todev_fill_desc:
                                list_add_tail(&desc->desc_node, &first->tx_list);
                        }
                        prev = desc;
+
+                       mem += dlen;
+                       len -= dlen;
                        total_len += dlen;
 
                        if (len)
@@ -828,13 +880,12 @@ slave_sg_todev_fill_desc:
 
                for_each_sg(sgl, sg, sg_len, i) {
                        struct dw_desc  *desc;
-                       u32             len, dlen, mem;
+                       u32             len, mem;
+                       size_t          dlen;
 
                        mem = sg_dma_address(sg);
                        len = sg_dma_len(sg);
 
-                       mem_width = __ffs(data_width | mem | len);
-
 slave_sg_fromdev_fill_desc:
                        desc = dwc_desc_get(dwc);
                        if (!desc)
@@ -842,16 +893,9 @@ slave_sg_fromdev_fill_desc:
 
                        lli_write(desc, sar, reg);
                        lli_write(desc, dar, mem);
+                       lli_write(desc, ctlhi, bytes2block(dwc, len, reg_width, &dlen));
+                       mem_width = __ffs(data_width | mem | dlen);
                        lli_write(desc, ctllo, ctllo | DWC_CTLL_DST_WIDTH(mem_width));
-                       if ((len >> reg_width) > dwc->block_size) {
-                               dlen = dwc->block_size << reg_width;
-                               mem += dlen;
-                               len -= dlen;
-                       } else {
-                               dlen = len;
-                               len = 0;
-                       }
-                       lli_write(desc, ctlhi, dlen >> reg_width);
                        desc->len = dlen;
 
                        if (!first) {
@@ -861,6 +905,9 @@ slave_sg_fromdev_fill_desc:
                                list_add_tail(&desc->desc_node, &first->tx_list);
                        }
                        prev = desc;
+
+                       mem += dlen;
+                       len -= dlen;
                        total_len += dlen;
 
                        if (len)
@@ -903,25 +950,20 @@ bool dw_dma_filter(struct dma_chan *chan, void *param)
 }
 EXPORT_SYMBOL_GPL(dw_dma_filter);
 
-/*
- * Fix sconfig's burst size according to dw_dmac. We need to convert them as:
- * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3.
- *
- * NOTE: burst size 2 is not supported by controller.
- *
- * This can be done by finding least significant bit set: n & (n - 1)
- */
-static inline void convert_burst(u32 *maxburst)
-{
-       if (*maxburst > 1)
-               *maxburst = fls(*maxburst) - 2;
-       else
-               *maxburst = 0;
-}
-
 static int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
 {
        struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
+       struct dma_slave_config *sc = &dwc->dma_sconfig;
+       struct dw_dma *dw = to_dw_dma(chan->device);
+       /*
+        * Fix sconfig's burst size according to dw_dmac. We need to convert
+        * them as:
+        * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3.
+        *
+        * NOTE: burst size 2 is not supported by DesignWare controller.
+        *       iDMA 32-bit supports it.
+        */
+       u32 s = dw->pdata->is_idma32 ? 1 : 2;
 
        /* Check if chan will be configured for slave transfers */
        if (!is_slave_direction(sconfig->direction))
@@ -930,28 +972,39 @@ static int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
        memcpy(&dwc->dma_sconfig, sconfig, sizeof(*sconfig));
        dwc->direction = sconfig->direction;
 
-       convert_burst(&dwc->dma_sconfig.src_maxburst);
-       convert_burst(&dwc->dma_sconfig.dst_maxburst);
+       sc->src_maxburst = sc->src_maxburst > 1 ? fls(sc->src_maxburst) - s : 0;
+       sc->dst_maxburst = sc->dst_maxburst > 1 ? fls(sc->dst_maxburst) - s : 0;
 
        return 0;
 }
 
-static int dwc_pause(struct dma_chan *chan)
+static void dwc_chan_pause(struct dw_dma_chan *dwc, bool drain)
 {
-       struct dw_dma_chan      *dwc = to_dw_dma_chan(chan);
-       unsigned long           flags;
+       struct dw_dma *dw = to_dw_dma(dwc->chan.device);
        unsigned int            count = 20;     /* timeout iterations */
        u32                     cfglo;
 
-       spin_lock_irqsave(&dwc->lock, flags);
-
        cfglo = channel_readl(dwc, CFG_LO);
+       if (dw->pdata->is_idma32) {
+               if (drain)
+                       cfglo |= IDMA32C_CFGL_CH_DRAIN;
+               else
+                       cfglo &= ~IDMA32C_CFGL_CH_DRAIN;
+       }
        channel_writel(dwc, CFG_LO, cfglo | DWC_CFGL_CH_SUSP);
        while (!(channel_readl(dwc, CFG_LO) & DWC_CFGL_FIFO_EMPTY) && count--)
                udelay(2);
 
        set_bit(DW_DMA_IS_PAUSED, &dwc->flags);
+}
 
+static int dwc_pause(struct dma_chan *chan)
+{
+       struct dw_dma_chan      *dwc = to_dw_dma_chan(chan);
+       unsigned long           flags;
+
+       spin_lock_irqsave(&dwc->lock, flags);
+       dwc_chan_pause(dwc, false);
        spin_unlock_irqrestore(&dwc->lock, flags);
 
        return 0;
@@ -993,6 +1046,8 @@ static int dwc_terminate_all(struct dma_chan *chan)
 
        clear_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags);
 
+       dwc_chan_pause(dwc, true);
+
        dwc_chan_disable(dw, dwc);
 
        dwc_chan_resume(dwc);
@@ -1085,6 +1140,32 @@ static void dwc_issue_pending(struct dma_chan *chan)
 
 /*----------------------------------------------------------------------*/
 
+/*
+ * Program FIFO size of channels.
+ *
+ * By default full FIFO (1024 bytes) is assigned to channel 0. Here we
+ * slice FIFO on equal parts between channels.
+ */
+static void idma32_fifo_partition(struct dw_dma *dw)
+{
+       u64 value = IDMA32C_FP_PSIZE_CH0(128) | IDMA32C_FP_PSIZE_CH1(128) |
+                   IDMA32C_FP_UPDATE;
+       u64 fifo_partition = 0;
+
+       if (!dw->pdata->is_idma32)
+               return;
+
+       /* Fill FIFO_PARTITION low bits (Channels 0..1, 4..5) */
+       fifo_partition |= value << 0;
+
+       /* Fill FIFO_PARTITION high bits (Channels 2..3, 6..7) */
+       fifo_partition |= value << 32;
+
+       /* Program FIFO Partition registers - 128 bytes for each channel */
+       idma32_writeq(dw, FIFO_PARTITION1, fifo_partition);
+       idma32_writeq(dw, FIFO_PARTITION0, fifo_partition);
+}
+
 static void dw_dma_off(struct dw_dma *dw)
 {
        unsigned int i;
@@ -1504,8 +1585,16 @@ int dw_dma_probe(struct dw_dma_chip *chip)
        /* Force dma off, just in case */
        dw_dma_off(dw);
 
+       idma32_fifo_partition(dw);
+
+       /* Device and instance ID for IRQ and DMA pool */
+       if (pdata->is_idma32)
+               snprintf(dw->name, sizeof(dw->name), "idma32:dmac%d", chip->id);
+       else
+               snprintf(dw->name, sizeof(dw->name), "dw:dmac%d", chip->id);
+
        /* Create a pool of consistent memory blocks for hardware descriptors */
-       dw->desc_pool = dmam_pool_create("dw_dmac_desc_pool", chip->dev,
+       dw->desc_pool = dmam_pool_create(dw->name, chip->dev,
                                         sizeof(struct dw_desc), 4, 0);
        if (!dw->desc_pool) {
                dev_err(chip->dev, "No memory for descriptors dma pool\n");
@@ -1516,7 +1605,7 @@ int dw_dma_probe(struct dw_dma_chip *chip)
        tasklet_init(&dw->tasklet, dw_dma_tasklet, (unsigned long)dw);
 
        err = request_irq(chip->irq, dw_dma_interrupt, IRQF_SHARED,
-                         "dw_dmac", dw);
+                         dw->name, dw);
        if (err)
                goto err_pdata;
 
@@ -1665,6 +1754,8 @@ int dw_dma_enable(struct dw_dma_chip *chip)
 {
        struct dw_dma *dw = chip->dw;
 
+       idma32_fifo_partition(dw);
+
        dw_dma_on(dw);
        return 0;
 }
index 0ae6c3b1d34e66b16359eb50efe0041498f18f9d..7778ed705a1adf2c91956460603329318569307f 100644 (file)
 
 #include "internal.h"
 
+static struct dw_dma_platform_data mrfld_pdata = {
+       .nr_channels = 8,
+       .is_private = true,
+       .is_memcpy = true,
+       .is_idma32 = true,
+       .chan_allocation_order = CHAN_ALLOCATION_ASCENDING,
+       .chan_priority = CHAN_PRIORITY_ASCENDING,
+       .block_size = 131071,
+       .nr_masters = 1,
+       .data_width = {4},
+};
+
 static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
 {
        const struct dw_dma_platform_data *pdata = (void *)pid->driver_data;
@@ -47,6 +59,7 @@ static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
                return -ENOMEM;
 
        chip->dev = &pdev->dev;
+       chip->id = pdev->devfn;
        chip->regs = pcim_iomap_table(pdev)[0];
        chip->irq = pdev->irq;
        chip->pdata = pdata;
@@ -95,14 +108,16 @@ static const struct dev_pm_ops dw_pci_dev_pm_ops = {
 };
 
 static const struct pci_device_id dw_pci_id_table[] = {
-       /* Medfield */
+       /* Medfield (GPDMA) */
        { PCI_VDEVICE(INTEL, 0x0827) },
-       { PCI_VDEVICE(INTEL, 0x0830) },
 
        /* BayTrail */
        { PCI_VDEVICE(INTEL, 0x0f06) },
        { PCI_VDEVICE(INTEL, 0x0f40) },
 
+       /* Merrifield iDMA 32-bit (GPDMA) */
+       { PCI_VDEVICE(INTEL, 0x11a2), (kernel_ulong_t)&mrfld_pdata },
+
        /* Braswell */
        { PCI_VDEVICE(INTEL, 0x2286) },
        { PCI_VDEVICE(INTEL, 0x22c0) },
index b1655e40cfa24f7313e11c49c7394951cda68451..c639c60b825abfcc5c1743096f855ccc413fe834 100644 (file)
@@ -202,6 +202,7 @@ static int dw_probe(struct platform_device *pdev)
                pdata = dw_dma_parse_dt(pdev);
 
        chip->dev = dev;
+       chip->id = pdev->id;
        chip->pdata = pdata;
 
        chip->clk = devm_clk_get(chip->dev, "hclk");
index 4e0128c627047741487123e8d51e38c010b6f914..32a328721c8872d2f94da638dbf429dd40fbfde5 100644 (file)
@@ -3,15 +3,19 @@
  *
  * Copyright (C) 2005-2007 Atmel Corporation
  * Copyright (C) 2010-2011 ST Microelectronics
+ * Copyright (C) 2016 Intel Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
 
+#include <linux/bitops.h>
 #include <linux/interrupt.h>
 #include <linux/dmaengine.h>
 
+#include <linux/io-64-nonatomic-hi-lo.h>
+
 #include "internal.h"
 
 #define DW_DMA_MAX_NR_REQUESTS 16
@@ -85,9 +89,9 @@ struct dw_dma_regs {
        DW_REG(ID);
        DW_REG(TEST);
 
-       /* reserved */
-       DW_REG(__reserved0);
-       DW_REG(__reserved1);
+       /* iDMA 32-bit support */
+       DW_REG(CLASS_PRIORITY0);
+       DW_REG(CLASS_PRIORITY1);
 
        /* optional encoded params, 0x3c8..0x3f7 */
        u32     __reserved;
@@ -99,6 +103,17 @@ struct dw_dma_regs {
 
        /* top-level parameters */
        u32     DW_PARAMS;
+
+       /* component ID */
+       u32     COMP_TYPE;
+       u32     COMP_VERSION;
+
+       /* iDMA 32-bit support */
+       DW_REG(FIFO_PARTITION0);
+       DW_REG(FIFO_PARTITION1);
+
+       DW_REG(SAI_ERR);
+       DW_REG(GLOBAL_CFG);
 };
 
 /*
@@ -170,8 +185,9 @@ enum dw_dma_msize {
 #define DWC_CTLL_LLP_S_EN      (1 << 28)       /* src block chain */
 
 /* Bitfields in CTL_HI */
-#define DWC_CTLH_DONE          0x00001000
-#define DWC_CTLH_BLOCK_TS_MASK 0x00000fff
+#define DWC_CTLH_BLOCK_TS_MASK GENMASK(11, 0)
+#define DWC_CTLH_BLOCK_TS(x)   ((x) & DWC_CTLH_BLOCK_TS_MASK)
+#define DWC_CTLH_DONE          (1 << 12)
 
 /* Bitfields in CFG_LO */
 #define DWC_CFGL_CH_PRIOR_MASK (0x7 << 5)      /* priority mask */
@@ -214,6 +230,33 @@ enum dw_dma_msize {
 /* Bitfields in CFG */
 #define DW_CFG_DMA_EN          (1 << 0)
 
+/* iDMA 32-bit support */
+
+/* Bitfields in CTL_HI */
+#define IDMA32C_CTLH_BLOCK_TS_MASK     GENMASK(16, 0)
+#define IDMA32C_CTLH_BLOCK_TS(x)       ((x) & IDMA32C_CTLH_BLOCK_TS_MASK)
+#define IDMA32C_CTLH_DONE              (1 << 17)
+
+/* Bitfields in CFG_LO */
+#define IDMA32C_CFGL_DST_BURST_ALIGN   (1 << 0)        /* dst burst align */
+#define IDMA32C_CFGL_SRC_BURST_ALIGN   (1 << 1)        /* src burst align */
+#define IDMA32C_CFGL_CH_DRAIN          (1 << 10)       /* drain FIFO */
+#define IDMA32C_CFGL_DST_OPT_BL                (1 << 20)       /* optimize dst burst length */
+#define IDMA32C_CFGL_SRC_OPT_BL                (1 << 21)       /* optimize src burst length */
+
+/* Bitfields in CFG_HI */
+#define IDMA32C_CFGH_SRC_PER(x)                ((x) << 0)
+#define IDMA32C_CFGH_DST_PER(x)                ((x) << 4)
+#define IDMA32C_CFGH_RD_ISSUE_THD(x)   ((x) << 8)
+#define IDMA32C_CFGH_RW_ISSUE_THD(x)   ((x) << 18)
+#define IDMA32C_CFGH_SRC_PER_EXT(x)    ((x) << 28)     /* src peripheral extension */
+#define IDMA32C_CFGH_DST_PER_EXT(x)    ((x) << 30)     /* dst peripheral extension */
+
+/* Bitfields in FIFO_PARTITION */
+#define IDMA32C_FP_PSIZE_CH0(x)                ((x) << 0)
+#define IDMA32C_FP_PSIZE_CH1(x)                ((x) << 13)
+#define IDMA32C_FP_UPDATE              (1 << 26)
+
 enum dw_dmac_flags {
        DW_DMA_IS_CYCLIC = 0,
        DW_DMA_IS_SOFT_LLP = 1,
@@ -270,6 +313,7 @@ static inline struct dw_dma_chan *to_dw_dma_chan(struct dma_chan *chan)
 
 struct dw_dma {
        struct dma_device       dma;
+       char                    name[20];
        void __iomem            *regs;
        struct dma_pool         *desc_pool;
        struct tasklet_struct   tasklet;
@@ -293,6 +337,11 @@ static inline struct dw_dma_regs __iomem *__dw_regs(struct dw_dma *dw)
 #define dma_writel(dw, name, val) \
        dma_writel_native((val), &(__dw_regs(dw)->name))
 
+#define idma32_readq(dw, name)                         \
+       hi_lo_readq(&(__dw_regs(dw)->name))
+#define idma32_writeq(dw, name, val)                   \
+       hi_lo_writeq((val), &(__dw_regs(dw)->name))
+
 #define channel_set_bit(dw, reg, mask) \
        dma_writel(dw, reg, ((mask) << 8) | (mask))
 #define channel_clear_bit(dw, reg, mask) \
index dd184b50e5b40a508c1bdacee874b6464d2b1055..284627806b887cc2fa58616639be17a244c8a058 100644 (file)
@@ -272,7 +272,7 @@ static void ipu_irq_handler(struct irq_desc *desc)
        u32 status;
        int i, line;
 
-       for (i = IPU_IRQ_NR_FN_BANKS; i < IPU_IRQ_NR_BANKS; i++) {
+       for (i = 0; i < IPU_IRQ_NR_BANKS; i++) {
                struct ipu_irq_bank *bank = irq_bank + i;
 
                raw_spin_lock(&bank_lock);
index 4c357d47546594c6bd0c9b1ca16e27c658a720cf..48b22d5c860260988f052c331f0c3050854b288c 100644 (file)
@@ -1724,6 +1724,7 @@ static int rcar_dmac_probe(struct platform_device *pdev)
 
        dmac->dev = &pdev->dev;
        platform_set_drvdata(pdev, dmac);
+       dma_set_mask_and_coherent(dmac->dev, DMA_BIT_MASK(40));
 
        ret = rcar_dmac_parse_of(&pdev->dev, dmac);
        if (ret < 0)
index 8684d11b29bba16650ff1bf154dc3ce0a16d1984..a6620b671d1d9b4b5b55de388743e1f7091db2c4 100644 (file)
@@ -2809,12 +2809,14 @@ static void __init d40_chan_init(struct d40_base *base, struct dma_device *dma,
 
 static void d40_ops_init(struct d40_base *base, struct dma_device *dev)
 {
-       if (dma_has_cap(DMA_SLAVE, dev->cap_mask))
+       if (dma_has_cap(DMA_SLAVE, dev->cap_mask)) {
                dev->device_prep_slave_sg = d40_prep_slave_sg;
+               dev->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+       }
 
        if (dma_has_cap(DMA_MEMCPY, dev->cap_mask)) {
                dev->device_prep_dma_memcpy = d40_prep_memcpy;
-
+               dev->directions = BIT(DMA_MEM_TO_MEM);
                /*
                 * This controller can only access address at even
                 * 32bit boundaries, i.e. 2^2
@@ -2836,6 +2838,7 @@ static void d40_ops_init(struct d40_base *base, struct dma_device *dev)
        dev->device_pause = d40_pause;
        dev->device_resume = d40_resume;
        dev->device_terminate_all = d40_terminate_all;
+       dev->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
        dev->dev = base->dev;
 }
 
index 3056ce7f8c69d01c61fe3ab0eeff6ad299f538f7..49f86cabcfec1e04b6d63f4dfb77d6f4a74654a4 100644 (file)
 #define STM32_DMA_MAX_CHANNELS         0x08
 #define STM32_DMA_MAX_REQUEST_ID       0x08
 #define STM32_DMA_MAX_DATA_PARAM       0x03
+#define STM32_DMA_MAX_BURST            16
 
 enum stm32_dma_width {
        STM32_DMA_BYTE,
@@ -403,6 +404,13 @@ static int stm32_dma_terminate_all(struct dma_chan *c)
        return 0;
 }
 
+static void stm32_dma_synchronize(struct dma_chan *c)
+{
+       struct stm32_dma_chan *chan = to_stm32_dma_chan(c);
+
+       vchan_synchronize(&chan->vchan);
+}
+
 static void stm32_dma_dump_reg(struct stm32_dma_chan *chan)
 {
        struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
@@ -421,7 +429,7 @@ static void stm32_dma_dump_reg(struct stm32_dma_chan *chan)
        dev_dbg(chan2dev(chan), "SFCR:  0x%08x\n", sfcr);
 }
 
-static int stm32_dma_start_transfer(struct stm32_dma_chan *chan)
+static void stm32_dma_start_transfer(struct stm32_dma_chan *chan)
 {
        struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
        struct virt_dma_desc *vdesc;
@@ -432,12 +440,12 @@ static int stm32_dma_start_transfer(struct stm32_dma_chan *chan)
 
        ret = stm32_dma_disable_chan(chan);
        if (ret < 0)
-               return ret;
+               return;
 
        if (!chan->desc) {
                vdesc = vchan_next_desc(&chan->vchan);
                if (!vdesc)
-                       return -EPERM;
+                       return;
 
                chan->desc = to_stm32_dma_desc(vdesc);
                chan->next_sg = 0;
@@ -471,7 +479,7 @@ static int stm32_dma_start_transfer(struct stm32_dma_chan *chan)
 
        chan->busy = true;
 
-       return 0;
+       dev_dbg(chan2dev(chan), "vchan %p: started\n", &chan->vchan);
 }
 
 static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan)
@@ -500,8 +508,6 @@ static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan)
                        dev_dbg(chan2dev(chan), "CT=0 <=> SM1AR: 0x%08x\n",
                                stm32_dma_read(dmadev, STM32_DMA_SM1AR(id)));
                }
-
-               chan->next_sg++;
        }
 }
 
@@ -510,6 +516,7 @@ static void stm32_dma_handle_chan_done(struct stm32_dma_chan *chan)
        if (chan->desc) {
                if (chan->desc->cyclic) {
                        vchan_cyclic_callback(&chan->desc->vdesc);
+                       chan->next_sg++;
                        stm32_dma_configure_next_sg(chan);
                } else {
                        chan->busy = false;
@@ -552,15 +559,13 @@ static void stm32_dma_issue_pending(struct dma_chan *c)
 {
        struct stm32_dma_chan *chan = to_stm32_dma_chan(c);
        unsigned long flags;
-       int ret;
 
        spin_lock_irqsave(&chan->vchan.lock, flags);
-       if (!chan->busy) {
-               if (vchan_issue_pending(&chan->vchan) && !chan->desc) {
-                       ret = stm32_dma_start_transfer(chan);
-                       if ((!ret) && (chan->desc->cyclic))
-                               stm32_dma_configure_next_sg(chan);
-               }
+       if (vchan_issue_pending(&chan->vchan) && !chan->desc && !chan->busy) {
+               dev_dbg(chan2dev(chan), "vchan %p: issued\n", &chan->vchan);
+               stm32_dma_start_transfer(chan);
+               if (chan->desc->cyclic)
+                       stm32_dma_configure_next_sg(chan);
        }
        spin_unlock_irqrestore(&chan->vchan.lock, flags);
 }
@@ -848,26 +853,40 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy(
        return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
 }
 
+static u32 stm32_dma_get_remaining_bytes(struct stm32_dma_chan *chan)
+{
+       u32 dma_scr, width, ndtr;
+       struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
+
+       dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id));
+       width = STM32_DMA_SCR_PSIZE_GET(dma_scr);
+       ndtr = stm32_dma_read(dmadev, STM32_DMA_SNDTR(chan->id));
+
+       return ndtr << width;
+}
+
 static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan,
                                     struct stm32_dma_desc *desc,
                                     u32 next_sg)
 {
-       struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
-       u32 dma_scr, width, residue, count;
+       u32 residue = 0;
        int i;
 
-       residue = 0;
+       /*
+        * In cyclic mode, for the last period, residue = remaining bytes from
+        * NDTR
+        */
+       if (chan->desc->cyclic && next_sg == 0)
+               return stm32_dma_get_remaining_bytes(chan);
 
+       /*
+        * For all other periods in cyclic mode, and in sg mode,
+        * residue = remaining bytes from NDTR + remaining periods/sg to be
+        * transferred
+        */
        for (i = next_sg; i < desc->num_sgs; i++)
                residue += desc->sg_req[i].len;
-
-       if (next_sg != 0) {
-               dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id));
-               width = STM32_DMA_SCR_PSIZE_GET(dma_scr);
-               count = stm32_dma_read(dmadev, STM32_DMA_SNDTR(chan->id));
-
-               residue += count << width;
-       }
+       residue += stm32_dma_get_remaining_bytes(chan);
 
        return residue;
 }
@@ -964,27 +983,36 @@ static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec,
                                           struct of_dma *ofdma)
 {
        struct stm32_dma_device *dmadev = ofdma->of_dma_data;
+       struct device *dev = dmadev->ddev.dev;
        struct stm32_dma_cfg cfg;
        struct stm32_dma_chan *chan;
        struct dma_chan *c;
 
-       if (dma_spec->args_count < 4)
+       if (dma_spec->args_count < 4) {
+               dev_err(dev, "Bad number of cells\n");
                return NULL;
+       }
 
        cfg.channel_id = dma_spec->args[0];
        cfg.request_line = dma_spec->args[1];
        cfg.stream_config = dma_spec->args[2];
        cfg.threshold = dma_spec->args[3];
 
-       if ((cfg.channel_id >= STM32_DMA_MAX_CHANNELS) || (cfg.request_line >=
-                               STM32_DMA_MAX_REQUEST_ID))
+       if ((cfg.channel_id >= STM32_DMA_MAX_CHANNELS) ||
+           (cfg.request_line >= STM32_DMA_MAX_REQUEST_ID)) {
+               dev_err(dev, "Bad channel and/or request id\n");
                return NULL;
+       }
 
        chan = &dmadev->chan[cfg.channel_id];
 
        c = dma_get_slave_channel(&chan->vchan.chan);
-       if (c)
-               stm32_dma_set_config(chan, &cfg);
+       if (!c) {
+               dev_err(dev, "No more channel avalaible\n");
+               return NULL;
+       }
+
+       stm32_dma_set_config(chan, &cfg);
 
        return c;
 }
@@ -1048,6 +1076,7 @@ static int stm32_dma_probe(struct platform_device *pdev)
        dd->device_prep_dma_cyclic = stm32_dma_prep_dma_cyclic;
        dd->device_config = stm32_dma_slave_config;
        dd->device_terminate_all = stm32_dma_terminate_all;
+       dd->device_synchronize = stm32_dma_synchronize;
        dd->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
                BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
                BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
@@ -1056,6 +1085,7 @@ static int stm32_dma_probe(struct platform_device *pdev)
                BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
        dd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
        dd->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
+       dd->max_burst = STM32_DMA_MAX_BURST;
        dd->dev = &pdev->dev;
        INIT_LIST_HEAD(&dd->channels);
 
diff --git a/drivers/dma/zx296702_dma.c b/drivers/dma/zx296702_dma.c
deleted file mode 100644 (file)
index 380276d..0000000
+++ /dev/null
@@ -1,950 +0,0 @@
-/*
- * Copyright 2015 Linaro.
- *
- * 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/sched.h>
-#include <linux/device.h>
-#include <linux/dmaengine.h>
-#include <linux/dma-mapping.h>
-#include <linux/dmapool.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/of_device.h>
-#include <linux/of.h>
-#include <linux/clk.h>
-#include <linux/of_dma.h>
-
-#include "virt-dma.h"
-
-#define DRIVER_NAME            "zx-dma"
-#define DMA_ALIGN              4
-#define DMA_MAX_SIZE           (0x10000 - PAGE_SIZE)
-#define LLI_BLOCK_SIZE         (4 * PAGE_SIZE)
-
-#define REG_ZX_SRC_ADDR                        0x00
-#define REG_ZX_DST_ADDR                        0x04
-#define REG_ZX_TX_X_COUNT              0x08
-#define REG_ZX_TX_ZY_COUNT             0x0c
-#define REG_ZX_SRC_ZY_STEP             0x10
-#define REG_ZX_DST_ZY_STEP             0x14
-#define REG_ZX_LLI_ADDR                        0x1c
-#define REG_ZX_CTRL                    0x20
-#define REG_ZX_TC_IRQ                  0x800
-#define REG_ZX_SRC_ERR_IRQ             0x804
-#define REG_ZX_DST_ERR_IRQ             0x808
-#define REG_ZX_CFG_ERR_IRQ             0x80c
-#define REG_ZX_TC_IRQ_RAW              0x810
-#define REG_ZX_SRC_ERR_IRQ_RAW         0x814
-#define REG_ZX_DST_ERR_IRQ_RAW         0x818
-#define REG_ZX_CFG_ERR_IRQ_RAW         0x81c
-#define REG_ZX_STATUS                  0x820
-#define REG_ZX_DMA_GRP_PRIO            0x824
-#define REG_ZX_DMA_ARB                 0x828
-
-#define ZX_FORCE_CLOSE                 BIT(31)
-#define ZX_DST_BURST_WIDTH(x)          (((x) & 0x7) << 13)
-#define ZX_MAX_BURST_LEN               16
-#define ZX_SRC_BURST_LEN(x)            (((x) & 0xf) << 9)
-#define ZX_SRC_BURST_WIDTH(x)          (((x) & 0x7) << 6)
-#define ZX_IRQ_ENABLE_ALL              (3 << 4)
-#define ZX_DST_FIFO_MODE               BIT(3)
-#define ZX_SRC_FIFO_MODE               BIT(2)
-#define ZX_SOFT_REQ                    BIT(1)
-#define ZX_CH_ENABLE                   BIT(0)
-
-#define ZX_DMA_BUSWIDTHS \
-       (BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) | \
-       BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
-       BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
-       BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \
-       BIT(DMA_SLAVE_BUSWIDTH_8_BYTES))
-
-enum zx_dma_burst_width {
-       ZX_DMA_WIDTH_8BIT       = 0,
-       ZX_DMA_WIDTH_16BIT      = 1,
-       ZX_DMA_WIDTH_32BIT      = 2,
-       ZX_DMA_WIDTH_64BIT      = 3,
-};
-
-struct zx_desc_hw {
-       u32 saddr;
-       u32 daddr;
-       u32 src_x;
-       u32 src_zy;
-       u32 src_zy_step;
-       u32 dst_zy_step;
-       u32 reserved1;
-       u32 lli;
-       u32 ctr;
-       u32 reserved[7]; /* pack as hardware registers region size */
-} __aligned(32);
-
-struct zx_dma_desc_sw {
-       struct virt_dma_desc    vd;
-       dma_addr_t              desc_hw_lli;
-       size_t                  desc_num;
-       size_t                  size;
-       struct zx_desc_hw       *desc_hw;
-};
-
-struct zx_dma_phy;
-
-struct zx_dma_chan {
-       struct dma_slave_config slave_cfg;
-       int                     id; /* Request phy chan id */
-       u32                     ccfg;
-       u32                     cyclic;
-       struct virt_dma_chan    vc;
-       struct zx_dma_phy       *phy;
-       struct list_head        node;
-       dma_addr_t              dev_addr;
-       enum dma_status         status;
-};
-
-struct zx_dma_phy {
-       u32                     idx;
-       void __iomem            *base;
-       struct zx_dma_chan      *vchan;
-       struct zx_dma_desc_sw   *ds_run;
-       struct zx_dma_desc_sw   *ds_done;
-};
-
-struct zx_dma_dev {
-       struct dma_device       slave;
-       void __iomem            *base;
-       spinlock_t              lock; /* lock for ch and phy */
-       struct list_head        chan_pending;
-       struct zx_dma_phy       *phy;
-       struct zx_dma_chan      *chans;
-       struct clk              *clk;
-       struct dma_pool         *pool;
-       u32                     dma_channels;
-       u32                     dma_requests;
-       int                     irq;
-};
-
-#define to_zx_dma(dmadev) container_of(dmadev, struct zx_dma_dev, slave)
-
-static struct zx_dma_chan *to_zx_chan(struct dma_chan *chan)
-{
-       return container_of(chan, struct zx_dma_chan, vc.chan);
-}
-
-static void zx_dma_terminate_chan(struct zx_dma_phy *phy, struct zx_dma_dev *d)
-{
-       u32 val = 0;
-
-       val = readl_relaxed(phy->base + REG_ZX_CTRL);
-       val &= ~ZX_CH_ENABLE;
-       val |= ZX_FORCE_CLOSE;
-       writel_relaxed(val, phy->base + REG_ZX_CTRL);
-
-       val = 0x1 << phy->idx;
-       writel_relaxed(val, d->base + REG_ZX_TC_IRQ_RAW);
-       writel_relaxed(val, d->base + REG_ZX_SRC_ERR_IRQ_RAW);
-       writel_relaxed(val, d->base + REG_ZX_DST_ERR_IRQ_RAW);
-       writel_relaxed(val, d->base + REG_ZX_CFG_ERR_IRQ_RAW);
-}
-
-static void zx_dma_set_desc(struct zx_dma_phy *phy, struct zx_desc_hw *hw)
-{
-       writel_relaxed(hw->saddr, phy->base + REG_ZX_SRC_ADDR);
-       writel_relaxed(hw->daddr, phy->base + REG_ZX_DST_ADDR);
-       writel_relaxed(hw->src_x, phy->base + REG_ZX_TX_X_COUNT);
-       writel_relaxed(0, phy->base + REG_ZX_TX_ZY_COUNT);
-       writel_relaxed(0, phy->base + REG_ZX_SRC_ZY_STEP);
-       writel_relaxed(0, phy->base + REG_ZX_DST_ZY_STEP);
-       writel_relaxed(hw->lli, phy->base + REG_ZX_LLI_ADDR);
-       writel_relaxed(hw->ctr, phy->base + REG_ZX_CTRL);
-}
-
-static u32 zx_dma_get_curr_lli(struct zx_dma_phy *phy)
-{
-       return readl_relaxed(phy->base + REG_ZX_LLI_ADDR);
-}
-
-static u32 zx_dma_get_chan_stat(struct zx_dma_dev *d)
-{
-       return readl_relaxed(d->base + REG_ZX_STATUS);
-}
-
-static void zx_dma_init_state(struct zx_dma_dev *d)
-{
-       /* set same priority */
-       writel_relaxed(0x0, d->base + REG_ZX_DMA_ARB);
-       /* clear all irq */
-       writel_relaxed(0xffffffff, d->base + REG_ZX_TC_IRQ_RAW);
-       writel_relaxed(0xffffffff, d->base + REG_ZX_SRC_ERR_IRQ_RAW);
-       writel_relaxed(0xffffffff, d->base + REG_ZX_DST_ERR_IRQ_RAW);
-       writel_relaxed(0xffffffff, d->base + REG_ZX_CFG_ERR_IRQ_RAW);
-}
-
-static int zx_dma_start_txd(struct zx_dma_chan *c)
-{
-       struct zx_dma_dev *d = to_zx_dma(c->vc.chan.device);
-       struct virt_dma_desc *vd = vchan_next_desc(&c->vc);
-
-       if (!c->phy)
-               return -EAGAIN;
-
-       if (BIT(c->phy->idx) & zx_dma_get_chan_stat(d))
-               return -EAGAIN;
-
-       if (vd) {
-               struct zx_dma_desc_sw *ds =
-                       container_of(vd, struct zx_dma_desc_sw, vd);
-               /*
-                * fetch and remove request from vc->desc_issued
-                * so vc->desc_issued only contains desc pending
-                */
-               list_del(&ds->vd.node);
-               c->phy->ds_run = ds;
-               c->phy->ds_done = NULL;
-               /* start dma */
-               zx_dma_set_desc(c->phy, ds->desc_hw);
-               return 0;
-       }
-       c->phy->ds_done = NULL;
-       c->phy->ds_run = NULL;
-       return -EAGAIN;
-}
-
-static void zx_dma_task(struct zx_dma_dev *d)
-{
-       struct zx_dma_phy *p;
-       struct zx_dma_chan *c, *cn;
-       unsigned pch, pch_alloc = 0;
-       unsigned long flags;
-
-       /* check new dma request of running channel in vc->desc_issued */
-       list_for_each_entry_safe(c, cn, &d->slave.channels,
-                                vc.chan.device_node) {
-               spin_lock_irqsave(&c->vc.lock, flags);
-               p = c->phy;
-               if (p && p->ds_done && zx_dma_start_txd(c)) {
-                       /* No current txd associated with this channel */
-                       dev_dbg(d->slave.dev, "pchan %u: free\n", p->idx);
-                       /* Mark this channel free */
-                       c->phy = NULL;
-                       p->vchan = NULL;
-               }
-               spin_unlock_irqrestore(&c->vc.lock, flags);
-       }
-
-       /* check new channel request in d->chan_pending */
-       spin_lock_irqsave(&d->lock, flags);
-       while (!list_empty(&d->chan_pending)) {
-               c = list_first_entry(&d->chan_pending,
-                                    struct zx_dma_chan, node);
-               p = &d->phy[c->id];
-               if (!p->vchan) {
-                       /* remove from d->chan_pending */
-                       list_del_init(&c->node);
-                       pch_alloc |= 1 << c->id;
-                       /* Mark this channel allocated */
-                       p->vchan = c;
-                       c->phy = p;
-               } else {
-                       dev_dbg(d->slave.dev, "pchan %u: busy!\n", c->id);
-               }
-       }
-       spin_unlock_irqrestore(&d->lock, flags);
-
-       for (pch = 0; pch < d->dma_channels; pch++) {
-               if (pch_alloc & (1 << pch)) {
-                       p = &d->phy[pch];
-                       c = p->vchan;
-                       if (c) {
-                               spin_lock_irqsave(&c->vc.lock, flags);
-                               zx_dma_start_txd(c);
-                               spin_unlock_irqrestore(&c->vc.lock, flags);
-                       }
-               }
-       }
-}
-
-static irqreturn_t zx_dma_int_handler(int irq, void *dev_id)
-{
-       struct zx_dma_dev *d = (struct zx_dma_dev *)dev_id;
-       struct zx_dma_phy *p;
-       struct zx_dma_chan *c;
-       u32 tc = readl_relaxed(d->base + REG_ZX_TC_IRQ);
-       u32 serr = readl_relaxed(d->base + REG_ZX_SRC_ERR_IRQ);
-       u32 derr = readl_relaxed(d->base + REG_ZX_DST_ERR_IRQ);
-       u32 cfg = readl_relaxed(d->base + REG_ZX_CFG_ERR_IRQ);
-       u32 i, irq_chan = 0, task = 0;
-
-       while (tc) {
-               i = __ffs(tc);
-               tc &= ~BIT(i);
-               p = &d->phy[i];
-               c = p->vchan;
-               if (c) {
-                       unsigned long flags;
-
-                       spin_lock_irqsave(&c->vc.lock, flags);
-                       if (c->cyclic) {
-                               vchan_cyclic_callback(&p->ds_run->vd);
-                       } else {
-                               vchan_cookie_complete(&p->ds_run->vd);
-                               p->ds_done = p->ds_run;
-                               task = 1;
-                       }
-                       spin_unlock_irqrestore(&c->vc.lock, flags);
-                       irq_chan |= BIT(i);
-               }
-       }
-
-       if (serr || derr || cfg)
-               dev_warn(d->slave.dev, "DMA ERR src 0x%x, dst 0x%x, cfg 0x%x\n",
-                        serr, derr, cfg);
-
-       writel_relaxed(irq_chan, d->base + REG_ZX_TC_IRQ_RAW);
-       writel_relaxed(serr, d->base + REG_ZX_SRC_ERR_IRQ_RAW);
-       writel_relaxed(derr, d->base + REG_ZX_DST_ERR_IRQ_RAW);
-       writel_relaxed(cfg, d->base + REG_ZX_CFG_ERR_IRQ_RAW);
-
-       if (task)
-               zx_dma_task(d);
-       return IRQ_HANDLED;
-}
-
-static void zx_dma_free_chan_resources(struct dma_chan *chan)
-{
-       struct zx_dma_chan *c = to_zx_chan(chan);
-       struct zx_dma_dev *d = to_zx_dma(chan->device);
-       unsigned long flags;
-
-       spin_lock_irqsave(&d->lock, flags);
-       list_del_init(&c->node);
-       spin_unlock_irqrestore(&d->lock, flags);
-
-       vchan_free_chan_resources(&c->vc);
-       c->ccfg = 0;
-}
-
-static enum dma_status zx_dma_tx_status(struct dma_chan *chan,
-                                       dma_cookie_t cookie,
-                                       struct dma_tx_state *state)
-{
-       struct zx_dma_chan *c = to_zx_chan(chan);
-       struct zx_dma_phy *p;
-       struct virt_dma_desc *vd;
-       unsigned long flags;
-       enum dma_status ret;
-       size_t bytes = 0;
-
-       ret = dma_cookie_status(&c->vc.chan, cookie, state);
-       if (ret == DMA_COMPLETE || !state)
-               return ret;
-
-       spin_lock_irqsave(&c->vc.lock, flags);
-       p = c->phy;
-       ret = c->status;
-
-       /*
-        * If the cookie is on our issue queue, then the residue is
-        * its total size.
-        */
-       vd = vchan_find_desc(&c->vc, cookie);
-       if (vd) {
-               bytes = container_of(vd, struct zx_dma_desc_sw, vd)->size;
-       } else if ((!p) || (!p->ds_run)) {
-               bytes = 0;
-       } else {
-               struct zx_dma_desc_sw *ds = p->ds_run;
-               u32 clli = 0, index = 0;
-
-               bytes = 0;
-               clli = zx_dma_get_curr_lli(p);
-               index = (clli - ds->desc_hw_lli) / sizeof(struct zx_desc_hw);
-               for (; index < ds->desc_num; index++) {
-                       bytes += ds->desc_hw[index].src_x;
-                       /* end of lli */
-                       if (!ds->desc_hw[index].lli)
-                               break;
-               }
-       }
-       spin_unlock_irqrestore(&c->vc.lock, flags);
-       dma_set_residue(state, bytes);
-       return ret;
-}
-
-static void zx_dma_issue_pending(struct dma_chan *chan)
-{
-       struct zx_dma_chan *c = to_zx_chan(chan);
-       struct zx_dma_dev *d = to_zx_dma(chan->device);
-       unsigned long flags;
-       int issue = 0;
-
-       spin_lock_irqsave(&c->vc.lock, flags);
-       /* add request to vc->desc_issued */
-       if (vchan_issue_pending(&c->vc)) {
-               spin_lock(&d->lock);
-               if (!c->phy && list_empty(&c->node)) {
-                       /* if new channel, add chan_pending */
-                       list_add_tail(&c->node, &d->chan_pending);
-                       issue = 1;
-                       dev_dbg(d->slave.dev, "vchan %p: issued\n", &c->vc);
-               }
-               spin_unlock(&d->lock);
-       } else {
-               dev_dbg(d->slave.dev, "vchan %p: nothing to issue\n", &c->vc);
-       }
-       spin_unlock_irqrestore(&c->vc.lock, flags);
-
-       if (issue)
-               zx_dma_task(d);
-}
-
-static void zx_dma_fill_desc(struct zx_dma_desc_sw *ds, dma_addr_t dst,
-                            dma_addr_t src, size_t len, u32 num, u32 ccfg)
-{
-       if ((num + 1) < ds->desc_num)
-               ds->desc_hw[num].lli = ds->desc_hw_lli + (num + 1) *
-                       sizeof(struct zx_desc_hw);
-       ds->desc_hw[num].saddr = src;
-       ds->desc_hw[num].daddr = dst;
-       ds->desc_hw[num].src_x = len;
-       ds->desc_hw[num].ctr = ccfg;
-}
-
-static struct zx_dma_desc_sw *zx_alloc_desc_resource(int num,
-                                                    struct dma_chan *chan)
-{
-       struct zx_dma_chan *c = to_zx_chan(chan);
-       struct zx_dma_desc_sw *ds;
-       struct zx_dma_dev *d = to_zx_dma(chan->device);
-       int lli_limit = LLI_BLOCK_SIZE / sizeof(struct zx_desc_hw);
-
-       if (num > lli_limit) {
-               dev_dbg(chan->device->dev, "vch %p: sg num %d exceed max %d\n",
-                       &c->vc, num, lli_limit);
-               return NULL;
-       }
-
-       ds = kzalloc(sizeof(*ds), GFP_ATOMIC);
-       if (!ds)
-               return NULL;
-
-       ds->desc_hw = dma_pool_zalloc(d->pool, GFP_NOWAIT, &ds->desc_hw_lli);
-       if (!ds->desc_hw) {
-               dev_dbg(chan->device->dev, "vch %p: dma alloc fail\n", &c->vc);
-               kfree(ds);
-               return NULL;
-       }
-       ds->desc_num = num;
-       return ds;
-}
-
-static enum zx_dma_burst_width zx_dma_burst_width(enum dma_slave_buswidth width)
-{
-       switch (width) {
-       case DMA_SLAVE_BUSWIDTH_1_BYTE:
-       case DMA_SLAVE_BUSWIDTH_2_BYTES:
-       case DMA_SLAVE_BUSWIDTH_4_BYTES:
-       case DMA_SLAVE_BUSWIDTH_8_BYTES:
-               return ffs(width) - 1;
-       default:
-               return ZX_DMA_WIDTH_32BIT;
-       }
-}
-
-static int zx_pre_config(struct zx_dma_chan *c, enum dma_transfer_direction dir)
-{
-       struct dma_slave_config *cfg = &c->slave_cfg;
-       enum zx_dma_burst_width src_width;
-       enum zx_dma_burst_width dst_width;
-       u32 maxburst = 0;
-
-       switch (dir) {
-       case DMA_MEM_TO_MEM:
-               c->ccfg = ZX_CH_ENABLE | ZX_SOFT_REQ
-                       | ZX_SRC_BURST_LEN(ZX_MAX_BURST_LEN - 1)
-                       | ZX_SRC_BURST_WIDTH(ZX_DMA_WIDTH_32BIT)
-                       | ZX_DST_BURST_WIDTH(ZX_DMA_WIDTH_32BIT);
-               break;
-       case DMA_MEM_TO_DEV:
-               c->dev_addr = cfg->dst_addr;
-               /* dst len is calculated from src width, len and dst width.
-                * We need make sure dst len not exceed MAX LEN.
-                * Trailing single transaction that does not fill a full
-                * burst also require identical src/dst data width.
-                */
-               dst_width = zx_dma_burst_width(cfg->dst_addr_width);
-               maxburst = cfg->dst_maxburst;
-               maxburst = maxburst < ZX_MAX_BURST_LEN ?
-                               maxburst : ZX_MAX_BURST_LEN;
-               c->ccfg = ZX_DST_FIFO_MODE | ZX_CH_ENABLE
-                       | ZX_SRC_BURST_LEN(maxburst - 1)
-                       | ZX_SRC_BURST_WIDTH(dst_width)
-                       | ZX_DST_BURST_WIDTH(dst_width);
-               break;
-       case DMA_DEV_TO_MEM:
-               c->dev_addr = cfg->src_addr;
-               src_width = zx_dma_burst_width(cfg->src_addr_width);
-               maxburst = cfg->src_maxburst;
-               maxburst = maxburst < ZX_MAX_BURST_LEN ?
-                               maxburst : ZX_MAX_BURST_LEN;
-               c->ccfg = ZX_SRC_FIFO_MODE | ZX_CH_ENABLE
-                       | ZX_SRC_BURST_LEN(maxburst - 1)
-                       | ZX_SRC_BURST_WIDTH(src_width)
-                       | ZX_DST_BURST_WIDTH(src_width);
-               break;
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static struct dma_async_tx_descriptor *zx_dma_prep_memcpy(
-       struct dma_chan *chan,  dma_addr_t dst, dma_addr_t src,
-       size_t len, unsigned long flags)
-{
-       struct zx_dma_chan *c = to_zx_chan(chan);
-       struct zx_dma_desc_sw *ds;
-       size_t copy = 0;
-       int num = 0;
-
-       if (!len)
-               return NULL;
-
-       if (zx_pre_config(c, DMA_MEM_TO_MEM))
-               return NULL;
-
-       num = DIV_ROUND_UP(len, DMA_MAX_SIZE);
-
-       ds = zx_alloc_desc_resource(num, chan);
-       if (!ds)
-               return NULL;
-
-       ds->size = len;
-       num = 0;
-
-       do {
-               copy = min_t(size_t, len, DMA_MAX_SIZE);
-               zx_dma_fill_desc(ds, dst, src, copy, num++, c->ccfg);
-
-               src += copy;
-               dst += copy;
-               len -= copy;
-       } while (len);
-
-       c->cyclic = 0;
-       ds->desc_hw[num - 1].lli = 0;   /* end of link */
-       ds->desc_hw[num - 1].ctr |= ZX_IRQ_ENABLE_ALL;
-       return vchan_tx_prep(&c->vc, &ds->vd, flags);
-}
-
-static struct dma_async_tx_descriptor *zx_dma_prep_slave_sg(
-       struct dma_chan *chan, struct scatterlist *sgl, unsigned int sglen,
-       enum dma_transfer_direction dir, unsigned long flags, void *context)
-{
-       struct zx_dma_chan *c = to_zx_chan(chan);
-       struct zx_dma_desc_sw *ds;
-       size_t len, avail, total = 0;
-       struct scatterlist *sg;
-       dma_addr_t addr, src = 0, dst = 0;
-       int num = sglen, i;
-
-       if (!sgl)
-               return NULL;
-
-       if (zx_pre_config(c, dir))
-               return NULL;
-
-       for_each_sg(sgl, sg, sglen, i) {
-               avail = sg_dma_len(sg);
-               if (avail > DMA_MAX_SIZE)
-                       num += DIV_ROUND_UP(avail, DMA_MAX_SIZE) - 1;
-       }
-
-       ds = zx_alloc_desc_resource(num, chan);
-       if (!ds)
-               return NULL;
-
-       c->cyclic = 0;
-       num = 0;
-       for_each_sg(sgl, sg, sglen, i) {
-               addr = sg_dma_address(sg);
-               avail = sg_dma_len(sg);
-               total += avail;
-
-               do {
-                       len = min_t(size_t, avail, DMA_MAX_SIZE);
-
-                       if (dir == DMA_MEM_TO_DEV) {
-                               src = addr;
-                               dst = c->dev_addr;
-                       } else if (dir == DMA_DEV_TO_MEM) {
-                               src = c->dev_addr;
-                               dst = addr;
-                       }
-
-                       zx_dma_fill_desc(ds, dst, src, len, num++, c->ccfg);
-
-                       addr += len;
-                       avail -= len;
-               } while (avail);
-       }
-
-       ds->desc_hw[num - 1].lli = 0;   /* end of link */
-       ds->desc_hw[num - 1].ctr |= ZX_IRQ_ENABLE_ALL;
-       ds->size = total;
-       return vchan_tx_prep(&c->vc, &ds->vd, flags);
-}
-
-static struct dma_async_tx_descriptor *zx_dma_prep_dma_cyclic(
-               struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
-               size_t period_len, enum dma_transfer_direction dir,
-               unsigned long flags)
-{
-       struct zx_dma_chan *c = to_zx_chan(chan);
-       struct zx_dma_desc_sw *ds;
-       dma_addr_t src = 0, dst = 0;
-       int num_periods = buf_len / period_len;
-       int buf = 0, num = 0;
-
-       if (period_len > DMA_MAX_SIZE) {
-               dev_err(chan->device->dev, "maximum period size exceeded\n");
-               return NULL;
-       }
-
-       if (zx_pre_config(c, dir))
-               return NULL;
-
-       ds = zx_alloc_desc_resource(num_periods, chan);
-       if (!ds)
-               return NULL;
-       c->cyclic = 1;
-
-       while (buf < buf_len) {
-               if (dir == DMA_MEM_TO_DEV) {
-                       src = dma_addr;
-                       dst = c->dev_addr;
-               } else if (dir == DMA_DEV_TO_MEM) {
-                       src = c->dev_addr;
-                       dst = dma_addr;
-               }
-               zx_dma_fill_desc(ds, dst, src, period_len, num++,
-                                c->ccfg | ZX_IRQ_ENABLE_ALL);
-               dma_addr += period_len;
-               buf += period_len;
-       }
-
-       ds->desc_hw[num - 1].lli = ds->desc_hw_lli;
-       ds->size = buf_len;
-       return vchan_tx_prep(&c->vc, &ds->vd, flags);
-}
-
-static int zx_dma_config(struct dma_chan *chan,
-                        struct dma_slave_config *cfg)
-{
-       struct zx_dma_chan *c = to_zx_chan(chan);
-
-       if (!cfg)
-               return -EINVAL;
-
-       memcpy(&c->slave_cfg, cfg, sizeof(*cfg));
-
-       return 0;
-}
-
-static int zx_dma_terminate_all(struct dma_chan *chan)
-{
-       struct zx_dma_chan *c = to_zx_chan(chan);
-       struct zx_dma_dev *d = to_zx_dma(chan->device);
-       struct zx_dma_phy *p = c->phy;
-       unsigned long flags;
-       LIST_HEAD(head);
-
-       dev_dbg(d->slave.dev, "vchan %p: terminate all\n", &c->vc);
-
-       /* Prevent this channel being scheduled */
-       spin_lock(&d->lock);
-       list_del_init(&c->node);
-       spin_unlock(&d->lock);
-
-       /* Clear the tx descriptor lists */
-       spin_lock_irqsave(&c->vc.lock, flags);
-       vchan_get_all_descriptors(&c->vc, &head);
-       if (p) {
-               /* vchan is assigned to a pchan - stop the channel */
-               zx_dma_terminate_chan(p, d);
-               c->phy = NULL;
-               p->vchan = NULL;
-               p->ds_run = NULL;
-               p->ds_done = NULL;
-       }
-       spin_unlock_irqrestore(&c->vc.lock, flags);
-       vchan_dma_desc_free_list(&c->vc, &head);
-
-       return 0;
-}
-
-static int zx_dma_transfer_pause(struct dma_chan *chan)
-{
-       struct zx_dma_chan *c = to_zx_chan(chan);
-       u32 val = 0;
-
-       val = readl_relaxed(c->phy->base + REG_ZX_CTRL);
-       val &= ~ZX_CH_ENABLE;
-       writel_relaxed(val, c->phy->base + REG_ZX_CTRL);
-
-       return 0;
-}
-
-static int zx_dma_transfer_resume(struct dma_chan *chan)
-{
-       struct zx_dma_chan *c = to_zx_chan(chan);
-       u32 val = 0;
-
-       val = readl_relaxed(c->phy->base + REG_ZX_CTRL);
-       val |= ZX_CH_ENABLE;
-       writel_relaxed(val, c->phy->base + REG_ZX_CTRL);
-
-       return 0;
-}
-
-static void zx_dma_free_desc(struct virt_dma_desc *vd)
-{
-       struct zx_dma_desc_sw *ds =
-               container_of(vd, struct zx_dma_desc_sw, vd);
-       struct zx_dma_dev *d = to_zx_dma(vd->tx.chan->device);
-
-       dma_pool_free(d->pool, ds->desc_hw, ds->desc_hw_lli);
-       kfree(ds);
-}
-
-static const struct of_device_id zx6702_dma_dt_ids[] = {
-       { .compatible = "zte,zx296702-dma", },
-       {}
-};
-MODULE_DEVICE_TABLE(of, zx6702_dma_dt_ids);
-
-static struct dma_chan *zx_of_dma_simple_xlate(struct of_phandle_args *dma_spec,
-                                              struct of_dma *ofdma)
-{
-       struct zx_dma_dev *d = ofdma->of_dma_data;
-       unsigned int request = dma_spec->args[0];
-       struct dma_chan *chan;
-       struct zx_dma_chan *c;
-
-       if (request >= d->dma_requests)
-               return NULL;
-
-       chan = dma_get_any_slave_channel(&d->slave);
-       if (!chan) {
-               dev_err(d->slave.dev, "get channel fail in %s.\n", __func__);
-               return NULL;
-       }
-       c = to_zx_chan(chan);
-       c->id = request;
-       dev_info(d->slave.dev, "zx_dma: pchan %u: alloc vchan %p\n",
-                c->id, &c->vc);
-       return chan;
-}
-
-static int zx_dma_probe(struct platform_device *op)
-{
-       struct zx_dma_dev *d;
-       struct resource *iores;
-       int i, ret = 0;
-
-       iores = platform_get_resource(op, IORESOURCE_MEM, 0);
-       if (!iores)
-               return -EINVAL;
-
-       d = devm_kzalloc(&op->dev, sizeof(*d), GFP_KERNEL);
-       if (!d)
-               return -ENOMEM;
-
-       d->base = devm_ioremap_resource(&op->dev, iores);
-       if (IS_ERR(d->base))
-               return PTR_ERR(d->base);
-
-       of_property_read_u32((&op->dev)->of_node,
-                            "dma-channels", &d->dma_channels);
-       of_property_read_u32((&op->dev)->of_node,
-                            "dma-requests", &d->dma_requests);
-       if (!d->dma_requests || !d->dma_channels)
-               return -EINVAL;
-
-       d->clk = devm_clk_get(&op->dev, NULL);
-       if (IS_ERR(d->clk)) {
-               dev_err(&op->dev, "no dma clk\n");
-               return PTR_ERR(d->clk);
-       }
-
-       d->irq = platform_get_irq(op, 0);
-       ret = devm_request_irq(&op->dev, d->irq, zx_dma_int_handler,
-                              0, DRIVER_NAME, d);
-       if (ret)
-               return ret;
-
-       /* A DMA memory pool for LLIs, align on 32-byte boundary */
-       d->pool = dmam_pool_create(DRIVER_NAME, &op->dev,
-                       LLI_BLOCK_SIZE, 32, 0);
-       if (!d->pool)
-               return -ENOMEM;
-
-       /* init phy channel */
-       d->phy = devm_kzalloc(&op->dev,
-               d->dma_channels * sizeof(struct zx_dma_phy), GFP_KERNEL);
-       if (!d->phy)
-               return -ENOMEM;
-
-       for (i = 0; i < d->dma_channels; i++) {
-               struct zx_dma_phy *p = &d->phy[i];
-
-               p->idx = i;
-               p->base = d->base + i * 0x40;
-       }
-
-       INIT_LIST_HEAD(&d->slave.channels);
-       dma_cap_set(DMA_SLAVE, d->slave.cap_mask);
-       dma_cap_set(DMA_MEMCPY, d->slave.cap_mask);
-       dma_cap_set(DMA_PRIVATE, d->slave.cap_mask);
-       d->slave.dev = &op->dev;
-       d->slave.device_free_chan_resources = zx_dma_free_chan_resources;
-       d->slave.device_tx_status = zx_dma_tx_status;
-       d->slave.device_prep_dma_memcpy = zx_dma_prep_memcpy;
-       d->slave.device_prep_slave_sg = zx_dma_prep_slave_sg;
-       d->slave.device_prep_dma_cyclic = zx_dma_prep_dma_cyclic;
-       d->slave.device_issue_pending = zx_dma_issue_pending;
-       d->slave.device_config = zx_dma_config;
-       d->slave.device_terminate_all = zx_dma_terminate_all;
-       d->slave.device_pause = zx_dma_transfer_pause;
-       d->slave.device_resume = zx_dma_transfer_resume;
-       d->slave.copy_align = DMA_ALIGN;
-       d->slave.src_addr_widths = ZX_DMA_BUSWIDTHS;
-       d->slave.dst_addr_widths = ZX_DMA_BUSWIDTHS;
-       d->slave.directions = BIT(DMA_MEM_TO_MEM) | BIT(DMA_MEM_TO_DEV)
-                       | BIT(DMA_DEV_TO_MEM);
-       d->slave.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
-
-       /* init virtual channel */
-       d->chans = devm_kzalloc(&op->dev,
-               d->dma_requests * sizeof(struct zx_dma_chan), GFP_KERNEL);
-       if (!d->chans)
-               return -ENOMEM;
-
-       for (i = 0; i < d->dma_requests; i++) {
-               struct zx_dma_chan *c = &d->chans[i];
-
-               c->status = DMA_IN_PROGRESS;
-               INIT_LIST_HEAD(&c->node);
-               c->vc.desc_free = zx_dma_free_desc;
-               vchan_init(&c->vc, &d->slave);
-       }
-
-       /* Enable clock before accessing registers */
-       ret = clk_prepare_enable(d->clk);
-       if (ret < 0) {
-               dev_err(&op->dev, "clk_prepare_enable failed: %d\n", ret);
-               goto zx_dma_out;
-       }
-
-       zx_dma_init_state(d);
-
-       spin_lock_init(&d->lock);
-       INIT_LIST_HEAD(&d->chan_pending);
-       platform_set_drvdata(op, d);
-
-       ret = dma_async_device_register(&d->slave);
-       if (ret)
-               goto clk_dis;
-
-       ret = of_dma_controller_register((&op->dev)->of_node,
-                                        zx_of_dma_simple_xlate, d);
-       if (ret)
-               goto of_dma_register_fail;
-
-       dev_info(&op->dev, "initialized\n");
-       return 0;
-
-of_dma_register_fail:
-       dma_async_device_unregister(&d->slave);
-clk_dis:
-       clk_disable_unprepare(d->clk);
-zx_dma_out:
-       return ret;
-}
-
-static int zx_dma_remove(struct platform_device *op)
-{
-       struct zx_dma_chan *c, *cn;
-       struct zx_dma_dev *d = platform_get_drvdata(op);
-
-       /* explictly free the irq */
-       devm_free_irq(&op->dev, d->irq, d);
-
-       dma_async_device_unregister(&d->slave);
-       of_dma_controller_free((&op->dev)->of_node);
-
-       list_for_each_entry_safe(c, cn, &d->slave.channels,
-                                vc.chan.device_node) {
-               list_del(&c->vc.chan.device_node);
-       }
-       clk_disable_unprepare(d->clk);
-       dmam_pool_destroy(d->pool);
-
-       return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int zx_dma_suspend_dev(struct device *dev)
-{
-       struct zx_dma_dev *d = dev_get_drvdata(dev);
-       u32 stat = 0;
-
-       stat = zx_dma_get_chan_stat(d);
-       if (stat) {
-               dev_warn(d->slave.dev,
-                        "chan %d is running fail to suspend\n", stat);
-               return -1;
-       }
-       clk_disable_unprepare(d->clk);
-       return 0;
-}
-
-static int zx_dma_resume_dev(struct device *dev)
-{
-       struct zx_dma_dev *d = dev_get_drvdata(dev);
-       int ret = 0;
-
-       ret = clk_prepare_enable(d->clk);
-       if (ret < 0) {
-               dev_err(d->slave.dev, "clk_prepare_enable failed: %d\n", ret);
-               return ret;
-       }
-       zx_dma_init_state(d);
-       return 0;
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(zx_dma_pmops, zx_dma_suspend_dev, zx_dma_resume_dev);
-
-static struct platform_driver zx_pdma_driver = {
-       .driver         = {
-               .name   = DRIVER_NAME,
-               .pm     = &zx_dma_pmops,
-               .of_match_table = zx6702_dma_dt_ids,
-       },
-       .probe          = zx_dma_probe,
-       .remove         = zx_dma_remove,
-};
-
-module_platform_driver(zx_pdma_driver);
-
-MODULE_DESCRIPTION("ZTE ZX296702 DMA Driver");
-MODULE_AUTHOR("Jun Nie jun.nie@linaro.org");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/dma/zx_dma.c b/drivers/dma/zx_dma.c
new file mode 100644 (file)
index 0000000..2bb6953
--- /dev/null
@@ -0,0 +1,952 @@
+/*
+ * Copyright 2015 Linaro.
+ *
+ * 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/sched.h>
+#include <linux/device.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/of_dma.h>
+
+#include "virt-dma.h"
+
+#define DRIVER_NAME            "zx-dma"
+#define DMA_ALIGN              4
+#define DMA_MAX_SIZE           (0x10000 - 512)
+#define LLI_BLOCK_SIZE         (4 * PAGE_SIZE)
+
+#define REG_ZX_SRC_ADDR                        0x00
+#define REG_ZX_DST_ADDR                        0x04
+#define REG_ZX_TX_X_COUNT              0x08
+#define REG_ZX_TX_ZY_COUNT             0x0c
+#define REG_ZX_SRC_ZY_STEP             0x10
+#define REG_ZX_DST_ZY_STEP             0x14
+#define REG_ZX_LLI_ADDR                        0x1c
+#define REG_ZX_CTRL                    0x20
+#define REG_ZX_TC_IRQ                  0x800
+#define REG_ZX_SRC_ERR_IRQ             0x804
+#define REG_ZX_DST_ERR_IRQ             0x808
+#define REG_ZX_CFG_ERR_IRQ             0x80c
+#define REG_ZX_TC_IRQ_RAW              0x810
+#define REG_ZX_SRC_ERR_IRQ_RAW         0x814
+#define REG_ZX_DST_ERR_IRQ_RAW         0x818
+#define REG_ZX_CFG_ERR_IRQ_RAW         0x81c
+#define REG_ZX_STATUS                  0x820
+#define REG_ZX_DMA_GRP_PRIO            0x824
+#define REG_ZX_DMA_ARB                 0x828
+
+#define ZX_FORCE_CLOSE                 BIT(31)
+#define ZX_DST_BURST_WIDTH(x)          (((x) & 0x7) << 13)
+#define ZX_MAX_BURST_LEN               16
+#define ZX_SRC_BURST_LEN(x)            (((x) & 0xf) << 9)
+#define ZX_SRC_BURST_WIDTH(x)          (((x) & 0x7) << 6)
+#define ZX_IRQ_ENABLE_ALL              (3 << 4)
+#define ZX_DST_FIFO_MODE               BIT(3)
+#define ZX_SRC_FIFO_MODE               BIT(2)
+#define ZX_SOFT_REQ                    BIT(1)
+#define ZX_CH_ENABLE                   BIT(0)
+
+#define ZX_DMA_BUSWIDTHS \
+       (BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) | \
+       BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
+       BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
+       BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \
+       BIT(DMA_SLAVE_BUSWIDTH_8_BYTES))
+
+enum zx_dma_burst_width {
+       ZX_DMA_WIDTH_8BIT       = 0,
+       ZX_DMA_WIDTH_16BIT      = 1,
+       ZX_DMA_WIDTH_32BIT      = 2,
+       ZX_DMA_WIDTH_64BIT      = 3,
+};
+
+struct zx_desc_hw {
+       u32 saddr;
+       u32 daddr;
+       u32 src_x;
+       u32 src_zy;
+       u32 src_zy_step;
+       u32 dst_zy_step;
+       u32 reserved1;
+       u32 lli;
+       u32 ctr;
+       u32 reserved[7]; /* pack as hardware registers region size */
+} __aligned(32);
+
+struct zx_dma_desc_sw {
+       struct virt_dma_desc    vd;
+       dma_addr_t              desc_hw_lli;
+       size_t                  desc_num;
+       size_t                  size;
+       struct zx_desc_hw       *desc_hw;
+};
+
+struct zx_dma_phy;
+
+struct zx_dma_chan {
+       struct dma_slave_config slave_cfg;
+       int                     id; /* Request phy chan id */
+       u32                     ccfg;
+       u32                     cyclic;
+       struct virt_dma_chan    vc;
+       struct zx_dma_phy       *phy;
+       struct list_head        node;
+       dma_addr_t              dev_addr;
+       enum dma_status         status;
+};
+
+struct zx_dma_phy {
+       u32                     idx;
+       void __iomem            *base;
+       struct zx_dma_chan      *vchan;
+       struct zx_dma_desc_sw   *ds_run;
+       struct zx_dma_desc_sw   *ds_done;
+};
+
+struct zx_dma_dev {
+       struct dma_device       slave;
+       void __iomem            *base;
+       spinlock_t              lock; /* lock for ch and phy */
+       struct list_head        chan_pending;
+       struct zx_dma_phy       *phy;
+       struct zx_dma_chan      *chans;
+       struct clk              *clk;
+       struct dma_pool         *pool;
+       u32                     dma_channels;
+       u32                     dma_requests;
+       int                     irq;
+};
+
+#define to_zx_dma(dmadev) container_of(dmadev, struct zx_dma_dev, slave)
+
+static struct zx_dma_chan *to_zx_chan(struct dma_chan *chan)
+{
+       return container_of(chan, struct zx_dma_chan, vc.chan);
+}
+
+static void zx_dma_terminate_chan(struct zx_dma_phy *phy, struct zx_dma_dev *d)
+{
+       u32 val = 0;
+
+       val = readl_relaxed(phy->base + REG_ZX_CTRL);
+       val &= ~ZX_CH_ENABLE;
+       val |= ZX_FORCE_CLOSE;
+       writel_relaxed(val, phy->base + REG_ZX_CTRL);
+
+       val = 0x1 << phy->idx;
+       writel_relaxed(val, d->base + REG_ZX_TC_IRQ_RAW);
+       writel_relaxed(val, d->base + REG_ZX_SRC_ERR_IRQ_RAW);
+       writel_relaxed(val, d->base + REG_ZX_DST_ERR_IRQ_RAW);
+       writel_relaxed(val, d->base + REG_ZX_CFG_ERR_IRQ_RAW);
+}
+
+static void zx_dma_set_desc(struct zx_dma_phy *phy, struct zx_desc_hw *hw)
+{
+       writel_relaxed(hw->saddr, phy->base + REG_ZX_SRC_ADDR);
+       writel_relaxed(hw->daddr, phy->base + REG_ZX_DST_ADDR);
+       writel_relaxed(hw->src_x, phy->base + REG_ZX_TX_X_COUNT);
+       writel_relaxed(0, phy->base + REG_ZX_TX_ZY_COUNT);
+       writel_relaxed(0, phy->base + REG_ZX_SRC_ZY_STEP);
+       writel_relaxed(0, phy->base + REG_ZX_DST_ZY_STEP);
+       writel_relaxed(hw->lli, phy->base + REG_ZX_LLI_ADDR);
+       writel_relaxed(hw->ctr, phy->base + REG_ZX_CTRL);
+}
+
+static u32 zx_dma_get_curr_lli(struct zx_dma_phy *phy)
+{
+       return readl_relaxed(phy->base + REG_ZX_LLI_ADDR);
+}
+
+static u32 zx_dma_get_chan_stat(struct zx_dma_dev *d)
+{
+       return readl_relaxed(d->base + REG_ZX_STATUS);
+}
+
+static void zx_dma_init_state(struct zx_dma_dev *d)
+{
+       /* set same priority */
+       writel_relaxed(0x0, d->base + REG_ZX_DMA_ARB);
+       /* clear all irq */
+       writel_relaxed(0xffffffff, d->base + REG_ZX_TC_IRQ_RAW);
+       writel_relaxed(0xffffffff, d->base + REG_ZX_SRC_ERR_IRQ_RAW);
+       writel_relaxed(0xffffffff, d->base + REG_ZX_DST_ERR_IRQ_RAW);
+       writel_relaxed(0xffffffff, d->base + REG_ZX_CFG_ERR_IRQ_RAW);
+}
+
+static int zx_dma_start_txd(struct zx_dma_chan *c)
+{
+       struct zx_dma_dev *d = to_zx_dma(c->vc.chan.device);
+       struct virt_dma_desc *vd = vchan_next_desc(&c->vc);
+
+       if (!c->phy)
+               return -EAGAIN;
+
+       if (BIT(c->phy->idx) & zx_dma_get_chan_stat(d))
+               return -EAGAIN;
+
+       if (vd) {
+               struct zx_dma_desc_sw *ds =
+                       container_of(vd, struct zx_dma_desc_sw, vd);
+               /*
+                * fetch and remove request from vc->desc_issued
+                * so vc->desc_issued only contains desc pending
+                */
+               list_del(&ds->vd.node);
+               c->phy->ds_run = ds;
+               c->phy->ds_done = NULL;
+               /* start dma */
+               zx_dma_set_desc(c->phy, ds->desc_hw);
+               return 0;
+       }
+       c->phy->ds_done = NULL;
+       c->phy->ds_run = NULL;
+       return -EAGAIN;
+}
+
+static void zx_dma_task(struct zx_dma_dev *d)
+{
+       struct zx_dma_phy *p;
+       struct zx_dma_chan *c, *cn;
+       unsigned pch, pch_alloc = 0;
+       unsigned long flags;
+
+       /* check new dma request of running channel in vc->desc_issued */
+       list_for_each_entry_safe(c, cn, &d->slave.channels,
+                                vc.chan.device_node) {
+               spin_lock_irqsave(&c->vc.lock, flags);
+               p = c->phy;
+               if (p && p->ds_done && zx_dma_start_txd(c)) {
+                       /* No current txd associated with this channel */
+                       dev_dbg(d->slave.dev, "pchan %u: free\n", p->idx);
+                       /* Mark this channel free */
+                       c->phy = NULL;
+                       p->vchan = NULL;
+               }
+               spin_unlock_irqrestore(&c->vc.lock, flags);
+       }
+
+       /* check new channel request in d->chan_pending */
+       spin_lock_irqsave(&d->lock, flags);
+       while (!list_empty(&d->chan_pending)) {
+               c = list_first_entry(&d->chan_pending,
+                                    struct zx_dma_chan, node);
+               p = &d->phy[c->id];
+               if (!p->vchan) {
+                       /* remove from d->chan_pending */
+                       list_del_init(&c->node);
+                       pch_alloc |= 1 << c->id;
+                       /* Mark this channel allocated */
+                       p->vchan = c;
+                       c->phy = p;
+               } else {
+                       dev_dbg(d->slave.dev, "pchan %u: busy!\n", c->id);
+               }
+       }
+       spin_unlock_irqrestore(&d->lock, flags);
+
+       for (pch = 0; pch < d->dma_channels; pch++) {
+               if (pch_alloc & (1 << pch)) {
+                       p = &d->phy[pch];
+                       c = p->vchan;
+                       if (c) {
+                               spin_lock_irqsave(&c->vc.lock, flags);
+                               zx_dma_start_txd(c);
+                               spin_unlock_irqrestore(&c->vc.lock, flags);
+                       }
+               }
+       }
+}
+
+static irqreturn_t zx_dma_int_handler(int irq, void *dev_id)
+{
+       struct zx_dma_dev *d = (struct zx_dma_dev *)dev_id;
+       struct zx_dma_phy *p;
+       struct zx_dma_chan *c;
+       u32 tc = readl_relaxed(d->base + REG_ZX_TC_IRQ);
+       u32 serr = readl_relaxed(d->base + REG_ZX_SRC_ERR_IRQ);
+       u32 derr = readl_relaxed(d->base + REG_ZX_DST_ERR_IRQ);
+       u32 cfg = readl_relaxed(d->base + REG_ZX_CFG_ERR_IRQ);
+       u32 i, irq_chan = 0, task = 0;
+
+       while (tc) {
+               i = __ffs(tc);
+               tc &= ~BIT(i);
+               p = &d->phy[i];
+               c = p->vchan;
+               if (c) {
+                       unsigned long flags;
+
+                       spin_lock_irqsave(&c->vc.lock, flags);
+                       if (c->cyclic) {
+                               vchan_cyclic_callback(&p->ds_run->vd);
+                       } else {
+                               vchan_cookie_complete(&p->ds_run->vd);
+                               p->ds_done = p->ds_run;
+                               task = 1;
+                       }
+                       spin_unlock_irqrestore(&c->vc.lock, flags);
+                       irq_chan |= BIT(i);
+               }
+       }
+
+       if (serr || derr || cfg)
+               dev_warn(d->slave.dev, "DMA ERR src 0x%x, dst 0x%x, cfg 0x%x\n",
+                        serr, derr, cfg);
+
+       writel_relaxed(irq_chan, d->base + REG_ZX_TC_IRQ_RAW);
+       writel_relaxed(serr, d->base + REG_ZX_SRC_ERR_IRQ_RAW);
+       writel_relaxed(derr, d->base + REG_ZX_DST_ERR_IRQ_RAW);
+       writel_relaxed(cfg, d->base + REG_ZX_CFG_ERR_IRQ_RAW);
+
+       if (task)
+               zx_dma_task(d);
+       return IRQ_HANDLED;
+}
+
+static void zx_dma_free_chan_resources(struct dma_chan *chan)
+{
+       struct zx_dma_chan *c = to_zx_chan(chan);
+       struct zx_dma_dev *d = to_zx_dma(chan->device);
+       unsigned long flags;
+
+       spin_lock_irqsave(&d->lock, flags);
+       list_del_init(&c->node);
+       spin_unlock_irqrestore(&d->lock, flags);
+
+       vchan_free_chan_resources(&c->vc);
+       c->ccfg = 0;
+}
+
+static enum dma_status zx_dma_tx_status(struct dma_chan *chan,
+                                       dma_cookie_t cookie,
+                                       struct dma_tx_state *state)
+{
+       struct zx_dma_chan *c = to_zx_chan(chan);
+       struct zx_dma_phy *p;
+       struct virt_dma_desc *vd;
+       unsigned long flags;
+       enum dma_status ret;
+       size_t bytes = 0;
+
+       ret = dma_cookie_status(&c->vc.chan, cookie, state);
+       if (ret == DMA_COMPLETE || !state)
+               return ret;
+
+       spin_lock_irqsave(&c->vc.lock, flags);
+       p = c->phy;
+       ret = c->status;
+
+       /*
+        * If the cookie is on our issue queue, then the residue is
+        * its total size.
+        */
+       vd = vchan_find_desc(&c->vc, cookie);
+       if (vd) {
+               bytes = container_of(vd, struct zx_dma_desc_sw, vd)->size;
+       } else if ((!p) || (!p->ds_run)) {
+               bytes = 0;
+       } else {
+               struct zx_dma_desc_sw *ds = p->ds_run;
+               u32 clli = 0, index = 0;
+
+               bytes = 0;
+               clli = zx_dma_get_curr_lli(p);
+               index = (clli - ds->desc_hw_lli) /
+                               sizeof(struct zx_desc_hw) + 1;
+               for (; index < ds->desc_num; index++) {
+                       bytes += ds->desc_hw[index].src_x;
+                       /* end of lli */
+                       if (!ds->desc_hw[index].lli)
+                               break;
+               }
+       }
+       spin_unlock_irqrestore(&c->vc.lock, flags);
+       dma_set_residue(state, bytes);
+       return ret;
+}
+
+static void zx_dma_issue_pending(struct dma_chan *chan)
+{
+       struct zx_dma_chan *c = to_zx_chan(chan);
+       struct zx_dma_dev *d = to_zx_dma(chan->device);
+       unsigned long flags;
+       int issue = 0;
+
+       spin_lock_irqsave(&c->vc.lock, flags);
+       /* add request to vc->desc_issued */
+       if (vchan_issue_pending(&c->vc)) {
+               spin_lock(&d->lock);
+               if (!c->phy && list_empty(&c->node)) {
+                       /* if new channel, add chan_pending */
+                       list_add_tail(&c->node, &d->chan_pending);
+                       issue = 1;
+                       dev_dbg(d->slave.dev, "vchan %p: issued\n", &c->vc);
+               }
+               spin_unlock(&d->lock);
+       } else {
+               dev_dbg(d->slave.dev, "vchan %p: nothing to issue\n", &c->vc);
+       }
+       spin_unlock_irqrestore(&c->vc.lock, flags);
+
+       if (issue)
+               zx_dma_task(d);
+}
+
+static void zx_dma_fill_desc(struct zx_dma_desc_sw *ds, dma_addr_t dst,
+                            dma_addr_t src, size_t len, u32 num, u32 ccfg)
+{
+       if ((num + 1) < ds->desc_num)
+               ds->desc_hw[num].lli = ds->desc_hw_lli + (num + 1) *
+                       sizeof(struct zx_desc_hw);
+       ds->desc_hw[num].saddr = src;
+       ds->desc_hw[num].daddr = dst;
+       ds->desc_hw[num].src_x = len;
+       ds->desc_hw[num].ctr = ccfg;
+}
+
+static struct zx_dma_desc_sw *zx_alloc_desc_resource(int num,
+                                                    struct dma_chan *chan)
+{
+       struct zx_dma_chan *c = to_zx_chan(chan);
+       struct zx_dma_desc_sw *ds;
+       struct zx_dma_dev *d = to_zx_dma(chan->device);
+       int lli_limit = LLI_BLOCK_SIZE / sizeof(struct zx_desc_hw);
+
+       if (num > lli_limit) {
+               dev_dbg(chan->device->dev, "vch %p: sg num %d exceed max %d\n",
+                       &c->vc, num, lli_limit);
+               return NULL;
+       }
+
+       ds = kzalloc(sizeof(*ds), GFP_ATOMIC);
+       if (!ds)
+               return NULL;
+
+       ds->desc_hw = dma_pool_zalloc(d->pool, GFP_NOWAIT, &ds->desc_hw_lli);
+       if (!ds->desc_hw) {
+               dev_dbg(chan->device->dev, "vch %p: dma alloc fail\n", &c->vc);
+               kfree(ds);
+               return NULL;
+       }
+       ds->desc_num = num;
+       return ds;
+}
+
+static enum zx_dma_burst_width zx_dma_burst_width(enum dma_slave_buswidth width)
+{
+       switch (width) {
+       case DMA_SLAVE_BUSWIDTH_1_BYTE:
+       case DMA_SLAVE_BUSWIDTH_2_BYTES:
+       case DMA_SLAVE_BUSWIDTH_4_BYTES:
+       case DMA_SLAVE_BUSWIDTH_8_BYTES:
+               return ffs(width) - 1;
+       default:
+               return ZX_DMA_WIDTH_32BIT;
+       }
+}
+
+static int zx_pre_config(struct zx_dma_chan *c, enum dma_transfer_direction dir)
+{
+       struct dma_slave_config *cfg = &c->slave_cfg;
+       enum zx_dma_burst_width src_width;
+       enum zx_dma_burst_width dst_width;
+       u32 maxburst = 0;
+
+       switch (dir) {
+       case DMA_MEM_TO_MEM:
+               c->ccfg = ZX_CH_ENABLE | ZX_SOFT_REQ
+                       | ZX_SRC_BURST_LEN(ZX_MAX_BURST_LEN - 1)
+                       | ZX_SRC_BURST_WIDTH(ZX_DMA_WIDTH_32BIT)
+                       | ZX_DST_BURST_WIDTH(ZX_DMA_WIDTH_32BIT);
+               break;
+       case DMA_MEM_TO_DEV:
+               c->dev_addr = cfg->dst_addr;
+               /* dst len is calculated from src width, len and dst width.
+                * We need make sure dst len not exceed MAX LEN.
+                * Trailing single transaction that does not fill a full
+                * burst also require identical src/dst data width.
+                */
+               dst_width = zx_dma_burst_width(cfg->dst_addr_width);
+               maxburst = cfg->dst_maxburst;
+               maxburst = maxburst < ZX_MAX_BURST_LEN ?
+                               maxburst : ZX_MAX_BURST_LEN;
+               c->ccfg = ZX_DST_FIFO_MODE | ZX_CH_ENABLE
+                       | ZX_SRC_BURST_LEN(maxburst - 1)
+                       | ZX_SRC_BURST_WIDTH(dst_width)
+                       | ZX_DST_BURST_WIDTH(dst_width);
+               break;
+       case DMA_DEV_TO_MEM:
+               c->dev_addr = cfg->src_addr;
+               src_width = zx_dma_burst_width(cfg->src_addr_width);
+               maxburst = cfg->src_maxburst;
+               maxburst = maxburst < ZX_MAX_BURST_LEN ?
+                               maxburst : ZX_MAX_BURST_LEN;
+               c->ccfg = ZX_SRC_FIFO_MODE | ZX_CH_ENABLE
+                       | ZX_SRC_BURST_LEN(maxburst - 1)
+                       | ZX_SRC_BURST_WIDTH(src_width)
+                       | ZX_DST_BURST_WIDTH(src_width);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static struct dma_async_tx_descriptor *zx_dma_prep_memcpy(
+       struct dma_chan *chan,  dma_addr_t dst, dma_addr_t src,
+       size_t len, unsigned long flags)
+{
+       struct zx_dma_chan *c = to_zx_chan(chan);
+       struct zx_dma_desc_sw *ds;
+       size_t copy = 0;
+       int num = 0;
+
+       if (!len)
+               return NULL;
+
+       if (zx_pre_config(c, DMA_MEM_TO_MEM))
+               return NULL;
+
+       num = DIV_ROUND_UP(len, DMA_MAX_SIZE);
+
+       ds = zx_alloc_desc_resource(num, chan);
+       if (!ds)
+               return NULL;
+
+       ds->size = len;
+       num = 0;
+
+       do {
+               copy = min_t(size_t, len, DMA_MAX_SIZE);
+               zx_dma_fill_desc(ds, dst, src, copy, num++, c->ccfg);
+
+               src += copy;
+               dst += copy;
+               len -= copy;
+       } while (len);
+
+       c->cyclic = 0;
+       ds->desc_hw[num - 1].lli = 0;   /* end of link */
+       ds->desc_hw[num - 1].ctr |= ZX_IRQ_ENABLE_ALL;
+       return vchan_tx_prep(&c->vc, &ds->vd, flags);
+}
+
+static struct dma_async_tx_descriptor *zx_dma_prep_slave_sg(
+       struct dma_chan *chan, struct scatterlist *sgl, unsigned int sglen,
+       enum dma_transfer_direction dir, unsigned long flags, void *context)
+{
+       struct zx_dma_chan *c = to_zx_chan(chan);
+       struct zx_dma_desc_sw *ds;
+       size_t len, avail, total = 0;
+       struct scatterlist *sg;
+       dma_addr_t addr, src = 0, dst = 0;
+       int num = sglen, i;
+
+       if (!sgl)
+               return NULL;
+
+       if (zx_pre_config(c, dir))
+               return NULL;
+
+       for_each_sg(sgl, sg, sglen, i) {
+               avail = sg_dma_len(sg);
+               if (avail > DMA_MAX_SIZE)
+                       num += DIV_ROUND_UP(avail, DMA_MAX_SIZE) - 1;
+       }
+
+       ds = zx_alloc_desc_resource(num, chan);
+       if (!ds)
+               return NULL;
+
+       c->cyclic = 0;
+       num = 0;
+       for_each_sg(sgl, sg, sglen, i) {
+               addr = sg_dma_address(sg);
+               avail = sg_dma_len(sg);
+               total += avail;
+
+               do {
+                       len = min_t(size_t, avail, DMA_MAX_SIZE);
+
+                       if (dir == DMA_MEM_TO_DEV) {
+                               src = addr;
+                               dst = c->dev_addr;
+                       } else if (dir == DMA_DEV_TO_MEM) {
+                               src = c->dev_addr;
+                               dst = addr;
+                       }
+
+                       zx_dma_fill_desc(ds, dst, src, len, num++, c->ccfg);
+
+                       addr += len;
+                       avail -= len;
+               } while (avail);
+       }
+
+       ds->desc_hw[num - 1].lli = 0;   /* end of link */
+       ds->desc_hw[num - 1].ctr |= ZX_IRQ_ENABLE_ALL;
+       ds->size = total;
+       return vchan_tx_prep(&c->vc, &ds->vd, flags);
+}
+
+static struct dma_async_tx_descriptor *zx_dma_prep_dma_cyclic(
+               struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
+               size_t period_len, enum dma_transfer_direction dir,
+               unsigned long flags)
+{
+       struct zx_dma_chan *c = to_zx_chan(chan);
+       struct zx_dma_desc_sw *ds;
+       dma_addr_t src = 0, dst = 0;
+       int num_periods = buf_len / period_len;
+       int buf = 0, num = 0;
+
+       if (period_len > DMA_MAX_SIZE) {
+               dev_err(chan->device->dev, "maximum period size exceeded\n");
+               return NULL;
+       }
+
+       if (zx_pre_config(c, dir))
+               return NULL;
+
+       ds = zx_alloc_desc_resource(num_periods, chan);
+       if (!ds)
+               return NULL;
+       c->cyclic = 1;
+
+       while (buf < buf_len) {
+               if (dir == DMA_MEM_TO_DEV) {
+                       src = dma_addr;
+                       dst = c->dev_addr;
+               } else if (dir == DMA_DEV_TO_MEM) {
+                       src = c->dev_addr;
+                       dst = dma_addr;
+               }
+               zx_dma_fill_desc(ds, dst, src, period_len, num++,
+                                c->ccfg | ZX_IRQ_ENABLE_ALL);
+               dma_addr += period_len;
+               buf += period_len;
+       }
+
+       ds->desc_hw[num - 1].lli = ds->desc_hw_lli;
+       ds->size = buf_len;
+       return vchan_tx_prep(&c->vc, &ds->vd, flags);
+}
+
+static int zx_dma_config(struct dma_chan *chan,
+                        struct dma_slave_config *cfg)
+{
+       struct zx_dma_chan *c = to_zx_chan(chan);
+
+       if (!cfg)
+               return -EINVAL;
+
+       memcpy(&c->slave_cfg, cfg, sizeof(*cfg));
+
+       return 0;
+}
+
+static int zx_dma_terminate_all(struct dma_chan *chan)
+{
+       struct zx_dma_chan *c = to_zx_chan(chan);
+       struct zx_dma_dev *d = to_zx_dma(chan->device);
+       struct zx_dma_phy *p = c->phy;
+       unsigned long flags;
+       LIST_HEAD(head);
+
+       dev_dbg(d->slave.dev, "vchan %p: terminate all\n", &c->vc);
+
+       /* Prevent this channel being scheduled */
+       spin_lock(&d->lock);
+       list_del_init(&c->node);
+       spin_unlock(&d->lock);
+
+       /* Clear the tx descriptor lists */
+       spin_lock_irqsave(&c->vc.lock, flags);
+       vchan_get_all_descriptors(&c->vc, &head);
+       if (p) {
+               /* vchan is assigned to a pchan - stop the channel */
+               zx_dma_terminate_chan(p, d);
+               c->phy = NULL;
+               p->vchan = NULL;
+               p->ds_run = NULL;
+               p->ds_done = NULL;
+       }
+       spin_unlock_irqrestore(&c->vc.lock, flags);
+       vchan_dma_desc_free_list(&c->vc, &head);
+
+       return 0;
+}
+
+static int zx_dma_transfer_pause(struct dma_chan *chan)
+{
+       struct zx_dma_chan *c = to_zx_chan(chan);
+       u32 val = 0;
+
+       val = readl_relaxed(c->phy->base + REG_ZX_CTRL);
+       val &= ~ZX_CH_ENABLE;
+       writel_relaxed(val, c->phy->base + REG_ZX_CTRL);
+
+       return 0;
+}
+
+static int zx_dma_transfer_resume(struct dma_chan *chan)
+{
+       struct zx_dma_chan *c = to_zx_chan(chan);
+       u32 val = 0;
+
+       val = readl_relaxed(c->phy->base + REG_ZX_CTRL);
+       val |= ZX_CH_ENABLE;
+       writel_relaxed(val, c->phy->base + REG_ZX_CTRL);
+
+       return 0;
+}
+
+static void zx_dma_free_desc(struct virt_dma_desc *vd)
+{
+       struct zx_dma_desc_sw *ds =
+               container_of(vd, struct zx_dma_desc_sw, vd);
+       struct zx_dma_dev *d = to_zx_dma(vd->tx.chan->device);
+
+       dma_pool_free(d->pool, ds->desc_hw, ds->desc_hw_lli);
+       kfree(ds);
+}
+
+static const struct of_device_id zx6702_dma_dt_ids[] = {
+       { .compatible = "zte,zx296702-dma", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, zx6702_dma_dt_ids);
+
+static struct dma_chan *zx_of_dma_simple_xlate(struct of_phandle_args *dma_spec,
+                                              struct of_dma *ofdma)
+{
+       struct zx_dma_dev *d = ofdma->of_dma_data;
+       unsigned int request = dma_spec->args[0];
+       struct dma_chan *chan;
+       struct zx_dma_chan *c;
+
+       if (request >= d->dma_requests)
+               return NULL;
+
+       chan = dma_get_any_slave_channel(&d->slave);
+       if (!chan) {
+               dev_err(d->slave.dev, "get channel fail in %s.\n", __func__);
+               return NULL;
+       }
+       c = to_zx_chan(chan);
+       c->id = request;
+       dev_info(d->slave.dev, "zx_dma: pchan %u: alloc vchan %p\n",
+                c->id, &c->vc);
+       return chan;
+}
+
+static int zx_dma_probe(struct platform_device *op)
+{
+       struct zx_dma_dev *d;
+       struct resource *iores;
+       int i, ret = 0;
+
+       iores = platform_get_resource(op, IORESOURCE_MEM, 0);
+       if (!iores)
+               return -EINVAL;
+
+       d = devm_kzalloc(&op->dev, sizeof(*d), GFP_KERNEL);
+       if (!d)
+               return -ENOMEM;
+
+       d->base = devm_ioremap_resource(&op->dev, iores);
+       if (IS_ERR(d->base))
+               return PTR_ERR(d->base);
+
+       of_property_read_u32((&op->dev)->of_node,
+                            "dma-channels", &d->dma_channels);
+       of_property_read_u32((&op->dev)->of_node,
+                            "dma-requests", &d->dma_requests);
+       if (!d->dma_requests || !d->dma_channels)
+               return -EINVAL;
+
+       d->clk = devm_clk_get(&op->dev, NULL);
+       if (IS_ERR(d->clk)) {
+               dev_err(&op->dev, "no dma clk\n");
+               return PTR_ERR(d->clk);
+       }
+
+       d->irq = platform_get_irq(op, 0);
+       ret = devm_request_irq(&op->dev, d->irq, zx_dma_int_handler,
+                              0, DRIVER_NAME, d);
+       if (ret)
+               return ret;
+
+       /* A DMA memory pool for LLIs, align on 32-byte boundary */
+       d->pool = dmam_pool_create(DRIVER_NAME, &op->dev,
+                       LLI_BLOCK_SIZE, 32, 0);
+       if (!d->pool)
+               return -ENOMEM;
+
+       /* init phy channel */
+       d->phy = devm_kzalloc(&op->dev,
+               d->dma_channels * sizeof(struct zx_dma_phy), GFP_KERNEL);
+       if (!d->phy)
+               return -ENOMEM;
+
+       for (i = 0; i < d->dma_channels; i++) {
+               struct zx_dma_phy *p = &d->phy[i];
+
+               p->idx = i;
+               p->base = d->base + i * 0x40;
+       }
+
+       INIT_LIST_HEAD(&d->slave.channels);
+       dma_cap_set(DMA_SLAVE, d->slave.cap_mask);
+       dma_cap_set(DMA_MEMCPY, d->slave.cap_mask);
+       dma_cap_set(DMA_CYCLIC, d->slave.cap_mask);
+       dma_cap_set(DMA_PRIVATE, d->slave.cap_mask);
+       d->slave.dev = &op->dev;
+       d->slave.device_free_chan_resources = zx_dma_free_chan_resources;
+       d->slave.device_tx_status = zx_dma_tx_status;
+       d->slave.device_prep_dma_memcpy = zx_dma_prep_memcpy;
+       d->slave.device_prep_slave_sg = zx_dma_prep_slave_sg;
+       d->slave.device_prep_dma_cyclic = zx_dma_prep_dma_cyclic;
+       d->slave.device_issue_pending = zx_dma_issue_pending;
+       d->slave.device_config = zx_dma_config;
+       d->slave.device_terminate_all = zx_dma_terminate_all;
+       d->slave.device_pause = zx_dma_transfer_pause;
+       d->slave.device_resume = zx_dma_transfer_resume;
+       d->slave.copy_align = DMA_ALIGN;
+       d->slave.src_addr_widths = ZX_DMA_BUSWIDTHS;
+       d->slave.dst_addr_widths = ZX_DMA_BUSWIDTHS;
+       d->slave.directions = BIT(DMA_MEM_TO_MEM) | BIT(DMA_MEM_TO_DEV)
+                       | BIT(DMA_DEV_TO_MEM);
+       d->slave.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
+
+       /* init virtual channel */
+       d->chans = devm_kzalloc(&op->dev,
+               d->dma_requests * sizeof(struct zx_dma_chan), GFP_KERNEL);
+       if (!d->chans)
+               return -ENOMEM;
+
+       for (i = 0; i < d->dma_requests; i++) {
+               struct zx_dma_chan *c = &d->chans[i];
+
+               c->status = DMA_IN_PROGRESS;
+               INIT_LIST_HEAD(&c->node);
+               c->vc.desc_free = zx_dma_free_desc;
+               vchan_init(&c->vc, &d->slave);
+       }
+
+       /* Enable clock before accessing registers */
+       ret = clk_prepare_enable(d->clk);
+       if (ret < 0) {
+               dev_err(&op->dev, "clk_prepare_enable failed: %d\n", ret);
+               goto zx_dma_out;
+       }
+
+       zx_dma_init_state(d);
+
+       spin_lock_init(&d->lock);
+       INIT_LIST_HEAD(&d->chan_pending);
+       platform_set_drvdata(op, d);
+
+       ret = dma_async_device_register(&d->slave);
+       if (ret)
+               goto clk_dis;
+
+       ret = of_dma_controller_register((&op->dev)->of_node,
+                                        zx_of_dma_simple_xlate, d);
+       if (ret)
+               goto of_dma_register_fail;
+
+       dev_info(&op->dev, "initialized\n");
+       return 0;
+
+of_dma_register_fail:
+       dma_async_device_unregister(&d->slave);
+clk_dis:
+       clk_disable_unprepare(d->clk);
+zx_dma_out:
+       return ret;
+}
+
+static int zx_dma_remove(struct platform_device *op)
+{
+       struct zx_dma_chan *c, *cn;
+       struct zx_dma_dev *d = platform_get_drvdata(op);
+
+       /* explictly free the irq */
+       devm_free_irq(&op->dev, d->irq, d);
+
+       dma_async_device_unregister(&d->slave);
+       of_dma_controller_free((&op->dev)->of_node);
+
+       list_for_each_entry_safe(c, cn, &d->slave.channels,
+                                vc.chan.device_node) {
+               list_del(&c->vc.chan.device_node);
+       }
+       clk_disable_unprepare(d->clk);
+       dmam_pool_destroy(d->pool);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int zx_dma_suspend_dev(struct device *dev)
+{
+       struct zx_dma_dev *d = dev_get_drvdata(dev);
+       u32 stat = 0;
+
+       stat = zx_dma_get_chan_stat(d);
+       if (stat) {
+               dev_warn(d->slave.dev,
+                        "chan %d is running fail to suspend\n", stat);
+               return -1;
+       }
+       clk_disable_unprepare(d->clk);
+       return 0;
+}
+
+static int zx_dma_resume_dev(struct device *dev)
+{
+       struct zx_dma_dev *d = dev_get_drvdata(dev);
+       int ret = 0;
+
+       ret = clk_prepare_enable(d->clk);
+       if (ret < 0) {
+               dev_err(d->slave.dev, "clk_prepare_enable failed: %d\n", ret);
+               return ret;
+       }
+       zx_dma_init_state(d);
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(zx_dma_pmops, zx_dma_suspend_dev, zx_dma_resume_dev);
+
+static struct platform_driver zx_pdma_driver = {
+       .driver         = {
+               .name   = DRIVER_NAME,
+               .pm     = &zx_dma_pmops,
+               .of_match_table = zx6702_dma_dt_ids,
+       },
+       .probe          = zx_dma_probe,
+       .remove         = zx_dma_remove,
+};
+
+module_platform_driver(zx_pdma_driver);
+
+MODULE_DESCRIPTION("ZTE ZX296702 DMA Driver");
+MODULE_AUTHOR("Jun Nie jun.nie@linaro.org");
+MODULE_LICENSE("GPL v2");
index 03a5925a423c93dbb9e381be0a1da6300990d9ac..fb16cc771c0ddfd88f8b51ad321f59c6601200eb 100644 (file)
 #include <linux/gpio/driver.h>
 #include <linux/pinctrl/consumer.h>
 
+struct aspeed_bank_props {
+       unsigned int bank;
+       u32 input;
+       u32 output;
+};
+
+struct aspeed_gpio_config {
+       unsigned int nr_gpios;
+       const struct aspeed_bank_props *props;
+};
+
 struct aspeed_gpio {
        struct gpio_chip chip;
        spinlock_t lock;
        void __iomem *base;
        int irq;
+       const struct aspeed_gpio_config *config;
 };
 
 struct aspeed_gpio_bank {
        uint16_t        val_regs;
        uint16_t        irq_regs;
-       const char      names[4];
+       const char      names[4][3];
 };
 
 static const struct aspeed_gpio_bank aspeed_gpio_banks[] = {
        {
                .val_regs = 0x0000,
                .irq_regs = 0x0008,
-               .names = { 'A', 'B', 'C', 'D' },
+               .names = { "A", "B", "C", "D" },
        },
        {
                .val_regs = 0x0020,
                .irq_regs = 0x0028,
-               .names = { 'E', 'F', 'G', 'H' },
+               .names = { "E", "F", "G", "H" },
        },
        {
                .val_regs = 0x0070,
                .irq_regs = 0x0098,
-               .names = { 'I', 'J', 'K', 'L' },
+               .names = { "I", "J", "K", "L" },
        },
        {
                .val_regs = 0x0078,
                .irq_regs = 0x00e8,
-               .names = { 'M', 'N', 'O', 'P' },
+               .names = { "M", "N", "O", "P" },
        },
        {
                .val_regs = 0x0080,
                .irq_regs = 0x0118,
-               .names = { 'Q', 'R', 'S', 'T' },
+               .names = { "Q", "R", "S", "T" },
        },
        {
                .val_regs = 0x0088,
                .irq_regs = 0x0148,
-               .names = { 'U', 'V', 'W', 'X' },
+               .names = { "U", "V", "W", "X" },
+       },
+       {
+               .val_regs = 0x01E0,
+               .irq_regs = 0x0178,
+               .names = { "Y", "Z", "AA", "AB" },
+       },
+       {
+               .val_regs = 0x01E8,
+               .irq_regs = 0x01A8,
+               .names = { "AC", "", "", "" },
        },
-       /*
-        * A bank exists for { 'Y', 'Z', "AA", "AB" }, but is not implemented.
-        * Only half of GPIOs Y support interrupt configuration, and none of Z,
-        * AA or AB do as they are output only.
-        */
 };
 
 #define GPIO_BANK(x)   ((x) >> 5)
@@ -90,6 +107,51 @@ static const struct aspeed_gpio_bank *to_bank(unsigned int offset)
        return &aspeed_gpio_banks[bank];
 }
 
+static inline bool is_bank_props_sentinel(const struct aspeed_bank_props *props)
+{
+       return !(props->input || props->output);
+}
+
+static inline const struct aspeed_bank_props *find_bank_props(
+               struct aspeed_gpio *gpio, unsigned int offset)
+{
+       const struct aspeed_bank_props *props = gpio->config->props;
+
+       while (!is_bank_props_sentinel(props)) {
+               if (props->bank == GPIO_BANK(offset))
+                       return props;
+               props++;
+       }
+
+       return NULL;
+}
+
+static inline bool have_gpio(struct aspeed_gpio *gpio, unsigned int offset)
+{
+       const struct aspeed_bank_props *props = find_bank_props(gpio, offset);
+       const struct aspeed_gpio_bank *bank = to_bank(offset);
+       unsigned int group = GPIO_OFFSET(offset) / 8;
+
+       return bank->names[group][0] != '\0' &&
+               (!props || ((props->input | props->output) & GPIO_BIT(offset)));
+}
+
+static inline bool have_input(struct aspeed_gpio *gpio, unsigned int offset)
+{
+       const struct aspeed_bank_props *props = find_bank_props(gpio, offset);
+
+       return !props || (props->input & GPIO_BIT(offset));
+}
+
+#define have_irq(g, o) have_input((g), (o))
+
+static inline bool have_output(struct aspeed_gpio *gpio, unsigned int offset)
+{
+       const struct aspeed_bank_props *props = find_bank_props(gpio, offset);
+
+       return !props || (props->output & GPIO_BIT(offset));
+}
+
 static void __iomem *bank_val_reg(struct aspeed_gpio *gpio,
                const struct aspeed_gpio_bank *bank,
                unsigned int reg)
@@ -152,6 +214,9 @@ static int aspeed_gpio_dir_in(struct gpio_chip *gc, unsigned int offset)
        unsigned long flags;
        u32 reg;
 
+       if (!have_input(gpio, offset))
+               return -ENOTSUPP;
+
        spin_lock_irqsave(&gpio->lock, flags);
 
        reg = ioread32(bank_val_reg(gpio, bank, GPIO_DIR));
@@ -170,6 +235,9 @@ static int aspeed_gpio_dir_out(struct gpio_chip *gc,
        unsigned long flags;
        u32 reg;
 
+       if (!have_output(gpio, offset))
+               return -ENOTSUPP;
+
        spin_lock_irqsave(&gpio->lock, flags);
 
        reg = ioread32(bank_val_reg(gpio, bank, GPIO_DIR));
@@ -189,6 +257,12 @@ static int aspeed_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
        unsigned long flags;
        u32 val;
 
+       if (!have_input(gpio, offset))
+               return 0;
+
+       if (!have_output(gpio, offset))
+               return 1;
+
        spin_lock_irqsave(&gpio->lock, flags);
 
        val = ioread32(bank_val_reg(gpio, bank, GPIO_DIR)) & GPIO_BIT(offset);
@@ -205,10 +279,17 @@ static inline int irqd_to_aspeed_gpio_data(struct irq_data *d,
                u32 *bit)
 {
        int offset;
+       struct aspeed_gpio *internal;
 
        offset = irqd_to_hwirq(d);
 
-       *gpio = irq_data_get_irq_chip_data(d);
+       internal = irq_data_get_irq_chip_data(d);
+
+       /* This might be a bit of a questionable place to check */
+       if (!have_irq(internal, offset))
+               return -ENOTSUPP;
+
+       *gpio = internal;
        *bank = to_bank(offset);
        *bit = GPIO_BIT(offset);
 
@@ -364,6 +445,28 @@ static struct irq_chip aspeed_gpio_irqchip = {
        .irq_set_type   = aspeed_gpio_set_type,
 };
 
+static void set_irq_valid_mask(struct aspeed_gpio *gpio)
+{
+       const struct aspeed_bank_props *props = gpio->config->props;
+
+       while (!is_bank_props_sentinel(props)) {
+               unsigned int offset;
+               const unsigned long int input = props->input;
+
+               /* Pretty crummy approach, but similar to GPIO core */
+               for_each_clear_bit(offset, &input, 32) {
+                       unsigned int i = props->bank * 32 + offset;
+
+                       if (i >= gpio->config->nr_gpios)
+                               break;
+
+                       clear_bit(i, gpio->chip.irq_valid_mask);
+               }
+
+               props++;
+       }
+}
+
 static int aspeed_gpio_setup_irqs(struct aspeed_gpio *gpio,
                struct platform_device *pdev)
 {
@@ -375,6 +478,8 @@ static int aspeed_gpio_setup_irqs(struct aspeed_gpio *gpio,
 
        gpio->irq = rc;
 
+       set_irq_valid_mask(gpio);
+
        rc = gpiochip_irqchip_add(&gpio->chip, &aspeed_gpio_irqchip,
                        0, handle_bad_irq, IRQ_TYPE_NONE);
        if (rc) {
@@ -390,6 +495,9 @@ static int aspeed_gpio_setup_irqs(struct aspeed_gpio *gpio,
 
 static int aspeed_gpio_request(struct gpio_chip *chip, unsigned int offset)
 {
+       if (!have_gpio(gpiochip_get_data(chip), offset))
+               return -ENODEV;
+
        return pinctrl_request_gpio(chip->base + offset);
 }
 
@@ -398,8 +506,46 @@ static void aspeed_gpio_free(struct gpio_chip *chip, unsigned int offset)
        pinctrl_free_gpio(chip->base + offset);
 }
 
+/*
+ * Any banks not specified in a struct aspeed_bank_props array are assumed to
+ * have the properties:
+ *
+ *     { .input = 0xffffffff, .output = 0xffffffff }
+ */
+
+static const struct aspeed_bank_props ast2400_bank_props[] = {
+       /*     input      output   */
+       { 5, 0xffffffff, 0x0000ffff }, /* U/V/W/X */
+       { 6, 0x0000000f, 0x0fffff0f }, /* Y/Z/AA/AB, two 4-GPIO holes */
+       { },
+};
+
+static const struct aspeed_gpio_config ast2400_config =
+       /* 220 for simplicity, really 216 with two 4-GPIO holes, four at end */
+       { .nr_gpios = 220, .props = ast2400_bank_props, };
+
+static const struct aspeed_bank_props ast2500_bank_props[] = {
+       /*     input      output   */
+       { 5, 0xffffffff, 0x0000ffff }, /* U/V/W/X */
+       { 6, 0x0fffffff, 0x0fffffff }, /* Y/Z/AA/AB, 4-GPIO hole */
+       { 7, 0x000000ff, 0x000000ff }, /* AC */
+       { },
+};
+
+static const struct aspeed_gpio_config ast2500_config =
+       /* 232 for simplicity, actual number is 228 (4-GPIO hole in GPIOAB) */
+       { .nr_gpios = 232, .props = ast2500_bank_props, };
+
+static const struct of_device_id aspeed_gpio_of_table[] = {
+       { .compatible = "aspeed,ast2400-gpio", .data = &ast2400_config, },
+       { .compatible = "aspeed,ast2500-gpio", .data = &ast2500_config, },
+       {}
+};
+MODULE_DEVICE_TABLE(of, aspeed_gpio_of_table);
+
 static int __init aspeed_gpio_probe(struct platform_device *pdev)
 {
+       const struct of_device_id *gpio_id;
        struct aspeed_gpio *gpio;
        struct resource *res;
        int rc;
@@ -415,8 +561,13 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
 
        spin_lock_init(&gpio->lock);
 
-       gpio->chip.ngpio = ARRAY_SIZE(aspeed_gpio_banks) * 32;
+       gpio_id = of_match_node(aspeed_gpio_of_table, pdev->dev.of_node);
+       if (!gpio_id)
+               return -EINVAL;
+
+       gpio->config = gpio_id->data;
 
+       gpio->chip.ngpio = gpio->config->nr_gpios;
        gpio->chip.parent = &pdev->dev;
        gpio->chip.direction_input = aspeed_gpio_dir_in;
        gpio->chip.direction_output = aspeed_gpio_dir_out;
@@ -427,6 +578,7 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
        gpio->chip.set = aspeed_gpio_set;
        gpio->chip.label = dev_name(&pdev->dev);
        gpio->chip.base = -1;
+       gpio->chip.irq_need_valid_mask = true;
 
        rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
        if (rc < 0)
@@ -435,13 +587,6 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
        return aspeed_gpio_setup_irqs(gpio, pdev);
 }
 
-static const struct of_device_id aspeed_gpio_of_table[] = {
-       { .compatible = "aspeed,ast2400-gpio" },
-       { .compatible = "aspeed,ast2500-gpio" },
-       {}
-};
-MODULE_DEVICE_TABLE(of, aspeed_gpio_of_table);
-
 static struct platform_driver aspeed_gpio_driver = {
        .driver = {
                .name = KBUILD_MODNAME,
index 3d1cf018e8e7e27c8d7baf06a9755c7ae6a5e429..41d0ac1425803eeeb5098c7a6f73d1c35aa17ce1 100644 (file)
@@ -308,6 +308,18 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio,
        return 0;
 }
 
+static int bcm_kona_gpio_set_config(struct gpio_chip *chip, unsigned gpio,
+                                   unsigned long config)
+{
+       u32 debounce;
+
+       if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
+               return -ENOTSUPP;
+
+       debounce = pinconf_to_config_argument(config);
+       return bcm_kona_gpio_set_debounce(chip, gpio, debounce);
+}
+
 static const struct gpio_chip template_chip = {
        .label = "bcm-kona-gpio",
        .owner = THIS_MODULE,
@@ -318,7 +330,7 @@ static const struct gpio_chip template_chip = {
        .get = bcm_kona_gpio_get,
        .direction_output = bcm_kona_gpio_direction_output,
        .set = bcm_kona_gpio_set,
-       .set_debounce = bcm_kona_gpio_set_debounce,
+       .set_config = bcm_kona_gpio_set_config,
        .to_irq = bcm_kona_gpio_to_irq,
        .base = 0,
 };
index 5d38b08d1ee25f01316ade4f2aa5364385ed3da7..aecb847166f537778d00ec7fe1df297b22d912eb 100644 (file)
@@ -272,12 +272,16 @@ static int dln2_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
        return dln2_gpio_set_direction(chip, offset, DLN2_GPIO_DIRECTION_OUT);
 }
 
-static int dln2_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
-                                 unsigned debounce)
+static int dln2_gpio_set_config(struct gpio_chip *chip, unsigned offset,
+                               unsigned long config)
 {
        struct dln2_gpio *dln2 = gpiochip_get_data(chip);
-       __le32 duration = cpu_to_le32(debounce);
+       __le32 duration;
 
+       if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
+               return -ENOTSUPP;
+
+       duration = cpu_to_le32(pinconf_to_config_argument(config));
        return dln2_transfer_tx(dln2->pdev, DLN2_GPIO_SET_DEBOUNCE,
                                &duration, sizeof(duration));
 }
@@ -474,7 +478,7 @@ static int dln2_gpio_probe(struct platform_device *pdev)
        dln2->gpio.get_direction = dln2_gpio_get_direction;
        dln2->gpio.direction_input = dln2_gpio_direction_input;
        dln2->gpio.direction_output = dln2_gpio_direction_output;
-       dln2->gpio.set_debounce = dln2_gpio_set_debounce;
+       dln2->gpio.set_config = dln2_gpio_set_config;
 
        platform_set_drvdata(pdev, dln2);
 
index 6193f62c0df494f91ea74295adb59ab7a0756455..9c15ee4ef4e9b3a560a537bf62447447f8a66732 100644 (file)
@@ -279,6 +279,18 @@ static int dwapb_gpio_set_debounce(struct gpio_chip *gc,
        return 0;
 }
 
+static int dwapb_gpio_set_config(struct gpio_chip *gc, unsigned offset,
+                                unsigned long config)
+{
+       u32 debounce;
+
+       if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
+               return -ENOTSUPP;
+
+       debounce = pinconf_to_config_argument(config);
+       return dwapb_gpio_set_debounce(gc, offset, debounce);
+}
+
 static irqreturn_t dwapb_irq_handler_mfd(int irq, void *dev_id)
 {
        u32 worked;
@@ -426,7 +438,7 @@ static int dwapb_gpio_add_port(struct dwapb_gpio *gpio,
 
        /* Only port A support debounce */
        if (pp->idx == 0)
-               port->gc.set_debounce = dwapb_gpio_set_debounce;
+               port->gc.set_config = dwapb_gpio_set_config;
 
        if (pp->irq)
                dwapb_configure_irqs(gpio, port, pp);
index d054219e18b930d1cc0df7880066fd3e8b3b0ed1..45d384039e9b1ca13c410fbbcfc3091a51e6bfb0 100644 (file)
@@ -291,15 +291,20 @@ static struct ep93xx_gpio_bank ep93xx_gpio_banks[] = {
        EP93XX_GPIO_BANK("H", 0x40, 0x44, 56, false),
 };
 
-static int ep93xx_gpio_set_debounce(struct gpio_chip *chip,
-                                   unsigned offset, unsigned debounce)
+static int ep93xx_gpio_set_config(struct gpio_chip *chip, unsigned offset,
+                                 unsigned long config)
 {
        int gpio = chip->base + offset;
        int irq = gpio_to_irq(gpio);
+       u32 debounce;
+
+       if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
+               return -ENOTSUPP;
 
        if (irq < 0)
                return -EINVAL;
 
+       debounce = pinconf_to_config_argument(config);
        ep93xx_gpio_int_debounce(irq, debounce ? true : false);
 
        return 0;
@@ -335,7 +340,7 @@ static int ep93xx_gpio_add_bank(struct gpio_chip *gc, struct device *dev,
        gc->base = bank->base;
 
        if (bank->has_debounce) {
-               gc->set_debounce = ep93xx_gpio_set_debounce;
+               gc->set_config = ep93xx_gpio_set_config;
                gc->to_irq = ep93xx_gpio_to_irq;
        }
 
index e8accde62aa71421809783c4615c6cf58354243f..56bd76c337675e96aeeec8fecb6bec9161a9dadb 100644 (file)
@@ -131,9 +131,8 @@ static int f7188x_gpio_get(struct gpio_chip *chip, unsigned offset);
 static int f7188x_gpio_direction_out(struct gpio_chip *chip,
                                     unsigned offset, int value);
 static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value);
-static int f7188x_gpio_set_single_ended(struct gpio_chip *gc,
-                                       unsigned offset,
-                                       enum single_ended_mode mode);
+static int f7188x_gpio_set_config(struct gpio_chip *chip, unsigned offset,
+                                 unsigned long config);
 
 #define F7188X_GPIO_BANK(_base, _ngpio, _regbase)                      \
        {                                                               \
@@ -145,7 +144,7 @@ static int f7188x_gpio_set_single_ended(struct gpio_chip *gc,
                        .get              = f7188x_gpio_get,            \
                        .direction_output = f7188x_gpio_direction_out,  \
                        .set              = f7188x_gpio_set,            \
-                       .set_single_ended = f7188x_gpio_set_single_ended, \
+                       .set_config       = f7188x_gpio_set_config,     \
                        .base             = _base,                      \
                        .ngpio            = _ngpio,                     \
                        .can_sleep        = true,                       \
@@ -326,17 +325,17 @@ static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
        superio_exit(sio->addr);
 }
 
-static int f7188x_gpio_set_single_ended(struct gpio_chip *chip,
-                                       unsigned offset,
-                                       enum single_ended_mode mode)
+static int f7188x_gpio_set_config(struct gpio_chip *chip, unsigned offset,
+                                 unsigned long config)
 {
        int err;
+       enum pin_config_param param = pinconf_to_config_param(config);
        struct f7188x_gpio_bank *bank = gpiochip_get_data(chip);
        struct f7188x_sio *sio = bank->data->sio;
        u8 data;
 
-       if (mode != LINE_MODE_OPEN_DRAIN &&
-           mode != LINE_MODE_PUSH_PULL)
+       if (param != PIN_CONFIG_DRIVE_OPEN_DRAIN &&
+           param != PIN_CONFIG_DRIVE_PUSH_PULL)
                return -ENOTSUPP;
 
        err = superio_enter(sio->addr);
@@ -345,7 +344,7 @@ static int f7188x_gpio_set_single_ended(struct gpio_chip *chip,
        superio_select(sio->addr, SIO_LD_GPIO);
 
        data = superio_inb(sio->addr, gpio_out_mode(bank->regbase));
-       if (mode == LINE_MODE_OPEN_DRAIN)
+       if (param == PIN_CONFIG_DRIVE_OPEN_DRAIN)
                data &= ~BIT(offset);
        else
                data |= BIT(offset);
index 218c706359aaf2ea9cdd706816facf2df7aeafa6..df0ad2cef0d2bfc3b3d80bd9aed01f3482379ff3 100644 (file)
@@ -100,21 +100,21 @@ static int lp873x_gpio_request(struct gpio_chip *gc, unsigned int offset)
        return 0;
 }
 
-static int lp873x_gpio_set_single_ended(struct gpio_chip *gc,
-                                       unsigned int offset,
-                                       enum single_ended_mode mode)
+static int lp873x_gpio_set_config(struct gpio_chip *gc, unsigned offset,
+                                 unsigned long config)
 {
        struct lp873x_gpio *gpio = gpiochip_get_data(gc);
 
-       switch (mode) {
-       case LINE_MODE_OPEN_DRAIN:
+       switch (pinconf_to_config_param(config)) {
+       case PIN_CONFIG_DRIVE_OPEN_DRAIN:
                return regmap_update_bits(gpio->lp873->regmap,
                                          LP873X_REG_GPO_CTRL,
                                          BIT(offset * BITS_PER_GPO +
                                          LP873X_GPO_CTRL_OD),
                                          BIT(offset * BITS_PER_GPO +
                                          LP873X_GPO_CTRL_OD));
-       case LINE_MODE_PUSH_PULL:
+
+       case PIN_CONFIG_DRIVE_PUSH_PULL:
                return regmap_update_bits(gpio->lp873->regmap,
                                          LP873X_REG_GPO_CTRL,
                                          BIT(offset * BITS_PER_GPO +
@@ -133,7 +133,7 @@ static const struct gpio_chip template_chip = {
        .direction_output       = lp873x_gpio_direction_output,
        .get                    = lp873x_gpio_get,
        .set                    = lp873x_gpio_set,
-       .set_single_ended       = lp873x_gpio_set_single_ended,
+       .set_config             = lp873x_gpio_set_config,
        .base                   = -1,
        .ngpio                  = 2,
        .can_sleep              = true,
index ec8de4190db9f266925f56e7f033ea036f18353a..743459d9477d746761f72c8f71623decf247ad88 100644 (file)
@@ -152,11 +152,10 @@ static int max77620_gpio_dir_output(struct gpio_chip *gc, unsigned int offset,
        return ret;
 }
 
-static int max77620_gpio_set_debounce(struct gpio_chip *gc,
+static int max77620_gpio_set_debounce(struct max77620_gpio *mgpio,
                                      unsigned int offset,
                                      unsigned int debounce)
 {
-       struct max77620_gpio *mgpio = gpiochip_get_data(gc);
        u8 val;
        int ret;
 
@@ -202,21 +201,23 @@ static void max77620_gpio_set(struct gpio_chip *gc, unsigned int offset,
                dev_err(mgpio->dev, "CNFG_GPIO_OUT update failed: %d\n", ret);
 }
 
-static int max77620_gpio_set_single_ended(struct gpio_chip *gc,
-                                         unsigned int offset,
-                                         enum single_ended_mode mode)
+static int max77620_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
+                                   unsigned long config)
 {
        struct max77620_gpio *mgpio = gpiochip_get_data(gc);
 
-       switch (mode) {
-       case LINE_MODE_OPEN_DRAIN:
+       switch (pinconf_to_config_param(config)) {
+       case PIN_CONFIG_DRIVE_OPEN_DRAIN:
                return regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),
                                          MAX77620_CNFG_GPIO_DRV_MASK,
                                          MAX77620_CNFG_GPIO_DRV_OPENDRAIN);
-       case LINE_MODE_PUSH_PULL:
+       case PIN_CONFIG_DRIVE_PUSH_PULL:
                return regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),
                                          MAX77620_CNFG_GPIO_DRV_MASK,
                                          MAX77620_CNFG_GPIO_DRV_PUSHPULL);
+       case PIN_CONFIG_INPUT_DEBOUNCE:
+               return max77620_gpio_set_debounce(mgpio, offset,
+                       pinconf_to_config_argument(config));
        default:
                break;
        }
@@ -257,9 +258,8 @@ static int max77620_gpio_probe(struct platform_device *pdev)
        mgpio->gpio_chip.direction_input = max77620_gpio_dir_input;
        mgpio->gpio_chip.get = max77620_gpio_get;
        mgpio->gpio_chip.direction_output = max77620_gpio_dir_output;
-       mgpio->gpio_chip.set_debounce = max77620_gpio_set_debounce;
        mgpio->gpio_chip.set = max77620_gpio_set;
-       mgpio->gpio_chip.set_single_ended = max77620_gpio_set_single_ended;
+       mgpio->gpio_chip.set_config = max77620_gpio_set_config;
        mgpio->gpio_chip.to_irq = max77620_gpio_to_irq;
        mgpio->gpio_chip.ngpio = MAX77620_GPIO_NR;
        mgpio->gpio_chip.can_sleep = 1;
index a1210e33057120668d50129447e5af540366d16b..e1037582e34d7f69da7b3e96586f288b1f723f0b 100644 (file)
@@ -89,22 +89,18 @@ static int men_z127_debounce(struct gpio_chip *gc, unsigned gpio,
 
 static int men_z127_set_single_ended(struct gpio_chip *gc,
                                     unsigned offset,
-                                    enum single_ended_mode mode)
+                                    enum pin_config_param param)
 {
        struct men_z127_gpio *priv = gpiochip_get_data(gc);
        u32 od_en;
 
-       if (mode != LINE_MODE_OPEN_DRAIN &&
-           mode != LINE_MODE_PUSH_PULL)
-               return -ENOTSUPP;
-
        spin_lock(&gc->bgpio_lock);
        od_en = readl(priv->reg_base + MEN_Z127_ODER);
 
-       if (mode == LINE_MODE_OPEN_DRAIN)
+       if (param == PIN_CONFIG_DRIVE_OPEN_DRAIN)
                od_en |= BIT(offset);
        else
-               /* Implicitly LINE_MODE_PUSH_PULL */
+               /* Implicitly PIN_CONFIG_DRIVE_PUSH_PULL */
                od_en &= ~BIT(offset);
 
        writel(od_en, priv->reg_base + MEN_Z127_ODER);
@@ -113,6 +109,27 @@ static int men_z127_set_single_ended(struct gpio_chip *gc,
        return 0;
 }
 
+static int men_z127_set_config(struct gpio_chip *gc, unsigned offset,
+                              unsigned long config)
+{
+       enum pin_config_param param = pinconf_to_config_param(config);
+
+       switch (param) {
+       case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+       case PIN_CONFIG_DRIVE_PUSH_PULL:
+               return men_z127_set_single_ended(gc, offset, param);
+
+       case PIN_CONFIG_INPUT_DEBOUNCE:
+               return men_z127_debounce(gc, offset,
+                       pinconf_to_config_argument(config));
+
+       default:
+               break;
+       }
+
+       return -ENOTSUPP;
+}
+
 static int men_z127_probe(struct mcb_device *mdev,
                          const struct mcb_device_id *id)
 {
@@ -149,8 +166,7 @@ static int men_z127_probe(struct mcb_device *mdev,
        if (ret)
                goto err_unmap;
 
-       men_z127_gpio->gc.set_debounce = men_z127_debounce;
-       men_z127_gpio->gc.set_single_ended = men_z127_set_single_ended;
+       men_z127_gpio->gc.set_config = men_z127_set_config;
 
        ret = gpiochip_add_data(&men_z127_gpio->gc, men_z127_gpio);
        if (ret) {
index 69e0f4ace46557c94b2f2d959b632d4d0f236ebd..f40088d268c174e5cf26ef0a54c6838159d4a4d3 100644 (file)
@@ -190,6 +190,18 @@ static int mrfld_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset,
        return 0;
 }
 
+static int mrfld_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
+                                unsigned long config)
+{
+       u32 debounce;
+
+       if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
+               return -ENOTSUPP;
+
+       debounce = pinconf_to_config_argument(config);
+       return mrfld_gpio_set_debounce(chip, offset, debounce);
+}
+
 static void mrfld_irq_ack(struct irq_data *d)
 {
        struct mrfld_gpio *priv = irq_data_get_irq_chip_data(d);
@@ -414,7 +426,7 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id
        priv->chip.get = mrfld_gpio_get;
        priv->chip.set = mrfld_gpio_set;
        priv->chip.get_direction = mrfld_gpio_get_direction;
-       priv->chip.set_debounce = mrfld_gpio_set_debounce;
+       priv->chip.set_config = mrfld_gpio_set_config;
        priv->chip.base = gpio_base;
        priv->chip.ngpio = MRFLD_NGPIO;
        priv->chip.can_sleep = false;
index b98ede78c9d854deffa8c79d205c3ddf253ac42e..efc85a279d5473b18079e43d4a5f51ef15f1d328 100644 (file)
@@ -974,6 +974,18 @@ static int omap_gpio_debounce(struct gpio_chip *chip, unsigned offset,
        return 0;
 }
 
+static int omap_gpio_set_config(struct gpio_chip *chip, unsigned offset,
+                               unsigned long config)
+{
+       u32 debounce;
+
+       if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
+               return -ENOTSUPP;
+
+       debounce = pinconf_to_config_argument(config);
+       return omap_gpio_debounce(chip, offset, debounce);
+}
+
 static void omap_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
        struct gpio_bank *bank;
@@ -1045,7 +1057,7 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
        bank->chip.direction_input = omap_gpio_input;
        bank->chip.get = omap_gpio_get;
        bank->chip.direction_output = omap_gpio_output;
-       bank->chip.set_debounce = omap_gpio_debounce;
+       bank->chip.set_config = omap_gpio_set_config;
        bank->chip.set = omap_gpio_set;
        if (bank->is_mpuio) {
                bank->chip.label = "mpuio";
index be97101c2c9a86f333059e133d0db2c515a8b447..433b45ef332e59b72a0ff34543d27a581f6d2940 100644 (file)
@@ -100,9 +100,8 @@ static int tc3589x_gpio_get_direction(struct gpio_chip *chip,
        return !(ret & BIT(pos));
 }
 
-static int tc3589x_gpio_set_single_ended(struct gpio_chip *chip,
-                                        unsigned int offset,
-                                        enum single_ended_mode mode)
+static int tc3589x_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
+                                  unsigned long config)
 {
        struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip);
        struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
@@ -116,22 +115,22 @@ static int tc3589x_gpio_set_single_ended(struct gpio_chip *chip,
        unsigned int pos = offset % 8;
        int ret;
 
-       switch(mode) {
-       case LINE_MODE_OPEN_DRAIN:
+       switch (pinconf_to_config_param(config)) {
+       case PIN_CONFIG_DRIVE_OPEN_DRAIN:
                /* Set open drain mode */
                ret = tc3589x_set_bits(tc3589x, odmreg, BIT(pos), 0);
                if (ret)
                        return ret;
                /* Enable open drain/source mode */
                return tc3589x_set_bits(tc3589x, odereg, BIT(pos), BIT(pos));
-       case LINE_MODE_OPEN_SOURCE:
+       case PIN_CONFIG_DRIVE_OPEN_SOURCE:
                /* Set open source mode */
                ret = tc3589x_set_bits(tc3589x, odmreg, BIT(pos), BIT(pos));
                if (ret)
                        return ret;
                /* Enable open drain/source mode */
                return tc3589x_set_bits(tc3589x, odereg, BIT(pos), BIT(pos));
-       case LINE_MODE_PUSH_PULL:
+       case PIN_CONFIG_DRIVE_PUSH_PULL:
                /* Disable open drain/source mode */
                return tc3589x_set_bits(tc3589x, odereg, BIT(pos), 0);
        default:
@@ -148,7 +147,7 @@ static const struct gpio_chip template_chip = {
        .direction_output       = tc3589x_gpio_direction_output,
        .direction_input        = tc3589x_gpio_direction_input,
        .get_direction          = tc3589x_gpio_get_direction,
-       .set_single_ended       = tc3589x_gpio_set_single_ended,
+       .set_config             = tc3589x_gpio_set_config,
        .can_sleep              = true,
 };
 
index 661b0e34e0672eedba9e7896c742944aeda18477..88529d3c06c9af4d6e4a69ea71557939ba0ff48e 100644 (file)
@@ -238,6 +238,18 @@ static int tegra_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset,
        return 0;
 }
 
+static int tegra_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
+                                unsigned long config)
+{
+       u32 debounce;
+
+       if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
+               return -ENOTSUPP;
+
+       debounce = pinconf_to_config_argument(config);
+       return tegra_gpio_set_debounce(chip, offset, debounce);
+}
+
 static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
        struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
@@ -615,7 +627,7 @@ static int tegra_gpio_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, tgi);
 
        if (config->debounce_supported)
-               tgi->gc.set_debounce = tegra_gpio_set_debounce;
+               tgi->gc.set_config = tegra_gpio_set_config;
 
        tgi->bank_info = devm_kzalloc(&pdev->dev, tgi->bank_count *
                                      sizeof(*tgi->bank_info), GFP_KERNEL);
index 46e6dcc089cbdd25fdf61025c53e7dc078233de3..a379bba57d31d5d960eaec381dff3627301ac6d8 100644 (file)
@@ -139,28 +139,28 @@ static int tps65218_gpio_request(struct gpio_chip *gc, unsigned offset)
        return 0;
 }
 
-static int tps65218_gpio_set_single_ended(struct gpio_chip *gc,
-                                         unsigned offset,
-                                         enum single_ended_mode mode)
+static int tps65218_gpio_set_config(struct gpio_chip *gc, unsigned offset,
+                                   unsigned long config)
 {
        struct tps65218_gpio *tps65218_gpio = gpiochip_get_data(gc);
        struct tps65218 *tps65218 = tps65218_gpio->tps65218;
+       enum pin_config_param param = pinconf_to_config_param(config);
 
        switch (offset) {
        case 0:
        case 2:
                /* GPO1 is hardwired to be open drain */
-               if (mode == LINE_MODE_OPEN_DRAIN)
+               if (param == PIN_CONFIG_DRIVE_OPEN_DRAIN)
                        return 0;
                return -ENOTSUPP;
        case 1:
                /* GPO2 is push-pull by default, can be set as open drain. */
-               if (mode == LINE_MODE_OPEN_DRAIN)
+               if (param == PIN_CONFIG_DRIVE_OPEN_DRAIN)
                        return tps65218_clear_bits(tps65218,
                                                   TPS65218_REG_CONFIG1,
                                                   TPS65218_CONFIG1_GPO2_BUF,
                                                   TPS65218_PROTECT_L1);
-               if (mode == LINE_MODE_PUSH_PULL)
+               if (param == PIN_CONFIG_DRIVE_PUSH_PULL)
                        return tps65218_set_bits(tps65218,
                                                 TPS65218_REG_CONFIG1,
                                                 TPS65218_CONFIG1_GPO2_BUF,
@@ -181,7 +181,7 @@ static const struct gpio_chip template_chip = {
        .direction_input        = tps65218_gpio_input,
        .get                    = tps65218_gpio_get,
        .set                    = tps65218_gpio_set,
-       .set_single_ended       = tps65218_gpio_set_single_ended,
+       .set_config             = tps65218_gpio_set_config,
        .can_sleep              = true,
        .ngpio                  = 3,
        .base                   = -1,
index 4e450121129bc12e1066ff90e7f2dd52756cc5ad..98a6f1fcc561a89f07f6cc396584fdd131a9dc79 100644 (file)
@@ -186,23 +186,24 @@ static int vx855gpio_direction_output(struct gpio_chip *gpio,
        return 0;
 }
 
-static int vx855gpio_set_single_ended(struct gpio_chip *gpio,
-                                     unsigned int nr,
-                                     enum single_ended_mode mode)
+static int vx855gpio_set_config(struct gpio_chip *gpio, unsigned int nr,
+                               unsigned long config)
 {
+       enum pin_config_param param = pinconf_to_config_param(config);
+
        /* The GPI cannot be single-ended */
        if (nr < NR_VX855_GPI)
                return -EINVAL;
 
        /* The GPO's are push-pull */
        if (nr < NR_VX855_GPInO) {
-               if (mode != LINE_MODE_PUSH_PULL)
+               if (param != PIN_CONFIG_DRIVE_PUSH_PULL)
                        return -ENOTSUPP;
                return 0;
        }
 
        /* The GPIO's are open drain */
-       if (mode != LINE_MODE_OPEN_DRAIN)
+       if (param != PIN_CONFIG_DRIVE_OPEN_DRAIN)
                return -ENOTSUPP;
 
        return 0;
@@ -231,7 +232,7 @@ static void vx855gpio_gpio_setup(struct vx855_gpio *vg)
        c->direction_output = vx855gpio_direction_output;
        c->get = vx855gpio_get;
        c->set = vx855gpio_set;
-       c->set_single_ended = vx855gpio_set_single_ended;
+       c->set_config = vx855gpio_set_config,
        c->dbg_show = NULL;
        c->base = 0;
        c->ngpio = NR_VX855_GP;
index 34baee5b1dd65ba876fd7c67c2c80cab7cfc0de8..97613de5304e27fc0ee89d6f63c26bbfcb19d71e 100644 (file)
@@ -202,17 +202,16 @@ static void wcove_gpio_set(struct gpio_chip *chip,
                regmap_update_bits(wg->regmap, to_reg(gpio, CTRL_OUT), 1, 0);
 }
 
-static int wcove_gpio_set_single_ended(struct gpio_chip *chip,
-                                       unsigned int gpio,
-                                       enum single_ended_mode mode)
+static int wcove_gpio_set_config(struct gpio_chip *chip, unsigned int gpio,
+                                unsigned long config)
 {
        struct wcove_gpio *wg = gpiochip_get_data(chip);
 
-       switch (mode) {
-       case LINE_MODE_OPEN_DRAIN:
+       switch (pinconf_to_config_param(config)) {
+       case PIN_CONFIG_DRIVE_OPEN_DRAIN:
                return regmap_update_bits(wg->regmap, to_reg(gpio, CTRL_OUT),
                                                CTLO_DRV_MASK, CTLO_DRV_OD);
-       case LINE_MODE_PUSH_PULL:
+       case PIN_CONFIG_DRIVE_PUSH_PULL:
                return regmap_update_bits(wg->regmap, to_reg(gpio, CTRL_OUT),
                                                CTLO_DRV_MASK, CTLO_DRV_CMOS);
        default:
@@ -411,7 +410,7 @@ static int wcove_gpio_probe(struct platform_device *pdev)
        wg->chip.get_direction = wcove_gpio_get_direction;
        wg->chip.get = wcove_gpio_get;
        wg->chip.set = wcove_gpio_set;
-       wg->chip.set_single_ended = wcove_gpio_set_single_ended,
+       wg->chip.set_config = wcove_gpio_set_config,
        wg->chip.base = -1;
        wg->chip.ngpio = WCOVE_VGPIO_NUM;
        wg->chip.can_sleep = true;
index 533707f943f44fd9890f5738149d65d96f34d856..00e3839b3f9688d70fff01515e73ac454aea5a70 100644 (file)
@@ -101,11 +101,9 @@ static int wm831x_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
                                  WM831X_IRQ_GPIO_1 + offset);
 }
 
-static int wm831x_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
+static int wm831x_gpio_set_debounce(struct wm831x *wm831x, unsigned offset,
                                    unsigned debounce)
 {
-       struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(chip);
-       struct wm831x *wm831x = wm831x_gpio->wm831x;
        int reg = WM831X_GPIO1_CONTROL + offset;
        int ret, fn;
 
@@ -132,21 +130,23 @@ static int wm831x_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
        return wm831x_set_bits(wm831x, reg, WM831X_GPN_FN_MASK, fn);
 }
 
-static int wm831x_set_single_ended(struct gpio_chip *chip,
-                                  unsigned int offset,
-                                  enum single_ended_mode mode)
+static int wm831x_set_config(struct gpio_chip *chip, unsigned int offset,
+                            unsigned long config)
 {
        struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(chip);
        struct wm831x *wm831x = wm831x_gpio->wm831x;
        int reg = WM831X_GPIO1_CONTROL + offset;
 
-       switch (mode) {
-       case LINE_MODE_OPEN_DRAIN:
+       switch (pinconf_to_config_param(config)) {
+       case PIN_CONFIG_DRIVE_OPEN_DRAIN:
                return wm831x_set_bits(wm831x, reg,
                                       WM831X_GPN_OD_MASK, WM831X_GPN_OD);
-       case LINE_MODE_PUSH_PULL:
+       case PIN_CONFIG_DRIVE_PUSH_PULL:
                return wm831x_set_bits(wm831x, reg,
                                       WM831X_GPN_OD_MASK, 0);
+       case PIN_CONFIG_INPUT_DEBOUNCE:
+               return wm831x_gpio_set_debounce(wm831x, offset,
+                       pinconf_to_config_argument(config));
        default:
                break;
        }
@@ -255,8 +255,7 @@ static const struct gpio_chip template_chip = {
        .direction_output       = wm831x_gpio_direction_out,
        .set                    = wm831x_gpio_set,
        .to_irq                 = wm831x_gpio_to_irq,
-       .set_debounce           = wm831x_gpio_set_debounce,
-       .set_single_ended       = wm831x_set_single_ended,
+       .set_config             = wm831x_set_config,
        .dbg_show               = wm831x_gpio_dbg_show,
        .can_sleep              = true,
 };
index 68410fda61383214cb5328645fcb71e237bece7c..1e35756ac55b74bd2d53e0575210a9fded1b705a 100644 (file)
@@ -103,19 +103,18 @@ static void wm8994_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
        wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset, WM8994_GPN_LVL, value);
 }
 
-static int wm8994_gpio_set_single_ended(struct gpio_chip *chip,
-                                       unsigned int offset,
-                                       enum single_ended_mode mode)
+static int wm8994_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
+                                 unsigned long config)
 {
        struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip);
        struct wm8994 *wm8994 = wm8994_gpio->wm8994;
 
-       switch (mode) {
-       case LINE_MODE_OPEN_DRAIN:
+       switch (pinconf_to_config_param(config)) {
+       case PIN_CONFIG_DRIVE_OPEN_DRAIN:
                return wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset,
                                       WM8994_GPN_OP_CFG_MASK,
                                       WM8994_GPN_OP_CFG);
-       case LINE_MODE_PUSH_PULL:
+       case PIN_CONFIG_DRIVE_PUSH_PULL:
                return wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset,
                                       WM8994_GPN_OP_CFG_MASK, 0);
        default:
@@ -257,7 +256,7 @@ static const struct gpio_chip template_chip = {
        .get                    = wm8994_gpio_get,
        .direction_output       = wm8994_gpio_direction_out,
        .set                    = wm8994_gpio_set,
-       .set_single_ended       = wm8994_gpio_set_single_ended,
+       .set_config             = wm8994_gpio_set_config,
        .to_irq                 = wm8994_gpio_to_irq,
        .dbg_show               = wm8994_gpio_dbg_show,
        .can_sleep              = true,
index a07ae9e37930767643302ccbec4a7284275a0f25..d0478f1853db0e974327e8269f1aaa31305455fd 100644 (file)
@@ -1876,6 +1876,19 @@ void gpiochip_generic_free(struct gpio_chip *chip, unsigned offset)
 }
 EXPORT_SYMBOL_GPL(gpiochip_generic_free);
 
+/**
+ * gpiochip_generic_config() - apply configuration for a pin
+ * @chip: the gpiochip owning the GPIO
+ * @offset: the offset of the GPIO to apply the configuration
+ * @config: the configuration to be applied
+ */
+int gpiochip_generic_config(struct gpio_chip *chip, unsigned offset,
+                           unsigned long config)
+{
+       return pinctrl_gpio_set_config(chip->gpiodev->base + offset, config);
+}
+EXPORT_SYMBOL_GPL(gpiochip_generic_config);
+
 #ifdef CONFIG_PINCTRL
 
 /**
@@ -2264,6 +2277,14 @@ int gpiod_direction_input(struct gpio_desc *desc)
 }
 EXPORT_SYMBOL_GPL(gpiod_direction_input);
 
+static int gpio_set_drive_single_ended(struct gpio_chip *gc, unsigned offset,
+                                      enum pin_config_param mode)
+{
+       unsigned long config = { PIN_CONF_PACKED(mode, 0) };
+
+       return gc->set_config ? gc->set_config(gc, offset, config) : -ENOTSUPP;
+}
+
 static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value)
 {
        struct gpio_chip *gc = desc->gdev->chip;
@@ -2280,32 +2301,25 @@ static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value)
 
        if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) {
                /* First see if we can enable open drain in hardware */
-               if (gc->set_single_ended) {
-                       ret = gc->set_single_ended(gc, gpio_chip_hwgpio(desc),
-                                                  LINE_MODE_OPEN_DRAIN);
-                       if (!ret)
-                               goto set_output_value;
-               }
+               ret = gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc),
+                                                 PIN_CONFIG_DRIVE_OPEN_DRAIN);
+               if (!ret)
+                       goto set_output_value;
                /* Emulate open drain by not actively driving the line high */
                if (val)
                        return gpiod_direction_input(desc);
        }
        else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) {
-               if (gc->set_single_ended) {
-                       ret = gc->set_single_ended(gc, gpio_chip_hwgpio(desc),
-                                                  LINE_MODE_OPEN_SOURCE);
-                       if (!ret)
-                               goto set_output_value;
-               }
+               ret = gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc),
+                                                 PIN_CONFIG_DRIVE_OPEN_SOURCE);
+               if (!ret)
+                       goto set_output_value;
                /* Emulate open source by not actively driving the line low */
                if (!val)
                        return gpiod_direction_input(desc);
        } else {
-               /* Make sure to disable open drain/source hardware, if any */
-               if (gc->set_single_ended)
-                       gc->set_single_ended(gc,
-                                            gpio_chip_hwgpio(desc),
-                                            LINE_MODE_PUSH_PULL);
+               gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc),
+                                           PIN_CONFIG_DRIVE_PUSH_PULL);
        }
 
 set_output_value:
@@ -2376,17 +2390,19 @@ EXPORT_SYMBOL_GPL(gpiod_direction_output);
 int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
 {
        struct gpio_chip        *chip;
+       unsigned long           config;
 
        VALIDATE_DESC(desc);
        chip = desc->gdev->chip;
-       if (!chip->set || !chip->set_debounce) {
+       if (!chip->set || !chip->set_config) {
                gpiod_dbg(desc,
-                         "%s: missing set() or set_debounce() operations\n",
+                         "%s: missing set() or set_config() operations\n",
                          __func__);
                return -ENOTSUPP;
        }
 
-       return chip->set_debounce(chip, gpio_chip_hwgpio(desc), debounce);
+       config = pinconf_to_config_packed(PIN_CONFIG_INPUT_DEBOUNCE, debounce);
+       return chip->set_config(chip, gpio_chip_hwgpio(desc), config);
 }
 EXPORT_SYMBOL_GPL(gpiod_set_debounce);
 
index 8c54cb8f5d6d1013ec1f4a39e8f88fcfe3333758..816679150b3510bf928683750d09ec97dc6c3194 100644 (file)
@@ -98,6 +98,18 @@ config HID_A4TECH
        ---help---
        Support for A4 tech X5 and WOP-35 / Trust 450L mice.
 
+config HID_ACCUTOUCH
+       tristate "Accutouch touch device"
+       depends on USB_HID
+       ---help---
+         This selects a driver for the Accutouch 2216 touch controller.
+
+         The driver works around a problem in the reported device capabilities
+         which causes userspace to detect the device as a mouse rather than
+          a touchscreen.
+
+         Say Y here if you have a Accutouch 2216 touch controller.
+
 config HID_ACRUX
        tristate "ACRUX game controller support"
        depends on HID
@@ -215,7 +227,8 @@ config HID_CMEDIA
 
 config HID_CP2112
        tristate "Silicon Labs CP2112 HID USB-to-SMBus Bridge support"
-       depends on USB_HID && I2C && GPIOLIB && GPIOLIB_IRQCHIP
+       depends on USB_HID && I2C && GPIOLIB
+       select GPIOLIB_IRQCHIP
        ---help---
        Support for Silicon Labs CP2112 HID USB to SMBus Master Bridge.
        This is a HID device driver which registers as an i2c adapter
@@ -441,6 +454,7 @@ config HID_LOGITECH_DJ
 config HID_LOGITECH_HIDPP
        tristate "Logitech HID++ devices support"
        depends on HID_LOGITECH
+       select POWER_SUPPLY
        ---help---
        Support for Logitech devices relyingon the HID++ Logitech specification
 
@@ -581,6 +595,12 @@ config HID_MULTITOUCH
          To compile this driver as a module, choose M here: the
          module will be called hid-multitouch.
 
+config HID_NTI
+       tristate "NTI keyboard adapters"
+       ---help---
+       Support for the "extra" Sun keyboard keys on keyboards attached
+       through Network Technologies USB-SUN keyboard adapters.
+
 config HID_NTRIG
        tristate "N-Trig touch screen"
        depends on USB_HID
index 4d111f23e801c28151a58a7e6745d8332758db76..fef027bc7fa3b17b6cd337c7d2460bd3245314d9 100644 (file)
@@ -21,6 +21,7 @@ hid-wiimote-y         := hid-wiimote-core.o hid-wiimote-modules.o
 hid-wiimote-$(CONFIG_DEBUG_FS) += hid-wiimote-debug.o
 
 obj-$(CONFIG_HID_A4TECH)       += hid-a4tech.o
+obj-$(CONFIG_HID_ACCUTOUCH)    += hid-accutouch.o
 obj-$(CONFIG_HID_ALPS)         += hid-alps.o
 obj-$(CONFIG_HID_ACRUX)                += hid-axff.o
 obj-$(CONFIG_HID_APPLE)                += hid-apple.o
@@ -62,6 +63,7 @@ obj-$(CONFIG_HID_MAYFLASH)    += hid-mf.o
 obj-$(CONFIG_HID_MICROSOFT)    += hid-microsoft.o
 obj-$(CONFIG_HID_MONTEREY)     += hid-monterey.o
 obj-$(CONFIG_HID_MULTITOUCH)   += hid-multitouch.o
+obj-$(CONFIG_HID_NTI)                  += hid-nti.o
 obj-$(CONFIG_HID_NTRIG)                += hid-ntrig.o
 obj-$(CONFIG_HID_ORTEK)                += hid-ortek.o
 obj-$(CONFIG_HID_PRODIKEYS)    += hid-prodikeys.o
diff --git a/drivers/hid/hid-accutouch.c b/drivers/hid/hid-accutouch.c
new file mode 100644 (file)
index 0000000..4e28716
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * HID driver for Elo Accutouch touchscreens
+ *
+ * Copyright (c) 2016, Collabora Ltd.
+ * Copyright (c) 2016, General Electric Company
+ *
+ * based on hid-penmount.c
+ *  Copyright (c) 2014 Christian Gmeiner <christian.gmeiner <at> 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.
+ */
+
+#include <linux/hid.h>
+#include <linux/module.h>
+#include "hid-ids.h"
+
+static int accutouch_input_mapping(struct hid_device *hdev,
+                                  struct hid_input *hi,
+                                  struct hid_field *field,
+                                  struct hid_usage *usage,
+                                  unsigned long **bit, int *max)
+{
+       if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) {
+               hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
+               return 1;
+       }
+
+       return 0;
+}
+
+static const struct hid_device_id accutouch_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_ACCUTOUCH_2216) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, accutouch_devices);
+
+static struct hid_driver accutouch_driver = {
+       .name = "hid-accutouch",
+       .id_table = accutouch_devices,
+       .input_mapping = accutouch_input_mapping,
+};
+
+module_hid_driver(accutouch_driver);
+
+MODULE_AUTHOR("Martyn Welch <martyn.welch@collabora.co.uk");
+MODULE_DESCRIPTION("Elo Accutouch HID TouchScreen driver");
+MODULE_LICENSE("GPL");
index d162f0dc76e3f44e2134eafa5509137ddf0cc411..cd6eba051b97e2de8b8489545a60935f9237d304 100644 (file)
@@ -1694,7 +1694,7 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
                len += sprintf(buf + len, "input");
        if (hdev->claimed & HID_CLAIMED_HIDDEV)
                len += sprintf(buf + len, "%shiddev%d", len ? "," : "",
-                               hdev->minor);
+                               ((struct hiddev *)hdev->hiddev)->minor);
        if (hdev->claimed & HID_CLAIMED_HIDRAW)
                len += sprintf(buf + len, "%shidraw%d", len ? "," : "",
                                ((struct hidraw *)hdev->hidraw)->minor);
@@ -1891,6 +1891,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0009) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0030) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_ACCUTOUCH_2216) },
        { HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) },
        { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) },
@@ -1991,6 +1992,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_NTI, USB_DEVICE_ID_USB_SUN) },
        { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) },
        { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) },
        { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2) },
index b22d0f83f8e38a9ee0d0eb7381e95d6b90442b61..078026f63b6f40999a2aa1feb8023d3905a6044c 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/gpio.h>
 #include <linux/gpio/driver.h>
 #include <linux/hid.h>
+#include <linux/hidraw.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/nls.h>
@@ -1297,7 +1298,8 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
        dev->adap.algo_data     = dev;
        dev->adap.dev.parent    = &hdev->dev;
        snprintf(dev->adap.name, sizeof(dev->adap.name),
-                "CP2112 SMBus Bridge on hiddev%d", hdev->minor);
+                "CP2112 SMBus Bridge on hidraw%d",
+                ((struct hidraw *)hdev->hidraw)->minor);
        dev->hwversion = buf[2];
        init_waitqueue_head(&dev->wait);
 
index acfb522a432ae51ff16d0a475783eed167969d7c..5a0061c0ee87a7f3c242345bec24b9f5fb829bf4 100644 (file)
@@ -140,9 +140,11 @@ static const struct hid_usage_entry hid_usage_table[] = {
     {0, 0x03, "LightPen"},
     {0, 0x04, "TouchScreen"},
     {0, 0x05, "TouchPad"},
+    {0, 0x0e, "DeviceConfiguration"},
     {0, 0x20, "Stylus"},
     {0, 0x21, "Puck"},
     {0, 0x22, "Finger"},
+    {0, 0x23, "DeviceSettings"},
     {0, 0x30, "TipPressure"},
     {0, 0x31, "BarrelPressure"},
     {0, 0x32, "InRange"},
index cac06b5144559c7c7dda02540992935324fb3e34..4b07a467d7a3574c5f4c84ee58e699ae43135ec3 100644 (file)
 #define USB_VENDOR_ID_ELO              0x04E7
 #define USB_DEVICE_ID_ELO_TS2515       0x0022
 #define USB_DEVICE_ID_ELO_TS2700       0x0020
+#define USB_DEVICE_ID_ELO_ACCUTOUCH_2216       0x0050
 
 #define USB_VENDOR_ID_EMS              0x2006
 #define USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II 0x0118
 #define USB_VENDOR_ID_IRTOUCHSYSTEMS   0x6615
 #define USB_DEVICE_ID_IRTOUCH_INFRARED_USB     0x0070
 
+#define USB_VENDOR_ID_INNOMEDIA                        0x1292
+#define USB_DEVICE_ID_INNEX_GENESIS_ATARI      0x4745
+
 #define USB_VENDOR_ID_ITE               0x048d
 #define USB_DEVICE_ID_ITE_LENOVO_YOGA   0x8386
 #define USB_DEVICE_ID_ITE_LENOVO_YOGA2  0x8350
 #define USB_DEVICE_ID_NOVATEK_PCT      0x0600
 #define USB_DEVICE_ID_NOVATEK_MOUSE    0x1602
 
+#define USB_VENDOR_ID_NTI               0x0757
+#define USB_DEVICE_ID_USB_SUN           0x0a00
+
 #define USB_VENDOR_ID_NTRIG            0x1b96
 #define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN   0x0001
 #define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1   0x0003
index d05f903c7614530625d9adc696cdc7f3661abe15..a1ebdd7d4d4d01c7942beb9e988a6fb36dd94714 100644 (file)
@@ -1150,18 +1150,26 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
 
        /*
         * Ignore out-of-range values as per HID specification,
-        * section 5.10 and 6.2.25.
+        * section 5.10 and 6.2.25, when NULL state bit is present.
+        * When it's not, clamp the value to match Microsoft's input
+        * driver as mentioned in "Required HID usages for digitizers":
+        * https://msdn.microsoft.com/en-us/library/windows/hardware/dn672278(v=vs.85).asp
         *
         * The logical_minimum < logical_maximum check is done so that we
         * don't unintentionally discard values sent by devices which
         * don't specify logical min and max.
         */
        if ((field->flags & HID_MAIN_ITEM_VARIABLE) &&
-           (field->logical_minimum < field->logical_maximum) &&
-           (value < field->logical_minimum ||
-            value > field->logical_maximum)) {
-               dbg_hid("Ignoring out-of-range value %x\n", value);
-               return;
+           (field->logical_minimum < field->logical_maximum)) {
+               if (field->flags & HID_MAIN_ITEM_NULL_STATE &&
+                   (value < field->logical_minimum ||
+                    value > field->logical_maximum)) {
+                       dbg_hid("Ignoring out-of-range value %x\n", value);
+                       return;
+               }
+               value = clamp(value,
+                             field->logical_minimum,
+                             field->logical_maximum);
        }
 
        /*
index 5bc6d80d5be79f465f3cbbb686c471db6162eb63..826fa1e1c8d985fb65a2af973c43568c043c6949 100644 (file)
@@ -692,8 +692,12 @@ static void logi_dj_ll_close(struct hid_device *hid)
        dbg_hid("%s:%s\n", __func__, hid->phys);
 }
 
-static u8 unifying_name_query[]  = {0x10, 0xff, 0x83, 0xb5, 0x40, 0x00, 0x00};
-static u8 unifying_name_answer[] = {0x11, 0xff, 0x83, 0xb5};
+/*
+ * Register 0xB5 is "pairing information". It is solely intended for the
+ * receiver, so do not overwrite the device index.
+ */
+static u8 unifying_pairing_query[]  = {0x10, 0xff, 0x83, 0xb5};
+static u8 unifying_pairing_answer[] = {0x11, 0xff, 0x83, 0xb5};
 
 static int logi_dj_ll_raw_request(struct hid_device *hid,
                                  unsigned char reportnum, __u8 *buf,
@@ -712,9 +716,9 @@ static int logi_dj_ll_raw_request(struct hid_device *hid,
 
                /* special case where we should not overwrite
                 * the device_index */
-               if (count == 7 && !memcmp(buf, unifying_name_query,
-                                         sizeof(unifying_name_query)))
-                       buf[4] |= djdev->device_index - 1;
+               if (count == 7 && !memcmp(buf, unifying_pairing_query,
+                                         sizeof(unifying_pairing_query)))
+                       buf[4] = (buf[4] & 0xf0) | (djdev->device_index - 1);
                else
                        buf[1] = djdev->device_index;
                return hid_hw_raw_request(djrcv_dev->hdev, reportnum, buf,
@@ -911,9 +915,8 @@ static int logi_dj_hidpp_event(struct hid_device *hdev,
                /* special case were the device wants to know its unifying
                 * name */
                if (size == HIDPP_REPORT_LONG_LENGTH &&
-                   !memcmp(data, unifying_name_answer,
-                           sizeof(unifying_name_answer)) &&
-                   ((data[4] & 0xF0) == 0x40))
+                   !memcmp(data, unifying_pairing_answer,
+                           sizeof(unifying_pairing_answer)))
                        device_index = (data[4] & 0x0F) + 1;
                else
                        return false;
index 2e2515a4c070eac305a834c9229d0e1fa27f722f..41b39464ded87f6ee3a4b0b302e0df52feddc520 100644 (file)
@@ -56,15 +56,21 @@ MODULE_PARM_DESC(disable_tap_to_click,
 #define HIDPP_QUIRK_CLASS_M560                 BIT(1)
 #define HIDPP_QUIRK_CLASS_K400                 BIT(2)
 #define HIDPP_QUIRK_CLASS_G920                 BIT(3)
+#define HIDPP_QUIRK_CLASS_K750                 BIT(4)
 
 /* bits 2..20 are reserved for classes */
-#define HIDPP_QUIRK_CONNECT_EVENTS             BIT(21)
+/* #define HIDPP_QUIRK_CONNECT_EVENTS          BIT(21) disabled */
 #define HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS       BIT(22)
 #define HIDPP_QUIRK_NO_HIDINPUT                        BIT(23)
 #define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS       BIT(24)
+#define HIDPP_QUIRK_UNIFYING                   BIT(25)
 
-#define HIDPP_QUIRK_DELAYED_INIT               (HIDPP_QUIRK_NO_HIDINPUT | \
-                                                HIDPP_QUIRK_CONNECT_EVENTS)
+#define HIDPP_QUIRK_DELAYED_INIT               HIDPP_QUIRK_NO_HIDINPUT
+
+#define HIDPP_CAPABILITY_HIDPP10_BATTERY       BIT(0)
+#define HIDPP_CAPABILITY_HIDPP20_BATTERY       BIT(1)
+#define HIDPP_CAPABILITY_BATTERY_MILEAGE       BIT(2)
+#define HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS  BIT(3)
 
 /*
  * There are two hidpp protocols in use, the first version hidpp10 is known
@@ -110,6 +116,18 @@ struct hidpp_report {
        };
 } __packed;
 
+struct hidpp_battery {
+       u8 feature_index;
+       u8 solar_feature_index;
+       struct power_supply_desc desc;
+       struct power_supply *ps;
+       char name[64];
+       int status;
+       int capacity;
+       int level;
+       bool online;
+};
+
 struct hidpp_device {
        struct hid_device *hid_dev;
        struct mutex send_mutex;
@@ -128,8 +146,10 @@ struct hidpp_device {
        struct input_dev *delayed_input;
 
        unsigned long quirks;
-};
+       unsigned long capabilities;
 
+       struct hidpp_battery battery;
+};
 
 /* HID++ 1.0 error codes */
 #define HIDPP_ERROR                            0x8f
@@ -380,15 +400,220 @@ static void hidpp_prefix_name(char **name, int name_length)
 #define HIDPP_SET_LONG_REGISTER                                0x82
 #define HIDPP_GET_LONG_REGISTER                                0x83
 
+#define HIDPP_REG_GENERAL                              0x00
+
+static int hidpp10_enable_battery_reporting(struct hidpp_device *hidpp_dev)
+{
+       struct hidpp_report response;
+       int ret;
+       u8 params[3] = { 0 };
+
+       ret = hidpp_send_rap_command_sync(hidpp_dev,
+                                       REPORT_ID_HIDPP_SHORT,
+                                       HIDPP_GET_REGISTER,
+                                       HIDPP_REG_GENERAL,
+                                       NULL, 0, &response);
+       if (ret)
+               return ret;
+
+       memcpy(params, response.rap.params, 3);
+
+       /* Set the battery bit */
+       params[0] |= BIT(4);
+
+       return hidpp_send_rap_command_sync(hidpp_dev,
+                                       REPORT_ID_HIDPP_SHORT,
+                                       HIDPP_SET_REGISTER,
+                                       HIDPP_REG_GENERAL,
+                                       params, 3, &response);
+}
+
+#define HIDPP_REG_BATTERY_STATUS                       0x07
+
+static int hidpp10_battery_status_map_level(u8 param)
+{
+       int level;
+
+       switch (param) {
+       case 1 ... 2:
+               level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
+               break;
+       case 3 ... 4:
+               level = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
+               break;
+       case 5 ... 6:
+               level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
+               break;
+       case 7:
+               level = POWER_SUPPLY_CAPACITY_LEVEL_HIGH;
+               break;
+       default:
+               level = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
+       }
+
+       return level;
+}
+
+static int hidpp10_battery_status_map_status(u8 param)
+{
+       int status;
+
+       switch (param) {
+       case 0x00:
+               /* discharging (in use) */
+               status = POWER_SUPPLY_STATUS_DISCHARGING;
+               break;
+       case 0x21: /* (standard) charging */
+       case 0x24: /* fast charging */
+       case 0x25: /* slow charging */
+               status = POWER_SUPPLY_STATUS_CHARGING;
+               break;
+       case 0x26: /* topping charge */
+       case 0x22: /* charge complete */
+               status = POWER_SUPPLY_STATUS_FULL;
+               break;
+       case 0x20: /* unknown */
+               status = POWER_SUPPLY_STATUS_UNKNOWN;
+               break;
+       /*
+        * 0x01...0x1F = reserved (not charging)
+        * 0x23 = charging error
+        * 0x27..0xff = reserved
+        */
+       default:
+               status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+               break;
+       }
+
+       return status;
+}
+
+static int hidpp10_query_battery_status(struct hidpp_device *hidpp)
+{
+       struct hidpp_report response;
+       int ret, status;
+
+       ret = hidpp_send_rap_command_sync(hidpp,
+                                       REPORT_ID_HIDPP_SHORT,
+                                       HIDPP_GET_REGISTER,
+                                       HIDPP_REG_BATTERY_STATUS,
+                                       NULL, 0, &response);
+       if (ret)
+               return ret;
+
+       hidpp->battery.level =
+               hidpp10_battery_status_map_level(response.rap.params[0]);
+       status = hidpp10_battery_status_map_status(response.rap.params[1]);
+       hidpp->battery.status = status;
+       /* the capacity is only available when discharging or full */
+       hidpp->battery.online = status == POWER_SUPPLY_STATUS_DISCHARGING ||
+                               status == POWER_SUPPLY_STATUS_FULL;
+
+       return 0;
+}
+
+#define HIDPP_REG_BATTERY_MILEAGE                      0x0D
+
+static int hidpp10_battery_mileage_map_status(u8 param)
+{
+       int status;
+
+       switch (param >> 6) {
+       case 0x00:
+               /* discharging (in use) */
+               status = POWER_SUPPLY_STATUS_DISCHARGING;
+               break;
+       case 0x01: /* charging */
+               status = POWER_SUPPLY_STATUS_CHARGING;
+               break;
+       case 0x02: /* charge complete */
+               status = POWER_SUPPLY_STATUS_FULL;
+               break;
+       /*
+        * 0x03 = charging error
+        */
+       default:
+               status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+               break;
+       }
+
+       return status;
+}
+
+static int hidpp10_query_battery_mileage(struct hidpp_device *hidpp)
+{
+       struct hidpp_report response;
+       int ret, status;
+
+       ret = hidpp_send_rap_command_sync(hidpp,
+                                       REPORT_ID_HIDPP_SHORT,
+                                       HIDPP_GET_REGISTER,
+                                       HIDPP_REG_BATTERY_MILEAGE,
+                                       NULL, 0, &response);
+       if (ret)
+               return ret;
+
+       hidpp->battery.capacity = response.rap.params[0];
+       status = hidpp10_battery_mileage_map_status(response.rap.params[2]);
+       hidpp->battery.status = status;
+       /* the capacity is only available when discharging or full */
+       hidpp->battery.online = status == POWER_SUPPLY_STATUS_DISCHARGING ||
+                               status == POWER_SUPPLY_STATUS_FULL;
+
+       return 0;
+}
+
+static int hidpp10_battery_event(struct hidpp_device *hidpp, u8 *data, int size)
+{
+       struct hidpp_report *report = (struct hidpp_report *)data;
+       int status, capacity, level;
+       bool changed;
+
+       if (report->report_id != REPORT_ID_HIDPP_SHORT)
+               return 0;
+
+       switch (report->rap.sub_id) {
+       case HIDPP_REG_BATTERY_STATUS:
+               capacity = hidpp->battery.capacity;
+               level = hidpp10_battery_status_map_level(report->rawbytes[1]);
+               status = hidpp10_battery_status_map_status(report->rawbytes[2]);
+               break;
+       case HIDPP_REG_BATTERY_MILEAGE:
+               capacity = report->rap.params[0];
+               level = hidpp->battery.level;
+               status = hidpp10_battery_mileage_map_status(report->rawbytes[3]);
+               break;
+       default:
+               return 0;
+       }
+
+       changed = capacity != hidpp->battery.capacity ||
+                 level != hidpp->battery.level ||
+                 status != hidpp->battery.status;
+
+       /* the capacity is only available when discharging or full */
+       hidpp->battery.online = status == POWER_SUPPLY_STATUS_DISCHARGING ||
+                               status == POWER_SUPPLY_STATUS_FULL;
+
+       if (changed) {
+               hidpp->battery.level = level;
+               hidpp->battery.status = status;
+               if (hidpp->battery.ps)
+                       power_supply_changed(hidpp->battery.ps);
+       }
+
+       return 0;
+}
+
 #define HIDPP_REG_PAIRING_INFORMATION                  0xB5
-#define DEVICE_NAME                                    0x40
+#define HIDPP_EXTENDED_PAIRING                         0x30
+#define HIDPP_DEVICE_NAME                              0x40
 
-static char *hidpp_get_unifying_name(struct hidpp_device *hidpp_dev)
+static char *hidpp_unifying_get_name(struct hidpp_device *hidpp_dev)
 {
        struct hidpp_report response;
        int ret;
-       /* hid-logitech-dj is in charge of setting the right device index */
-       u8 params[1] = { DEVICE_NAME };
+       u8 params[1] = { HIDPP_DEVICE_NAME };
        char *name;
        int len;
 
@@ -417,6 +642,54 @@ static char *hidpp_get_unifying_name(struct hidpp_device *hidpp_dev)
        return name;
 }
 
+static int hidpp_unifying_get_serial(struct hidpp_device *hidpp, u32 *serial)
+{
+       struct hidpp_report response;
+       int ret;
+       u8 params[1] = { HIDPP_EXTENDED_PAIRING };
+
+       ret = hidpp_send_rap_command_sync(hidpp,
+                                       REPORT_ID_HIDPP_SHORT,
+                                       HIDPP_GET_LONG_REGISTER,
+                                       HIDPP_REG_PAIRING_INFORMATION,
+                                       params, 1, &response);
+       if (ret)
+               return ret;
+
+       /*
+        * We don't care about LE or BE, we will output it as a string
+        * with %4phD, so we need to keep the order.
+        */
+       *serial = *((u32 *)&response.rap.params[1]);
+       return 0;
+}
+
+static int hidpp_unifying_init(struct hidpp_device *hidpp)
+{
+       struct hid_device *hdev = hidpp->hid_dev;
+       const char *name;
+       u32 serial;
+       int ret;
+
+       ret = hidpp_unifying_get_serial(hidpp, &serial);
+       if (ret)
+               return ret;
+
+       snprintf(hdev->uniq, sizeof(hdev->uniq), "%04x-%4phD",
+                hdev->product, &serial);
+       dbg_hid("HID++ Unifying: Got serial: %s\n", hdev->uniq);
+
+       name = hidpp_unifying_get_name(hidpp);
+       if (!name)
+               return -EIO;
+
+       snprintf(hdev->name, sizeof(hdev->name), "%s", name);
+       dbg_hid("HID++ Unifying: Got name: %s\n", name);
+
+       kfree(name);
+       return 0;
+}
+
 /* -------------------------------------------------------------------------- */
 /* 0x0000: Root                                                               */
 /* -------------------------------------------------------------------------- */
@@ -441,6 +714,9 @@ static int hidpp_root_get_feature(struct hidpp_device *hidpp, u16 feature,
        if (ret)
                return ret;
 
+       if (response.fap.params[0] == 0)
+               return -ENOENT;
+
        *feature_index = response.fap.params[0];
        *feature_type = response.fap.params[1];
 
@@ -606,6 +882,355 @@ static char *hidpp_get_device_name(struct hidpp_device *hidpp)
        return name;
 }
 
+/* -------------------------------------------------------------------------- */
+/* 0x1000: Battery level status                                               */
+/* -------------------------------------------------------------------------- */
+
+#define HIDPP_PAGE_BATTERY_LEVEL_STATUS                                0x1000
+
+#define CMD_BATTERY_LEVEL_STATUS_GET_BATTERY_LEVEL_STATUS      0x00
+#define CMD_BATTERY_LEVEL_STATUS_GET_BATTERY_CAPABILITY                0x10
+
+#define EVENT_BATTERY_LEVEL_STATUS_BROADCAST                   0x00
+
+#define FLAG_BATTERY_LEVEL_DISABLE_OSD                         BIT(0)
+#define FLAG_BATTERY_LEVEL_MILEAGE                             BIT(1)
+#define FLAG_BATTERY_LEVEL_RECHARGEABLE                                BIT(2)
+
+static int hidpp_map_battery_level(int capacity)
+{
+       if (capacity < 11)
+               return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
+       else if (capacity < 31)
+               return POWER_SUPPLY_CAPACITY_LEVEL_LOW;
+       else if (capacity < 81)
+               return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
+       return POWER_SUPPLY_CAPACITY_LEVEL_FULL;
+}
+
+static int hidpp20_batterylevel_map_status_capacity(u8 data[3], int *capacity,
+                                                   int *next_capacity,
+                                                   int *level)
+{
+       int status;
+
+       *capacity = data[0];
+       *next_capacity = data[1];
+       *level = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
+
+       /* When discharging, we can rely on the device reported capacity.
+        * For all other states the device reports 0 (unknown).
+        */
+       switch (data[2]) {
+               case 0: /* discharging (in use) */
+                       status = POWER_SUPPLY_STATUS_DISCHARGING;
+                       *level = hidpp_map_battery_level(*capacity);
+                       break;
+               case 1: /* recharging */
+                       status = POWER_SUPPLY_STATUS_CHARGING;
+                       break;
+               case 2: /* charge in final stage */
+                       status = POWER_SUPPLY_STATUS_CHARGING;
+                       break;
+               case 3: /* charge complete */
+                       status = POWER_SUPPLY_STATUS_FULL;
+                       *level = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
+                       *capacity = 100;
+                       break;
+               case 4: /* recharging below optimal speed */
+                       status = POWER_SUPPLY_STATUS_CHARGING;
+                       break;
+               /* 5 = invalid battery type
+                  6 = thermal error
+                  7 = other charging error */
+               default:
+                       status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+                       break;
+       }
+
+       return status;
+}
+
+static int hidpp20_batterylevel_get_battery_capacity(struct hidpp_device *hidpp,
+                                                    u8 feature_index,
+                                                    int *status,
+                                                    int *capacity,
+                                                    int *next_capacity,
+                                                    int *level)
+{
+       struct hidpp_report response;
+       int ret;
+       u8 *params = (u8 *)response.fap.params;
+
+       ret = hidpp_send_fap_command_sync(hidpp, feature_index,
+                                         CMD_BATTERY_LEVEL_STATUS_GET_BATTERY_LEVEL_STATUS,
+                                         NULL, 0, &response);
+       if (ret > 0) {
+               hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
+                       __func__, ret);
+               return -EPROTO;
+       }
+       if (ret)
+               return ret;
+
+       *status = hidpp20_batterylevel_map_status_capacity(params, capacity,
+                                                          next_capacity,
+                                                          level);
+
+       return 0;
+}
+
+static int hidpp20_batterylevel_get_battery_info(struct hidpp_device *hidpp,
+                                                 u8 feature_index)
+{
+       struct hidpp_report response;
+       int ret;
+       u8 *params = (u8 *)response.fap.params;
+       unsigned int level_count, flags;
+
+       ret = hidpp_send_fap_command_sync(hidpp, feature_index,
+                                         CMD_BATTERY_LEVEL_STATUS_GET_BATTERY_CAPABILITY,
+                                         NULL, 0, &response);
+       if (ret > 0) {
+               hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
+                       __func__, ret);
+               return -EPROTO;
+       }
+       if (ret)
+               return ret;
+
+       level_count = params[0];
+       flags = params[1];
+
+       if (level_count < 10 || !(flags & FLAG_BATTERY_LEVEL_MILEAGE))
+               hidpp->capabilities |= HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS;
+       else
+               hidpp->capabilities |= HIDPP_CAPABILITY_BATTERY_MILEAGE;
+
+       return 0;
+}
+
+static int hidpp20_query_battery_info(struct hidpp_device *hidpp)
+{
+       u8 feature_type;
+       int ret;
+       int status, capacity, next_capacity, level;
+
+       if (hidpp->battery.feature_index == 0xff) {
+               ret = hidpp_root_get_feature(hidpp,
+                                            HIDPP_PAGE_BATTERY_LEVEL_STATUS,
+                                            &hidpp->battery.feature_index,
+                                            &feature_type);
+               if (ret)
+                       return ret;
+       }
+
+       ret = hidpp20_batterylevel_get_battery_capacity(hidpp,
+                                               hidpp->battery.feature_index,
+                                               &status, &capacity,
+                                               &next_capacity, &level);
+       if (ret)
+               return ret;
+
+       ret = hidpp20_batterylevel_get_battery_info(hidpp,
+                                               hidpp->battery.feature_index);
+       if (ret)
+               return ret;
+
+       hidpp->battery.status = status;
+       hidpp->battery.capacity = capacity;
+       hidpp->battery.level = level;
+       /* the capacity is only available when discharging or full */
+       hidpp->battery.online = status == POWER_SUPPLY_STATUS_DISCHARGING ||
+                               status == POWER_SUPPLY_STATUS_FULL;
+
+       return 0;
+}
+
+static int hidpp20_battery_event(struct hidpp_device *hidpp,
+                                u8 *data, int size)
+{
+       struct hidpp_report *report = (struct hidpp_report *)data;
+       int status, capacity, next_capacity, level;
+       bool changed;
+
+       if (report->fap.feature_index != hidpp->battery.feature_index ||
+           report->fap.funcindex_clientid != EVENT_BATTERY_LEVEL_STATUS_BROADCAST)
+               return 0;
+
+       status = hidpp20_batterylevel_map_status_capacity(report->fap.params,
+                                                         &capacity,
+                                                         &next_capacity,
+                                                         &level);
+
+       /* the capacity is only available when discharging or full */
+       hidpp->battery.online = status == POWER_SUPPLY_STATUS_DISCHARGING ||
+                               status == POWER_SUPPLY_STATUS_FULL;
+
+       changed = capacity != hidpp->battery.capacity ||
+                 level != hidpp->battery.level ||
+                 status != hidpp->battery.status;
+
+       if (changed) {
+               hidpp->battery.level = level;
+               hidpp->battery.capacity = capacity;
+               hidpp->battery.status = status;
+               if (hidpp->battery.ps)
+                       power_supply_changed(hidpp->battery.ps);
+       }
+
+       return 0;
+}
+
+static enum power_supply_property hidpp_battery_props[] = {
+       POWER_SUPPLY_PROP_ONLINE,
+       POWER_SUPPLY_PROP_STATUS,
+       POWER_SUPPLY_PROP_SCOPE,
+       POWER_SUPPLY_PROP_MODEL_NAME,
+       POWER_SUPPLY_PROP_MANUFACTURER,
+       POWER_SUPPLY_PROP_SERIAL_NUMBER,
+       0, /* placeholder for POWER_SUPPLY_PROP_CAPACITY, */
+       0, /* placeholder for POWER_SUPPLY_PROP_CAPACITY_LEVEL, */
+};
+
+static int hidpp_battery_get_property(struct power_supply *psy,
+                                     enum power_supply_property psp,
+                                     union power_supply_propval *val)
+{
+       struct hidpp_device *hidpp = power_supply_get_drvdata(psy);
+       int ret = 0;
+
+       switch(psp) {
+               case POWER_SUPPLY_PROP_STATUS:
+                       val->intval = hidpp->battery.status;
+                       break;
+               case POWER_SUPPLY_PROP_CAPACITY:
+                       val->intval = hidpp->battery.capacity;
+                       break;
+               case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
+                       val->intval = hidpp->battery.level;
+                       break;
+               case POWER_SUPPLY_PROP_SCOPE:
+                       val->intval = POWER_SUPPLY_SCOPE_DEVICE;
+                       break;
+               case POWER_SUPPLY_PROP_ONLINE:
+                       val->intval = hidpp->battery.online;
+                       break;
+               case POWER_SUPPLY_PROP_MODEL_NAME:
+                       if (!strncmp(hidpp->name, "Logitech ", 9))
+                               val->strval = hidpp->name + 9;
+                       else
+                               val->strval = hidpp->name;
+                       break;
+               case POWER_SUPPLY_PROP_MANUFACTURER:
+                       val->strval = "Logitech";
+                       break;
+               case POWER_SUPPLY_PROP_SERIAL_NUMBER:
+                       val->strval = hidpp->hid_dev->uniq;
+                       break;
+               default:
+                       ret = -EINVAL;
+                       break;
+       }
+
+       return ret;
+}
+
+/* -------------------------------------------------------------------------- */
+/* 0x4301: Solar Keyboard                                                     */
+/* -------------------------------------------------------------------------- */
+
+#define HIDPP_PAGE_SOLAR_KEYBOARD                      0x4301
+
+#define CMD_SOLAR_SET_LIGHT_MEASURE                    0x00
+
+#define EVENT_SOLAR_BATTERY_BROADCAST                  0x00
+#define EVENT_SOLAR_BATTERY_LIGHT_MEASURE              0x10
+#define EVENT_SOLAR_CHECK_LIGHT_BUTTON                 0x20
+
+static int hidpp_solar_request_battery_event(struct hidpp_device *hidpp)
+{
+       struct hidpp_report response;
+       u8 params[2] = { 1, 1 };
+       u8 feature_type;
+       int ret;
+
+       if (hidpp->battery.feature_index == 0xff) {
+               ret = hidpp_root_get_feature(hidpp,
+                                            HIDPP_PAGE_SOLAR_KEYBOARD,
+                                            &hidpp->battery.solar_feature_index,
+                                            &feature_type);
+               if (ret)
+                       return ret;
+       }
+
+       ret = hidpp_send_fap_command_sync(hidpp,
+                                         hidpp->battery.solar_feature_index,
+                                         CMD_SOLAR_SET_LIGHT_MEASURE,
+                                         params, 2, &response);
+       if (ret > 0) {
+               hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
+                       __func__, ret);
+               return -EPROTO;
+       }
+       if (ret)
+               return ret;
+
+       hidpp->capabilities |= HIDPP_CAPABILITY_BATTERY_MILEAGE;
+
+       return 0;
+}
+
+static int hidpp_solar_battery_event(struct hidpp_device *hidpp,
+                                    u8 *data, int size)
+{
+       struct hidpp_report *report = (struct hidpp_report *)data;
+       int capacity, lux, status;
+       u8 function;
+
+       function = report->fap.funcindex_clientid;
+
+
+       if (report->fap.feature_index != hidpp->battery.solar_feature_index ||
+           !(function == EVENT_SOLAR_BATTERY_BROADCAST ||
+             function == EVENT_SOLAR_BATTERY_LIGHT_MEASURE ||
+             function == EVENT_SOLAR_CHECK_LIGHT_BUTTON))
+               return 0;
+
+       capacity = report->fap.params[0];
+
+       switch (function) {
+       case EVENT_SOLAR_BATTERY_LIGHT_MEASURE:
+               lux = (report->fap.params[1] << 8) | report->fap.params[2];
+               if (lux > 200)
+                       status = POWER_SUPPLY_STATUS_CHARGING;
+               else
+                       status = POWER_SUPPLY_STATUS_DISCHARGING;
+               break;
+       case EVENT_SOLAR_CHECK_LIGHT_BUTTON:
+       default:
+               if (capacity < hidpp->battery.capacity)
+                       status = POWER_SUPPLY_STATUS_DISCHARGING;
+               else
+                       status = POWER_SUPPLY_STATUS_CHARGING;
+
+       }
+
+       if (capacity == 100)
+               status = POWER_SUPPLY_STATUS_FULL;
+
+       hidpp->battery.online = true;
+       if (capacity != hidpp->battery.capacity ||
+           status != hidpp->battery.status) {
+               hidpp->battery.capacity = capacity;
+               hidpp->battery.status = status;
+               if (hidpp->battery.ps)
+                       power_supply_changed(hidpp->battery.ps);
+       }
+
+       return 0;
+}
+
 /* -------------------------------------------------------------------------- */
 /* 0x6010: Touchpad FW items                                                  */
 /* -------------------------------------------------------------------------- */
@@ -1599,9 +2224,6 @@ static int wtp_connect(struct hid_device *hdev, bool connected)
        struct wtp_data *wd = hidpp->private_data;
        int ret;
 
-       if (!connected)
-               return 0;
-
        if (!wd->x_size) {
                ret = wtp_get_config(hidpp);
                if (ret) {
@@ -1669,9 +2291,6 @@ static int m560_send_config_command(struct hid_device *hdev, bool connected)
 
        hidpp_dev = hid_get_drvdata(hdev);
 
-       if (!connected)
-               return -ENODEV;
-
        return hidpp_send_rap_command_sync(
                hidpp_dev,
                REPORT_ID_HIDPP_SHORT,
@@ -1875,9 +2494,6 @@ static int k400_connect(struct hid_device *hdev, bool connected)
 {
        struct hidpp_device *hidpp = hid_get_drvdata(hdev);
 
-       if (!connected)
-               return 0;
-
        if (!disable_tap_to_click)
                return 0;
 
@@ -1974,6 +2590,7 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
        struct hidpp_report *question = hidpp->send_receive_buf;
        struct hidpp_report *answer = hidpp->send_receive_buf;
        struct hidpp_report *report = (struct hidpp_report *)data;
+       int ret;
 
        /*
         * If the mutex is locked then we have a pending answer from a
@@ -2002,12 +2619,26 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
        if (unlikely(hidpp_report_is_connect_event(report))) {
                atomic_set(&hidpp->connected,
                                !(report->rap.params[0] & (1 << 6)));
-               if ((hidpp->quirks & HIDPP_QUIRK_CONNECT_EVENTS) &&
-                   (schedule_work(&hidpp->work) == 0))
+               if (schedule_work(&hidpp->work) == 0)
                        dbg_hid("%s: connect event already queued\n", __func__);
                return 1;
        }
 
+       if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP20_BATTERY) {
+               ret = hidpp20_battery_event(hidpp, data, size);
+               if (ret != 0)
+                       return ret;
+               ret = hidpp_solar_battery_event(hidpp, data, size);
+               if (ret != 0)
+                       return ret;
+       }
+
+       if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP10_BATTERY) {
+               ret = hidpp10_battery_event(hidpp, data, size);
+               if (ret != 0)
+                       return ret;
+       }
+
        return 0;
 }
 
@@ -2058,20 +2689,90 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report,
        return 0;
 }
 
-static void hidpp_overwrite_name(struct hid_device *hdev, bool use_unifying)
+static int hidpp_initialize_battery(struct hidpp_device *hidpp)
+{
+       static atomic_t battery_no = ATOMIC_INIT(0);
+       struct power_supply_config cfg = { .drv_data = hidpp };
+       struct power_supply_desc *desc = &hidpp->battery.desc;
+       enum power_supply_property *battery_props;
+       struct hidpp_battery *battery;
+       unsigned int num_battery_props;
+       unsigned long n;
+       int ret;
+
+       if (hidpp->battery.ps)
+               return 0;
+
+       hidpp->battery.feature_index = 0xff;
+       hidpp->battery.solar_feature_index = 0xff;
+
+       if (hidpp->protocol_major >= 2) {
+               if (hidpp->quirks & HIDPP_QUIRK_CLASS_K750)
+                       ret = hidpp_solar_request_battery_event(hidpp);
+               else
+                       ret = hidpp20_query_battery_info(hidpp);
+
+               if (ret)
+                       return ret;
+               hidpp->capabilities |= HIDPP_CAPABILITY_HIDPP20_BATTERY;
+       } else {
+               ret = hidpp10_query_battery_status(hidpp);
+               if (ret) {
+                       ret = hidpp10_query_battery_mileage(hidpp);
+                       if (ret)
+                               return -ENOENT;
+                       hidpp->capabilities |= HIDPP_CAPABILITY_BATTERY_MILEAGE;
+               } else {
+                       hidpp->capabilities |= HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS;
+               }
+               hidpp->capabilities |= HIDPP_CAPABILITY_HIDPP10_BATTERY;
+       }
+
+       battery_props = devm_kmemdup(&hidpp->hid_dev->dev,
+                                    hidpp_battery_props,
+                                    sizeof(hidpp_battery_props),
+                                    GFP_KERNEL);
+       num_battery_props = ARRAY_SIZE(hidpp_battery_props) - 2;
+
+       if (hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_MILEAGE)
+               battery_props[num_battery_props++] =
+                               POWER_SUPPLY_PROP_CAPACITY;
+
+       if (hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS)
+               battery_props[num_battery_props++] =
+                               POWER_SUPPLY_PROP_CAPACITY_LEVEL;
+
+       battery = &hidpp->battery;
+
+       n = atomic_inc_return(&battery_no) - 1;
+       desc->properties = battery_props;
+       desc->num_properties = num_battery_props;
+       desc->get_property = hidpp_battery_get_property;
+       sprintf(battery->name, "hidpp_battery_%ld", n);
+       desc->name = battery->name;
+       desc->type = POWER_SUPPLY_TYPE_BATTERY;
+       desc->use_for_apm = 0;
+
+       battery->ps = devm_power_supply_register(&hidpp->hid_dev->dev,
+                                                &battery->desc,
+                                                &cfg);
+       if (IS_ERR(battery->ps))
+               return PTR_ERR(battery->ps);
+
+       power_supply_powers(battery->ps, &hidpp->hid_dev->dev);
+
+       return ret;
+}
+
+static void hidpp_overwrite_name(struct hid_device *hdev)
 {
        struct hidpp_device *hidpp = hid_get_drvdata(hdev);
        char *name;
 
-       if (use_unifying)
-               /*
-                * the device is connected through an Unifying receiver, and
-                * might not be already connected.
-                * Ask the receiver for its name.
-                */
-               name = hidpp_get_unifying_name(hidpp);
-       else
-               name = hidpp_get_device_name(hidpp);
+       if (hidpp->protocol_major < 2)
+               return;
+
+       name = hidpp_get_device_name(hidpp);
 
        if (!name) {
                hid_err(hdev, "unable to retrieve the name of the device");
@@ -2129,6 +2830,16 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
        struct input_dev *input;
        char *name, *devm_name;
 
+       if (!connected) {
+               if (hidpp->battery.ps) {
+                       hidpp->battery.online = false;
+                       hidpp->battery.status = POWER_SUPPLY_STATUS_UNKNOWN;
+                       hidpp->battery.level = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
+                       power_supply_changed(hidpp->battery.ps);
+               }
+               return;
+       }
+
        if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) {
                ret = wtp_connect(hdev, connected);
                if (ret)
@@ -2143,9 +2854,6 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
                        return;
        }
 
-       if (!connected || hidpp->delayed_input)
-               return;
-
        /* the device is already connected, we can ask for its name and
         * protocol */
        if (!hidpp->protocol_major) {
@@ -2158,11 +2866,7 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
                         hidpp->protocol_major, hidpp->protocol_minor);
        }
 
-       if (!(hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT))
-               /* if HID created the input nodes for us, we can stop now */
-               return;
-
-       if (!hidpp->name || hidpp->name == hdev->name) {
+       if (hidpp->name == hdev->name && hidpp->protocol_major >= 2) {
                name = hidpp_get_device_name(hidpp);
                if (!name) {
                        hid_err(hdev,
@@ -2178,6 +2882,25 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
                hidpp->name = devm_name;
        }
 
+       hidpp_initialize_battery(hidpp);
+
+       /* forward current battery state */
+       if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP10_BATTERY) {
+               hidpp10_enable_battery_reporting(hidpp);
+               if (hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_MILEAGE)
+                       hidpp10_query_battery_mileage(hidpp);
+               else
+                       hidpp10_query_battery_status(hidpp);
+       } else if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP20_BATTERY) {
+               hidpp20_query_battery_info(hidpp);
+       }
+       if (hidpp->battery.ps)
+               power_supply_changed(hidpp->battery.ps);
+
+       if (!(hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT) || hidpp->delayed_input)
+               /* if the input nodes are already created, we can stop now */
+               return;
+
        input = hidpp_allocate_input(hdev);
        if (!input) {
                hid_err(hdev, "cannot allocate new input device: %d\n", ret);
@@ -2193,6 +2916,17 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
        hidpp->delayed_input = input;
 }
 
+static DEVICE_ATTR(builtin_power_supply, 0000, NULL, NULL);
+
+static struct attribute *sysfs_attrs[] = {
+       &dev_attr_builtin_power_supply.attr,
+       NULL
+};
+
+static struct attribute_group ps_attribute_group = {
+       .attrs = sysfs_attrs
+};
+
 static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
        struct hidpp_device *hidpp;
@@ -2211,9 +2945,11 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        hidpp->quirks = id->driver_data;
 
+       if (id->group == HID_GROUP_LOGITECH_DJ_DEVICE)
+               hidpp->quirks |= HIDPP_QUIRK_UNIFYING;
+
        if (disable_raw_mode) {
                hidpp->quirks &= ~HIDPP_QUIRK_CLASS_WTP;
-               hidpp->quirks &= ~HIDPP_QUIRK_CONNECT_EVENTS;
                hidpp->quirks &= ~HIDPP_QUIRK_NO_HIDINPUT;
        }
 
@@ -2235,6 +2971,12 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
        mutex_init(&hidpp->send_mutex);
        init_waitqueue_head(&hidpp->wait);
 
+       /* indicates we are handling the battery properties in the kernel */
+       ret = sysfs_create_group(&hdev->dev.kobj, &ps_attribute_group);
+       if (ret)
+               hid_warn(hdev, "Cannot allocate sysfs group for %s\n",
+                        hdev->name);
+
        ret = hid_parse(hdev);
        if (ret) {
                hid_err(hdev, "%s:parse failed\n", __func__);
@@ -2263,8 +3005,12 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
        /* Allow incoming packets */
        hid_device_io_start(hdev);
 
+       if (hidpp->quirks & HIDPP_QUIRK_UNIFYING)
+               hidpp_unifying_init(hidpp);
+
        connected = hidpp_is_connected(hidpp);
-       if (id->group != HID_GROUP_LOGITECH_DJ_DEVICE) {
+       atomic_set(&hidpp->connected, connected);
+       if (!(hidpp->quirks & HIDPP_QUIRK_UNIFYING)) {
                if (!connected) {
                        ret = -ENODEV;
                        hid_err(hdev, "Device not connected");
@@ -2273,10 +3019,9 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
                hid_info(hdev, "HID++ %u.%u device connected.\n",
                         hidpp->protocol_major, hidpp->protocol_minor);
-       }
 
-       hidpp_overwrite_name(hdev, id->group == HID_GROUP_LOGITECH_DJ_DEVICE);
-       atomic_set(&hidpp->connected, connected);
+               hidpp_overwrite_name(hdev);
+       }
 
        if (connected && (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)) {
                ret = wtp_get_config(hidpp);
@@ -2299,12 +3044,10 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
                }
        }
 
-       if (hidpp->quirks & HIDPP_QUIRK_CONNECT_EVENTS) {
-               /* Allow incoming packets */
-               hid_device_io_start(hdev);
+       /* Allow incoming packets */
+       hid_device_io_start(hdev);
 
-               hidpp_connect_event(hidpp);
-       }
+       hidpp_connect_event(hidpp);
 
        return ret;
 
@@ -2316,6 +3059,7 @@ hid_hw_open_failed:
        }
 hid_hw_start_fail:
 hid_parse_fail:
+       sysfs_remove_group(&hdev->dev.kobj, &ps_attribute_group);
        cancel_work_sync(&hidpp->work);
        mutex_destroy(&hidpp->send_mutex);
 allocate_fail:
@@ -2327,6 +3071,8 @@ static void hidpp_remove(struct hid_device *hdev)
 {
        struct hidpp_device *hidpp = hid_get_drvdata(hdev);
 
+       sysfs_remove_group(&hdev->dev.kobj, &ps_attribute_group);
+
        if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
                hidpp_ff_deinit(hdev);
                hid_hw_close(hdev);
@@ -2357,7 +3103,11 @@ static const struct hid_device_id hidpp_devices[] = {
        { /* Keyboard logitech K400 */
          HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
                USB_VENDOR_ID_LOGITECH, 0x4024),
-         .driver_data = HIDPP_QUIRK_CONNECT_EVENTS | HIDPP_QUIRK_CLASS_K400 },
+         .driver_data = HIDPP_QUIRK_CLASS_K400 },
+       { /* Solar Keyboard Logitech K750 */
+         HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
+               USB_VENDOR_ID_LOGITECH, 0x4002),
+         .driver_data = HIDPP_QUIRK_CLASS_K750 },
 
        { HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
                USB_VENDOR_ID_LOGITECH, HID_ANY_ID)},
index 692647485a53b3316ec442518b0b84648113dda9..24d5b6deb5718356f52c3953a3fe5aa068d7563c 100644 (file)
@@ -69,6 +69,7 @@ MODULE_LICENSE("GPL");
 #define MT_QUIRK_CONTACT_CNT_ACCURATE  (1 << 12)
 #define MT_QUIRK_FORCE_GET_FEATURE     (1 << 13)
 #define MT_QUIRK_FIX_CONST_CONTACT_ID  (1 << 14)
+#define MT_QUIRK_TOUCH_SIZE_SCALING    (1 << 15)
 
 #define MT_INPUTMODE_TOUCHSCREEN       0x02
 #define MT_INPUTMODE_TOUCHPAD          0x03
@@ -222,7 +223,8 @@ static struct mt_class mt_classes[] = {
         */
        { .name = MT_CLS_3M,
                .quirks = MT_QUIRK_VALID_IS_CONFIDENCE |
-                       MT_QUIRK_SLOT_IS_CONTACTID,
+                       MT_QUIRK_SLOT_IS_CONTACTID |
+                       MT_QUIRK_TOUCH_SIZE_SCALING,
                .sn_move = 2048,
                .sn_width = 128,
                .sn_height = 128,
@@ -658,9 +660,17 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
                if (active) {
                        /* this finger is in proximity of the sensor */
                        int wide = (s->w > s->h);
-                       /* divided by two to match visual scale of touch */
-                       int major = max(s->w, s->h) >> 1;
-                       int minor = min(s->w, s->h) >> 1;
+                       int major = max(s->w, s->h);
+                       int minor = min(s->w, s->h);
+
+                       /*
+                        * divided by two to match visual scale of touch
+                        * for devices with this quirk
+                        */
+                       if (td->mtclass.quirks & MT_QUIRK_TOUCH_SIZE_SCALING) {
+                               major = major >> 1;
+                               minor = minor >> 1;
+                       }
 
                        input_event(input, EV_ABS, ABS_MT_POSITION_X, s->x);
                        input_event(input, EV_ABS, ABS_MT_POSITION_Y, s->y);
diff --git a/drivers/hid/hid-nti.c b/drivers/hid/hid-nti.c
new file mode 100644 (file)
index 0000000..5bb827b
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ *  USB HID quirks support for Network Technologies, Inc. "USB-SUN" USB
+ *  adapter for pre-USB Sun keyboards
+ *
+ *  Copyright (c) 2011 Google, Inc.
+ *
+ * Based on HID apple driver by
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2008 Jiri Slaby <jirislaby@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.
+ */
+
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+MODULE_AUTHOR("Jonathan Klabunde Tomer <jktomer@google.com>");
+MODULE_DESCRIPTION("HID driver for Network Technologies USB-SUN keyboard adapter");
+
+/*
+ * NTI Sun keyboard adapter has wrong logical maximum in report descriptor
+ */
+static __u8 *nti_usbsun_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+               unsigned int *rsize)
+{
+       if (*rsize >= 60 && rdesc[53] == 0x65 && rdesc[59] == 0x65) {
+               hid_info(hdev, "fixing up NTI USB-SUN keyboard adapter report descriptor\n");
+               rdesc[53] = rdesc[59] = 0xe7;
+       }
+       return rdesc;
+}
+
+static const struct hid_device_id nti_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_NTI, USB_DEVICE_ID_USB_SUN) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, nti_devices);
+
+static struct hid_driver nti_driver = {
+       .name = "nti",
+       .id_table = nti_devices,
+       .report_fixup = nti_usbsun_report_fixup
+};
+
+module_hid_driver(nti_driver);
+
+MODULE_LICENSE("GPL");
index 96286510f42e990eef1a0fd6a03abfd57fd42f57..8ffbb6f65a65a4befda7b2a1257400cab31c6e8b 100644 (file)
@@ -108,13 +108,12 @@ int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report)
        struct rc_dev *rdev;
        int ret = 0;
 
-       rdev = rc_allocate_device();
+       rdev = rc_allocate_device(RC_DRIVER_IR_RAW);
        if (!rdev)
                return -ENOMEM;
 
        rdev->priv             = data;
-       rdev->driver_type      = RC_DRIVER_IR_RAW;
-       rdev->allowed_protocols = RC_BIT_ALL;
+       rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
        rdev->open             = picolcd_cir_open;
        rdev->close            = picolcd_cir_close;
        rdev->input_name       = data->hdev->name;
index ea3c3546cef7f81f0f1c82b996c3ed5ab9fb26ed..8daa8ce64ebba51e91e57ec801fa7e702fb2a072 100644 (file)
@@ -508,66 +508,6 @@ static int i2c_hid_get_report_length(struct hid_report *report)
                report->device->report_enum[report->type].numbered + 2;
 }
 
-static void i2c_hid_init_report(struct hid_report *report, u8 *buffer,
-       size_t bufsize)
-{
-       struct hid_device *hid = report->device;
-       struct i2c_client *client = hid->driver_data;
-       struct i2c_hid *ihid = i2c_get_clientdata(client);
-       unsigned int size, ret_size;
-
-       size = i2c_hid_get_report_length(report);
-       if (i2c_hid_get_report(client,
-                       report->type == HID_FEATURE_REPORT ? 0x03 : 0x01,
-                       report->id, buffer, size))
-               return;
-
-       i2c_hid_dbg(ihid, "report (len=%d): %*ph\n", size, size, buffer);
-
-       ret_size = buffer[0] | (buffer[1] << 8);
-
-       if (ret_size != size) {
-               dev_err(&client->dev, "error in %s size:%d / ret_size:%d\n",
-                       __func__, size, ret_size);
-               return;
-       }
-
-       /* hid->driver_lock is held as we are in probe function,
-        * we just need to setup the input fields, so using
-        * hid_report_raw_event is safe. */
-       hid_report_raw_event(hid, report->type, buffer + 2, size - 2, 1);
-}
-
-/*
- * Initialize all reports
- */
-static void i2c_hid_init_reports(struct hid_device *hid)
-{
-       struct hid_report *report;
-       struct i2c_client *client = hid->driver_data;
-       struct i2c_hid *ihid = i2c_get_clientdata(client);
-       u8 *inbuf = kzalloc(ihid->bufsize, GFP_KERNEL);
-
-       if (!inbuf) {
-               dev_err(&client->dev, "can not retrieve initial reports\n");
-               return;
-       }
-
-       /*
-        * The device must be powered on while we fetch initial reports
-        * from it.
-        */
-       pm_runtime_get_sync(&client->dev);
-
-       list_for_each_entry(report,
-               &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
-               i2c_hid_init_report(report, inbuf, ihid->bufsize);
-
-       pm_runtime_put(&client->dev);
-
-       kfree(inbuf);
-}
-
 /*
  * Traverse the supplied list of reports and find the longest
  */
@@ -789,9 +729,6 @@ static int i2c_hid_start(struct hid_device *hid)
                        return ret;
        }
 
-       if (!(hid->quirks & HID_QUIRK_NO_INIT_REPORTS))
-               i2c_hid_init_reports(hid);
-
        return 0;
 }
 
@@ -994,6 +931,11 @@ static int i2c_hid_of_probe(struct i2c_client *client,
        }
        pdata->hid_descriptor_address = val;
 
+       ret = of_property_read_u32(dev->of_node, "post-power-on-delay-ms",
+                                  &val);
+       if (!ret)
+               pdata->post_power_delay_ms = val;
+
        return 0;
 }
 
@@ -1053,6 +995,24 @@ static int i2c_hid_probe(struct i2c_client *client,
                ihid->pdata = *platform_data;
        }
 
+       ihid->pdata.supply = devm_regulator_get(&client->dev, "vdd");
+       if (IS_ERR(ihid->pdata.supply)) {
+               ret = PTR_ERR(ihid->pdata.supply);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(&client->dev, "Failed to get regulator: %d\n",
+                               ret);
+               goto err;
+       }
+
+       ret = regulator_enable(ihid->pdata.supply);
+       if (ret < 0) {
+               dev_err(&client->dev, "Failed to enable regulator: %d\n",
+                       ret);
+               goto err;
+       }
+       if (ihid->pdata.post_power_delay_ms)
+               msleep(ihid->pdata.post_power_delay_ms);
+
        i2c_set_clientdata(client, ihid);
 
        ihid->client = client;
@@ -1068,7 +1028,7 @@ static int i2c_hid_probe(struct i2c_client *client,
         * real computation later. */
        ret = i2c_hid_alloc_buffers(ihid, HID_MIN_BUFFER_SIZE);
        if (ret < 0)
-               goto err;
+               goto err_regulator;
 
        pm_runtime_get_noresume(&client->dev);
        pm_runtime_set_active(&client->dev);
@@ -1125,6 +1085,9 @@ err_pm:
        pm_runtime_put_noidle(&client->dev);
        pm_runtime_disable(&client->dev);
 
+err_regulator:
+       regulator_disable(ihid->pdata.supply);
+
 err:
        i2c_hid_free_buffers(ihid);
        kfree(ihid);
@@ -1149,6 +1112,8 @@ static int i2c_hid_remove(struct i2c_client *client)
        if (ihid->bufsize)
                i2c_hid_free_buffers(ihid);
 
+       regulator_disable(ihid->pdata.supply);
+
        kfree(ihid);
 
        return 0;
@@ -1199,6 +1164,10 @@ static int i2c_hid_suspend(struct device *dev)
                else
                        hid_warn(hid, "Failed to enable irq wake: %d\n",
                                wake_status);
+       } else {
+               ret = regulator_disable(ihid->pdata.supply);
+               if (ret < 0)
+                       hid_warn(hid, "Failed to disable supply: %d\n", ret);
        }
 
        return 0;
@@ -1212,7 +1181,13 @@ static int i2c_hid_resume(struct device *dev)
        struct hid_device *hid = ihid->hid;
        int wake_status;
 
-       if (device_may_wakeup(&client->dev) && ihid->irq_wake_enabled) {
+       if (!device_may_wakeup(&client->dev)) {
+               ret = regulator_enable(ihid->pdata.supply);
+               if (ret < 0)
+                       hid_warn(hid, "Failed to enable supply: %d\n", ret);
+               if (ihid->pdata.post_power_delay_ms)
+                       msleep(ihid->pdata.post_power_delay_ms);
+       } else if (ihid->irq_wake_enabled) {
                wake_status = disable_irq_wake(client->irq);
                if (!wake_status)
                        ihid->irq_wake_enabled = false;
index 961bc6fdd2d908835fa9a07d169a4746fb44189d..83772fa7d92a6f6178cd3a4a5c0fea28350040b5 100644 (file)
@@ -52,6 +52,10 @@ static unsigned int hid_mousepoll_interval;
 module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644);
 MODULE_PARM_DESC(mousepoll, "Polling interval of mice");
 
+static unsigned int hid_jspoll_interval;
+module_param_named(jspoll, hid_jspoll_interval, uint, 0644);
+MODULE_PARM_DESC(jspoll, "Polling interval of joysticks");
+
 static unsigned int ignoreled;
 module_param_named(ignoreled, ignoreled, uint, 0644);
 MODULE_PARM_DESC(ignoreled, "Autosuspend with active leds");
@@ -753,11 +757,9 @@ void usbhid_init_reports(struct hid_device *hid)
        struct hid_report_enum *report_enum;
        int err, ret;
 
-       if (!(hid->quirks & HID_QUIRK_NO_INIT_INPUT_REPORTS)) {
-               report_enum = &hid->report_enum[HID_INPUT_REPORT];
-               list_for_each_entry(report, &report_enum->report_list, list)
-                       usbhid_submit_report(hid, report, USB_DIR_IN);
-       }
+       report_enum = &hid->report_enum[HID_INPUT_REPORT];
+       list_for_each_entry(report, &report_enum->report_list, list)
+               usbhid_submit_report(hid, report, USB_DIR_IN);
 
        report_enum = &hid->report_enum[HID_FEATURE_REPORT];
        list_for_each_entry(report, &report_enum->report_list, list)
@@ -1004,10 +1006,9 @@ static int usbhid_parse(struct hid_device *hid)
                return -EINVAL;
        }
 
-       if (!(rdesc = kmalloc(rsize, GFP_KERNEL))) {
-               dbg_hid("couldn't allocate rdesc memory\n");
+       rdesc = kmalloc(rsize, GFP_KERNEL);
+       if (!rdesc)
                return -ENOMEM;
-       }
 
        hid_set_idle(dev, interface->desc.bInterfaceNumber, 0, 0);
 
@@ -1077,13 +1078,21 @@ static int usbhid_start(struct hid_device *hid)
                if (hid->quirks & HID_QUIRK_FULLSPEED_INTERVAL &&
                    dev->speed == USB_SPEED_HIGH) {
                        interval = fls(endpoint->bInterval*8);
-                       printk(KERN_INFO "%s: Fixing fullspeed to highspeed interval: %d -> %d\n",
-                              hid->name, endpoint->bInterval, interval);
+                       pr_info("%s: Fixing fullspeed to highspeed interval: %d -> %d\n",
+                               hid->name, endpoint->bInterval, interval);
                }
 
-               /* Change the polling interval of mice. */
-               if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0)
-                       interval = hid_mousepoll_interval;
+               /* Change the polling interval of mice and joysticks. */
+               switch (hid->collection->usage) {
+               case HID_GD_MOUSE:
+                       if (hid_mousepoll_interval > 0)
+                               interval = hid_mousepoll_interval;
+                       break;
+               case HID_GD_JOYSTICK:
+                       if (hid_jspoll_interval > 0)
+                               interval = hid_jspoll_interval;
+                       break;
+               }
 
                ret = -ENOMEM;
                if (usb_endpoint_dir_in(endpoint)) {
@@ -1120,9 +1129,6 @@ static int usbhid_start(struct hid_device *hid)
        usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;
        usbhid->urbctrl->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
-       if (!(hid->quirks & HID_QUIRK_NO_INIT_REPORTS))
-               usbhid_init_reports(hid);
-
        set_bit(HID_STARTED, &usbhid->iofl);
 
        if (hid->quirks & HID_QUIRK_ALWAYS_POLL) {
@@ -1456,10 +1462,9 @@ static int hid_post_reset(struct usb_interface *intf)
         * the size of the HID report descriptor has not changed.
         */
        rdesc = kmalloc(hid->dev_rsize, GFP_KERNEL);
-       if (!rdesc) {
-               dbg_hid("couldn't allocate rdesc memory (post_reset)\n");
+       if (!rdesc)
                return -ENOMEM;
-       }
+
        status = hid_get_class_descriptor(dev,
                                interface->desc.bInterfaceNumber,
                                HID_DT_REPORT, rdesc, hid->dev_rsize);
@@ -1637,7 +1642,7 @@ static int __init hid_init(void)
        retval = usb_register(&hid_driver);
        if (retval)
                goto usb_register_fail;
-       printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
+       pr_info(KBUILD_MODNAME ": " DRIVER_DESC "\n");
 
        return 0;
 usb_register_fail:
index 8284781782cdd1af9041e34c3a82d5dbc4d2644f..6316498b78128574ff63b0047772f009e6d0cfeb 100644 (file)
@@ -162,10 +162,11 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_HD, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_QUAD_HD, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_TP_V103, HID_QUIRK_NO_INIT_REPORTS },
-       { USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD_A096, HID_QUIRK_NO_INIT_INPUT_REPORTS },
+       { USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD_A096, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_MULTIPLE_1781, USB_DEVICE_ID_RAPHNET_4NES4SNES_OLD, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_2NES2SNES, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_4NES4SNES, HID_QUIRK_MULTI_INPUT },
+       { USB_VENDOR_ID_INNOMEDIA, USB_DEVICE_ID_INNEX_GENESIS_ATARI, HID_QUIRK_MULTI_INPUT },
 
        { 0, 0 }
 };
@@ -241,10 +242,8 @@ static int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct,
        }
 
        q_new = kmalloc(sizeof(struct quirks_list_struct), GFP_KERNEL);
-       if (!q_new) {
-               dbg_hid("Could not allocate quirks_list_struct\n");
+       if (!q_new)
                return -ENOMEM;
-       }
 
        q_new->hid_bl_item.idVendor = idVendor;
        q_new->hid_bl_item.idProduct = idProduct;
@@ -310,10 +309,9 @@ int usbhid_quirks_init(char **quirks_param)
                                &idVendor, &idProduct, &quirks);
 
                if (m != 3 ||
-                               usbhid_modify_dquirk(idVendor, idProduct, quirks) != 0) {
-                       printk(KERN_WARNING
-                                       "Could not parse HID quirk module param %s\n",
-                                       quirks_param[n]);
+                   usbhid_modify_dquirk(idVendor, idProduct, quirks) != 0) {
+                       pr_warn("Could not parse HID quirk module param %s\n",
+                               quirks_param[n]);
                }
        }
 
index 700145b1508894f30a018aef278d15cfc458ef3a..a8baaf60e28a44934380757e24cae5c178d060bd 100644 (file)
 #endif
 #define HIDDEV_BUFFER_SIZE     2048
 
-struct hiddev {
-       int exist;
-       int open;
-       struct mutex existancelock;
-       wait_queue_head_t wait;
-       struct hid_device *hid;
-       struct list_head list;
-       spinlock_t list_lock;
-};
-
 struct hiddev_list {
        struct hiddev_usage_ref buffer[HIDDEV_BUFFER_SIZE];
        int head;
@@ -689,6 +679,7 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
        case HIDIOCINITREPORT:
                usbhid_init_reports(hid);
+               hiddev->initialized = true;
                r = 0;
                break;
 
@@ -790,6 +781,10 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case HIDIOCGUSAGES:
        case HIDIOCSUSAGES:
        case HIDIOCGCOLLECTIONINDEX:
+               if (!hiddev->initialized) {
+                       usbhid_init_reports(hid);
+                       hiddev->initialized = true;
+               }
                r = hiddev_ioctl_usage(hiddev, cmd, user_arg);
                break;
 
@@ -910,6 +905,15 @@ int hiddev_connect(struct hid_device *hid, unsigned int force)
                kfree(hiddev);
                return -1;
        }
+
+       /*
+        * If HID_QUIRK_NO_INIT_REPORTS is set, make sure we don't initialize
+        * the reports.
+        */
+       hiddev->initialized = hid->quirks & HID_QUIRK_NO_INIT_REPORTS;
+
+       hiddev->minor = usbhid->intf->minor;
+
        return 0;
 }
 
index 38ee2125412f32c87db8fd5159e443cf0f7bffbf..c7b9ab1907d87aa6ddd8d09829e112105ca2e0d3 100644 (file)
@@ -110,6 +110,7 @@ enum wacom_worker {
        WACOM_WORKER_WIRELESS,
        WACOM_WORKER_BATTERY,
        WACOM_WORKER_REMOTE,
+       WACOM_WORKER_MODE_CHANGE,
 };
 
 struct wacom;
@@ -167,6 +168,7 @@ struct wacom {
        struct work_struct remote_work;
        struct delayed_work init_work;
        struct wacom_remote *remote;
+       struct work_struct mode_change_work;
        bool generic_has_leds;
        struct wacom_leds {
                struct wacom_group_leds *groups;
@@ -196,6 +198,9 @@ static inline void wacom_schedule_work(struct wacom_wac *wacom_wac,
        case WACOM_WORKER_REMOTE:
                schedule_work(&wacom->remote_work);
                break;
+       case WACOM_WORKER_MODE_CHANGE:
+               schedule_work(&wacom->mode_change_work);
+               break;
        }
 }
 
index e2666ef84dc1ca479646fd1211f45341704755a8..0022c0dac88a20c79e4d080cbbdd35850ab36712 100644 (file)
@@ -325,6 +325,13 @@ static void wacom_post_parse_hid(struct hid_device *hdev,
 
        if (features->type == HID_GENERIC) {
                /* Any last-minute generic device setup */
+               if (wacom_wac->has_mode_change) {
+                       if (wacom_wac->is_direct_mode)
+                               features->device_type |= WACOM_DEVICETYPE_DIRECT;
+                       else
+                               features->device_type &= ~WACOM_DEVICETYPE_DIRECT;
+               }
+
                if (features->touch_max > 1) {
                        if (features->device_type & WACOM_DEVICETYPE_DIRECT)
                                input_mt_init_slots(wacom_wac->touch_input,
@@ -2093,8 +2100,10 @@ static void wacom_set_shared_values(struct wacom_wac *wacom_wac)
                wacom_wac->shared->touch_input = wacom_wac->touch_input;
        }
 
-       if (wacom_wac->has_mute_touch_switch)
+       if (wacom_wac->has_mute_touch_switch) {
                wacom_wac->shared->has_mute_touch_switch = true;
+               wacom_wac->shared->is_touch_on = true;
+       }
 
        if (wacom_wac->shared->has_mute_touch_switch &&
            wacom_wac->shared->touch_input) {
@@ -2490,6 +2499,46 @@ static void wacom_remote_work(struct work_struct *work)
        }
 }
 
+static void wacom_mode_change_work(struct work_struct *work)
+{
+       struct wacom *wacom = container_of(work, struct wacom, mode_change_work);
+       struct wacom_shared *shared = wacom->wacom_wac.shared;
+       struct wacom *wacom1 = NULL;
+       struct wacom *wacom2 = NULL;
+       bool is_direct = wacom->wacom_wac.is_direct_mode;
+       int error = 0;
+
+       if (shared->pen) {
+               wacom1 = hid_get_drvdata(shared->pen);
+               wacom_release_resources(wacom1);
+               hid_hw_stop(wacom1->hdev);
+               wacom1->wacom_wac.has_mode_change = true;
+               wacom1->wacom_wac.is_direct_mode = is_direct;
+       }
+
+       if (shared->touch) {
+               wacom2 = hid_get_drvdata(shared->touch);
+               wacom_release_resources(wacom2);
+               hid_hw_stop(wacom2->hdev);
+               wacom2->wacom_wac.has_mode_change = true;
+               wacom2->wacom_wac.is_direct_mode = is_direct;
+       }
+
+       if (wacom1) {
+               error = wacom_parse_and_register(wacom1, false);
+               if (error)
+                       return;
+       }
+
+       if (wacom2) {
+               error = wacom_parse_and_register(wacom2, false);
+               if (error)
+                       return;
+       }
+
+       return;
+}
+
 static int wacom_probe(struct hid_device *hdev,
                const struct hid_device_id *id)
 {
@@ -2534,6 +2583,7 @@ static int wacom_probe(struct hid_device *hdev,
        INIT_WORK(&wacom->wireless_work, wacom_wireless_work);
        INIT_WORK(&wacom->battery_work, wacom_battery_work);
        INIT_WORK(&wacom->remote_work, wacom_remote_work);
+       INIT_WORK(&wacom->mode_change_work, wacom_mode_change_work);
 
        /* ask for the report descriptor to be loaded by HID */
        error = hid_parse(hdev);
@@ -2576,6 +2626,7 @@ static void wacom_remove(struct hid_device *hdev)
        cancel_work_sync(&wacom->wireless_work);
        cancel_work_sync(&wacom->battery_work);
        cancel_work_sync(&wacom->remote_work);
+       cancel_work_sync(&wacom->mode_change_work);
        if (hdev->bus == BUS_BLUETOOTH)
                device_remove_file(&hdev->dev, &dev_attr_speed);
 
index c68ac65db7ffec361169c326ede5bbf263a00b1b..4b225fb19a16842f635026d1b1023d5d1cf5068e 100644 (file)
@@ -773,131 +773,6 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
        return 0;
 }
 
-static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
-{
-       unsigned char *data = wacom_wac->data;
-       struct input_dev *input;
-       struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
-       struct wacom_remote *remote = wacom->remote;
-       int bat_charging, bat_percent, touch_ring_mode;
-       __u32 serial;
-       int i, index = -1;
-       unsigned long flags;
-
-       if (data[0] != WACOM_REPORT_REMOTE) {
-               hid_dbg(wacom->hdev, "%s: received unknown report #%d",
-                       __func__, data[0]);
-               return 0;
-       }
-
-       serial = data[3] + (data[4] << 8) + (data[5] << 16);
-       wacom_wac->id[0] = PAD_DEVICE_ID;
-
-       spin_lock_irqsave(&remote->remote_lock, flags);
-
-       for (i = 0; i < WACOM_MAX_REMOTES; i++) {
-               if (remote->remotes[i].serial == serial) {
-                       index = i;
-                       break;
-               }
-       }
-
-       if (index < 0 || !remote->remotes[index].registered)
-               goto out;
-
-       input = remote->remotes[index].input;
-
-       input_report_key(input, BTN_0, (data[9] & 0x01));
-       input_report_key(input, BTN_1, (data[9] & 0x02));
-       input_report_key(input, BTN_2, (data[9] & 0x04));
-       input_report_key(input, BTN_3, (data[9] & 0x08));
-       input_report_key(input, BTN_4, (data[9] & 0x10));
-       input_report_key(input, BTN_5, (data[9] & 0x20));
-       input_report_key(input, BTN_6, (data[9] & 0x40));
-       input_report_key(input, BTN_7, (data[9] & 0x80));
-
-       input_report_key(input, BTN_8, (data[10] & 0x01));
-       input_report_key(input, BTN_9, (data[10] & 0x02));
-       input_report_key(input, BTN_A, (data[10] & 0x04));
-       input_report_key(input, BTN_B, (data[10] & 0x08));
-       input_report_key(input, BTN_C, (data[10] & 0x10));
-       input_report_key(input, BTN_X, (data[10] & 0x20));
-       input_report_key(input, BTN_Y, (data[10] & 0x40));
-       input_report_key(input, BTN_Z, (data[10] & 0x80));
-
-       input_report_key(input, BTN_BASE, (data[11] & 0x01));
-       input_report_key(input, BTN_BASE2, (data[11] & 0x02));
-
-       if (data[12] & 0x80)
-               input_report_abs(input, ABS_WHEEL, (data[12] & 0x7f));
-       else
-               input_report_abs(input, ABS_WHEEL, 0);
-
-       bat_percent = data[7] & 0x7f;
-       bat_charging = !!(data[7] & 0x80);
-
-       if (data[9] | data[10] | (data[11] & 0x03) | data[12])
-               input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
-       else
-               input_report_abs(input, ABS_MISC, 0);
-
-       input_event(input, EV_MSC, MSC_SERIAL, serial);
-
-       input_sync(input);
-
-       /*Which mode select (LED light) is currently on?*/
-       touch_ring_mode = (data[11] & 0xC0) >> 6;
-
-       for (i = 0; i < WACOM_MAX_REMOTES; i++) {
-               if (remote->remotes[i].serial == serial)
-                       wacom->led.groups[i].select = touch_ring_mode;
-       }
-
-       __wacom_notify_battery(&remote->remotes[index].battery, bat_percent,
-                               bat_charging, 1, bat_charging);
-
-out:
-       spin_unlock_irqrestore(&remote->remote_lock, flags);
-       return 0;
-}
-
-static void wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
-{
-       struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
-       unsigned char *data = wacom_wac->data;
-       struct wacom_remote *remote = wacom->remote;
-       struct wacom_remote_data remote_data;
-       unsigned long flags;
-       int i, ret;
-
-       if (data[0] != WACOM_REPORT_DEVICE_LIST)
-               return;
-
-       memset(&remote_data, 0, sizeof(struct wacom_remote_data));
-
-       for (i = 0; i < WACOM_MAX_REMOTES; i++) {
-               int j = i * 6;
-               int serial = (data[j+6] << 16) + (data[j+5] << 8) + data[j+4];
-               bool connected = data[j+2];
-
-               remote_data.remote[i].serial = serial;
-               remote_data.remote[i].connected = connected;
-       }
-
-       spin_lock_irqsave(&remote->remote_lock, flags);
-
-       ret = kfifo_in(&remote->remote_fifo, &remote_data, sizeof(remote_data));
-       if (ret != sizeof(remote_data)) {
-               spin_unlock_irqrestore(&remote->remote_lock, flags);
-               hid_err(wacom->hdev, "Can't queue Remote status event.\n");
-               return;
-       }
-
-       spin_unlock_irqrestore(&remote->remote_lock, flags);
-
-       wacom_schedule_work(wacom_wac, WACOM_WORKER_REMOTE);
-}
-
 static inline bool report_touch_events(struct wacom_wac *wacom)
 {
        return (touch_arbitration ? !wacom->shared->stylus_in_proximity : 1);
@@ -1116,6 +991,131 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
        return 0;
 }
 
+static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
+{
+       unsigned char *data = wacom_wac->data;
+       struct input_dev *input;
+       struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
+       struct wacom_remote *remote = wacom->remote;
+       int bat_charging, bat_percent, touch_ring_mode;
+       __u32 serial;
+       int i, index = -1;
+       unsigned long flags;
+
+       if (data[0] != WACOM_REPORT_REMOTE) {
+               hid_dbg(wacom->hdev, "%s: received unknown report #%d",
+                       __func__, data[0]);
+               return 0;
+       }
+
+       serial = data[3] + (data[4] << 8) + (data[5] << 16);
+       wacom_wac->id[0] = PAD_DEVICE_ID;
+
+       spin_lock_irqsave(&remote->remote_lock, flags);
+
+       for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+               if (remote->remotes[i].serial == serial) {
+                       index = i;
+                       break;
+               }
+       }
+
+       if (index < 0 || !remote->remotes[index].registered)
+               goto out;
+
+       input = remote->remotes[index].input;
+
+       input_report_key(input, BTN_0, (data[9] & 0x01));
+       input_report_key(input, BTN_1, (data[9] & 0x02));
+       input_report_key(input, BTN_2, (data[9] & 0x04));
+       input_report_key(input, BTN_3, (data[9] & 0x08));
+       input_report_key(input, BTN_4, (data[9] & 0x10));
+       input_report_key(input, BTN_5, (data[9] & 0x20));
+       input_report_key(input, BTN_6, (data[9] & 0x40));
+       input_report_key(input, BTN_7, (data[9] & 0x80));
+
+       input_report_key(input, BTN_8, (data[10] & 0x01));
+       input_report_key(input, BTN_9, (data[10] & 0x02));
+       input_report_key(input, BTN_A, (data[10] & 0x04));
+       input_report_key(input, BTN_B, (data[10] & 0x08));
+       input_report_key(input, BTN_C, (data[10] & 0x10));
+       input_report_key(input, BTN_X, (data[10] & 0x20));
+       input_report_key(input, BTN_Y, (data[10] & 0x40));
+       input_report_key(input, BTN_Z, (data[10] & 0x80));
+
+       input_report_key(input, BTN_BASE, (data[11] & 0x01));
+       input_report_key(input, BTN_BASE2, (data[11] & 0x02));
+
+       if (data[12] & 0x80)
+               input_report_abs(input, ABS_WHEEL, (data[12] & 0x7f));
+       else
+               input_report_abs(input, ABS_WHEEL, 0);
+
+       bat_percent = data[7] & 0x7f;
+       bat_charging = !!(data[7] & 0x80);
+
+       if (data[9] | data[10] | (data[11] & 0x03) | data[12])
+               input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
+       else
+               input_report_abs(input, ABS_MISC, 0);
+
+       input_event(input, EV_MSC, MSC_SERIAL, serial);
+
+       input_sync(input);
+
+       /*Which mode select (LED light) is currently on?*/
+       touch_ring_mode = (data[11] & 0xC0) >> 6;
+
+       for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+               if (remote->remotes[i].serial == serial)
+                       wacom->led.groups[i].select = touch_ring_mode;
+       }
+
+       __wacom_notify_battery(&remote->remotes[index].battery, bat_percent,
+                               bat_charging, 1, bat_charging);
+
+out:
+       spin_unlock_irqrestore(&remote->remote_lock, flags);
+       return 0;
+}
+
+static void wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
+{
+       struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
+       unsigned char *data = wacom_wac->data;
+       struct wacom_remote *remote = wacom->remote;
+       struct wacom_remote_data remote_data;
+       unsigned long flags;
+       int i, ret;
+
+       if (data[0] != WACOM_REPORT_DEVICE_LIST)
+               return;
+
+       memset(&remote_data, 0, sizeof(struct wacom_remote_data));
+
+       for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+               int j = i * 6;
+               int serial = (data[j+6] << 16) + (data[j+5] << 8) + data[j+4];
+               bool connected = data[j+2];
+
+               remote_data.remote[i].serial = serial;
+               remote_data.remote[i].connected = connected;
+       }
+
+       spin_lock_irqsave(&remote->remote_lock, flags);
+
+       ret = kfifo_in(&remote->remote_fifo, &remote_data, sizeof(remote_data));
+       if (ret != sizeof(remote_data)) {
+               spin_unlock_irqrestore(&remote->remote_lock, flags);
+               hid_err(wacom->hdev, "Can't queue Remote status event.\n");
+               return;
+       }
+
+       spin_unlock_irqrestore(&remote->remote_lock, flags);
+
+       wacom_schedule_work(wacom_wac, WACOM_WORKER_REMOTE);
+}
+
 static int int_dist(int x1, int y1, int x2, int y2)
 {
        int x = x2 - x1;
@@ -1739,6 +1739,7 @@ static void wacom_wac_pad_usage_mapping(struct hid_device *hdev,
                features->device_type |= WACOM_DEVICETYPE_PAD;
                break;
        case WACOM_HID_WD_TOUCHONOFF:
+       case WACOM_HID_WD_MUTE_DEVICE:
                /*
                 * This usage, which is used to mute touch events, comes
                 * from the pad packet, but is reported on the touch
@@ -1768,6 +1769,26 @@ static void wacom_wac_pad_usage_mapping(struct hid_device *hdev,
                wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0);
                features->device_type |= WACOM_DEVICETYPE_PAD;
                break;
+       case WACOM_HID_WD_BUTTONCONFIG:
+               wacom_map_usage(input, usage, field, EV_KEY, KEY_BUTTONCONFIG, 0);
+               features->device_type |= WACOM_DEVICETYPE_PAD;
+               break;
+       case WACOM_HID_WD_ONSCREEN_KEYBOARD:
+               wacom_map_usage(input, usage, field, EV_KEY, KEY_ONSCREEN_KEYBOARD, 0);
+               features->device_type |= WACOM_DEVICETYPE_PAD;
+               break;
+       case WACOM_HID_WD_CONTROLPANEL:
+               wacom_map_usage(input, usage, field, EV_KEY, KEY_CONTROLPANEL, 0);
+               features->device_type |= WACOM_DEVICETYPE_PAD;
+               break;
+       case WACOM_HID_WD_MODE_CHANGE:
+               /* do not overwrite previous data */
+               if (!wacom_wac->has_mode_change) {
+                       wacom_wac->has_mode_change = true;
+                       wacom_wac->is_direct_mode = true;
+               }
+               features->device_type |= WACOM_DEVICETYPE_PAD;
+               break;
        }
 
        switch (equivalent_usage & 0xfffffff0) {
@@ -1811,12 +1832,13 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
        struct wacom_features *features = &wacom_wac->features;
        unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
        int i;
+       bool is_touch_on = value;
 
        /*
         * Avoid reporting this event and setting inrange_state if this usage
         * hasn't been mapped.
         */
-       if (!usage->type)
+       if (!usage->type && equivalent_usage != WACOM_HID_WD_MODE_CHANGE)
                return;
 
        if (wacom_equivalent_usage(field->physical) == HID_DG_TABLETFUNCTIONKEY) {
@@ -1830,14 +1852,28 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
                        input_event(input, usage->type, usage->code, 0);
                break;
 
+       case WACOM_HID_WD_MUTE_DEVICE:
+               if (wacom_wac->shared->touch_input && value) {
+                       wacom_wac->shared->is_touch_on = !wacom_wac->shared->is_touch_on;
+                       is_touch_on = wacom_wac->shared->is_touch_on;
+               }
+
+               /* fall through*/
        case WACOM_HID_WD_TOUCHONOFF:
                if (wacom_wac->shared->touch_input) {
                        input_report_switch(wacom_wac->shared->touch_input,
-                                           SW_MUTE_DEVICE, !value);
+                                           SW_MUTE_DEVICE, !is_touch_on);
                        input_sync(wacom_wac->shared->touch_input);
                }
                break;
 
+       case WACOM_HID_WD_MODE_CHANGE:
+               if (wacom_wac->is_direct_mode != value) {
+                       wacom_wac->is_direct_mode = value;
+                       wacom_schedule_work(&wacom->wacom_wac, WACOM_WORKER_MODE_CHANGE);
+               }
+               break;
+
        case WACOM_HID_WD_BUTTONCENTER:
                for (i = 0; i < wacom->led.count; i++)
                        wacom_update_led(wacom, features->numbered_buttons,
@@ -1845,6 +1881,8 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
                 /* fall through*/
        default:
                input_event(input, usage->type, usage->code, value);
+               if (value)
+                       wacom_wac->hid_data.pad_input_event_flag = true;
                break;
        }
 }
@@ -1885,9 +1923,12 @@ static void wacom_wac_pad_report(struct hid_device *hdev,
        bool active = wacom_wac->hid_data.inrange_state != 0;
 
        /* report prox for expresskey events */
-       if (wacom_equivalent_usage(report->field[0]->physical) == HID_DG_TABLETFUNCTIONKEY) {
+       if ((wacom_equivalent_usage(report->field[0]->physical) == HID_DG_TABLETFUNCTIONKEY) &&
+           wacom_wac->hid_data.pad_input_event_flag) {
                input_event(input, EV_ABS, ABS_MISC, active ? PAD_DEVICE_ID : 0);
                input_sync(input);
+               if (!active)
+                       wacom_wac->hid_data.pad_input_event_flag = false;
        }
 
 }
@@ -2197,6 +2238,13 @@ static void wacom_wac_finger_slot(struct wacom_wac *wacom_wac,
        bool prox = hid_data->tipswitch &&
                    report_touch_events(wacom_wac);
 
+       if (wacom_wac->shared->has_mute_touch_switch &&
+           !wacom_wac->shared->is_touch_on) {
+               if (!wacom_wac->shared->touch_down)
+                       return;
+               prox = 0;
+       }
+
        wacom_wac->hid_data.num_received++;
        if (wacom_wac->hid_data.num_received > wacom_wac->hid_data.num_expected)
                return;
@@ -4127,7 +4175,7 @@ static const struct wacom_features wacom_features_0x300 =
          BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x301 =
        { "Wacom Bamboo One M", 21648, 13530, 1023, 31,
-         BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+         BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x302 =
        { "Wacom Intuos PT S", 15200, 9500, 1023, 31,
          INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16,
index 857ccee16f389f30c1553750f7c59453ceb3d8a6..570d29582b8206c2c0ba530029916b70500baaa0 100644 (file)
 #define WACOM_HID_WD_BATTERY_LEVEL      (WACOM_HID_UP_WACOMDIGITIZER | 0x043b)
 #define WACOM_HID_WD_EXPRESSKEY00       (WACOM_HID_UP_WACOMDIGITIZER | 0x0910)
 #define WACOM_HID_WD_EXPRESSKEYCAP00    (WACOM_HID_UP_WACOMDIGITIZER | 0x0950)
+#define WACOM_HID_WD_MODE_CHANGE        (WACOM_HID_UP_WACOMDIGITIZER | 0x0980)
+#define WACOM_HID_WD_MUTE_DEVICE        (WACOM_HID_UP_WACOMDIGITIZER | 0x0981)
+#define WACOM_HID_WD_CONTROLPANEL       (WACOM_HID_UP_WACOMDIGITIZER | 0x0982)
+#define WACOM_HID_WD_ONSCREEN_KEYBOARD  (WACOM_HID_UP_WACOMDIGITIZER | 0x0983)
+#define WACOM_HID_WD_BUTTONCONFIG       (WACOM_HID_UP_WACOMDIGITIZER | 0x0986)
 #define WACOM_HID_WD_BUTTONHOME         (WACOM_HID_UP_WACOMDIGITIZER | 0x0990)
 #define WACOM_HID_WD_BUTTONUP           (WACOM_HID_UP_WACOMDIGITIZER | 0x0991)
 #define WACOM_HID_WD_BUTTONDOWN         (WACOM_HID_UP_WACOMDIGITIZER | 0x0992)
@@ -270,6 +275,7 @@ struct wacom_shared {
        struct hid_device *pen;
        struct hid_device *touch;
        bool has_mute_touch_switch;
+       bool is_touch_on;
 };
 
 struct hid_data {
@@ -295,6 +301,7 @@ struct hid_data {
        int bat_charging;
        int bat_connected;
        int ps_connected;
+       bool pad_input_event_flag;
 };
 
 struct wacom_remote_data {
@@ -327,6 +334,9 @@ struct wacom_wac {
        int mode_value;
        struct hid_data hid_data;
        bool has_mute_touch_switch;
+       bool has_mode_change;
+       bool is_direct_mode;
+
 };
 
 #endif
index 583e95042a21d86fe235d2e9784a1f6a6723205b..bfb6ba7cac00f4fc22587b9241775197920e4cb7 100644 (file)
@@ -221,7 +221,8 @@ static int i2c_acpi_get_info(struct acpi_device *adev,
 
        acpi_dev_free_resource_list(&resource_list);
 
-       strlcpy(info->type, dev_name(&adev->dev), sizeof(info->type));
+       acpi_set_modalias(adev, dev_name(&adev->dev), info->type,
+                         sizeof(info->type));
 
        return 0;
 }
@@ -1335,15 +1336,29 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
        client->dev.fwnode = info->fwnode;
 
        i2c_dev_set_name(adap, client);
+
+       if (info->properties) {
+               status = device_add_properties(&client->dev, info->properties);
+               if (status) {
+                       dev_err(&adap->dev,
+                               "Failed to add properties to client %s: %d\n",
+                               client->name, status);
+                       goto out_err;
+               }
+       }
+
        status = device_register(&client->dev);
        if (status)
-               goto out_err;
+               goto out_free_props;
 
        dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n",
                client->name, dev_name(&client->dev));
 
        return client;
 
+out_free_props:
+       if (info->properties)
+               device_remove_properties(&client->dev);
 out_err:
        dev_err(&adap->dev,
                "Failed to register i2c client %s at 0x%02x (%d)\n",
index 39ea67f9b066989ff901674cea38d2b1bb0ff2b3..c99a25c075bcb943c7eefd1f47ade7fc8ff7b8fb 100644 (file)
@@ -10,6 +10,7 @@ menuconfig IDE
        tristate "ATA/ATAPI/MFM/RLL support (DEPRECATED)"
        depends on HAVE_IDE
        depends on BLOCK
+       select BLK_SCSI_REQUEST
        ---help---
          If you say Y here, your kernel will be able to manage ATA/(E)IDE and
          ATAPI units. The most common cases are IDE hard drives and ATAPI
index f90ea221f7f2708af8b5ee0ca9fed43268b5c296..feb30061123bc07c14b7d1ae0b5b7ce19d533790 100644 (file)
@@ -92,8 +92,9 @@ int ide_queue_pc_tail(ide_drive_t *drive, struct gendisk *disk,
        struct request *rq;
        int error;
 
-       rq = blk_get_request(drive->queue, READ, __GFP_RECLAIM);
-       rq->cmd_type = REQ_TYPE_DRV_PRIV;
+       rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, __GFP_RECLAIM);
+       scsi_req_init(rq);
+       ide_req(rq)->type = ATA_PRIV_MISC;
        rq->special = (char *)pc;
 
        if (buf && bufflen) {
@@ -103,9 +104,9 @@ int ide_queue_pc_tail(ide_drive_t *drive, struct gendisk *disk,
                        goto put_req;
        }
 
-       memcpy(rq->cmd, pc->c, 12);
+       memcpy(scsi_req(rq)->cmd, pc->c, 12);
        if (drive->media == ide_tape)
-               rq->cmd[13] = REQ_IDETAPE_PC1;
+               scsi_req(rq)->cmd[13] = REQ_IDETAPE_PC1;
        error = blk_execute_rq(drive->queue, disk, rq, 0);
 put_req:
        blk_put_request(rq);
@@ -171,7 +172,8 @@ EXPORT_SYMBOL_GPL(ide_create_request_sense_cmd);
 void ide_prep_sense(ide_drive_t *drive, struct request *rq)
 {
        struct request_sense *sense = &drive->sense_data;
-       struct request *sense_rq = &drive->sense_rq;
+       struct request *sense_rq = drive->sense_rq;
+       struct scsi_request *req = scsi_req(sense_rq);
        unsigned int cmd_len, sense_len;
        int err;
 
@@ -191,12 +193,13 @@ void ide_prep_sense(ide_drive_t *drive, struct request *rq)
 
        BUG_ON(sense_len > sizeof(*sense));
 
-       if (rq->cmd_type == REQ_TYPE_ATA_SENSE || drive->sense_rq_armed)
+       if (ata_sense_request(rq) || drive->sense_rq_armed)
                return;
 
        memset(sense, 0, sizeof(*sense));
 
        blk_rq_init(rq->q, sense_rq);
+       scsi_req_init(sense_rq);
 
        err = blk_rq_map_kern(drive->queue, sense_rq, sense, sense_len,
                              GFP_NOIO);
@@ -208,13 +211,14 @@ void ide_prep_sense(ide_drive_t *drive, struct request *rq)
        }
 
        sense_rq->rq_disk = rq->rq_disk;
-       sense_rq->cmd[0] = GPCMD_REQUEST_SENSE;
-       sense_rq->cmd[4] = cmd_len;
-       sense_rq->cmd_type = REQ_TYPE_ATA_SENSE;
+       sense_rq->cmd_flags = REQ_OP_DRV_IN;
+       ide_req(sense_rq)->type = ATA_PRIV_SENSE;
        sense_rq->rq_flags |= RQF_PREEMPT;
 
+       req->cmd[0] = GPCMD_REQUEST_SENSE;
+       req->cmd[4] = cmd_len;
        if (drive->media == ide_tape)
-               sense_rq->cmd[13] = REQ_IDETAPE_PC1;
+               req->cmd[13] = REQ_IDETAPE_PC1;
 
        drive->sense_rq_armed = true;
 }
@@ -229,12 +233,12 @@ int ide_queue_sense_rq(ide_drive_t *drive, void *special)
                return -ENOMEM;
        }
 
-       drive->sense_rq.special = special;
+       drive->sense_rq->special = special;
        drive->sense_rq_armed = false;
 
        drive->hwif->rq = NULL;
 
-       elv_add_request(drive->queue, &drive->sense_rq, ELEVATOR_INSERT_FRONT);
+       elv_add_request(drive->queue, drive->sense_rq, ELEVATOR_INSERT_FRONT);
        return 0;
 }
 EXPORT_SYMBOL_GPL(ide_queue_sense_rq);
@@ -247,14 +251,14 @@ EXPORT_SYMBOL_GPL(ide_queue_sense_rq);
 void ide_retry_pc(ide_drive_t *drive)
 {
        struct request *failed_rq = drive->hwif->rq;
-       struct request *sense_rq = &drive->sense_rq;
+       struct request *sense_rq = drive->sense_rq;
        struct ide_atapi_pc *pc = &drive->request_sense_pc;
 
        (void)ide_read_error(drive);
 
        /* init pc from sense_rq */
        ide_init_pc(pc);
-       memcpy(pc->c, sense_rq->cmd, 12);
+       memcpy(pc->c, scsi_req(sense_rq)->cmd, 12);
 
        if (drive->media == ide_tape)
                drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC;
@@ -286,7 +290,7 @@ int ide_cd_expiry(ide_drive_t *drive)
         * commands/drives support that. Let ide_timer_expiry keep polling us
         * for these.
         */
-       switch (rq->cmd[0]) {
+       switch (scsi_req(rq)->cmd[0]) {
        case GPCMD_BLANK:
        case GPCMD_FORMAT_UNIT:
        case GPCMD_RESERVE_RZONE_TRACK:
@@ -297,7 +301,7 @@ int ide_cd_expiry(ide_drive_t *drive)
        default:
                if (!(rq->rq_flags & RQF_QUIET))
                        printk(KERN_INFO PFX "cmd 0x%x timed out\n",
-                                        rq->cmd[0]);
+                                        scsi_req(rq)->cmd[0]);
                wait = 0;
                break;
        }
@@ -307,15 +311,21 @@ EXPORT_SYMBOL_GPL(ide_cd_expiry);
 
 int ide_cd_get_xferlen(struct request *rq)
 {
-       switch (rq->cmd_type) {
-       case REQ_TYPE_FS:
+       switch (req_op(rq)) {
+       default:
                return 32768;
-       case REQ_TYPE_ATA_SENSE:
-       case REQ_TYPE_BLOCK_PC:
-       case REQ_TYPE_ATA_PC:
+       case REQ_OP_SCSI_IN:
+       case REQ_OP_SCSI_OUT:
                return blk_rq_bytes(rq);
-       default:
-               return 0;
+       case REQ_OP_DRV_IN:
+       case REQ_OP_DRV_OUT:
+               switch (ide_req(rq)->type) {
+               case ATA_PRIV_PC:
+               case ATA_PRIV_SENSE:
+                       return blk_rq_bytes(rq);
+               default:
+                       return 0;
+               }
        }
 }
 EXPORT_SYMBOL_GPL(ide_cd_get_xferlen);
@@ -374,7 +384,7 @@ int ide_check_ireason(ide_drive_t *drive, struct request *rq, int len,
                                drive->name, __func__, ireason);
        }
 
-       if (dev_is_idecd(drive) && rq->cmd_type == REQ_TYPE_ATA_PC)
+       if (dev_is_idecd(drive) && ata_pc_request(rq))
                rq->rq_flags |= RQF_FAILED;
 
        return 1;
@@ -420,7 +430,7 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
                                                     ? "write" : "read");
                        pc->flags |= PC_FLAG_DMA_ERROR;
                } else
-                       rq->resid_len = 0;
+                       scsi_req(rq)->resid_len = 0;
                debug_log("%s: DMA finished\n", drive->name);
        }
 
@@ -436,7 +446,7 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
                local_irq_enable_in_hardirq();
 
                if (drive->media == ide_tape &&
-                   (stat & ATA_ERR) && rq->cmd[0] == REQUEST_SENSE)
+                   (stat & ATA_ERR) && scsi_req(rq)->cmd[0] == REQUEST_SENSE)
                        stat &= ~ATA_ERR;
 
                if ((stat & ATA_ERR) || (pc->flags & PC_FLAG_DMA_ERROR)) {
@@ -446,7 +456,7 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
                        if (drive->media != ide_tape)
                                pc->rq->errors++;
 
-                       if (rq->cmd[0] == REQUEST_SENSE) {
+                       if (scsi_req(rq)->cmd[0] == REQUEST_SENSE) {
                                printk(KERN_ERR PFX "%s: I/O error in request "
                                                "sense command\n", drive->name);
                                return ide_do_reset(drive);
@@ -477,12 +487,12 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
                if (uptodate == 0)
                        drive->failed_pc = NULL;
 
-               if (rq->cmd_type == REQ_TYPE_DRV_PRIV) {
+               if (ata_misc_request(rq)) {
                        rq->errors = 0;
                        error = 0;
                } else {
 
-                       if (rq->cmd_type != REQ_TYPE_FS && uptodate <= 0) {
+                       if (blk_rq_is_passthrough(rq) && uptodate <= 0) {
                                if (rq->errors == 0)
                                        rq->errors = -EIO;
                        }
@@ -512,7 +522,7 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
        ide_pio_bytes(drive, cmd, write, done);
 
        /* Update transferred byte count */
-       rq->resid_len -= done;
+       scsi_req(rq)->resid_len -= done;
 
        bcount -= done;
 
@@ -520,7 +530,7 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
                ide_pad_transfer(drive, write, bcount);
 
        debug_log("[cmd %x] transferred %d bytes, padded %d bytes, resid: %u\n",
-                 rq->cmd[0], done, bcount, rq->resid_len);
+                 rq->cmd[0], done, bcount, scsi_req(rq)->resid_len);
 
        /* And set the interrupt handler again */
        ide_set_handler(drive, ide_pc_intr, timeout);
@@ -603,7 +613,7 @@ static ide_startstop_t ide_transfer_pc(ide_drive_t *drive)
 
        if (dev_is_idecd(drive)) {
                /* ATAPI commands get padded out to 12 bytes minimum */
-               cmd_len = COMMAND_SIZE(rq->cmd[0]);
+               cmd_len = COMMAND_SIZE(scsi_req(rq)->cmd[0]);
                if (cmd_len < ATAPI_MIN_CDB_BYTES)
                        cmd_len = ATAPI_MIN_CDB_BYTES;
 
@@ -650,7 +660,7 @@ static ide_startstop_t ide_transfer_pc(ide_drive_t *drive)
 
        /* Send the actual packet */
        if ((drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) == 0)
-               hwif->tp_ops->output_data(drive, NULL, rq->cmd, cmd_len);
+               hwif->tp_ops->output_data(drive, NULL, scsi_req(rq)->cmd, cmd_len);
 
        /* Begin DMA, if necessary */
        if (dev_is_idecd(drive)) {
@@ -695,7 +705,7 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_cmd *cmd)
                                                             bytes, 63 * 1024));
 
                /* We haven't transferred any data yet */
-               rq->resid_len = bcount;
+               scsi_req(rq)->resid_len = bcount;
 
                if (pc->flags & PC_FLAG_DMA_ERROR) {
                        pc->flags &= ~PC_FLAG_DMA_ERROR;
index 9cbd217bc0c9201c63ca3573ab95749789595a55..aef00511ca864628c723cd3c90f01e27e9efcc86 100644 (file)
@@ -121,7 +121,7 @@ static int cdrom_log_sense(ide_drive_t *drive, struct request *rq)
                 * don't log START_STOP unit with LoEj set, since we cannot
                 * reliably check if drive can auto-close
                 */
-               if (rq->cmd[0] == GPCMD_START_STOP_UNIT && sense->asc == 0x24)
+               if (scsi_req(rq)->cmd[0] == GPCMD_START_STOP_UNIT && sense->asc == 0x24)
                        break;
                log = 1;
                break;
@@ -163,7 +163,7 @@ static void cdrom_analyze_sense_data(ide_drive_t *drive,
         * toc has not been recorded yet, it will fail with 05/24/00 (which is a
         * confusing error)
         */
-       if (failed_command && failed_command->cmd[0] == GPCMD_READ_TOC_PMA_ATIP)
+       if (failed_command && scsi_req(failed_command)->cmd[0] == GPCMD_READ_TOC_PMA_ATIP)
                if (sense->sense_key == 0x05 && sense->asc == 0x24)
                        return;
 
@@ -176,7 +176,7 @@ static void cdrom_analyze_sense_data(ide_drive_t *drive,
                        if (!sense->valid)
                                break;
                        if (failed_command == NULL ||
-                           failed_command->cmd_type != REQ_TYPE_FS)
+                           blk_rq_is_passthrough(failed_command))
                                break;
                        sector = (sense->information[0] << 24) |
                                 (sense->information[1] << 16) |
@@ -210,7 +210,7 @@ static void cdrom_analyze_sense_data(ide_drive_t *drive,
 static void ide_cd_complete_failed_rq(ide_drive_t *drive, struct request *rq)
 {
        /*
-        * For REQ_TYPE_ATA_SENSE, "rq->special" points to the original
+        * For ATA_PRIV_SENSE, "rq->special" points to the original
         * failed request.  Also, the sense data should be read
         * directly from rq which might be different from the original
         * sense buffer if it got copied during mapping.
@@ -219,15 +219,12 @@ static void ide_cd_complete_failed_rq(ide_drive_t *drive, struct request *rq)
        void *sense = bio_data(rq->bio);
 
        if (failed) {
-               if (failed->sense) {
-                       /*
-                        * Sense is always read into drive->sense_data.
-                        * Copy back if the failed request has its
-                        * sense pointer set.
-                        */
-                       memcpy(failed->sense, sense, 18);
-                       failed->sense_len = rq->sense_len;
-               }
+               /*
+                * Sense is always read into drive->sense_data, copy back to the
+                * original request.
+                */
+               memcpy(scsi_req(failed)->sense, sense, 18);
+               scsi_req(failed)->sense_len = scsi_req(rq)->sense_len;
                cdrom_analyze_sense_data(drive, failed);
 
                if (ide_end_rq(drive, failed, -EIO, blk_rq_bytes(failed)))
@@ -285,7 +282,7 @@ static int cdrom_decode_status(ide_drive_t *drive, u8 stat)
                                  "stat 0x%x",
                                  rq->cmd[0], rq->cmd_type, err, stat);
 
-       if (rq->cmd_type == REQ_TYPE_ATA_SENSE) {
+       if (ata_sense_request(rq)) {
                /*
                 * We got an error trying to get sense info from the drive
                 * (probably while trying to recover from a former error).
@@ -296,7 +293,7 @@ static int cdrom_decode_status(ide_drive_t *drive, u8 stat)
        }
 
        /* if we have an error, pass CHECK_CONDITION as the SCSI status byte */
-       if (rq->cmd_type == REQ_TYPE_BLOCK_PC && !rq->errors)
+       if (blk_rq_is_scsi(rq) && !rq->errors)
                rq->errors = SAM_STAT_CHECK_CONDITION;
 
        if (blk_noretry_request(rq))
@@ -304,13 +301,13 @@ static int cdrom_decode_status(ide_drive_t *drive, u8 stat)
 
        switch (sense_key) {
        case NOT_READY:
-               if (rq->cmd_type == REQ_TYPE_FS && rq_data_dir(rq) == WRITE) {
+               if (req_op(rq) == REQ_OP_WRITE) {
                        if (ide_cd_breathe(drive, rq))
                                return 1;
                } else {
                        cdrom_saw_media_change(drive);
 
-                       if (rq->cmd_type == REQ_TYPE_FS &&
+                       if (!blk_rq_is_passthrough(rq) &&
                            !(rq->rq_flags & RQF_QUIET))
                                printk(KERN_ERR PFX "%s: tray open\n",
                                        drive->name);
@@ -320,7 +317,7 @@ static int cdrom_decode_status(ide_drive_t *drive, u8 stat)
        case UNIT_ATTENTION:
                cdrom_saw_media_change(drive);
 
-               if (rq->cmd_type != REQ_TYPE_FS)
+               if (blk_rq_is_passthrough(rq))
                        return 0;
 
                /*
@@ -338,7 +335,7 @@ static int cdrom_decode_status(ide_drive_t *drive, u8 stat)
                 *
                 * cdrom_log_sense() knows this!
                 */
-               if (rq->cmd[0] == GPCMD_START_STOP_UNIT)
+               if (scsi_req(rq)->cmd[0] == GPCMD_START_STOP_UNIT)
                        break;
                /* fall-through */
        case DATA_PROTECT:
@@ -368,7 +365,7 @@ static int cdrom_decode_status(ide_drive_t *drive, u8 stat)
                do_end_request = 1;
                break;
        default:
-               if (rq->cmd_type != REQ_TYPE_FS)
+               if (blk_rq_is_passthrough(rq))
                        break;
                if (err & ~ATA_ABORTED) {
                        /* go to the default handler for other errors */
@@ -379,7 +376,7 @@ static int cdrom_decode_status(ide_drive_t *drive, u8 stat)
                        do_end_request = 1;
        }
 
-       if (rq->cmd_type != REQ_TYPE_FS) {
+       if (blk_rq_is_passthrough(rq)) {
                rq->rq_flags |= RQF_FAILED;
                do_end_request = 1;
        }
@@ -414,7 +411,7 @@ static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct ide_cmd *cmd)
         * Some of the trailing request sense fields are optional,
         * and some drives don't send them.  Sigh.
         */
-       if (rq->cmd[0] == GPCMD_REQUEST_SENSE &&
+       if (scsi_req(rq)->cmd[0] == GPCMD_REQUEST_SENSE &&
            cmd->nleft > 0 && cmd->nleft <= 5)
                cmd->nleft = 0;
 }
@@ -425,12 +422,8 @@ int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd,
                    req_flags_t rq_flags)
 {
        struct cdrom_info *info = drive->driver_data;
-       struct request_sense local_sense;
        int retries = 10;
-       req_flags_t flags = 0;
-
-       if (!sense)
-               sense = &local_sense;
+       bool failed;
 
        ide_debug_log(IDE_DBG_PC, "cmd[0]: 0x%x, write: 0x%x, timeout: %d, "
                                  "rq_flags: 0x%x",
@@ -440,12 +433,13 @@ int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd,
        do {
                struct request *rq;
                int error;
+               bool delay = false;
 
-               rq = blk_get_request(drive->queue, write, __GFP_RECLAIM);
-
-               memcpy(rq->cmd, cmd, BLK_MAX_CDB);
-               rq->cmd_type = REQ_TYPE_ATA_PC;
-               rq->sense = sense;
+               rq = blk_get_request(drive->queue,
+                       write ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN,  __GFP_RECLAIM);
+               scsi_req_init(rq);
+               memcpy(scsi_req(rq)->cmd, cmd, BLK_MAX_CDB);
+               ide_req(rq)->type = ATA_PRIV_PC;
                rq->rq_flags |= rq_flags;
                rq->timeout = timeout;
                if (buffer) {
@@ -460,21 +454,21 @@ int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd,
                error = blk_execute_rq(drive->queue, info->disk, rq, 0);
 
                if (buffer)
-                       *bufflen = rq->resid_len;
-
-               flags = rq->rq_flags;
-               blk_put_request(rq);
+                       *bufflen = scsi_req(rq)->resid_len;
+               if (sense)
+                       memcpy(sense, scsi_req(rq)->sense, sizeof(*sense));
 
                /*
                 * FIXME: we should probably abort/retry or something in case of
                 * failure.
                 */
-               if (flags & RQF_FAILED) {
+               failed = (rq->rq_flags & RQF_FAILED) != 0;
+               if (failed) {
                        /*
                         * The request failed.  Retry if it was due to a unit
                         * attention status (usually means media was changed).
                         */
-                       struct request_sense *reqbuf = sense;
+                       struct request_sense *reqbuf = scsi_req(rq)->sense;
 
                        if (reqbuf->sense_key == UNIT_ATTENTION)
                                cdrom_saw_media_change(drive);
@@ -485,19 +479,20 @@ int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd,
                                 * a disk.  Retry, but wait a little to give
                                 * the drive time to complete the load.
                                 */
-                               ssleep(2);
+                               delay = true;
                        } else {
                                /* otherwise, don't retry */
                                retries = 0;
                        }
                        --retries;
                }
-
-               /* end of retry loop */
-       } while ((flags & RQF_FAILED) && retries >= 0);
+               blk_put_request(rq);
+               if (delay)
+                       ssleep(2);
+       } while (failed && retries >= 0);
 
        /* return an error if the command failed */
-       return (flags & RQF_FAILED) ? -EIO : 0;
+       return failed ? -EIO : 0;
 }
 
 /*
@@ -526,7 +521,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
        ide_expiry_t *expiry = NULL;
        int dma_error = 0, dma, thislen, uptodate = 0;
        int write = (rq_data_dir(rq) == WRITE) ? 1 : 0, rc = 0;
-       int sense = (rq->cmd_type == REQ_TYPE_ATA_SENSE);
+       int sense = ata_sense_request(rq);
        unsigned int timeout;
        u16 len;
        u8 ireason, stat;
@@ -569,7 +564,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
 
        ide_read_bcount_and_ireason(drive, &len, &ireason);
 
-       thislen = (rq->cmd_type == REQ_TYPE_FS) ? len : cmd->nleft;
+       thislen = !blk_rq_is_passthrough(rq) ? len : cmd->nleft;
        if (thislen > len)
                thislen = len;
 
@@ -578,7 +573,8 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
 
        /* If DRQ is clear, the command has completed. */
        if ((stat & ATA_DRQ) == 0) {
-               if (rq->cmd_type == REQ_TYPE_FS) {
+               switch (req_op(rq)) {
+               default:
                        /*
                         * If we're not done reading/writing, complain.
                         * Otherwise, complete the command normally.
@@ -592,7 +588,9 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
                                        rq->rq_flags |= RQF_FAILED;
                                uptodate = 0;
                        }
-               } else if (rq->cmd_type != REQ_TYPE_BLOCK_PC) {
+                       goto out_end;
+               case REQ_OP_DRV_IN:
+               case REQ_OP_DRV_OUT:
                        ide_cd_request_sense_fixup(drive, cmd);
 
                        uptodate = cmd->nleft ? 0 : 1;
@@ -608,8 +606,11 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
 
                        if (!uptodate)
                                rq->rq_flags |= RQF_FAILED;
+                       goto out_end;
+               case REQ_OP_SCSI_IN:
+               case REQ_OP_SCSI_OUT:
+                       goto out_end;
                }
-               goto out_end;
        }
 
        rc = ide_check_ireason(drive, rq, len, ireason, write);
@@ -636,12 +637,12 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
                len -= blen;
 
                if (sense && write == 0)
-                       rq->sense_len += blen;
+                       scsi_req(rq)->sense_len += blen;
        }
 
        /* pad, if necessary */
        if (len > 0) {
-               if (rq->cmd_type != REQ_TYPE_FS || write == 0)
+               if (blk_rq_is_passthrough(rq) || write == 0)
                        ide_pad_transfer(drive, write, len);
                else {
                        printk(KERN_ERR PFX "%s: confused, missing data\n",
@@ -650,12 +651,18 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
                }
        }
 
-       if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
+       switch (req_op(rq)) {
+       case REQ_OP_SCSI_IN:
+       case REQ_OP_SCSI_OUT:
                timeout = rq->timeout;
-       } else {
+               break;
+       case REQ_OP_DRV_IN:
+       case REQ_OP_DRV_OUT:
+               expiry = ide_cd_expiry;
+               /*FALLTHRU*/
+       default:
                timeout = ATAPI_WAIT_PC;
-               if (rq->cmd_type != REQ_TYPE_FS)
-                       expiry = ide_cd_expiry;
+               break;
        }
 
        hwif->expiry = expiry;
@@ -663,15 +670,15 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
        return ide_started;
 
 out_end:
-       if (rq->cmd_type == REQ_TYPE_BLOCK_PC && rc == 0) {
-               rq->resid_len = 0;
+       if (blk_rq_is_scsi(rq) && rc == 0) {
+               scsi_req(rq)->resid_len = 0;
                blk_end_request_all(rq, 0);
                hwif->rq = NULL;
        } else {
                if (sense && uptodate)
                        ide_cd_complete_failed_rq(drive, rq);
 
-               if (rq->cmd_type == REQ_TYPE_FS) {
+               if (!blk_rq_is_passthrough(rq)) {
                        if (cmd->nleft == 0)
                                uptodate = 1;
                } else {
@@ -684,10 +691,10 @@ out_end:
                                return ide_stopped;
 
                /* make sure it's fully ended */
-               if (rq->cmd_type != REQ_TYPE_FS) {
-                       rq->resid_len -= cmd->nbytes - cmd->nleft;
+               if (blk_rq_is_passthrough(rq)) {
+                       scsi_req(rq)->resid_len -= cmd->nbytes - cmd->nleft;
                        if (uptodate == 0 && (cmd->tf_flags & IDE_TFLAG_WRITE))
-                               rq->resid_len += cmd->last_xfer_len;
+                               scsi_req(rq)->resid_len += cmd->last_xfer_len;
                }
 
                ide_complete_rq(drive, uptodate ? 0 : -EIO, blk_rq_bytes(rq));
@@ -744,7 +751,7 @@ static void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
        ide_debug_log(IDE_DBG_PC, "rq->cmd[0]: 0x%x, rq->cmd_type: 0x%x",
                                  rq->cmd[0], rq->cmd_type);
 
-       if (rq->cmd_type == REQ_TYPE_BLOCK_PC)
+       if (blk_rq_is_scsi(rq))
                rq->rq_flags |= RQF_QUIET;
        else
                rq->rq_flags &= ~RQF_FAILED;
@@ -786,25 +793,31 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq,
        if (drive->debug_mask & IDE_DBG_RQ)
                blk_dump_rq_flags(rq, "ide_cd_do_request");
 
-       switch (rq->cmd_type) {
-       case REQ_TYPE_FS:
+       switch (req_op(rq)) {
+       default:
                if (cdrom_start_rw(drive, rq) == ide_stopped)
                        goto out_end;
                break;
-       case REQ_TYPE_ATA_SENSE:
-       case REQ_TYPE_BLOCK_PC:
-       case REQ_TYPE_ATA_PC:
+       case REQ_OP_SCSI_IN:
+       case REQ_OP_SCSI_OUT:
+       handle_pc:
                if (!rq->timeout)
                        rq->timeout = ATAPI_WAIT_PC;
-
                cdrom_do_block_pc(drive, rq);
                break;
-       case REQ_TYPE_DRV_PRIV:
-               /* right now this can only be a reset... */
-               uptodate = 1;
-               goto out_end;
-       default:
-               BUG();
+       case REQ_OP_DRV_IN:
+       case REQ_OP_DRV_OUT:
+               switch (ide_req(rq)->type) {
+               case ATA_PRIV_MISC:
+                       /* right now this can only be a reset... */
+                       uptodate = 1;
+                       goto out_end;
+               case ATA_PRIV_SENSE:
+               case ATA_PRIV_PC:
+                       goto handle_pc;
+               default:
+                       BUG();
+               }
        }
 
        /* prepare sense request for this command */
@@ -817,7 +830,7 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq,
 
        cmd.rq = rq;
 
-       if (rq->cmd_type == REQ_TYPE_FS || blk_rq_bytes(rq)) {
+       if (!blk_rq_is_passthrough(rq) || blk_rq_bytes(rq)) {
                ide_init_sg_cmd(&cmd, blk_rq_bytes(rq));
                ide_map_sg(drive, &cmd);
        }
@@ -1166,7 +1179,7 @@ void ide_cdrom_update_speed(ide_drive_t *drive, u8 *buf)
         CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_GENERIC_PACKET | \
         CDC_MO_DRIVE | CDC_MRW | CDC_MRW_W | CDC_RAM)
 
-static struct cdrom_device_ops ide_cdrom_dops = {
+static const struct cdrom_device_ops ide_cdrom_dops = {
        .open                   = ide_cdrom_open_real,
        .release                = ide_cdrom_release_real,
        .drive_status           = ide_cdrom_drive_status,
@@ -1312,28 +1325,29 @@ static int ide_cdrom_prep_fs(struct request_queue *q, struct request *rq)
        int hard_sect = queue_logical_block_size(q);
        long block = (long)blk_rq_pos(rq) / (hard_sect >> 9);
        unsigned long blocks = blk_rq_sectors(rq) / (hard_sect >> 9);
+       struct scsi_request *req = scsi_req(rq);
 
-       memset(rq->cmd, 0, BLK_MAX_CDB);
+       memset(req->cmd, 0, BLK_MAX_CDB);
 
        if (rq_data_dir(rq) == READ)
-               rq->cmd[0] = GPCMD_READ_10;
+               req->cmd[0] = GPCMD_READ_10;
        else
-               rq->cmd[0] = GPCMD_WRITE_10;
+               req->cmd[0] = GPCMD_WRITE_10;
 
        /*
         * fill in lba
         */
-       rq->cmd[2] = (block >> 24) & 0xff;
-       rq->cmd[3] = (block >> 16) & 0xff;
-       rq->cmd[4] = (block >>  8) & 0xff;
-       rq->cmd[5] = block & 0xff;
+       req->cmd[2] = (block >> 24) & 0xff;
+       req->cmd[3] = (block >> 16) & 0xff;
+       req->cmd[4] = (block >>  8) & 0xff;
+       req->cmd[5] = block & 0xff;
 
        /*
         * and transfer length
         */
-       rq->cmd[7] = (blocks >> 8) & 0xff;
-       rq->cmd[8] = blocks & 0xff;
-       rq->cmd_len = 10;
+       req->cmd[7] = (blocks >> 8) & 0xff;
+       req->cmd[8] = blocks & 0xff;
+       req->cmd_len = 10;
        return BLKPREP_OK;
 }
 
@@ -1343,7 +1357,7 @@ static int ide_cdrom_prep_fs(struct request_queue *q, struct request *rq)
  */
 static int ide_cdrom_prep_pc(struct request *rq)
 {
-       u8 *c = rq->cmd;
+       u8 *c = scsi_req(rq)->cmd;
 
        /* transform 6-byte read/write commands to the 10-byte version */
        if (c[0] == READ_6 || c[0] == WRITE_6) {
@@ -1354,7 +1368,7 @@ static int ide_cdrom_prep_pc(struct request *rq)
                c[2] = 0;
                c[1] &= 0xe0;
                c[0] += (READ_10 - READ_6);
-               rq->cmd_len = 10;
+               scsi_req(rq)->cmd_len = 10;
                return BLKPREP_OK;
        }
 
@@ -1373,9 +1387,9 @@ static int ide_cdrom_prep_pc(struct request *rq)
 
 static int ide_cdrom_prep_fn(struct request_queue *q, struct request *rq)
 {
-       if (rq->cmd_type == REQ_TYPE_FS)
+       if (!blk_rq_is_passthrough(rq))
                return ide_cdrom_prep_fs(q, rq);
-       else if (rq->cmd_type == REQ_TYPE_BLOCK_PC)
+       else if (blk_rq_is_scsi(rq))
                return ide_cdrom_prep_pc(rq);
 
        return 0;
index f085e3a2e1d69ed40d6f28006e71fc04710135dc..9fcefbc8425e748cf27b4967f2a16fcc67605965 100644 (file)
@@ -303,8 +303,9 @@ int ide_cdrom_reset(struct cdrom_device_info *cdi)
        struct request *rq;
        int ret;
 
-       rq = blk_get_request(drive->queue, READ, __GFP_RECLAIM);
-       rq->cmd_type = REQ_TYPE_DRV_PRIV;
+       rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, __GFP_RECLAIM);
+       scsi_req_init(rq);
+       ide_req(rq)->type = ATA_PRIV_MISC;
        rq->rq_flags = RQF_QUIET;
        ret = blk_execute_rq(drive->queue, cd->disk, rq, 0);
        blk_put_request(rq);
index f079ca2f260b605ae5f20b7f1010d653baad22e2..58a6feb74c02f150388adfb67f64914c23273ed2 100644 (file)
@@ -315,12 +315,12 @@ void ide_cd_log_error(const char *name, struct request *failed_command,
                while (hi > lo) {
                        mid = (lo + hi) / 2;
                        if (packet_command_texts[mid].packet_command ==
-                           failed_command->cmd[0]) {
+                           scsi_req(failed_command)->cmd[0]) {
                                s = packet_command_texts[mid].text;
                                break;
                        }
                        if (packet_command_texts[mid].packet_command >
-                           failed_command->cmd[0])
+                           scsi_req(failed_command)->cmd[0])
                                hi = mid;
                        else
                                lo = mid + 1;
@@ -329,7 +329,7 @@ void ide_cd_log_error(const char *name, struct request *failed_command,
                printk(KERN_ERR "  The failed \"%s\" packet command "
                                "was: \n  \"", s);
                for (i = 0; i < BLK_MAX_CDB; i++)
-                       printk(KERN_CONT "%02x ", failed_command->cmd[i]);
+                       printk(KERN_CONT "%02x ", scsi_req(failed_command)->cmd[i]);
                printk(KERN_CONT "\"\n");
        }
 
index 0dd43b4fcec6353633d12338be557b8e1e13ef14..a45dda5386e4403206ee73a18b8bb8b16b012e65 100644 (file)
@@ -165,11 +165,12 @@ int ide_devset_execute(ide_drive_t *drive, const struct ide_devset *setting,
        if (!(setting->flags & DS_SYNC))
                return setting->set(drive, arg);
 
-       rq = blk_get_request(q, READ, __GFP_RECLAIM);
-       rq->cmd_type = REQ_TYPE_DRV_PRIV;
-       rq->cmd_len = 5;
-       rq->cmd[0] = REQ_DEVSET_EXEC;
-       *(int *)&rq->cmd[1] = arg;
+       rq = blk_get_request(q, REQ_OP_DRV_IN, __GFP_RECLAIM);
+       scsi_req_init(rq);
+       ide_req(rq)->type = ATA_PRIV_MISC;
+       scsi_req(rq)->cmd_len = 5;
+       scsi_req(rq)->cmd[0] = REQ_DEVSET_EXEC;
+       *(int *)&scsi_req(rq)->cmd[1] = arg;
        rq->special = setting->set;
 
        if (blk_execute_rq(q, NULL, rq, 0))
@@ -183,7 +184,7 @@ ide_startstop_t ide_do_devset(ide_drive_t *drive, struct request *rq)
 {
        int err, (*setfunc)(ide_drive_t *, int) = rq->special;
 
-       err = setfunc(drive, *(int *)&rq->cmd[1]);
+       err = setfunc(drive, *(int *)&scsi_req(rq)->cmd[1]);
        if (err)
                rq->errors = err;
        ide_complete_rq(drive, err, blk_rq_bytes(rq));
index 5ceace542b775931524d60a569881e4cd79a51bc..186159715b71c6fd7a01eb11bc92239487c4dc7e 100644 (file)
@@ -184,7 +184,7 @@ static ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
        ide_hwif_t *hwif = drive->hwif;
 
        BUG_ON(drive->dev_flags & IDE_DFLAG_BLOCKED);
-       BUG_ON(rq->cmd_type != REQ_TYPE_FS);
+       BUG_ON(blk_rq_is_passthrough(rq));
 
        ledtrig_disk_activity();
 
@@ -452,8 +452,9 @@ static int idedisk_prep_fn(struct request_queue *q, struct request *rq)
        cmd->valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
        cmd->tf_flags = IDE_TFLAG_DYN;
        cmd->protocol = ATA_PROT_NODATA;
-
-       rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
+       rq->cmd_flags &= ~REQ_OP_MASK;
+       rq->cmd_flags |= REQ_OP_DRV_OUT;
+       ide_req(rq)->type = ATA_PRIV_TASKFILE;
        rq->special = cmd;
        cmd->rq = rq;
 
@@ -477,8 +478,9 @@ static int set_multcount(ide_drive_t *drive, int arg)
        if (drive->special_flags & IDE_SFLAG_SET_MULTMODE)
                return -EBUSY;
 
-       rq = blk_get_request(drive->queue, READ, __GFP_RECLAIM);
-       rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
+       rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, __GFP_RECLAIM);
+       scsi_req_init(rq);
+       ide_req(rq)->type = ATA_PRIV_TASKFILE;
 
        drive->mult_req = arg;
        drive->special_flags |= IDE_SFLAG_SET_MULTMODE;
index d6da011299f582934bf50c1c05c0719577d41ba6..cf3af68403689a62f9c237d7d1ced636a1aca6b5 100644 (file)
@@ -123,8 +123,8 @@ ide_startstop_t ide_error(ide_drive_t *drive, const char *msg, u8 stat)
                return ide_stopped;
 
        /* retry only "normal" I/O: */
-       if (rq->cmd_type != REQ_TYPE_FS) {
-               if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
+       if (blk_rq_is_passthrough(rq)) {
+               if (ata_taskfile_request(rq)) {
                        struct ide_cmd *cmd = rq->special;
 
                        if (cmd)
@@ -147,8 +147,8 @@ static inline void ide_complete_drive_reset(ide_drive_t *drive, int err)
 {
        struct request *rq = drive->hwif->rq;
 
-       if (rq && rq->cmd_type == REQ_TYPE_DRV_PRIV &&
-           rq->cmd[0] == REQ_DRIVE_RESET) {
+       if (rq && ata_misc_request(rq) &&
+           scsi_req(rq)->cmd[0] == REQ_DRIVE_RESET) {
                if (err <= 0 && rq->errors == 0)
                        rq->errors = -EIO;
                ide_complete_rq(drive, err ? err : 0, blk_rq_bytes(rq));
index f079d8d1d8569a43a035adebbba2a63ee8ca5379..a69e8013f1dff9ff0e8b63fea7cee0ca3767a23f 100644 (file)
@@ -72,7 +72,7 @@ static int ide_floppy_callback(ide_drive_t *drive, int dsc)
                drive->failed_pc = NULL;
 
        if (pc->c[0] == GPCMD_READ_10 || pc->c[0] == GPCMD_WRITE_10 ||
-           rq->cmd_type == REQ_TYPE_BLOCK_PC)
+           (req_op(rq) == REQ_OP_SCSI_IN || req_op(rq) == REQ_OP_SCSI_OUT))
                uptodate = 1; /* FIXME */
        else if (pc->c[0] == GPCMD_REQUEST_SENSE) {
 
@@ -97,7 +97,7 @@ static int ide_floppy_callback(ide_drive_t *drive, int dsc)
                               "Aborting request!\n");
        }
 
-       if (rq->cmd_type == REQ_TYPE_DRV_PRIV)
+       if (ata_misc_request(rq))
                rq->errors = uptodate ? 0 : IDE_DRV_ERROR_GENERAL;
 
        return uptodate;
@@ -203,7 +203,7 @@ static void idefloppy_create_rw_cmd(ide_drive_t *drive,
        put_unaligned(cpu_to_be16(blocks), (unsigned short *)&pc->c[7]);
        put_unaligned(cpu_to_be32(block), (unsigned int *) &pc->c[2]);
 
-       memcpy(rq->cmd, pc->c, 12);
+       memcpy(scsi_req(rq)->cmd, pc->c, 12);
 
        pc->rq = rq;
        if (cmd == WRITE)
@@ -216,7 +216,7 @@ static void idefloppy_blockpc_cmd(struct ide_disk_obj *floppy,
                struct ide_atapi_pc *pc, struct request *rq)
 {
        ide_init_pc(pc);
-       memcpy(pc->c, rq->cmd, sizeof(pc->c));
+       memcpy(pc->c, scsi_req(rq)->cmd, sizeof(pc->c));
        pc->rq = rq;
        if (blk_rq_bytes(rq)) {
                pc->flags |= PC_FLAG_DMA_OK;
@@ -246,7 +246,7 @@ static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive,
                } else
                        printk(KERN_ERR PFX "%s: I/O error\n", drive->name);
 
-               if (rq->cmd_type == REQ_TYPE_DRV_PRIV) {
+               if (ata_misc_request(rq)) {
                        rq->errors = 0;
                        ide_complete_rq(drive, 0, blk_rq_bytes(rq));
                        return ide_stopped;
@@ -254,8 +254,8 @@ static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive,
                        goto out_end;
        }
 
-       switch (rq->cmd_type) {
-       case REQ_TYPE_FS:
+       switch (req_op(rq)) {
+       default:
                if (((long)blk_rq_pos(rq) % floppy->bs_factor) ||
                    (blk_rq_sectors(rq) % floppy->bs_factor)) {
                        printk(KERN_ERR PFX "%s: unsupported r/w rq size\n",
@@ -265,16 +265,21 @@ static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive,
                pc = &floppy->queued_pc;
                idefloppy_create_rw_cmd(drive, pc, rq, (unsigned long)block);
                break;
-       case REQ_TYPE_DRV_PRIV:
-       case REQ_TYPE_ATA_SENSE:
-               pc = (struct ide_atapi_pc *)rq->special;
-               break;
-       case REQ_TYPE_BLOCK_PC:
+       case REQ_OP_SCSI_IN:
+       case REQ_OP_SCSI_OUT:
                pc = &floppy->queued_pc;
                idefloppy_blockpc_cmd(floppy, pc, rq);
                break;
-       default:
-               BUG();
+       case REQ_OP_DRV_IN:
+       case REQ_OP_DRV_OUT:
+               switch (ide_req(rq)->type) {
+               case ATA_PRIV_MISC:
+               case ATA_PRIV_SENSE:
+                       pc = (struct ide_atapi_pc *)rq->special;
+                       break;
+               default:
+                       BUG();
+               }
        }
 
        ide_prep_sense(drive, rq);
@@ -286,7 +291,7 @@ static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive,
 
        cmd.rq = rq;
 
-       if (rq->cmd_type == REQ_TYPE_FS || blk_rq_bytes(rq)) {
+       if (!blk_rq_is_passthrough(rq) || blk_rq_bytes(rq)) {
                ide_init_sg_cmd(&cmd, blk_rq_bytes(rq));
                ide_map_sg(drive, &cmd);
        }
@@ -296,7 +301,7 @@ static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive,
        return ide_floppy_issue_pc(drive, &cmd, pc);
 out_end:
        drive->failed_pc = NULL;
-       if (rq->cmd_type != REQ_TYPE_FS && rq->errors == 0)
+       if (blk_rq_is_passthrough(rq) && rq->errors == 0)
                rq->errors = -EIO;
        ide_complete_rq(drive, -EIO, blk_rq_bytes(rq));
        return ide_stopped;
index 201e43fcbc940019a499260b7275ef4dbe18ef84..043b1fb963cb89982029dddad977c386f8e6bfde 100644 (file)
@@ -102,7 +102,7 @@ void ide_complete_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat, u8 err)
                        drive->dev_flags |= IDE_DFLAG_PARKED;
        }
 
-       if (rq && rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
+       if (rq && ata_taskfile_request(rq)) {
                struct ide_cmd *orig_cmd = rq->special;
 
                if (cmd->tf_flags & IDE_TFLAG_DYN)
@@ -135,7 +135,7 @@ EXPORT_SYMBOL(ide_complete_rq);
 
 void ide_kill_rq(ide_drive_t *drive, struct request *rq)
 {
-       u8 drv_req = (rq->cmd_type == REQ_TYPE_DRV_PRIV) && rq->rq_disk;
+       u8 drv_req = ata_misc_request(rq) && rq->rq_disk;
        u8 media = drive->media;
 
        drive->failed_pc = NULL;
@@ -145,7 +145,7 @@ void ide_kill_rq(ide_drive_t *drive, struct request *rq)
        } else {
                if (media == ide_tape)
                        rq->errors = IDE_DRV_ERROR_GENERAL;
-               else if (rq->cmd_type != REQ_TYPE_FS && rq->errors == 0)
+               else if (blk_rq_is_passthrough(rq) && rq->errors == 0)
                        rq->errors = -EIO;
        }
 
@@ -279,7 +279,7 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive,
 
 static ide_startstop_t ide_special_rq(ide_drive_t *drive, struct request *rq)
 {
-       u8 cmd = rq->cmd[0];
+       u8 cmd = scsi_req(rq)->cmd[0];
 
        switch (cmd) {
        case REQ_PARK_HEADS:
@@ -340,7 +340,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
                if (drive->current_speed == 0xff)
                        ide_config_drive_speed(drive, drive->desired_speed);
 
-               if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE)
+               if (ata_taskfile_request(rq))
                        return execute_drive_cmd(drive, rq);
                else if (ata_pm_request(rq)) {
                        struct ide_pm_state *pm = rq->special;
@@ -353,7 +353,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
                            pm->pm_step == IDE_PM_COMPLETED)
                                ide_complete_pm_rq(drive, rq);
                        return startstop;
-               } else if (!rq->rq_disk && rq->cmd_type == REQ_TYPE_DRV_PRIV)
+               } else if (!rq->rq_disk && ata_misc_request(rq))
                        /*
                         * TODO: Once all ULDs have been modified to
                         * check for specific op codes rather than
@@ -545,6 +545,7 @@ repeat:
                        goto plug_device;
                }
 
+               scsi_req(rq)->resid_len = blk_rq_bytes(rq);
                hwif->rq = rq;
 
                spin_unlock_irq(&hwif->lock);
index d05db2469209bb1dfe1f9757d078b0298e55d180..248a3e0ceb468bdb57e896425a642375e77355be 100644 (file)
@@ -125,8 +125,9 @@ static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg)
        if (NULL == (void *) arg) {
                struct request *rq;
 
-               rq = blk_get_request(drive->queue, READ, __GFP_RECLAIM);
-               rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
+               rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, __GFP_RECLAIM);
+               scsi_req_init(rq);
+               ide_req(rq)->type = ATA_PRIV_TASKFILE;
                err = blk_execute_rq(drive->queue, NULL, rq, 0);
                blk_put_request(rq);
 
@@ -221,10 +222,11 @@ static int generic_drive_reset(ide_drive_t *drive)
        struct request *rq;
        int ret = 0;
 
-       rq = blk_get_request(drive->queue, READ, __GFP_RECLAIM);
-       rq->cmd_type = REQ_TYPE_DRV_PRIV;
-       rq->cmd_len = 1;
-       rq->cmd[0] = REQ_DRIVE_RESET;
+       rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, __GFP_RECLAIM);
+       scsi_req_init(rq);
+       ide_req(rq)->type = ATA_PRIV_MISC;
+       scsi_req(rq)->cmd_len = 1;
+       scsi_req(rq)->cmd[0] = REQ_DRIVE_RESET;
        if (blk_execute_rq(drive->queue, NULL, rq, 1))
                ret = rq->errors;
        blk_put_request(rq);
index 2d7dca56dd244387a633e2eec30b177dfbd25a70..101aed9a61ca319439d825c6e433a53175e0ed64 100644 (file)
@@ -31,10 +31,11 @@ static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout)
        }
        spin_unlock_irq(&hwif->lock);
 
-       rq = blk_get_request(q, READ, __GFP_RECLAIM);
-       rq->cmd[0] = REQ_PARK_HEADS;
-       rq->cmd_len = 1;
-       rq->cmd_type = REQ_TYPE_DRV_PRIV;
+       rq = blk_get_request(q, REQ_OP_DRV_IN, __GFP_RECLAIM);
+       scsi_req_init(rq);
+       scsi_req(rq)->cmd[0] = REQ_PARK_HEADS;
+       scsi_req(rq)->cmd_len = 1;
+       ide_req(rq)->type = ATA_PRIV_MISC;
        rq->special = &timeout;
        rc = blk_execute_rq(q, NULL, rq, 1);
        blk_put_request(rq);
@@ -45,13 +46,14 @@ static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout)
         * Make sure that *some* command is sent to the drive after the
         * timeout has expired, so power management will be reenabled.
         */
-       rq = blk_get_request(q, READ, GFP_NOWAIT);
+       rq = blk_get_request(q, REQ_OP_DRV_IN, GFP_NOWAIT);
+       scsi_req_init(rq);
        if (IS_ERR(rq))
                goto out;
 
-       rq->cmd[0] = REQ_UNPARK_HEADS;
-       rq->cmd_len = 1;
-       rq->cmd_type = REQ_TYPE_DRV_PRIV;
+       scsi_req(rq)->cmd[0] = REQ_UNPARK_HEADS;
+       scsi_req(rq)->cmd_len = 1;
+       ide_req(rq)->type = ATA_PRIV_MISC;
        elv_add_request(q, rq, ELEVATOR_INSERT_FRONT);
 
 out:
@@ -64,7 +66,7 @@ ide_startstop_t ide_do_park_unpark(ide_drive_t *drive, struct request *rq)
        struct ide_taskfile *tf = &cmd.tf;
 
        memset(&cmd, 0, sizeof(cmd));
-       if (rq->cmd[0] == REQ_PARK_HEADS) {
+       if (scsi_req(rq)->cmd[0] == REQ_PARK_HEADS) {
                drive->sleep = *(unsigned long *)rq->special;
                drive->dev_flags |= IDE_DFLAG_SLEEPING;
                tf->command = ATA_CMD_IDLEIMMEDIATE;
index a015acdffb39337eace20d331213fe2bc90d85a7..ec951be4b0c8ab0950ca31dbeb070520c925230e 100644 (file)
@@ -18,8 +18,9 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg)
        }
 
        memset(&rqpm, 0, sizeof(rqpm));
-       rq = blk_get_request(drive->queue, READ, __GFP_RECLAIM);
-       rq->cmd_type = REQ_TYPE_ATA_PM_SUSPEND;
+       rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, __GFP_RECLAIM);
+       scsi_req_init(rq);
+       ide_req(rq)->type = ATA_PRIV_PM_SUSPEND;
        rq->special = &rqpm;
        rqpm.pm_step = IDE_PM_START_SUSPEND;
        if (mesg.event == PM_EVENT_PRETHAW)
@@ -88,8 +89,9 @@ int generic_ide_resume(struct device *dev)
        }
 
        memset(&rqpm, 0, sizeof(rqpm));
-       rq = blk_get_request(drive->queue, READ, __GFP_RECLAIM);
-       rq->cmd_type = REQ_TYPE_ATA_PM_RESUME;
+       rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, __GFP_RECLAIM);
+       scsi_req_init(rq);
+       ide_req(rq)->type = ATA_PRIV_PM_RESUME;
        rq->rq_flags |= RQF_PREEMPT;
        rq->special = &rqpm;
        rqpm.pm_step = IDE_PM_START_RESUME;
@@ -221,10 +223,10 @@ void ide_complete_pm_rq(ide_drive_t *drive, struct request *rq)
 
 #ifdef DEBUG_PM
        printk("%s: completing PM request, %s\n", drive->name,
-              (rq->cmd_type == REQ_TYPE_ATA_PM_SUSPEND) ? "suspend" : "resume");
+              (ide_req(rq)->type == ATA_PRIV_PM_SUSPEND) ? "suspend" : "resume");
 #endif
        spin_lock_irqsave(q->queue_lock, flags);
-       if (rq->cmd_type == REQ_TYPE_ATA_PM_SUSPEND)
+       if (ide_req(rq)->type == ATA_PRIV_PM_SUSPEND)
                blk_stop_queue(q);
        else
                drive->dev_flags &= ~IDE_DFLAG_BLOCKED;
@@ -240,11 +242,13 @@ void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
 {
        struct ide_pm_state *pm = rq->special;
 
-       if (rq->cmd_type == REQ_TYPE_ATA_PM_SUSPEND &&
+       if (blk_rq_is_private(rq) &&
+           ide_req(rq)->type == ATA_PRIV_PM_SUSPEND &&
            pm->pm_step == IDE_PM_START_SUSPEND)
                /* Mark drive blocked when starting the suspend sequence. */
                drive->dev_flags |= IDE_DFLAG_BLOCKED;
-       else if (rq->cmd_type == REQ_TYPE_ATA_PM_RESUME &&
+       else if (blk_rq_is_private(rq) &&
+                ide_req(rq)->type == ATA_PRIV_PM_RESUME &&
                 pm->pm_step == IDE_PM_START_RESUME) {
                /*
                 * The first thing we do on wakeup is to wait for BSY bit to
index 330e319419e6aabfc6fe82c2750238d3fb845f0d..a74ae8df4bb834464fee6f60ea0cc8c7441fdbc0 100644 (file)
@@ -741,6 +741,14 @@ static void ide_port_tune_devices(ide_hwif_t *hwif)
        }
 }
 
+static int ide_init_rq(struct request_queue *q, struct request *rq, gfp_t gfp)
+{
+       struct ide_request *req = blk_mq_rq_to_pdu(rq);
+
+       req->sreq.sense = req->sense;
+       return 0;
+}
+
 /*
  * init request queue
  */
@@ -758,11 +766,18 @@ static int ide_init_queue(ide_drive_t *drive)
         *      limits and LBA48 we could raise it but as yet
         *      do not.
         */
-
-       q = blk_init_queue_node(do_ide_request, NULL, hwif_to_node(hwif));
+       q = blk_alloc_queue_node(GFP_KERNEL, hwif_to_node(hwif));
        if (!q)
                return 1;
 
+       q->request_fn = do_ide_request;
+       q->init_rq_fn = ide_init_rq;
+       q->cmd_size = sizeof(struct ide_request);
+       if (blk_init_allocated_queue(q) < 0) {
+               blk_cleanup_queue(q);
+               return 1;
+       }
+
        q->queuedata = drive;
        blk_queue_segment_boundary(q, 0xffff);
 
@@ -1131,10 +1146,12 @@ static void ide_port_init_devices_data(ide_hwif_t *hwif)
        ide_port_for_each_dev(i, drive, hwif) {
                u8 j = (hwif->index * MAX_DRIVES) + i;
                u16 *saved_id = drive->id;
+               struct request *saved_sense_rq = drive->sense_rq;
 
                memset(drive, 0, sizeof(*drive));
                memset(saved_id, 0, SECTOR_SIZE);
                drive->id = saved_id;
+               drive->sense_rq = saved_sense_rq;
 
                drive->media                    = ide_disk;
                drive->select                   = (i << 4) | ATA_DEVICE_OBS;
@@ -1241,6 +1258,7 @@ static void ide_port_free_devices(ide_hwif_t *hwif)
        int i;
 
        ide_port_for_each_dev(i, drive, hwif) {
+               kfree(drive->sense_rq);
                kfree(drive->id);
                kfree(drive);
        }
@@ -1248,11 +1266,10 @@ static void ide_port_free_devices(ide_hwif_t *hwif)
 
 static int ide_port_alloc_devices(ide_hwif_t *hwif, int node)
 {
+       ide_drive_t *drive;
        int i;
 
        for (i = 0; i < MAX_DRIVES; i++) {
-               ide_drive_t *drive;
-
                drive = kzalloc_node(sizeof(*drive), GFP_KERNEL, node);
                if (drive == NULL)
                        goto out_nomem;
@@ -1267,12 +1284,21 @@ static int ide_port_alloc_devices(ide_hwif_t *hwif, int node)
                 */
                drive->id = kzalloc_node(SECTOR_SIZE, GFP_KERNEL, node);
                if (drive->id == NULL)
-                       goto out_nomem;
+                       goto out_free_drive;
+
+               drive->sense_rq = kmalloc(sizeof(struct request) +
+                               sizeof(struct ide_request), GFP_KERNEL);
+               if (!drive->sense_rq)
+                       goto out_free_id;
 
                hwif->devices[i] = drive;
        }
        return 0;
 
+out_free_id:
+       kfree(drive->id);
+out_free_drive:
+       kfree(drive);
 out_nomem:
        ide_port_free_devices(hwif);
        return -ENOMEM;
index 9ecf4e35adcd3c7765a7b84b8c7869a847bdc8ce..3c1b7974d66de7657d357943646293de7c10efff 100644 (file)
@@ -282,7 +282,7 @@ static void idetape_analyze_error(ide_drive_t *drive)
 
        /* correct remaining bytes to transfer */
        if (pc->flags & PC_FLAG_DMA_ERROR)
-               rq->resid_len = tape->blk_size * get_unaligned_be32(&sense[3]);
+               scsi_req(rq)->resid_len = tape->blk_size * get_unaligned_be32(&sense[3]);
 
        /*
         * If error was the result of a zero-length read or write command,
@@ -316,7 +316,7 @@ static void idetape_analyze_error(ide_drive_t *drive)
                        pc->flags |= PC_FLAG_ABORT;
                }
                if (!(pc->flags & PC_FLAG_ABORT) &&
-                   (blk_rq_bytes(rq) - rq->resid_len))
+                   (blk_rq_bytes(rq) - scsi_req(rq)->resid_len))
                        pc->retries = IDETAPE_MAX_PC_RETRIES + 1;
        }
 }
@@ -348,7 +348,7 @@ static int ide_tape_callback(ide_drive_t *drive, int dsc)
                                        "itself - Aborting request!\n");
        } else if (pc->c[0] == READ_6 || pc->c[0] == WRITE_6) {
                unsigned int blocks =
-                       (blk_rq_bytes(rq) - rq->resid_len) / tape->blk_size;
+                       (blk_rq_bytes(rq) - scsi_req(rq)->resid_len) / tape->blk_size;
 
                tape->avg_size += blocks * tape->blk_size;
 
@@ -560,7 +560,7 @@ static void ide_tape_create_rw_cmd(idetape_tape_t *tape,
                pc->flags |= PC_FLAG_WRITING;
        }
 
-       memcpy(rq->cmd, pc->c, 12);
+       memcpy(scsi_req(rq)->cmd, pc->c, 12);
 }
 
 static ide_startstop_t idetape_do_request(ide_drive_t *drive,
@@ -570,14 +570,16 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
        idetape_tape_t *tape = drive->driver_data;
        struct ide_atapi_pc *pc = NULL;
        struct ide_cmd cmd;
+       struct scsi_request *req = scsi_req(rq);
        u8 stat;
 
        ide_debug_log(IDE_DBG_RQ, "cmd: 0x%x, sector: %llu, nr_sectors: %u",
-                     rq->cmd[0], (unsigned long long)blk_rq_pos(rq),
+                     req->cmd[0], (unsigned long long)blk_rq_pos(rq),
                      blk_rq_sectors(rq));
 
-       BUG_ON(!(rq->cmd_type == REQ_TYPE_DRV_PRIV ||
-                rq->cmd_type == REQ_TYPE_ATA_SENSE));
+       BUG_ON(!blk_rq_is_private(rq));
+       BUG_ON(ide_req(rq)->type != ATA_PRIV_MISC &&
+              ide_req(rq)->type != ATA_PRIV_SENSE);
 
        /* Retry a failed packet command */
        if (drive->failed_pc && drive->pc->c[0] == REQUEST_SENSE) {
@@ -592,7 +594,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
        stat = hwif->tp_ops->read_status(hwif);
 
        if ((drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) == 0 &&
-           (rq->cmd[13] & REQ_IDETAPE_PC2) == 0)
+           (req->cmd[13] & REQ_IDETAPE_PC2) == 0)
                drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC;
 
        if (drive->dev_flags & IDE_DFLAG_POST_RESET) {
@@ -609,7 +611,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
                } else if (time_after(jiffies, tape->dsc_timeout)) {
                        printk(KERN_ERR "ide-tape: %s: DSC timeout\n",
                                tape->name);
-                       if (rq->cmd[13] & REQ_IDETAPE_PC2) {
+                       if (req->cmd[13] & REQ_IDETAPE_PC2) {
                                idetape_media_access_finished(drive);
                                return ide_stopped;
                        } else {
@@ -626,23 +628,23 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
                tape->postponed_rq = false;
        }
 
-       if (rq->cmd[13] & REQ_IDETAPE_READ) {
+       if (req->cmd[13] & REQ_IDETAPE_READ) {
                pc = &tape->queued_pc;
                ide_tape_create_rw_cmd(tape, pc, rq, READ_6);
                goto out;
        }
-       if (rq->cmd[13] & REQ_IDETAPE_WRITE) {
+       if (req->cmd[13] & REQ_IDETAPE_WRITE) {
                pc = &tape->queued_pc;
                ide_tape_create_rw_cmd(tape, pc, rq, WRITE_6);
                goto out;
        }
-       if (rq->cmd[13] & REQ_IDETAPE_PC1) {
+       if (req->cmd[13] & REQ_IDETAPE_PC1) {
                pc = (struct ide_atapi_pc *)rq->special;
-               rq->cmd[13] &= ~(REQ_IDETAPE_PC1);
-               rq->cmd[13] |= REQ_IDETAPE_PC2;
+               req->cmd[13] &= ~(REQ_IDETAPE_PC1);
+               req->cmd[13] |= REQ_IDETAPE_PC2;
                goto out;
        }
-       if (rq->cmd[13] & REQ_IDETAPE_PC2) {
+       if (req->cmd[13] & REQ_IDETAPE_PC2) {
                idetape_media_access_finished(drive);
                return ide_stopped;
        }
@@ -852,9 +854,10 @@ static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int size)
        BUG_ON(cmd != REQ_IDETAPE_READ && cmd != REQ_IDETAPE_WRITE);
        BUG_ON(size < 0 || size % tape->blk_size);
 
-       rq = blk_get_request(drive->queue, READ, __GFP_RECLAIM);
-       rq->cmd_type = REQ_TYPE_DRV_PRIV;
-       rq->cmd[13] = cmd;
+       rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, __GFP_RECLAIM);
+       scsi_req_init(rq);
+       ide_req(rq)->type = ATA_PRIV_MISC;
+       scsi_req(rq)->cmd[13] = cmd;
        rq->rq_disk = tape->disk;
        rq->__sector = tape->first_frame;
 
@@ -868,7 +871,7 @@ static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int size)
        blk_execute_rq(drive->queue, tape->disk, rq, 0);
 
        /* calculate the number of transferred bytes and update buffer state */
-       size -= rq->resid_len;
+       size -= scsi_req(rq)->resid_len;
        tape->cur = tape->buf;
        if (cmd == REQ_IDETAPE_READ)
                tape->valid = size;
index a716693417a308c49186bcfb4e692aa86ef1d99d..247b9faccce171d607b275e4849dc28d9c8d1f23 100644 (file)
@@ -428,10 +428,12 @@ int ide_raw_taskfile(ide_drive_t *drive, struct ide_cmd *cmd, u8 *buf,
 {
        struct request *rq;
        int error;
-       int rw = !(cmd->tf_flags & IDE_TFLAG_WRITE) ? READ : WRITE;
 
-       rq = blk_get_request(drive->queue, rw, __GFP_RECLAIM);
-       rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
+       rq = blk_get_request(drive->queue,
+               (cmd->tf_flags & IDE_TFLAG_WRITE) ?
+                       REQ_OP_DRV_OUT : REQ_OP_DRV_IN, __GFP_RECLAIM);
+       scsi_req_init(rq);
+       ide_req(rq)->type = ATA_PRIV_TASKFILE;
 
        /*
         * (ks) We transfer currently only whole sectors.
index 247853ea1368b7c0a83db3e9f1094616ac7f8b5e..c3062b53056f2b70e63230e53a4c6465e8349af2 100644 (file)
@@ -54,7 +54,7 @@
 #define DRV_NAME "sis5513"
 
 /* registers layout and init values are chipset family dependent */
-
+#undef ATA_16
 #define ATA_16         0x01
 #define ATA_33         0x02
 #define ATA_66         0x03
index e71af717e71b0f5e6d82eb36b65d887c6005dc09..30a6985909e0d95c446eb51abe17cf570dd18f73 100644 (file)
@@ -994,6 +994,7 @@ static struct scsi_host_template iscsi_iser_sht = {
        .change_queue_depth     = scsi_change_queue_depth,
        .sg_tablesize           = ISCSI_ISER_DEF_SG_TABLESIZE,
        .cmd_per_lun            = ISER_DEF_CMD_PER_LUN,
+       .eh_timed_out           = iscsi_eh_cmd_timed_out,
        .eh_abort_handler       = iscsi_eh_abort,
        .eh_device_reset_handler= iscsi_eh_device_reset,
        .eh_target_reset_handler = iscsi_eh_recover_target,
index 79bf48477ddb104097471a7a6040bcef2dfa0533..36529e390e48adce23c26c00984bd540876e620a 100644 (file)
@@ -2869,6 +2869,7 @@ static struct scsi_host_template srp_template = {
        .info                           = srp_target_info,
        .queuecommand                   = srp_queuecommand,
        .change_queue_depth             = srp_change_queue_depth,
+       .eh_timed_out                   = srp_timed_out,
        .eh_abort_handler               = srp_abort,
        .eh_device_reset_handler        = srp_reset_device,
        .eh_host_reset_handler          = srp_reset_host,
index c621cbbb5768a79e95869344fab58461d15f3e4e..275f467956eedf5469661be675fad42a95d16b0d 100644 (file)
@@ -29,6 +29,15 @@ config LEDS_CLASS_FLASH
          for the flash related features of a LED device. It can be built
          as a module.
 
+config LEDS_BRIGHTNESS_HW_CHANGED
+       bool "LED Class brightness_hw_changed attribute support"
+       depends on LEDS_CLASS
+       help
+         This option enables support for the brightness_hw_changed attribute
+         for led sysfs class devices under /sys/class/leds.
+
+         See Documentation/ABI/testing/sysfs-class-led for details.
+
 comment "LED drivers"
 
 config LEDS_88PM860X
index 326ee6e925a205531f97f0815451e4af87505ceb..f2b0a80a62b46712a17e642efebd148ea2c99537 100644 (file)
@@ -103,6 +103,68 @@ static const struct attribute_group *led_groups[] = {
        NULL,
 };
 
+#ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED
+static ssize_t brightness_hw_changed_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+
+       if (led_cdev->brightness_hw_changed == -1)
+               return -ENODATA;
+
+       return sprintf(buf, "%u\n", led_cdev->brightness_hw_changed);
+}
+
+static DEVICE_ATTR_RO(brightness_hw_changed);
+
+static int led_add_brightness_hw_changed(struct led_classdev *led_cdev)
+{
+       struct device *dev = led_cdev->dev;
+       int ret;
+
+       ret = device_create_file(dev, &dev_attr_brightness_hw_changed);
+       if (ret) {
+               dev_err(dev, "Error creating brightness_hw_changed\n");
+               return ret;
+       }
+
+       led_cdev->brightness_hw_changed_kn =
+               sysfs_get_dirent(dev->kobj.sd, "brightness_hw_changed");
+       if (!led_cdev->brightness_hw_changed_kn) {
+               dev_err(dev, "Error getting brightness_hw_changed kn\n");
+               device_remove_file(dev, &dev_attr_brightness_hw_changed);
+               return -ENXIO;
+       }
+
+       return 0;
+}
+
+static void led_remove_brightness_hw_changed(struct led_classdev *led_cdev)
+{
+       sysfs_put(led_cdev->brightness_hw_changed_kn);
+       device_remove_file(led_cdev->dev, &dev_attr_brightness_hw_changed);
+}
+
+void led_classdev_notify_brightness_hw_changed(struct led_classdev *led_cdev,
+                                              enum led_brightness brightness)
+{
+       if (WARN_ON(!led_cdev->brightness_hw_changed_kn))
+               return;
+
+       led_cdev->brightness_hw_changed = brightness;
+       sysfs_notify_dirent(led_cdev->brightness_hw_changed_kn);
+}
+EXPORT_SYMBOL_GPL(led_classdev_notify_brightness_hw_changed);
+#else
+static int led_add_brightness_hw_changed(struct led_classdev *led_cdev)
+{
+       return 0;
+}
+static void led_remove_brightness_hw_changed(struct led_classdev *led_cdev)
+{
+}
+#endif
+
 /**
  * led_classdev_suspend - suspend an led_classdev.
  * @led_cdev: the led_classdev to suspend.
@@ -204,9 +266,20 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
                dev_warn(parent, "Led %s renamed to %s due to name collision",
                                led_cdev->name, dev_name(led_cdev->dev));
 
+       if (led_cdev->flags & LED_BRIGHT_HW_CHANGED) {
+               ret = led_add_brightness_hw_changed(led_cdev);
+               if (ret) {
+                       device_unregister(led_cdev->dev);
+                       return ret;
+               }
+       }
+
        led_cdev->work_flags = 0;
 #ifdef CONFIG_LEDS_TRIGGERS
        init_rwsem(&led_cdev->trigger_lock);
+#endif
+#ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED
+       led_cdev->brightness_hw_changed = -1;
 #endif
        mutex_init(&led_cdev->led_access);
        /* add to the list of leds */
@@ -256,6 +329,9 @@ void led_classdev_unregister(struct led_classdev *led_cdev)
 
        flush_work(&led_cdev->set_brightness_work);
 
+       if (led_cdev->flags & LED_BRIGHT_HW_CHANGED)
+               led_remove_brightness_hw_changed(led_cdev);
+
        device_unregister(led_cdev->dev);
 
        down_write(&leds_list_lock);
index bf23ba191ad06857a3a3e1a7ab8e2725d910262f..45296aaca9daafb74d7d161285c9b124efe0a2f2 100644 (file)
@@ -270,15 +270,15 @@ static int ktd2692_parse_dt(struct ktd2692_context *led, struct device *dev,
                return -ENXIO;
 
        led->ctrl_gpio = devm_gpiod_get(dev, "ctrl", GPIOD_ASIS);
-       if (IS_ERR(led->ctrl_gpio)) {
-               ret = PTR_ERR(led->ctrl_gpio);
+       ret = PTR_ERR_OR_ZERO(led->ctrl_gpio);
+       if (ret) {
                dev_err(dev, "cannot get ctrl-gpios %d\n", ret);
                return ret;
        }
 
        led->aux_gpio = devm_gpiod_get(dev, "aux", GPIOD_ASIS);
-       if (IS_ERR(led->aux_gpio)) {
-               ret = PTR_ERR(led->aux_gpio);
+       ret = PTR_ERR_OR_ZERO(led->aux_gpio);
+       if (ret) {
                dev_err(dev, "cannot get aux-gpios %d\n", ret);
                return ret;
        }
index c9f386213e9ef16ae006e2270e2615e4bb60253e..e6f2f8b9f09ad427b83f460cf360fff3907aaa64 100644 (file)
@@ -43,6 +43,9 @@ static void led_heartbeat_function(unsigned long data)
                return;
        }
 
+       if (test_and_clear_bit(LED_BLINK_BRIGHTNESS_CHANGE, &led_cdev->work_flags))
+               led_cdev->blink_brightness = led_cdev->new_blink_brightness;
+
        /* acts like an actual heart beat -- ie thump-thump-pause... */
        switch (heartbeat_data->phase) {
        case 0:
@@ -59,26 +62,26 @@ static void led_heartbeat_function(unsigned long data)
                delay = msecs_to_jiffies(70);
                heartbeat_data->phase++;
                if (!heartbeat_data->invert)
-                       brightness = led_cdev->max_brightness;
+                       brightness = led_cdev->blink_brightness;
                break;
        case 1:
                delay = heartbeat_data->period / 4 - msecs_to_jiffies(70);
                heartbeat_data->phase++;
                if (heartbeat_data->invert)
-                       brightness = led_cdev->max_brightness;
+                       brightness = led_cdev->blink_brightness;
                break;
        case 2:
                delay = msecs_to_jiffies(70);
                heartbeat_data->phase++;
                if (!heartbeat_data->invert)
-                       brightness = led_cdev->max_brightness;
+                       brightness = led_cdev->blink_brightness;
                break;
        default:
                delay = heartbeat_data->period - heartbeat_data->period / 4 -
                        msecs_to_jiffies(70);
                heartbeat_data->phase = 0;
                if (heartbeat_data->invert)
-                       brightness = led_cdev->max_brightness;
+                       brightness = led_cdev->blink_brightness;
                break;
        }
 
@@ -133,7 +136,10 @@ static void heartbeat_trig_activate(struct led_classdev *led_cdev)
        setup_timer(&heartbeat_data->timer,
                    led_heartbeat_function, (unsigned long) led_cdev);
        heartbeat_data->phase = 0;
+       if (!led_cdev->blink_brightness)
+               led_cdev->blink_brightness = led_cdev->max_brightness;
        led_heartbeat_function(heartbeat_data->timer.data);
+       set_bit(LED_BLINK_SW, &led_cdev->work_flags);
        led_cdev->activated = true;
 }
 
@@ -145,6 +151,7 @@ static void heartbeat_trig_deactivate(struct led_classdev *led_cdev)
                del_timer_sync(&heartbeat_data->timer);
                device_remove_file(led_cdev->dev, &dev_attr_invert);
                kfree(heartbeat_data);
+               clear_bit(LED_BLINK_SW, &led_cdev->work_flags);
                led_cdev->activated = false;
        }
 }
index 2f5d5f4a4c75b37d7e848a9e97f63c88ee40de84..052714106b7b8b8d5125e5199d1333d0e3cadc8d 100644 (file)
@@ -26,15 +26,6 @@ config NVM_DEBUG
 
        It is required to create/remove targets without IOCTLs.
 
-config NVM_GENNVM
-       tristate "General Non-Volatile Memory Manager for Open-Channel SSDs"
-       ---help---
-       Non-volatile memory media manager for Open-Channel SSDs that implements
-       physical media metadata management and block provisioning API.
-
-       This is the standard media manager for using Open-Channel SSDs, and
-       required for targets to be instantiated.
-
 config NVM_RRPC
        tristate "Round-robin Hybrid Open-Channel SSD target"
        ---help---
index a7a0a22cf1a59661b22f9997589eab9e73a13ec7..b2a39e2d28952659932f44ef2f079b75ab0f01ff 100644 (file)
@@ -2,6 +2,5 @@
 # Makefile for Open-Channel SSDs.
 #
 
-obj-$(CONFIG_NVM)              := core.o sysblk.o
-obj-$(CONFIG_NVM_GENNVM)       += gennvm.o
+obj-$(CONFIG_NVM)              := core.o
 obj-$(CONFIG_NVM_RRPC)         += rrpc.o
index 02240a0b39c9d96e203b04a8e0cee96f31bed4d5..5262ba66a7a74c94d91d2c5815eb5bf19f2c62a2 100644 (file)
 
 static LIST_HEAD(nvm_tgt_types);
 static DECLARE_RWSEM(nvm_tgtt_lock);
-static LIST_HEAD(nvm_mgrs);
 static LIST_HEAD(nvm_devices);
 static DECLARE_RWSEM(nvm_lock);
 
+/* Map between virtual and physical channel and lun */
+struct nvm_ch_map {
+       int ch_off;
+       int nr_luns;
+       int *lun_offs;
+};
+
+struct nvm_dev_map {
+       struct nvm_ch_map *chnls;
+       int nr_chnls;
+};
+
+struct nvm_area {
+       struct list_head list;
+       sector_t begin;
+       sector_t end;   /* end is excluded */
+};
+
+static struct nvm_target *nvm_find_target(struct nvm_dev *dev, const char *name)
+{
+       struct nvm_target *tgt;
+
+       list_for_each_entry(tgt, &dev->targets, list)
+               if (!strcmp(name, tgt->disk->disk_name))
+                       return tgt;
+
+       return NULL;
+}
+
+static int nvm_reserve_luns(struct nvm_dev *dev, int lun_begin, int lun_end)
+{
+       int i;
+
+       for (i = lun_begin; i <= lun_end; i++) {
+               if (test_and_set_bit(i, dev->lun_map)) {
+                       pr_err("nvm: lun %d already allocated\n", i);
+                       goto err;
+               }
+       }
+
+       return 0;
+err:
+       while (--i > lun_begin)
+               clear_bit(i, dev->lun_map);
+
+       return -EBUSY;
+}
+
+static void nvm_release_luns_err(struct nvm_dev *dev, int lun_begin,
+                                int lun_end)
+{
+       int i;
+
+       for (i = lun_begin; i <= lun_end; i++)
+               WARN_ON(!test_and_clear_bit(i, dev->lun_map));
+}
+
+static void nvm_remove_tgt_dev(struct nvm_tgt_dev *tgt_dev)
+{
+       struct nvm_dev *dev = tgt_dev->parent;
+       struct nvm_dev_map *dev_map = tgt_dev->map;
+       int i, j;
+
+       for (i = 0; i < dev_map->nr_chnls; i++) {
+               struct nvm_ch_map *ch_map = &dev_map->chnls[i];
+               int *lun_offs = ch_map->lun_offs;
+               int ch = i + ch_map->ch_off;
+
+               for (j = 0; j < ch_map->nr_luns; j++) {
+                       int lun = j + lun_offs[j];
+                       int lunid = (ch * dev->geo.luns_per_chnl) + lun;
+
+                       WARN_ON(!test_and_clear_bit(lunid, dev->lun_map));
+               }
+
+               kfree(ch_map->lun_offs);
+       }
+
+       kfree(dev_map->chnls);
+       kfree(dev_map);
+
+       kfree(tgt_dev->luns);
+       kfree(tgt_dev);
+}
+
+static struct nvm_tgt_dev *nvm_create_tgt_dev(struct nvm_dev *dev,
+                                             int lun_begin, int lun_end)
+{
+       struct nvm_tgt_dev *tgt_dev = NULL;
+       struct nvm_dev_map *dev_rmap = dev->rmap;
+       struct nvm_dev_map *dev_map;
+       struct ppa_addr *luns;
+       int nr_luns = lun_end - lun_begin + 1;
+       int luns_left = nr_luns;
+       int nr_chnls = nr_luns / dev->geo.luns_per_chnl;
+       int nr_chnls_mod = nr_luns % dev->geo.luns_per_chnl;
+       int bch = lun_begin / dev->geo.luns_per_chnl;
+       int blun = lun_begin % dev->geo.luns_per_chnl;
+       int lunid = 0;
+       int lun_balanced = 1;
+       int prev_nr_luns;
+       int i, j;
+
+       nr_chnls = nr_luns / dev->geo.luns_per_chnl;
+       nr_chnls = (nr_chnls_mod == 0) ? nr_chnls : nr_chnls + 1;
+
+       dev_map = kmalloc(sizeof(struct nvm_dev_map), GFP_KERNEL);
+       if (!dev_map)
+               goto err_dev;
+
+       dev_map->chnls = kcalloc(nr_chnls, sizeof(struct nvm_ch_map),
+                                                               GFP_KERNEL);
+       if (!dev_map->chnls)
+               goto err_chnls;
+
+       luns = kcalloc(nr_luns, sizeof(struct ppa_addr), GFP_KERNEL);
+       if (!luns)
+               goto err_luns;
+
+       prev_nr_luns = (luns_left > dev->geo.luns_per_chnl) ?
+                                       dev->geo.luns_per_chnl : luns_left;
+       for (i = 0; i < nr_chnls; i++) {
+               struct nvm_ch_map *ch_rmap = &dev_rmap->chnls[i + bch];
+               int *lun_roffs = ch_rmap->lun_offs;
+               struct nvm_ch_map *ch_map = &dev_map->chnls[i];
+               int *lun_offs;
+               int luns_in_chnl = (luns_left > dev->geo.luns_per_chnl) ?
+                                       dev->geo.luns_per_chnl : luns_left;
+
+               if (lun_balanced && prev_nr_luns != luns_in_chnl)
+                       lun_balanced = 0;
+
+               ch_map->ch_off = ch_rmap->ch_off = bch;
+               ch_map->nr_luns = luns_in_chnl;
+
+               lun_offs = kcalloc(luns_in_chnl, sizeof(int), GFP_KERNEL);
+               if (!lun_offs)
+                       goto err_ch;
+
+               for (j = 0; j < luns_in_chnl; j++) {
+                       luns[lunid].ppa = 0;
+                       luns[lunid].g.ch = i;
+                       luns[lunid++].g.lun = j;
+
+                       lun_offs[j] = blun;
+                       lun_roffs[j + blun] = blun;
+               }
+
+               ch_map->lun_offs = lun_offs;
+
+               /* when starting a new channel, lun offset is reset */
+               blun = 0;
+               luns_left -= luns_in_chnl;
+       }
+
+       dev_map->nr_chnls = nr_chnls;
+
+       tgt_dev = kmalloc(sizeof(struct nvm_tgt_dev), GFP_KERNEL);
+       if (!tgt_dev)
+               goto err_ch;
+
+       memcpy(&tgt_dev->geo, &dev->geo, sizeof(struct nvm_geo));
+       /* Target device only owns a portion of the physical device */
+       tgt_dev->geo.nr_chnls = nr_chnls;
+       tgt_dev->geo.nr_luns = nr_luns;
+       tgt_dev->geo.luns_per_chnl = (lun_balanced) ? prev_nr_luns : -1;
+       tgt_dev->total_secs = nr_luns * tgt_dev->geo.sec_per_lun;
+       tgt_dev->q = dev->q;
+       tgt_dev->map = dev_map;
+       tgt_dev->luns = luns;
+       memcpy(&tgt_dev->identity, &dev->identity, sizeof(struct nvm_id));
+
+       tgt_dev->parent = dev;
+
+       return tgt_dev;
+err_ch:
+       while (--i > 0)
+               kfree(dev_map->chnls[i].lun_offs);
+       kfree(luns);
+err_luns:
+       kfree(dev_map->chnls);
+err_chnls:
+       kfree(dev_map);
+err_dev:
+       return tgt_dev;
+}
+
+static const struct block_device_operations nvm_fops = {
+       .owner          = THIS_MODULE,
+};
+
+static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
+{
+       struct nvm_ioctl_create_simple *s = &create->conf.s;
+       struct request_queue *tqueue;
+       struct gendisk *tdisk;
+       struct nvm_tgt_type *tt;
+       struct nvm_target *t;
+       struct nvm_tgt_dev *tgt_dev;
+       void *targetdata;
+
+       tt = nvm_find_target_type(create->tgttype, 1);
+       if (!tt) {
+               pr_err("nvm: target type %s not found\n", create->tgttype);
+               return -EINVAL;
+       }
+
+       mutex_lock(&dev->mlock);
+       t = nvm_find_target(dev, create->tgtname);
+       if (t) {
+               pr_err("nvm: target name already exists.\n");
+               mutex_unlock(&dev->mlock);
+               return -EINVAL;
+       }
+       mutex_unlock(&dev->mlock);
+
+       if (nvm_reserve_luns(dev, s->lun_begin, s->lun_end))
+               return -ENOMEM;
+
+       t = kmalloc(sizeof(struct nvm_target), GFP_KERNEL);
+       if (!t)
+               goto err_reserve;
+
+       tgt_dev = nvm_create_tgt_dev(dev, s->lun_begin, s->lun_end);
+       if (!tgt_dev) {
+               pr_err("nvm: could not create target device\n");
+               goto err_t;
+       }
+
+       tqueue = blk_alloc_queue_node(GFP_KERNEL, dev->q->node);
+       if (!tqueue)
+               goto err_dev;
+       blk_queue_make_request(tqueue, tt->make_rq);
+
+       tdisk = alloc_disk(0);
+       if (!tdisk)
+               goto err_queue;
+
+       sprintf(tdisk->disk_name, "%s", create->tgtname);
+       tdisk->flags = GENHD_FL_EXT_DEVT;
+       tdisk->major = 0;
+       tdisk->first_minor = 0;
+       tdisk->fops = &nvm_fops;
+       tdisk->queue = tqueue;
+
+       targetdata = tt->init(tgt_dev, tdisk);
+       if (IS_ERR(targetdata))
+               goto err_init;
+
+       tdisk->private_data = targetdata;
+       tqueue->queuedata = targetdata;
+
+       blk_queue_max_hw_sectors(tqueue, 8 * dev->ops->max_phys_sect);
+
+       set_capacity(tdisk, tt->capacity(targetdata));
+       add_disk(tdisk);
+
+       if (tt->sysfs_init && tt->sysfs_init(tdisk))
+               goto err_sysfs;
+
+       t->type = tt;
+       t->disk = tdisk;
+       t->dev = tgt_dev;
+
+       mutex_lock(&dev->mlock);
+       list_add_tail(&t->list, &dev->targets);
+       mutex_unlock(&dev->mlock);
+
+       return 0;
+err_sysfs:
+       if (tt->exit)
+               tt->exit(targetdata);
+err_init:
+       put_disk(tdisk);
+err_queue:
+       blk_cleanup_queue(tqueue);
+err_dev:
+       nvm_remove_tgt_dev(tgt_dev);
+err_t:
+       kfree(t);
+err_reserve:
+       nvm_release_luns_err(dev, s->lun_begin, s->lun_end);
+       return -ENOMEM;
+}
+
+static void __nvm_remove_target(struct nvm_target *t)
+{
+       struct nvm_tgt_type *tt = t->type;
+       struct gendisk *tdisk = t->disk;
+       struct request_queue *q = tdisk->queue;
+
+       del_gendisk(tdisk);
+       blk_cleanup_queue(q);
+
+       if (tt->sysfs_exit)
+               tt->sysfs_exit(tdisk);
+
+       if (tt->exit)
+               tt->exit(tdisk->private_data);
+
+       nvm_remove_tgt_dev(t->dev);
+       put_disk(tdisk);
+
+       list_del(&t->list);
+       kfree(t);
+}
+
+/**
+ * nvm_remove_tgt - Removes a target from the media manager
+ * @dev:       device
+ * @remove:    ioctl structure with target name to remove.
+ *
+ * Returns:
+ * 0: on success
+ * 1: on not found
+ * <0: on error
+ */
+static int nvm_remove_tgt(struct nvm_dev *dev, struct nvm_ioctl_remove *remove)
+{
+       struct nvm_target *t;
+
+       mutex_lock(&dev->mlock);
+       t = nvm_find_target(dev, remove->tgtname);
+       if (!t) {
+               mutex_unlock(&dev->mlock);
+               return 1;
+       }
+       __nvm_remove_target(t);
+       mutex_unlock(&dev->mlock);
+
+       return 0;
+}
+
+static int nvm_register_map(struct nvm_dev *dev)
+{
+       struct nvm_dev_map *rmap;
+       int i, j;
+
+       rmap = kmalloc(sizeof(struct nvm_dev_map), GFP_KERNEL);
+       if (!rmap)
+               goto err_rmap;
+
+       rmap->chnls = kcalloc(dev->geo.nr_chnls, sizeof(struct nvm_ch_map),
+                                                               GFP_KERNEL);
+       if (!rmap->chnls)
+               goto err_chnls;
+
+       for (i = 0; i < dev->geo.nr_chnls; i++) {
+               struct nvm_ch_map *ch_rmap;
+               int *lun_roffs;
+               int luns_in_chnl = dev->geo.luns_per_chnl;
+
+               ch_rmap = &rmap->chnls[i];
+
+               ch_rmap->ch_off = -1;
+               ch_rmap->nr_luns = luns_in_chnl;
+
+               lun_roffs = kcalloc(luns_in_chnl, sizeof(int), GFP_KERNEL);
+               if (!lun_roffs)
+                       goto err_ch;
+
+               for (j = 0; j < luns_in_chnl; j++)
+                       lun_roffs[j] = -1;
+
+               ch_rmap->lun_offs = lun_roffs;
+       }
+
+       dev->rmap = rmap;
+
+       return 0;
+err_ch:
+       while (--i >= 0)
+               kfree(rmap->chnls[i].lun_offs);
+err_chnls:
+       kfree(rmap);
+err_rmap:
+       return -ENOMEM;
+}
+
+static void nvm_map_to_dev(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *p)
+{
+       struct nvm_dev_map *dev_map = tgt_dev->map;
+       struct nvm_ch_map *ch_map = &dev_map->chnls[p->g.ch];
+       int lun_off = ch_map->lun_offs[p->g.lun];
+
+       p->g.ch += ch_map->ch_off;
+       p->g.lun += lun_off;
+}
+
+static void nvm_map_to_tgt(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *p)
+{
+       struct nvm_dev *dev = tgt_dev->parent;
+       struct nvm_dev_map *dev_rmap = dev->rmap;
+       struct nvm_ch_map *ch_rmap = &dev_rmap->chnls[p->g.ch];
+       int lun_roff = ch_rmap->lun_offs[p->g.lun];
+
+       p->g.ch -= ch_rmap->ch_off;
+       p->g.lun -= lun_roff;
+}
+
+static void nvm_ppa_tgt_to_dev(struct nvm_tgt_dev *tgt_dev,
+                               struct ppa_addr *ppa_list, int nr_ppas)
+{
+       int i;
+
+       for (i = 0; i < nr_ppas; i++) {
+               nvm_map_to_dev(tgt_dev, &ppa_list[i]);
+               ppa_list[i] = generic_to_dev_addr(tgt_dev, ppa_list[i]);
+       }
+}
+
+static void nvm_ppa_dev_to_tgt(struct nvm_tgt_dev *tgt_dev,
+                               struct ppa_addr *ppa_list, int nr_ppas)
+{
+       int i;
+
+       for (i = 0; i < nr_ppas; i++) {
+               ppa_list[i] = dev_to_generic_addr(tgt_dev, ppa_list[i]);
+               nvm_map_to_tgt(tgt_dev, &ppa_list[i]);
+       }
+}
+
+static void nvm_rq_tgt_to_dev(struct nvm_tgt_dev *tgt_dev, struct nvm_rq *rqd)
+{
+       if (rqd->nr_ppas == 1) {
+               nvm_ppa_tgt_to_dev(tgt_dev, &rqd->ppa_addr, 1);
+               return;
+       }
+
+       nvm_ppa_tgt_to_dev(tgt_dev, rqd->ppa_list, rqd->nr_ppas);
+}
+
+static void nvm_rq_dev_to_tgt(struct nvm_tgt_dev *tgt_dev, struct nvm_rq *rqd)
+{
+       if (rqd->nr_ppas == 1) {
+               nvm_ppa_dev_to_tgt(tgt_dev, &rqd->ppa_addr, 1);
+               return;
+       }
+
+       nvm_ppa_dev_to_tgt(tgt_dev, rqd->ppa_list, rqd->nr_ppas);
+}
+
+void nvm_part_to_tgt(struct nvm_dev *dev, sector_t *entries,
+                    int len)
+{
+       struct nvm_geo *geo = &dev->geo;
+       struct nvm_dev_map *dev_rmap = dev->rmap;
+       u64 i;
+
+       for (i = 0; i < len; i++) {
+               struct nvm_ch_map *ch_rmap;
+               int *lun_roffs;
+               struct ppa_addr gaddr;
+               u64 pba = le64_to_cpu(entries[i]);
+               int off;
+               u64 diff;
+
+               if (!pba)
+                       continue;
+
+               gaddr = linear_to_generic_addr(geo, pba);
+               ch_rmap = &dev_rmap->chnls[gaddr.g.ch];
+               lun_roffs = ch_rmap->lun_offs;
+
+               off = gaddr.g.ch * geo->luns_per_chnl + gaddr.g.lun;
+
+               diff = ((ch_rmap->ch_off * geo->luns_per_chnl) +
+                               (lun_roffs[gaddr.g.lun])) * geo->sec_per_lun;
+
+               entries[i] -= cpu_to_le64(diff);
+       }
+}
+EXPORT_SYMBOL(nvm_part_to_tgt);
+
 struct nvm_tgt_type *nvm_find_target_type(const char *name, int lock)
 {
        struct nvm_tgt_type *tmp, *tt = NULL;
@@ -92,78 +565,6 @@ void nvm_dev_dma_free(struct nvm_dev *dev, void *addr, dma_addr_t dma_handler)
 }
 EXPORT_SYMBOL(nvm_dev_dma_free);
 
-static struct nvmm_type *nvm_find_mgr_type(const char *name)
-{
-       struct nvmm_type *mt;
-
-       list_for_each_entry(mt, &nvm_mgrs, list)
-               if (!strcmp(name, mt->name))
-                       return mt;
-
-       return NULL;
-}
-
-static struct nvmm_type *nvm_init_mgr(struct nvm_dev *dev)
-{
-       struct nvmm_type *mt;
-       int ret;
-
-       lockdep_assert_held(&nvm_lock);
-
-       list_for_each_entry(mt, &nvm_mgrs, list) {
-               if (strncmp(dev->sb.mmtype, mt->name, NVM_MMTYPE_LEN))
-                       continue;
-
-               ret = mt->register_mgr(dev);
-               if (ret < 0) {
-                       pr_err("nvm: media mgr failed to init (%d) on dev %s\n",
-                                                               ret, dev->name);
-                       return NULL; /* initialization failed */
-               } else if (ret > 0)
-                       return mt;
-       }
-
-       return NULL;
-}
-
-int nvm_register_mgr(struct nvmm_type *mt)
-{
-       struct nvm_dev *dev;
-       int ret = 0;
-
-       down_write(&nvm_lock);
-       if (nvm_find_mgr_type(mt->name)) {
-               ret = -EEXIST;
-               goto finish;
-       } else {
-               list_add(&mt->list, &nvm_mgrs);
-       }
-
-       /* try to register media mgr if any device have none configured */
-       list_for_each_entry(dev, &nvm_devices, devices) {
-               if (dev->mt)
-                       continue;
-
-               dev->mt = nvm_init_mgr(dev);
-       }
-finish:
-       up_write(&nvm_lock);
-
-       return ret;
-}
-EXPORT_SYMBOL(nvm_register_mgr);
-
-void nvm_unregister_mgr(struct nvmm_type *mt)
-{
-       if (!mt)
-               return;
-
-       down_write(&nvm_lock);
-       list_del(&mt->list);
-       up_write(&nvm_lock);
-}
-EXPORT_SYMBOL(nvm_unregister_mgr);
-
 static struct nvm_dev *nvm_find_nvm_dev(const char *name)
 {
        struct nvm_dev *dev;
@@ -175,53 +576,6 @@ static struct nvm_dev *nvm_find_nvm_dev(const char *name)
        return NULL;
 }
 
-static void nvm_tgt_generic_to_addr_mode(struct nvm_tgt_dev *tgt_dev,
-                                        struct nvm_rq *rqd)
-{
-       struct nvm_dev *dev = tgt_dev->parent;
-       int i;
-
-       if (rqd->nr_ppas > 1) {
-               for (i = 0; i < rqd->nr_ppas; i++) {
-                       rqd->ppa_list[i] = dev->mt->trans_ppa(tgt_dev,
-                                       rqd->ppa_list[i], TRANS_TGT_TO_DEV);
-                       rqd->ppa_list[i] = generic_to_dev_addr(dev,
-                                                       rqd->ppa_list[i]);
-               }
-       } else {
-               rqd->ppa_addr = dev->mt->trans_ppa(tgt_dev, rqd->ppa_addr,
-                                               TRANS_TGT_TO_DEV);
-               rqd->ppa_addr = generic_to_dev_addr(dev, rqd->ppa_addr);
-       }
-}
-
-int nvm_set_bb_tbl(struct nvm_dev *dev, struct ppa_addr *ppas, int nr_ppas,
-                                                               int type)
-{
-       struct nvm_rq rqd;
-       int ret;
-
-       if (nr_ppas > dev->ops->max_phys_sect) {
-               pr_err("nvm: unable to update all sysblocks atomically\n");
-               return -EINVAL;
-       }
-
-       memset(&rqd, 0, sizeof(struct nvm_rq));
-
-       nvm_set_rqd_ppalist(dev, &rqd, ppas, nr_ppas, 1);
-       nvm_generic_to_addr_mode(dev, &rqd);
-
-       ret = dev->ops->set_bb_tbl(dev, &rqd.ppa_addr, rqd.nr_ppas, type);
-       nvm_free_rqd_ppalist(dev, &rqd);
-       if (ret) {
-               pr_err("nvm: sysblk failed bb mark\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL(nvm_set_bb_tbl);
-
 int nvm_set_tgt_bb_tbl(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *ppas,
                       int nr_ppas, int type)
 {
@@ -237,12 +591,12 @@ int nvm_set_tgt_bb_tbl(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *ppas,
        memset(&rqd, 0, sizeof(struct nvm_rq));
 
        nvm_set_rqd_ppalist(dev, &rqd, ppas, nr_ppas, 1);
-       nvm_tgt_generic_to_addr_mode(tgt_dev, &rqd);
+       nvm_rq_tgt_to_dev(tgt_dev, &rqd);
 
        ret = dev->ops->set_bb_tbl(dev, &rqd.ppa_addr, rqd.nr_ppas, type);
        nvm_free_rqd_ppalist(dev, &rqd);
        if (ret) {
-               pr_err("nvm: sysblk failed bb mark\n");
+               pr_err("nvm: failed bb mark\n");
                return -EINVAL;
        }
 
@@ -262,15 +616,42 @@ int nvm_submit_io(struct nvm_tgt_dev *tgt_dev, struct nvm_rq *rqd)
 {
        struct nvm_dev *dev = tgt_dev->parent;
 
-       return dev->mt->submit_io(tgt_dev, rqd);
+       if (!dev->ops->submit_io)
+               return -ENODEV;
+
+       nvm_rq_tgt_to_dev(tgt_dev, rqd);
+
+       rqd->dev = tgt_dev;
+       return dev->ops->submit_io(dev, rqd);
 }
 EXPORT_SYMBOL(nvm_submit_io);
 
-int nvm_erase_blk(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *p, int flags)
+int nvm_erase_blk(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *ppas, int flags)
 {
        struct nvm_dev *dev = tgt_dev->parent;
+       struct nvm_rq rqd;
+       int ret;
+
+       if (!dev->ops->erase_block)
+               return 0;
+
+       nvm_map_to_dev(tgt_dev, ppas);
+
+       memset(&rqd, 0, sizeof(struct nvm_rq));
+
+       ret = nvm_set_rqd_ppalist(dev, &rqd, ppas, 1, 1);
+       if (ret)
+               return ret;
+
+       nvm_rq_tgt_to_dev(tgt_dev, &rqd);
+
+       rqd.flags = flags;
+
+       ret = dev->ops->erase_block(dev, &rqd);
 
-       return dev->mt->erase_blk(tgt_dev, p, flags);
+       nvm_free_rqd_ppalist(dev, &rqd);
+
+       return ret;
 }
 EXPORT_SYMBOL(nvm_erase_blk);
 
@@ -289,46 +670,67 @@ EXPORT_SYMBOL(nvm_get_l2p_tbl);
 int nvm_get_area(struct nvm_tgt_dev *tgt_dev, sector_t *lba, sector_t len)
 {
        struct nvm_dev *dev = tgt_dev->parent;
+       struct nvm_geo *geo = &dev->geo;
+       struct nvm_area *area, *prev, *next;
+       sector_t begin = 0;
+       sector_t max_sectors = (geo->sec_size * dev->total_secs) >> 9;
 
-       return dev->mt->get_area(dev, lba, len);
-}
-EXPORT_SYMBOL(nvm_get_area);
+       if (len > max_sectors)
+               return -EINVAL;
 
-void nvm_put_area(struct nvm_tgt_dev *tgt_dev, sector_t lba)
-{
-       struct nvm_dev *dev = tgt_dev->parent;
+       area = kmalloc(sizeof(struct nvm_area), GFP_KERNEL);
+       if (!area)
+               return -ENOMEM;
 
-       dev->mt->put_area(dev, lba);
-}
-EXPORT_SYMBOL(nvm_put_area);
+       prev = NULL;
 
-void nvm_addr_to_generic_mode(struct nvm_dev *dev, struct nvm_rq *rqd)
-{
-       int i;
+       spin_lock(&dev->lock);
+       list_for_each_entry(next, &dev->area_list, list) {
+               if (begin + len > next->begin) {
+                       begin = next->end;
+                       prev = next;
+                       continue;
+               }
+               break;
+       }
 
-       if (rqd->nr_ppas > 1) {
-               for (i = 0; i < rqd->nr_ppas; i++)
-                       rqd->ppa_list[i] = dev_to_generic_addr(dev,
-                                                       rqd->ppa_list[i]);
-       } else {
-               rqd->ppa_addr = dev_to_generic_addr(dev, rqd->ppa_addr);
+       if ((begin + len) > max_sectors) {
+               spin_unlock(&dev->lock);
+               kfree(area);
+               return -EINVAL;
        }
+
+       area->begin = *lba = begin;
+       area->end = begin + len;
+
+       if (prev) /* insert into sorted order */
+               list_add(&area->list, &prev->list);
+       else
+               list_add(&area->list, &dev->area_list);
+       spin_unlock(&dev->lock);
+
+       return 0;
 }
-EXPORT_SYMBOL(nvm_addr_to_generic_mode);
+EXPORT_SYMBOL(nvm_get_area);
 
-void nvm_generic_to_addr_mode(struct nvm_dev *dev, struct nvm_rq *rqd)
+void nvm_put_area(struct nvm_tgt_dev *tgt_dev, sector_t begin)
 {
-       int i;
+       struct nvm_dev *dev = tgt_dev->parent;
+       struct nvm_area *area;
 
-       if (rqd->nr_ppas > 1) {
-               for (i = 0; i < rqd->nr_ppas; i++)
-                       rqd->ppa_list[i] = generic_to_dev_addr(dev,
-                                                       rqd->ppa_list[i]);
-       } else {
-               rqd->ppa_addr = generic_to_dev_addr(dev, rqd->ppa_addr);
+       spin_lock(&dev->lock);
+       list_for_each_entry(area, &dev->area_list, list) {
+               if (area->begin != begin)
+                       continue;
+
+               list_del(&area->list);
+               spin_unlock(&dev->lock);
+               kfree(area);
+               return;
        }
+       spin_unlock(&dev->lock);
 }
-EXPORT_SYMBOL(nvm_generic_to_addr_mode);
+EXPORT_SYMBOL(nvm_put_area);
 
 int nvm_set_rqd_ppalist(struct nvm_dev *dev, struct nvm_rq *rqd,
                        const struct ppa_addr *ppas, int nr_ppas, int vblk)
@@ -380,149 +782,19 @@ void nvm_free_rqd_ppalist(struct nvm_dev *dev, struct nvm_rq *rqd)
 }
 EXPORT_SYMBOL(nvm_free_rqd_ppalist);
 
-int nvm_erase_ppa(struct nvm_dev *dev, struct ppa_addr *ppas, int nr_ppas,
-                                                               int flags)
+void nvm_end_io(struct nvm_rq *rqd)
 {
-       struct nvm_rq rqd;
-       int ret;
+       struct nvm_tgt_dev *tgt_dev = rqd->dev;
 
-       if (!dev->ops->erase_block)
-               return 0;
+       /* Convert address space */
+       if (tgt_dev)
+               nvm_rq_dev_to_tgt(tgt_dev, rqd);
 
-       memset(&rqd, 0, sizeof(struct nvm_rq));
-
-       ret = nvm_set_rqd_ppalist(dev, &rqd, ppas, nr_ppas, 1);
-       if (ret)
-               return ret;
-
-       nvm_generic_to_addr_mode(dev, &rqd);
-
-       rqd.flags = flags;
-
-       ret = dev->ops->erase_block(dev, &rqd);
-
-       nvm_free_rqd_ppalist(dev, &rqd);
-
-       return ret;
-}
-EXPORT_SYMBOL(nvm_erase_ppa);
-
-void nvm_end_io(struct nvm_rq *rqd, int error)
-{
-       rqd->error = error;
-       rqd->end_io(rqd);
+       if (rqd->end_io)
+               rqd->end_io(rqd);
 }
 EXPORT_SYMBOL(nvm_end_io);
 
-static void nvm_end_io_sync(struct nvm_rq *rqd)
-{
-       struct completion *waiting = rqd->wait;
-
-       rqd->wait = NULL;
-
-       complete(waiting);
-}
-
-static int __nvm_submit_ppa(struct nvm_dev *dev, struct nvm_rq *rqd, int opcode,
-                                               int flags, void *buf, int len)
-{
-       DECLARE_COMPLETION_ONSTACK(wait);
-       struct bio *bio;
-       int ret;
-       unsigned long hang_check;
-
-       bio = bio_map_kern(dev->q, buf, len, GFP_KERNEL);
-       if (IS_ERR_OR_NULL(bio))
-               return -ENOMEM;
-
-       nvm_generic_to_addr_mode(dev, rqd);
-
-       rqd->dev = NULL;
-       rqd->opcode = opcode;
-       rqd->flags = flags;
-       rqd->bio = bio;
-       rqd->wait = &wait;
-       rqd->end_io = nvm_end_io_sync;
-
-       ret = dev->ops->submit_io(dev, rqd);
-       if (ret) {
-               bio_put(bio);
-               return ret;
-       }
-
-       /* Prevent hang_check timer from firing at us during very long I/O */
-       hang_check = sysctl_hung_task_timeout_secs;
-       if (hang_check)
-               while (!wait_for_completion_io_timeout(&wait,
-                                                       hang_check * (HZ/2)))
-                       ;
-       else
-               wait_for_completion_io(&wait);
-
-       return rqd->error;
-}
-
-/**
- * nvm_submit_ppa_list - submit user-defined ppa list to device. The user must
- *                      take to free ppa list if necessary.
- * @dev:       device
- * @ppa_list:  user created ppa_list
- * @nr_ppas:   length of ppa_list
- * @opcode:    device opcode
- * @flags:     device flags
- * @buf:       data buffer
- * @len:       data buffer length
- */
-int nvm_submit_ppa_list(struct nvm_dev *dev, struct ppa_addr *ppa_list,
-                       int nr_ppas, int opcode, int flags, void *buf, int len)
-{
-       struct nvm_rq rqd;
-
-       if (dev->ops->max_phys_sect < nr_ppas)
-               return -EINVAL;
-
-       memset(&rqd, 0, sizeof(struct nvm_rq));
-
-       rqd.nr_ppas = nr_ppas;
-       if (nr_ppas > 1)
-               rqd.ppa_list = ppa_list;
-       else
-               rqd.ppa_addr = ppa_list[0];
-
-       return __nvm_submit_ppa(dev, &rqd, opcode, flags, buf, len);
-}
-EXPORT_SYMBOL(nvm_submit_ppa_list);
-
-/**
- * nvm_submit_ppa - submit PPAs to device. PPAs will automatically be unfolded
- *                 as single, dual, quad plane PPAs depending on device type.
- * @dev:       device
- * @ppa:       user created ppa_list
- * @nr_ppas:   length of ppa_list
- * @opcode:    device opcode
- * @flags:     device flags
- * @buf:       data buffer
- * @len:       data buffer length
- */
-int nvm_submit_ppa(struct nvm_dev *dev, struct ppa_addr *ppa, int nr_ppas,
-                               int opcode, int flags, void *buf, int len)
-{
-       struct nvm_rq rqd;
-       int ret;
-
-       memset(&rqd, 0, sizeof(struct nvm_rq));
-       ret = nvm_set_rqd_ppalist(dev, &rqd, ppa, nr_ppas, 1);
-       if (ret)
-               return ret;
-
-       ret = __nvm_submit_ppa(dev, &rqd, opcode, flags, buf, len);
-
-       nvm_free_rqd_ppalist(dev, &rqd);
-
-       return ret;
-}
-EXPORT_SYMBOL(nvm_submit_ppa);
-
 /*
  * folds a bad block list from its plane representation to its virtual
  * block representation. The fold is done in place and reduced size is
@@ -559,21 +831,14 @@ int nvm_bb_tbl_fold(struct nvm_dev *dev, u8 *blks, int nr_blks)
 }
 EXPORT_SYMBOL(nvm_bb_tbl_fold);
 
-int nvm_get_bb_tbl(struct nvm_dev *dev, struct ppa_addr ppa, u8 *blks)
-{
-       ppa = generic_to_dev_addr(dev, ppa);
-
-       return dev->ops->get_bb_tbl(dev, ppa, blks);
-}
-EXPORT_SYMBOL(nvm_get_bb_tbl);
-
 int nvm_get_tgt_bb_tbl(struct nvm_tgt_dev *tgt_dev, struct ppa_addr ppa,
                       u8 *blks)
 {
        struct nvm_dev *dev = tgt_dev->parent;
 
-       ppa = dev->mt->trans_ppa(tgt_dev, ppa, TRANS_TGT_TO_DEV);
-       return nvm_get_bb_tbl(dev, ppa, blks);
+       nvm_ppa_tgt_to_dev(tgt_dev, &ppa, 1);
+
+       return dev->ops->get_bb_tbl(dev, ppa, blks);
 }
 EXPORT_SYMBOL(nvm_get_tgt_bb_tbl);
 
@@ -627,7 +892,7 @@ static int nvm_init_mlc_tbl(struct nvm_dev *dev, struct nvm_id_group *grp)
 static int nvm_core_init(struct nvm_dev *dev)
 {
        struct nvm_id *id = &dev->identity;
-       struct nvm_id_group *grp = &id->groups[0];
+       struct nvm_id_group *grp = &id->grp;
        struct nvm_geo *geo = &dev->geo;
        int ret;
 
@@ -691,36 +956,31 @@ static int nvm_core_init(struct nvm_dev *dev)
                goto err_fmtype;
        }
 
+       INIT_LIST_HEAD(&dev->area_list);
+       INIT_LIST_HEAD(&dev->targets);
        mutex_init(&dev->mlock);
        spin_lock_init(&dev->lock);
 
-       blk_queue_logical_block_size(dev->q, geo->sec_size);
+       ret = nvm_register_map(dev);
+       if (ret)
+               goto err_fmtype;
 
+       blk_queue_logical_block_size(dev->q, geo->sec_size);
        return 0;
 err_fmtype:
        kfree(dev->lun_map);
        return ret;
 }
 
-static void nvm_free_mgr(struct nvm_dev *dev)
-{
-       if (!dev->mt)
-               return;
-
-       dev->mt->unregister_mgr(dev);
-       dev->mt = NULL;
-}
-
 void nvm_free(struct nvm_dev *dev)
 {
        if (!dev)
                return;
 
-       nvm_free_mgr(dev);
-
        if (dev->dma_pool)
                dev->ops->destroy_dma_pool(dev->dma_pool);
 
+       kfree(dev->rmap);
        kfree(dev->lptbl);
        kfree(dev->lun_map);
        kfree(dev);
@@ -731,28 +991,19 @@ static int nvm_init(struct nvm_dev *dev)
        struct nvm_geo *geo = &dev->geo;
        int ret = -EINVAL;
 
-       if (!dev->q || !dev->ops)
-               return ret;
-
        if (dev->ops->identity(dev, &dev->identity)) {
                pr_err("nvm: device could not be identified\n");
                goto err;
        }
 
-       pr_debug("nvm: ver:%x nvm_vendor:%x groups:%u\n",
-                       dev->identity.ver_id, dev->identity.vmnt,
-                                                       dev->identity.cgrps);
+       pr_debug("nvm: ver:%x nvm_vendor:%x\n",
+                       dev->identity.ver_id, dev->identity.vmnt);
 
        if (dev->identity.ver_id != 1) {
                pr_err("nvm: device not supported by kernel.");
                goto err;
        }
 
-       if (dev->identity.cgrps != 1) {
-               pr_err("nvm: only one group configuration supported.");
-               goto err;
-       }
-
        ret = nvm_core_init(dev);
        if (ret) {
                pr_err("nvm: could not initialize core structures.\n");
@@ -779,49 +1030,50 @@ int nvm_register(struct nvm_dev *dev)
 {
        int ret;
 
-       ret = nvm_init(dev);
-       if (ret)
-               goto err_init;
+       if (!dev->q || !dev->ops)
+               return -EINVAL;
 
        if (dev->ops->max_phys_sect > 256) {
                pr_info("nvm: max sectors supported is 256.\n");
-               ret = -EINVAL;
-               goto err_init;
+               return -EINVAL;
        }
 
        if (dev->ops->max_phys_sect > 1) {
                dev->dma_pool = dev->ops->create_dma_pool(dev, "ppalist");
                if (!dev->dma_pool) {
                        pr_err("nvm: could not create dma pool\n");
-                       ret = -ENOMEM;
-                       goto err_init;
+                       return -ENOMEM;
                }
        }
 
-       if (dev->identity.cap & NVM_ID_DCAP_BBLKMGMT) {
-               ret = nvm_get_sysblock(dev, &dev->sb);
-               if (!ret)
-                       pr_err("nvm: device not initialized.\n");
-               else if (ret < 0)
-                       pr_err("nvm: err (%d) on device initialization\n", ret);
-       }
+       ret = nvm_init(dev);
+       if (ret)
+               goto err_init;
 
        /* register device with a supported media manager */
        down_write(&nvm_lock);
-       if (ret > 0)
-               dev->mt = nvm_init_mgr(dev);
        list_add(&dev->devices, &nvm_devices);
        up_write(&nvm_lock);
 
        return 0;
 err_init:
-       kfree(dev->lun_map);
+       dev->ops->destroy_dma_pool(dev->dma_pool);
        return ret;
 }
 EXPORT_SYMBOL(nvm_register);
 
 void nvm_unregister(struct nvm_dev *dev)
 {
+       struct nvm_target *t, *tmp;
+
+       mutex_lock(&dev->mlock);
+       list_for_each_entry_safe(t, tmp, &dev->targets, list) {
+               if (t->dev->parent != dev)
+                       continue;
+               __nvm_remove_target(t);
+       }
+       mutex_unlock(&dev->mlock);
+
        down_write(&nvm_lock);
        list_del(&dev->devices);
        up_write(&nvm_lock);
@@ -844,24 +1096,24 @@ static int __nvm_configure_create(struct nvm_ioctl_create *create)
                return -EINVAL;
        }
 
-       if (!dev->mt) {
-               pr_info("nvm: device has no media manager registered.\n");
-               return -ENODEV;
-       }
-
        if (create->conf.type != NVM_CONFIG_TYPE_SIMPLE) {
                pr_err("nvm: config type not valid\n");
                return -EINVAL;
        }
        s = &create->conf.s;
 
-       if (s->lun_begin > s->lun_end || s->lun_end > dev->geo.nr_luns) {
+       if (s->lun_begin == -1 && s->lun_end == -1) {
+               s->lun_begin = 0;
+               s->lun_end = dev->geo.nr_luns - 1;
+       }
+
+       if (s->lun_begin > s->lun_end || s->lun_end >= dev->geo.nr_luns) {
                pr_err("nvm: lun out of bound (%u:%u > %u)\n",
-                       s->lun_begin, s->lun_end, dev->geo.nr_luns);
+                       s->lun_begin, s->lun_end, dev->geo.nr_luns - 1);
                return -EINVAL;
        }
 
-       return dev->mt->create_tgt(dev, create);
+       return nvm_create_tgt(dev, create);
 }
 
 static long nvm_ioctl_info(struct file *file, void __user *arg)
@@ -923,16 +1175,14 @@ static long nvm_ioctl_get_devices(struct file *file, void __user *arg)
                struct nvm_ioctl_device_info *info = &devices->info[i];
 
                sprintf(info->devname, "%s", dev->name);
-               if (dev->mt) {
-                       info->bmversion[0] = dev->mt->version[0];
-                       info->bmversion[1] = dev->mt->version[1];
-                       info->bmversion[2] = dev->mt->version[2];
-                       sprintf(info->bmname, "%s", dev->mt->name);
-               } else {
-                       sprintf(info->bmname, "none");
-               }
 
+               /* kept for compatibility */
+               info->bmversion[0] = 1;
+               info->bmversion[1] = 0;
+               info->bmversion[2] = 0;
+               sprintf(info->bmname, "%s", "gennvm");
                i++;
+
                if (i > 31) {
                        pr_err("nvm: max 31 devices can be reported.\n");
                        break;
@@ -994,7 +1244,7 @@ static long nvm_ioctl_dev_remove(struct file *file, void __user *arg)
        }
 
        list_for_each_entry(dev, &nvm_devices, devices) {
-               ret = dev->mt->remove_tgt(dev, &remove);
+               ret = nvm_remove_tgt(dev, &remove);
                if (!ret)
                        break;
        }
@@ -1002,47 +1252,7 @@ static long nvm_ioctl_dev_remove(struct file *file, void __user *arg)
        return ret;
 }
 
-static void nvm_setup_nvm_sb_info(struct nvm_sb_info *info)
-{
-       info->seqnr = 1;
-       info->erase_cnt = 0;
-       info->version = 1;
-}
-
-static long __nvm_ioctl_dev_init(struct nvm_ioctl_dev_init *init)
-{
-       struct nvm_dev *dev;
-       struct nvm_sb_info info;
-       int ret;
-
-       down_write(&nvm_lock);
-       dev = nvm_find_nvm_dev(init->dev);
-       up_write(&nvm_lock);
-       if (!dev) {
-               pr_err("nvm: device not found\n");
-               return -EINVAL;
-       }
-
-       nvm_setup_nvm_sb_info(&info);
-
-       strncpy(info.mmtype, init->mmtype, NVM_MMTYPE_LEN);
-       info.fs_ppa.ppa = -1;
-
-       if (dev->identity.cap & NVM_ID_DCAP_BBLKMGMT) {
-               ret = nvm_init_sysblock(dev, &info);
-               if (ret)
-                       return ret;
-       }
-
-       memcpy(&dev->sb, &info, sizeof(struct nvm_sb_info));
-
-       down_write(&nvm_lock);
-       dev->mt = nvm_init_mgr(dev);
-       up_write(&nvm_lock);
-
-       return 0;
-}
-
+/* kept for compatibility reasons */
 static long nvm_ioctl_dev_init(struct file *file, void __user *arg)
 {
        struct nvm_ioctl_dev_init init;
@@ -1058,15 +1268,13 @@ static long nvm_ioctl_dev_init(struct file *file, void __user *arg)
                return -EINVAL;
        }
 
-       init.dev[DISK_NAME_LEN - 1] = '\0';
-
-       return __nvm_ioctl_dev_init(&init);
+       return 0;
 }
 
+/* Kept for compatibility reasons */
 static long nvm_ioctl_dev_factory(struct file *file, void __user *arg)
 {
        struct nvm_ioctl_dev_factory fact;
-       struct nvm_dev *dev;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
@@ -1079,19 +1287,6 @@ static long nvm_ioctl_dev_factory(struct file *file, void __user *arg)
        if (fact.flags & ~(NVM_FACTORY_NR_BITS - 1))
                return -EINVAL;
 
-       down_write(&nvm_lock);
-       dev = nvm_find_nvm_dev(fact.dev);
-       up_write(&nvm_lock);
-       if (!dev) {
-               pr_err("nvm: device not found\n");
-               return -EINVAL;
-       }
-
-       nvm_free_mgr(dev);
-
-       if (dev->identity.cap & NVM_ID_DCAP_BBLKMGMT)
-               return nvm_dev_factory(dev, fact.flags);
-
        return 0;
 }
 
diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c
deleted file mode 100644 (file)
index ca78800..0000000
+++ /dev/null
@@ -1,657 +0,0 @@
-/*
- * Copyright (C) 2015 Matias Bjorling <m@bjorling.me>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.  If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
- * USA.
- *
- * Implementation of a general nvm manager for Open-Channel SSDs.
- */
-
-#include "gennvm.h"
-
-static struct nvm_target *gen_find_target(struct gen_dev *gn, const char *name)
-{
-       struct nvm_target *tgt;
-
-       list_for_each_entry(tgt, &gn->targets, list)
-               if (!strcmp(name, tgt->disk->disk_name))
-                       return tgt;
-
-       return NULL;
-}
-
-static const struct block_device_operations gen_fops = {
-       .owner          = THIS_MODULE,
-};
-
-static int gen_reserve_luns(struct nvm_dev *dev, struct nvm_target *t,
-                           int lun_begin, int lun_end)
-{
-       int i;
-
-       for (i = lun_begin; i <= lun_end; i++) {
-               if (test_and_set_bit(i, dev->lun_map)) {
-                       pr_err("nvm: lun %d already allocated\n", i);
-                       goto err;
-               }
-       }
-
-       return 0;
-
-err:
-       while (--i > lun_begin)
-               clear_bit(i, dev->lun_map);
-
-       return -EBUSY;
-}
-
-static void gen_release_luns_err(struct nvm_dev *dev, int lun_begin,
-                                int lun_end)
-{
-       int i;
-
-       for (i = lun_begin; i <= lun_end; i++)
-               WARN_ON(!test_and_clear_bit(i, dev->lun_map));
-}
-
-static void gen_remove_tgt_dev(struct nvm_tgt_dev *tgt_dev)
-{
-       struct nvm_dev *dev = tgt_dev->parent;
-       struct gen_dev_map *dev_map = tgt_dev->map;
-       int i, j;
-
-       for (i = 0; i < dev_map->nr_chnls; i++) {
-               struct gen_ch_map *ch_map = &dev_map->chnls[i];
-               int *lun_offs = ch_map->lun_offs;
-               int ch = i + ch_map->ch_off;
-
-               for (j = 0; j < ch_map->nr_luns; j++) {
-                       int lun = j + lun_offs[j];
-                       int lunid = (ch * dev->geo.luns_per_chnl) + lun;
-
-                       WARN_ON(!test_and_clear_bit(lunid, dev->lun_map));
-               }
-
-               kfree(ch_map->lun_offs);
-       }
-
-       kfree(dev_map->chnls);
-       kfree(dev_map);
-       kfree(tgt_dev->luns);
-       kfree(tgt_dev);
-}
-
-static struct nvm_tgt_dev *gen_create_tgt_dev(struct nvm_dev *dev,
-                                             int lun_begin, int lun_end)
-{
-       struct nvm_tgt_dev *tgt_dev = NULL;
-       struct gen_dev_map *dev_rmap = dev->rmap;
-       struct gen_dev_map *dev_map;
-       struct ppa_addr *luns;
-       int nr_luns = lun_end - lun_begin + 1;
-       int luns_left = nr_luns;
-       int nr_chnls = nr_luns / dev->geo.luns_per_chnl;
-       int nr_chnls_mod = nr_luns % dev->geo.luns_per_chnl;
-       int bch = lun_begin / dev->geo.luns_per_chnl;
-       int blun = lun_begin % dev->geo.luns_per_chnl;
-       int lunid = 0;
-       int lun_balanced = 1;
-       int prev_nr_luns;
-       int i, j;
-
-       nr_chnls = nr_luns / dev->geo.luns_per_chnl;
-       nr_chnls = (nr_chnls_mod == 0) ? nr_chnls : nr_chnls + 1;
-
-       dev_map = kmalloc(sizeof(struct gen_dev_map), GFP_KERNEL);
-       if (!dev_map)
-               goto err_dev;
-
-       dev_map->chnls = kcalloc(nr_chnls, sizeof(struct gen_ch_map),
-                                                               GFP_KERNEL);
-       if (!dev_map->chnls)
-               goto err_chnls;
-
-       luns = kcalloc(nr_luns, sizeof(struct ppa_addr), GFP_KERNEL);
-       if (!luns)
-               goto err_luns;
-
-       prev_nr_luns = (luns_left > dev->geo.luns_per_chnl) ?
-                                       dev->geo.luns_per_chnl : luns_left;
-       for (i = 0; i < nr_chnls; i++) {
-               struct gen_ch_map *ch_rmap = &dev_rmap->chnls[i + bch];
-               int *lun_roffs = ch_rmap->lun_offs;
-               struct gen_ch_map *ch_map = &dev_map->chnls[i];
-               int *lun_offs;
-               int luns_in_chnl = (luns_left > dev->geo.luns_per_chnl) ?
-                                       dev->geo.luns_per_chnl : luns_left;
-
-               if (lun_balanced && prev_nr_luns != luns_in_chnl)
-                       lun_balanced = 0;
-
-               ch_map->ch_off = ch_rmap->ch_off = bch;
-               ch_map->nr_luns = luns_in_chnl;
-
-               lun_offs = kcalloc(luns_in_chnl, sizeof(int), GFP_KERNEL);
-               if (!lun_offs)
-                       goto err_ch;
-
-               for (j = 0; j < luns_in_chnl; j++) {
-                       luns[lunid].ppa = 0;
-                       luns[lunid].g.ch = i;
-                       luns[lunid++].g.lun = j;
-
-                       lun_offs[j] = blun;
-                       lun_roffs[j + blun] = blun;
-               }
-
-               ch_map->lun_offs = lun_offs;
-
-               /* when starting a new channel, lun offset is reset */
-               blun = 0;
-               luns_left -= luns_in_chnl;
-       }
-
-       dev_map->nr_chnls = nr_chnls;
-
-       tgt_dev = kmalloc(sizeof(struct nvm_tgt_dev), GFP_KERNEL);
-       if (!tgt_dev)
-               goto err_ch;
-
-       memcpy(&tgt_dev->geo, &dev->geo, sizeof(struct nvm_geo));
-       /* Target device only owns a portion of the physical device */
-       tgt_dev->geo.nr_chnls = nr_chnls;
-       tgt_dev->geo.nr_luns = nr_luns;
-       tgt_dev->geo.luns_per_chnl = (lun_balanced) ? prev_nr_luns : -1;
-       tgt_dev->total_secs = nr_luns * tgt_dev->geo.sec_per_lun;
-       tgt_dev->q = dev->q;
-       tgt_dev->map = dev_map;
-       tgt_dev->luns = luns;
-       memcpy(&tgt_dev->identity, &dev->identity, sizeof(struct nvm_id));
-
-       tgt_dev->parent = dev;
-
-       return tgt_dev;
-err_ch:
-       while (--i > 0)
-               kfree(dev_map->chnls[i].lun_offs);
-       kfree(luns);
-err_luns:
-       kfree(dev_map->chnls);
-err_chnls:
-       kfree(dev_map);
-err_dev:
-       return tgt_dev;
-}
-
-static int gen_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
-{
-       struct gen_dev *gn = dev->mp;
-       struct nvm_ioctl_create_simple *s = &create->conf.s;
-       struct request_queue *tqueue;
-       struct gendisk *tdisk;
-       struct nvm_tgt_type *tt;
-       struct nvm_target *t;
-       struct nvm_tgt_dev *tgt_dev;
-       void *targetdata;
-
-       tt = nvm_find_target_type(create->tgttype, 1);
-       if (!tt) {
-               pr_err("nvm: target type %s not found\n", create->tgttype);
-               return -EINVAL;
-       }
-
-       mutex_lock(&gn->lock);
-       t = gen_find_target(gn, create->tgtname);
-       if (t) {
-               pr_err("nvm: target name already exists.\n");
-               mutex_unlock(&gn->lock);
-               return -EINVAL;
-       }
-       mutex_unlock(&gn->lock);
-
-       t = kmalloc(sizeof(struct nvm_target), GFP_KERNEL);
-       if (!t)
-               return -ENOMEM;
-
-       if (gen_reserve_luns(dev, t, s->lun_begin, s->lun_end))
-               goto err_t;
-
-       tgt_dev = gen_create_tgt_dev(dev, s->lun_begin, s->lun_end);
-       if (!tgt_dev) {
-               pr_err("nvm: could not create target device\n");
-               goto err_reserve;
-       }
-
-       tqueue = blk_alloc_queue_node(GFP_KERNEL, dev->q->node);
-       if (!tqueue)
-               goto err_dev;
-       blk_queue_make_request(tqueue, tt->make_rq);
-
-       tdisk = alloc_disk(0);
-       if (!tdisk)
-               goto err_queue;
-
-       sprintf(tdisk->disk_name, "%s", create->tgtname);
-       tdisk->flags = GENHD_FL_EXT_DEVT;
-       tdisk->major = 0;
-       tdisk->first_minor = 0;
-       tdisk->fops = &gen_fops;
-       tdisk->queue = tqueue;
-
-       targetdata = tt->init(tgt_dev, tdisk);
-       if (IS_ERR(targetdata))
-               goto err_init;
-
-       tdisk->private_data = targetdata;
-       tqueue->queuedata = targetdata;
-
-       blk_queue_max_hw_sectors(tqueue, 8 * dev->ops->max_phys_sect);
-
-       set_capacity(tdisk, tt->capacity(targetdata));
-       add_disk(tdisk);
-
-       t->type = tt;
-       t->disk = tdisk;
-       t->dev = tgt_dev;
-
-       mutex_lock(&gn->lock);
-       list_add_tail(&t->list, &gn->targets);
-       mutex_unlock(&gn->lock);
-
-       return 0;
-err_init:
-       put_disk(tdisk);
-err_queue:
-       blk_cleanup_queue(tqueue);
-err_dev:
-       kfree(tgt_dev);
-err_reserve:
-       gen_release_luns_err(dev, s->lun_begin, s->lun_end);
-err_t:
-       kfree(t);
-       return -ENOMEM;
-}
-
-static void __gen_remove_target(struct nvm_target *t)
-{
-       struct nvm_tgt_type *tt = t->type;
-       struct gendisk *tdisk = t->disk;
-       struct request_queue *q = tdisk->queue;
-
-       del_gendisk(tdisk);
-       blk_cleanup_queue(q);
-
-       if (tt->exit)
-               tt->exit(tdisk->private_data);
-
-       gen_remove_tgt_dev(t->dev);
-       put_disk(tdisk);
-
-       list_del(&t->list);
-       kfree(t);
-}
-
-/**
- * gen_remove_tgt - Removes a target from the media manager
- * @dev:       device
- * @remove:    ioctl structure with target name to remove.
- *
- * Returns:
- * 0: on success
- * 1: on not found
- * <0: on error
- */
-static int gen_remove_tgt(struct nvm_dev *dev, struct nvm_ioctl_remove *remove)
-{
-       struct gen_dev *gn = dev->mp;
-       struct nvm_target *t;
-
-       if (!gn)
-               return 1;
-
-       mutex_lock(&gn->lock);
-       t = gen_find_target(gn, remove->tgtname);
-       if (!t) {
-               mutex_unlock(&gn->lock);
-               return 1;
-       }
-       __gen_remove_target(t);
-       mutex_unlock(&gn->lock);
-
-       return 0;
-}
-
-static int gen_get_area(struct nvm_dev *dev, sector_t *lba, sector_t len)
-{
-       struct nvm_geo *geo = &dev->geo;
-       struct gen_dev *gn = dev->mp;
-       struct gen_area *area, *prev, *next;
-       sector_t begin = 0;
-       sector_t max_sectors = (geo->sec_size * dev->total_secs) >> 9;
-
-       if (len > max_sectors)
-               return -EINVAL;
-
-       area = kmalloc(sizeof(struct gen_area), GFP_KERNEL);
-       if (!area)
-               return -ENOMEM;
-
-       prev = NULL;
-
-       spin_lock(&dev->lock);
-       list_for_each_entry(next, &gn->area_list, list) {
-               if (begin + len > next->begin) {
-                       begin = next->end;
-                       prev = next;
-                       continue;
-               }
-               break;
-       }
-
-       if ((begin + len) > max_sectors) {
-               spin_unlock(&dev->lock);
-               kfree(area);
-               return -EINVAL;
-       }
-
-       area->begin = *lba = begin;
-       area->end = begin + len;
-
-       if (prev) /* insert into sorted order */
-               list_add(&area->list, &prev->list);
-       else
-               list_add(&area->list, &gn->area_list);
-       spin_unlock(&dev->lock);
-
-       return 0;
-}
-
-static void gen_put_area(struct nvm_dev *dev, sector_t begin)
-{
-       struct gen_dev *gn = dev->mp;
-       struct gen_area *area;
-
-       spin_lock(&dev->lock);
-       list_for_each_entry(area, &gn->area_list, list) {
-               if (area->begin != begin)
-                       continue;
-
-               list_del(&area->list);
-               spin_unlock(&dev->lock);
-               kfree(area);
-               return;
-       }
-       spin_unlock(&dev->lock);
-}
-
-static void gen_free(struct nvm_dev *dev)
-{
-       kfree(dev->mp);
-       kfree(dev->rmap);
-       dev->mp = NULL;
-}
-
-static int gen_register(struct nvm_dev *dev)
-{
-       struct gen_dev *gn;
-       struct gen_dev_map *dev_rmap;
-       int i, j;
-
-       if (!try_module_get(THIS_MODULE))
-               return -ENODEV;
-
-       gn = kzalloc(sizeof(struct gen_dev), GFP_KERNEL);
-       if (!gn)
-               goto err_gn;
-
-       dev_rmap = kmalloc(sizeof(struct gen_dev_map), GFP_KERNEL);
-       if (!dev_rmap)
-               goto err_rmap;
-
-       dev_rmap->chnls = kcalloc(dev->geo.nr_chnls, sizeof(struct gen_ch_map),
-                                                               GFP_KERNEL);
-       if (!dev_rmap->chnls)
-               goto err_chnls;
-
-       for (i = 0; i < dev->geo.nr_chnls; i++) {
-               struct gen_ch_map *ch_rmap;
-               int *lun_roffs;
-               int luns_in_chnl = dev->geo.luns_per_chnl;
-
-               ch_rmap = &dev_rmap->chnls[i];
-
-               ch_rmap->ch_off = -1;
-               ch_rmap->nr_luns = luns_in_chnl;
-
-               lun_roffs = kcalloc(luns_in_chnl, sizeof(int), GFP_KERNEL);
-               if (!lun_roffs)
-                       goto err_ch;
-
-               for (j = 0; j < luns_in_chnl; j++)
-                       lun_roffs[j] = -1;
-
-               ch_rmap->lun_offs = lun_roffs;
-       }
-
-       gn->dev = dev;
-       gn->nr_luns = dev->geo.nr_luns;
-       INIT_LIST_HEAD(&gn->area_list);
-       mutex_init(&gn->lock);
-       INIT_LIST_HEAD(&gn->targets);
-       dev->mp = gn;
-       dev->rmap = dev_rmap;
-
-       return 1;
-err_ch:
-       while (--i >= 0)
-               kfree(dev_rmap->chnls[i].lun_offs);
-err_chnls:
-       kfree(dev_rmap);
-err_rmap:
-       gen_free(dev);
-err_gn:
-       module_put(THIS_MODULE);
-       return -ENOMEM;
-}
-
-static void gen_unregister(struct nvm_dev *dev)
-{
-       struct gen_dev *gn = dev->mp;
-       struct nvm_target *t, *tmp;
-
-       mutex_lock(&gn->lock);
-       list_for_each_entry_safe(t, tmp, &gn->targets, list) {
-               if (t->dev->parent != dev)
-                       continue;
-               __gen_remove_target(t);
-       }
-       mutex_unlock(&gn->lock);
-
-       gen_free(dev);
-       module_put(THIS_MODULE);
-}
-
-static int gen_map_to_dev(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *p)
-{
-       struct gen_dev_map *dev_map = tgt_dev->map;
-       struct gen_ch_map *ch_map = &dev_map->chnls[p->g.ch];
-       int lun_off = ch_map->lun_offs[p->g.lun];
-       struct nvm_dev *dev = tgt_dev->parent;
-       struct gen_dev_map *dev_rmap = dev->rmap;
-       struct gen_ch_map *ch_rmap;
-       int lun_roff;
-
-       p->g.ch += ch_map->ch_off;
-       p->g.lun += lun_off;
-
-       ch_rmap = &dev_rmap->chnls[p->g.ch];
-       lun_roff = ch_rmap->lun_offs[p->g.lun];
-
-       if (unlikely(ch_rmap->ch_off < 0 || lun_roff < 0)) {
-               pr_err("nvm: corrupted device partition table\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int gen_map_to_tgt(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *p)
-{
-       struct nvm_dev *dev = tgt_dev->parent;
-       struct gen_dev_map *dev_rmap = dev->rmap;
-       struct gen_ch_map *ch_rmap = &dev_rmap->chnls[p->g.ch];
-       int lun_roff = ch_rmap->lun_offs[p->g.lun];
-
-       p->g.ch -= ch_rmap->ch_off;
-       p->g.lun -= lun_roff;
-
-       return 0;
-}
-
-static int gen_trans_rq(struct nvm_tgt_dev *tgt_dev, struct nvm_rq *rqd,
-                       int flag)
-{
-       gen_trans_fn *f;
-       int i;
-       int ret = 0;
-
-       f = (flag == TRANS_TGT_TO_DEV) ? gen_map_to_dev : gen_map_to_tgt;
-
-       if (rqd->nr_ppas == 1)
-               return f(tgt_dev, &rqd->ppa_addr);
-
-       for (i = 0; i < rqd->nr_ppas; i++) {
-               ret = f(tgt_dev, &rqd->ppa_list[i]);
-               if (ret)
-                       goto out;
-       }
-
-out:
-       return ret;
-}
-
-static void gen_end_io(struct nvm_rq *rqd)
-{
-       struct nvm_tgt_dev *tgt_dev = rqd->dev;
-       struct nvm_tgt_instance *ins = rqd->ins;
-
-       /* Convert address space */
-       if (tgt_dev)
-               gen_trans_rq(tgt_dev, rqd, TRANS_DEV_TO_TGT);
-
-       ins->tt->end_io(rqd);
-}
-
-static int gen_submit_io(struct nvm_tgt_dev *tgt_dev, struct nvm_rq *rqd)
-{
-       struct nvm_dev *dev = tgt_dev->parent;
-
-       if (!dev->ops->submit_io)
-               return -ENODEV;
-
-       /* Convert address space */
-       gen_trans_rq(tgt_dev, rqd, TRANS_TGT_TO_DEV);
-       nvm_generic_to_addr_mode(dev, rqd);
-
-       rqd->dev = tgt_dev;
-       rqd->end_io = gen_end_io;
-       return dev->ops->submit_io(dev, rqd);
-}
-
-static int gen_erase_blk(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *p,
-                        int flags)
-{
-       /* Convert address space */
-       gen_map_to_dev(tgt_dev, p);
-
-       return nvm_erase_ppa(tgt_dev->parent, p, 1, flags);
-}
-
-static struct ppa_addr gen_trans_ppa(struct nvm_tgt_dev *tgt_dev,
-                                    struct ppa_addr p, int direction)
-{
-       gen_trans_fn *f;
-       struct ppa_addr ppa = p;
-
-       f = (direction == TRANS_TGT_TO_DEV) ? gen_map_to_dev : gen_map_to_tgt;
-       f(tgt_dev, &ppa);
-
-       return ppa;
-}
-
-static void gen_part_to_tgt(struct nvm_dev *dev, sector_t *entries,
-                              int len)
-{
-       struct nvm_geo *geo = &dev->geo;
-       struct gen_dev_map *dev_rmap = dev->rmap;
-       u64 i;
-
-       for (i = 0; i < len; i++) {
-               struct gen_ch_map *ch_rmap;
-               int *lun_roffs;
-               struct ppa_addr gaddr;
-               u64 pba = le64_to_cpu(entries[i]);
-               int off;
-               u64 diff;
-
-               if (!pba)
-                       continue;
-
-               gaddr = linear_to_generic_addr(geo, pba);
-               ch_rmap = &dev_rmap->chnls[gaddr.g.ch];
-               lun_roffs = ch_rmap->lun_offs;
-
-               off = gaddr.g.ch * geo->luns_per_chnl + gaddr.g.lun;
-
-               diff = ((ch_rmap->ch_off * geo->luns_per_chnl) +
-                               (lun_roffs[gaddr.g.lun])) * geo->sec_per_lun;
-
-               entries[i] -= cpu_to_le64(diff);
-       }
-}
-
-static struct nvmm_type gen = {
-       .name                   = "gennvm",
-       .version                = {0, 1, 0},
-
-       .register_mgr           = gen_register,
-       .unregister_mgr         = gen_unregister,
-
-       .create_tgt             = gen_create_tgt,
-       .remove_tgt             = gen_remove_tgt,
-
-       .submit_io              = gen_submit_io,
-       .erase_blk              = gen_erase_blk,
-
-       .get_area               = gen_get_area,
-       .put_area               = gen_put_area,
-
-       .trans_ppa              = gen_trans_ppa,
-       .part_to_tgt            = gen_part_to_tgt,
-};
-
-static int __init gen_module_init(void)
-{
-       return nvm_register_mgr(&gen);
-}
-
-static void gen_module_exit(void)
-{
-       nvm_unregister_mgr(&gen);
-}
-
-module_init(gen_module_init);
-module_exit(gen_module_exit);
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("General media manager for Open-Channel SSDs");
diff --git a/drivers/lightnvm/gennvm.h b/drivers/lightnvm/gennvm.h
deleted file mode 100644 (file)
index 6a4b3f3..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright: Matias Bjorling <mb@bjorling.me>
- *
- * 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 GENNVM_H_
-#define GENNVM_H_
-
-#include <linux/module.h>
-#include <linux/vmalloc.h>
-
-#include <linux/lightnvm.h>
-
-struct gen_dev {
-       struct nvm_dev *dev;
-
-       int nr_luns;
-       struct list_head area_list;
-
-       struct mutex lock;
-       struct list_head targets;
-};
-
-/* Map between virtual and physical channel and lun */
-struct gen_ch_map {
-       int ch_off;
-       int nr_luns;
-       int *lun_offs;
-};
-
-struct gen_dev_map {
-       struct gen_ch_map *chnls;
-       int nr_chnls;
-};
-
-struct gen_area {
-       struct list_head list;
-       sector_t begin;
-       sector_t end;   /* end is excluded */
-};
-
-static inline void *ch_map_to_lun_offs(struct gen_ch_map *ch_map)
-{
-       return ch_map + 1;
-}
-
-typedef int (gen_trans_fn)(struct nvm_tgt_dev *, struct ppa_addr *);
-
-#define gen_for_each_lun(bm, lun, i) \
-               for ((i) = 0, lun = &(bm)->luns[0]; \
-                       (i) < (bm)->nr_luns; (i)++, lun = &(bm)->luns[(i)])
-
-#endif /* GENNVM_H_ */
index 9fb7de395915ca8e3893f16273a5e6c20d4a763d..e00b1d7b976f0e892c7ff27ce697e3eaeadd6481 100644 (file)
@@ -779,7 +779,7 @@ static void rrpc_end_io_write(struct rrpc *rrpc, struct rrpc_rq *rrqd,
 
 static void rrpc_end_io(struct nvm_rq *rqd)
 {
-       struct rrpc *rrpc = container_of(rqd->ins, struct rrpc, instance);
+       struct rrpc *rrpc = rqd->private;
        struct nvm_tgt_dev *dev = rrpc->dev;
        struct rrpc_rq *rrqd = nvm_rq_to_pdu(rqd);
        uint8_t npages = rqd->nr_ppas;
@@ -972,8 +972,9 @@ static int rrpc_submit_io(struct rrpc *rrpc, struct bio *bio,
 
        bio_get(bio);
        rqd->bio = bio;
-       rqd->ins = &rrpc->instance;
+       rqd->private = rrpc;
        rqd->nr_ppas = nr_pages;
+       rqd->end_io = rrpc_end_io;
        rrq->flags = flags;
 
        err = nvm_submit_io(dev, rqd);
@@ -1532,7 +1533,6 @@ static void *rrpc_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk)
        if (!rrpc)
                return ERR_PTR(-ENOMEM);
 
-       rrpc->instance.tt = &tt_rrpc;
        rrpc->dev = dev;
        rrpc->disk = tdisk;
 
@@ -1611,7 +1611,6 @@ static struct nvm_tgt_type tt_rrpc = {
 
        .make_rq        = rrpc_make_rq,
        .capacity       = rrpc_capacity,
-       .end_io         = rrpc_end_io,
 
        .init           = rrpc_init,
        .exit           = rrpc_exit,
index 94e4d73116b2948888a7539cded74e198b412634..fdb6ff902903e3f640543d79004517d6111c5a3c 100644 (file)
@@ -102,9 +102,6 @@ struct rrpc_lun {
 };
 
 struct rrpc {
-       /* instance must be kept in top to resolve rrpc in unprep */
-       struct nvm_tgt_instance instance;
-
        struct nvm_tgt_dev *dev;
        struct gendisk *disk;
 
diff --git a/drivers/lightnvm/sysblk.c b/drivers/lightnvm/sysblk.c
deleted file mode 100644 (file)
index 12002bf..0000000
+++ /dev/null
@@ -1,733 +0,0 @@
-/*
- * Copyright (C) 2015 Matias Bjorling. 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.  If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
- * USA.
- *
- */
-
-#include <linux/lightnvm.h>
-
-#define MAX_SYSBLKS 3  /* remember to update mapping scheme on change */
-#define MAX_BLKS_PR_SYSBLK 2 /* 2 blks with 256 pages and 3000 erases
-                             * enables ~1.5M updates per sysblk unit
-                             */
-
-struct sysblk_scan {
-       /* A row is a collection of flash blocks for a system block. */
-       int nr_rows;
-       int row;
-       int act_blk[MAX_SYSBLKS];
-
-       int nr_ppas;
-       struct ppa_addr ppas[MAX_SYSBLKS * MAX_BLKS_PR_SYSBLK];/* all sysblks */
-};
-
-static inline int scan_ppa_idx(int row, int blkid)
-{
-       return (row * MAX_BLKS_PR_SYSBLK) + blkid;
-}
-
-static void nvm_sysblk_to_cpu(struct nvm_sb_info *info,
-                             struct nvm_system_block *sb)
-{
-       info->seqnr = be32_to_cpu(sb->seqnr);
-       info->erase_cnt = be32_to_cpu(sb->erase_cnt);
-       info->version = be16_to_cpu(sb->version);
-       strncpy(info->mmtype, sb->mmtype, NVM_MMTYPE_LEN);
-       info->fs_ppa.ppa = be64_to_cpu(sb->fs_ppa);
-}
-
-static void nvm_cpu_to_sysblk(struct nvm_system_block *sb,
-                             struct nvm_sb_info *info)
-{
-       sb->magic = cpu_to_be32(NVM_SYSBLK_MAGIC);
-       sb->seqnr = cpu_to_be32(info->seqnr);
-       sb->erase_cnt = cpu_to_be32(info->erase_cnt);
-       sb->version = cpu_to_be16(info->version);
-       strncpy(sb->mmtype, info->mmtype, NVM_MMTYPE_LEN);
-       sb->fs_ppa = cpu_to_be64(info->fs_ppa.ppa);
-}
-
-static int nvm_setup_sysblks(struct nvm_dev *dev, struct ppa_addr *sysblk_ppas)
-{
-       struct nvm_geo *geo = &dev->geo;
-       int nr_rows = min_t(int, MAX_SYSBLKS, geo->nr_chnls);
-       int i;
-
-       for (i = 0; i < nr_rows; i++)
-               sysblk_ppas[i].ppa = 0;
-
-       /* if possible, place sysblk at first channel, middle channel and last
-        * channel of the device. If not, create only one or two sys blocks
-        */
-       switch (geo->nr_chnls) {
-       case 2:
-               sysblk_ppas[1].g.ch = 1;
-               /* fall-through */
-       case 1:
-               sysblk_ppas[0].g.ch = 0;
-               break;
-       default:
-               sysblk_ppas[0].g.ch = 0;
-               sysblk_ppas[1].g.ch = geo->nr_chnls / 2;
-               sysblk_ppas[2].g.ch = geo->nr_chnls - 1;
-               break;
-       }
-
-       return nr_rows;
-}
-
-static void nvm_setup_sysblk_scan(struct nvm_dev *dev, struct sysblk_scan *s,
-                                               struct ppa_addr *sysblk_ppas)
-{
-       memset(s, 0, sizeof(struct sysblk_scan));
-       s->nr_rows = nvm_setup_sysblks(dev, sysblk_ppas);
-}
-
-static int sysblk_get_free_blks(struct nvm_dev *dev, struct ppa_addr ppa,
-                                       u8 *blks, int nr_blks,
-                                       struct sysblk_scan *s)
-{
-       struct ppa_addr *sppa;
-       int i, blkid = 0;
-
-       nr_blks = nvm_bb_tbl_fold(dev, blks, nr_blks);
-       if (nr_blks < 0)
-               return nr_blks;
-
-       for (i = 0; i < nr_blks; i++) {
-               if (blks[i] == NVM_BLK_T_HOST)
-                       return -EEXIST;
-
-               if (blks[i] != NVM_BLK_T_FREE)
-                       continue;
-
-               sppa = &s->ppas[scan_ppa_idx(s->row, blkid)];
-               sppa->g.ch = ppa.g.ch;
-               sppa->g.lun = ppa.g.lun;
-               sppa->g.blk = i;
-               s->nr_ppas++;
-               blkid++;
-
-               pr_debug("nvm: use (%u %u %u) as sysblk\n",
-                                       sppa->g.ch, sppa->g.lun, sppa->g.blk);
-               if (blkid > MAX_BLKS_PR_SYSBLK - 1)
-                       return 0;
-       }
-
-       pr_err("nvm: sysblk failed get sysblk\n");
-       return -EINVAL;
-}
-
-static int sysblk_get_host_blks(struct nvm_dev *dev, struct ppa_addr ppa,
-                                       u8 *blks, int nr_blks,
-                                       struct sysblk_scan *s)
-{
-       int i, nr_sysblk = 0;
-
-       nr_blks = nvm_bb_tbl_fold(dev, blks, nr_blks);
-       if (nr_blks < 0)
-               return nr_blks;
-
-       for (i = 0; i < nr_blks; i++) {
-               if (blks[i] != NVM_BLK_T_HOST)
-                       continue;
-
-               if (s->nr_ppas == MAX_BLKS_PR_SYSBLK * MAX_SYSBLKS) {
-                       pr_err("nvm: too many host blks\n");
-                       return -EINVAL;
-               }
-
-               ppa.g.blk = i;
-
-               s->ppas[scan_ppa_idx(s->row, nr_sysblk)] = ppa;
-               s->nr_ppas++;
-               nr_sysblk++;
-       }
-
-       return 0;
-}
-
-static int nvm_get_all_sysblks(struct nvm_dev *dev, struct sysblk_scan *s,
-                               struct ppa_addr *ppas, int get_free)
-{
-       struct nvm_geo *geo = &dev->geo;
-       int i, nr_blks, ret = 0;
-       u8 *blks;
-
-       s->nr_ppas = 0;
-       nr_blks = geo->blks_per_lun * geo->plane_mode;
-
-       blks = kmalloc(nr_blks, GFP_KERNEL);
-       if (!blks)
-               return -ENOMEM;
-
-       for (i = 0; i < s->nr_rows; i++) {
-               s->row = i;
-
-               ret = nvm_get_bb_tbl(dev, ppas[i], blks);
-               if (ret) {
-                       pr_err("nvm: failed bb tbl for ppa (%u %u)\n",
-                                                       ppas[i].g.ch,
-                                                       ppas[i].g.blk);
-                       goto err_get;
-               }
-
-               if (get_free)
-                       ret = sysblk_get_free_blks(dev, ppas[i], blks, nr_blks,
-                                                                       s);
-               else
-                       ret = sysblk_get_host_blks(dev, ppas[i], blks, nr_blks,
-                                                                       s);
-
-               if (ret)
-                       goto err_get;
-       }
-
-err_get:
-       kfree(blks);
-       return ret;
-}
-
-/*
- * scans a block for latest sysblk.
- * Returns:
- *     0 - newer sysblk not found. PPA is updated to latest page.
- *     1 - newer sysblk found and stored in *cur. PPA is updated to
- *         next valid page.
- *     <0- error.
- */
-static int nvm_scan_block(struct nvm_dev *dev, struct ppa_addr *ppa,
-                                               struct nvm_system_block *sblk)
-{
-       struct nvm_geo *geo = &dev->geo;
-       struct nvm_system_block *cur;
-       int pg, ret, found = 0;
-
-       /* the full buffer for a flash page is allocated. Only the first of it
-        * contains the system block information
-        */
-       cur = kmalloc(geo->pfpg_size, GFP_KERNEL);
-       if (!cur)
-               return -ENOMEM;
-
-       /* perform linear scan through the block */
-       for (pg = 0; pg < dev->lps_per_blk; pg++) {
-               ppa->g.pg = ppa_to_slc(dev, pg);
-
-               ret = nvm_submit_ppa(dev, ppa, 1, NVM_OP_PREAD, NVM_IO_SLC_MODE,
-                                                       cur, geo->pfpg_size);
-               if (ret) {
-                       if (ret == NVM_RSP_ERR_EMPTYPAGE) {
-                               pr_debug("nvm: sysblk scan empty ppa (%u %u %u %u)\n",
-                                                       ppa->g.ch,
-                                                       ppa->g.lun,
-                                                       ppa->g.blk,
-                                                       ppa->g.pg);
-                               break;
-                       }
-                       pr_err("nvm: read failed (%x) for ppa (%u %u %u %u)",
-                                                       ret,
-                                                       ppa->g.ch,
-                                                       ppa->g.lun,
-                                                       ppa->g.blk,
-                                                       ppa->g.pg);
-                       break; /* if we can't read a page, continue to the
-                               * next blk
-                               */
-               }
-
-               if (be32_to_cpu(cur->magic) != NVM_SYSBLK_MAGIC) {
-                       pr_debug("nvm: scan break for ppa (%u %u %u %u)\n",
-                                                       ppa->g.ch,
-                                                       ppa->g.lun,
-                                                       ppa->g.blk,
-                                                       ppa->g.pg);
-                       break; /* last valid page already found */
-               }
-
-               if (be32_to_cpu(cur->seqnr) < be32_to_cpu(sblk->seqnr))
-                       continue;
-
-               memcpy(sblk, cur, sizeof(struct nvm_system_block));
-               found = 1;
-       }
-
-       kfree(cur);
-
-       return found;
-}
-
-static int nvm_sysblk_set_bb_tbl(struct nvm_dev *dev, struct sysblk_scan *s,
-                                                               int type)
-{
-       return nvm_set_bb_tbl(dev, s->ppas, s->nr_ppas, type);
-}
-
-static int nvm_write_and_verify(struct nvm_dev *dev, struct nvm_sb_info *info,
-                                                       struct sysblk_scan *s)
-{
-       struct nvm_geo *geo = &dev->geo;
-       struct nvm_system_block nvmsb;
-       void *buf;
-       int i, sect, ret = 0;
-       struct ppa_addr *ppas;
-
-       nvm_cpu_to_sysblk(&nvmsb, info);
-
-       buf = kzalloc(geo->pfpg_size, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-       memcpy(buf, &nvmsb, sizeof(struct nvm_system_block));
-
-       ppas = kcalloc(geo->sec_per_pg, sizeof(struct ppa_addr), GFP_KERNEL);
-       if (!ppas) {
-               ret = -ENOMEM;
-               goto err;
-       }
-
-       /* Write and verify */
-       for (i = 0; i < s->nr_rows; i++) {
-               ppas[0] = s->ppas[scan_ppa_idx(i, s->act_blk[i])];
-
-               pr_debug("nvm: writing sysblk to ppa (%u %u %u %u)\n",
-                                                       ppas[0].g.ch,
-                                                       ppas[0].g.lun,
-                                                       ppas[0].g.blk,
-                                                       ppas[0].g.pg);
-
-               /* Expand to all sectors within a flash page */
-               if (geo->sec_per_pg > 1) {
-                       for (sect = 1; sect < geo->sec_per_pg; sect++) {
-                               ppas[sect].ppa = ppas[0].ppa;
-                               ppas[sect].g.sec = sect;
-                       }
-               }
-
-               ret = nvm_submit_ppa(dev, ppas, geo->sec_per_pg, NVM_OP_PWRITE,
-                                       NVM_IO_SLC_MODE, buf, geo->pfpg_size);
-               if (ret) {
-                       pr_err("nvm: sysblk failed program (%u %u %u)\n",
-                                                       ppas[0].g.ch,
-                                                       ppas[0].g.lun,
-                                                       ppas[0].g.blk);
-                       break;
-               }
-
-               ret = nvm_submit_ppa(dev, ppas, geo->sec_per_pg, NVM_OP_PREAD,
-                                       NVM_IO_SLC_MODE, buf, geo->pfpg_size);
-               if (ret) {
-                       pr_err("nvm: sysblk failed read (%u %u %u)\n",
-                                                       ppas[0].g.ch,
-                                                       ppas[0].g.lun,
-                                                       ppas[0].g.blk);
-                       break;
-               }
-
-               if (memcmp(buf, &nvmsb, sizeof(struct nvm_system_block))) {
-                       pr_err("nvm: sysblk failed verify (%u %u %u)\n",
-                                                       ppas[0].g.ch,
-                                                       ppas[0].g.lun,
-                                                       ppas[0].g.blk);
-                       ret = -EINVAL;
-                       break;
-               }
-       }
-
-       kfree(ppas);
-err:
-       kfree(buf);
-
-       return ret;
-}
-
-static int nvm_prepare_new_sysblks(struct nvm_dev *dev, struct sysblk_scan *s)
-{
-       int i, ret;
-       unsigned long nxt_blk;
-       struct ppa_addr *ppa;
-
-       for (i = 0; i < s->nr_rows; i++) {
-               nxt_blk = (s->act_blk[i] + 1) % MAX_BLKS_PR_SYSBLK;
-               ppa = &s->ppas[scan_ppa_idx(i, nxt_blk)];
-               ppa->g.pg = ppa_to_slc(dev, 0);
-
-               ret = nvm_erase_ppa(dev, ppa, 1, 0);
-               if (ret)
-                       return ret;
-
-               s->act_blk[i] = nxt_blk;
-       }
-
-       return 0;
-}
-
-int nvm_get_sysblock(struct nvm_dev *dev, struct nvm_sb_info *info)
-{
-       struct ppa_addr sysblk_ppas[MAX_SYSBLKS];
-       struct sysblk_scan s;
-       struct nvm_system_block *cur;
-       int i, j, found = 0;
-       int ret = -ENOMEM;
-
-       /*
-        * 1. setup sysblk locations
-        * 2. get bad block list
-        * 3. filter on host-specific (type 3)
-        * 4. iterate through all and find the highest seq nr.
-        * 5. return superblock information
-        */
-
-       if (!dev->ops->get_bb_tbl)
-               return -EINVAL;
-
-       nvm_setup_sysblk_scan(dev, &s, sysblk_ppas);
-
-       mutex_lock(&dev->mlock);
-       ret = nvm_get_all_sysblks(dev, &s, sysblk_ppas, 0);
-       if (ret)
-               goto err_sysblk;
-
-       /* no sysblocks initialized */
-       if (!s.nr_ppas)
-               goto err_sysblk;
-
-       cur = kzalloc(sizeof(struct nvm_system_block), GFP_KERNEL);
-       if (!cur)
-               goto err_sysblk;
-
-       /* find the latest block across all sysblocks */
-       for (i = 0; i < s.nr_rows; i++) {
-               for (j = 0; j < MAX_BLKS_PR_SYSBLK; j++) {
-                       struct ppa_addr ppa = s.ppas[scan_ppa_idx(i, j)];
-
-                       ret = nvm_scan_block(dev, &ppa, cur);
-                       if (ret > 0)
-                               found = 1;
-                       else if (ret < 0)
-                               break;
-               }
-       }
-
-       nvm_sysblk_to_cpu(info, cur);
-
-       kfree(cur);
-err_sysblk:
-       mutex_unlock(&dev->mlock);
-
-       if (found)
-               return 1;
-       return ret;
-}
-
-int nvm_update_sysblock(struct nvm_dev *dev, struct nvm_sb_info *new)
-{
-       /* 1. for each latest superblock
-        * 2. if room
-        *    a. write new flash page entry with the updated information
-        * 3. if no room
-        *    a. find next available block on lun (linear search)
-        *       if none, continue to next lun
-        *       if none at all, report error. also report that it wasn't
-        *       possible to write to all superblocks.
-        *    c. write data to block.
-        */
-       struct ppa_addr sysblk_ppas[MAX_SYSBLKS];
-       struct sysblk_scan s;
-       struct nvm_system_block *cur;
-       int i, j, ppaidx, found = 0;
-       int ret = -ENOMEM;
-
-       if (!dev->ops->get_bb_tbl)
-               return -EINVAL;
-
-       nvm_setup_sysblk_scan(dev, &s, sysblk_ppas);
-
-       mutex_lock(&dev->mlock);
-       ret = nvm_get_all_sysblks(dev, &s, sysblk_ppas, 0);
-       if (ret)
-               goto err_sysblk;
-
-       cur = kzalloc(sizeof(struct nvm_system_block), GFP_KERNEL);
-       if (!cur)
-               goto err_sysblk;
-
-       /* Get the latest sysblk for each sysblk row */
-       for (i = 0; i < s.nr_rows; i++) {
-               found = 0;
-               for (j = 0; j < MAX_BLKS_PR_SYSBLK; j++) {
-                       ppaidx = scan_ppa_idx(i, j);
-                       ret = nvm_scan_block(dev, &s.ppas[ppaidx], cur);
-                       if (ret > 0) {
-                               s.act_blk[i] = j;
-                               found = 1;
-                       } else if (ret < 0)
-                               break;
-               }
-       }
-
-       if (!found) {
-               pr_err("nvm: no valid sysblks found to update\n");
-               ret = -EINVAL;
-               goto err_cur;
-       }
-
-       /*
-        * All sysblocks found. Check that they have same page id in their flash
-        * blocks
-        */
-       for (i = 1; i < s.nr_rows; i++) {
-               struct ppa_addr l = s.ppas[scan_ppa_idx(0, s.act_blk[0])];
-               struct ppa_addr r = s.ppas[scan_ppa_idx(i, s.act_blk[i])];
-
-               if (l.g.pg != r.g.pg) {
-                       pr_err("nvm: sysblks not on same page. Previous update failed.\n");
-                       ret = -EINVAL;
-                       goto err_cur;
-               }
-       }
-
-       /*
-        * Check that there haven't been another update to the seqnr since we
-        * began
-        */
-       if ((new->seqnr - 1) != be32_to_cpu(cur->seqnr)) {
-               pr_err("nvm: seq is not sequential\n");
-               ret = -EINVAL;
-               goto err_cur;
-       }
-
-       /*
-        * When all pages in a block has been written, a new block is selected
-        * and writing is performed on the new block.
-        */
-       if (s.ppas[scan_ppa_idx(0, s.act_blk[0])].g.pg ==
-                                               dev->lps_per_blk - 1) {
-               ret = nvm_prepare_new_sysblks(dev, &s);
-               if (ret)
-                       goto err_cur;
-       }
-
-       ret = nvm_write_and_verify(dev, new, &s);
-err_cur:
-       kfree(cur);
-err_sysblk:
-       mutex_unlock(&dev->mlock);
-
-       return ret;
-}
-
-int nvm_init_sysblock(struct nvm_dev *dev, struct nvm_sb_info *info)
-{
-       struct nvm_geo *geo = &dev->geo;
-       struct ppa_addr sysblk_ppas[MAX_SYSBLKS];
-       struct sysblk_scan s;
-       int ret;
-
-       /*
-        * 1. select master blocks and select first available blks
-        * 2. get bad block list
-        * 3. mark MAX_SYSBLKS block as host-based device allocated.
-        * 4. write and verify data to block
-        */
-
-       if (!dev->ops->get_bb_tbl || !dev->ops->set_bb_tbl)
-               return -EINVAL;
-
-       if (!(geo->mccap & NVM_ID_CAP_SLC) || !dev->lps_per_blk) {
-               pr_err("nvm: memory does not support SLC access\n");
-               return -EINVAL;
-       }
-
-       /* Index all sysblocks and mark them as host-driven */
-       nvm_setup_sysblk_scan(dev, &s, sysblk_ppas);
-
-       mutex_lock(&dev->mlock);
-       ret = nvm_get_all_sysblks(dev, &s, sysblk_ppas, 1);
-       if (ret)
-               goto err_mark;
-
-       ret = nvm_sysblk_set_bb_tbl(dev, &s, NVM_BLK_T_HOST);
-       if (ret)
-               goto err_mark;
-
-       /* Write to the first block of each row */
-       ret = nvm_write_and_verify(dev, info, &s);
-err_mark:
-       mutex_unlock(&dev->mlock);
-       return ret;
-}
-
-static int factory_nblks(int nblks)
-{
-       /* Round up to nearest BITS_PER_LONG */
-       return (nblks + (BITS_PER_LONG - 1)) & ~(BITS_PER_LONG - 1);
-}
-
-static unsigned int factory_blk_offset(struct nvm_geo *geo, struct ppa_addr ppa)
-{
-       int nblks = factory_nblks(geo->blks_per_lun);
-
-       return ((ppa.g.ch * geo->luns_per_chnl * nblks) + (ppa.g.lun * nblks)) /
-                                                               BITS_PER_LONG;
-}
-
-static int nvm_factory_blks(struct nvm_dev *dev, struct ppa_addr ppa,
-                                       u8 *blks, int nr_blks,
-                                       unsigned long *blk_bitmap, int flags)
-{
-       int i, lunoff;
-
-       nr_blks = nvm_bb_tbl_fold(dev, blks, nr_blks);
-       if (nr_blks < 0)
-               return nr_blks;
-
-       lunoff = factory_blk_offset(&dev->geo, ppa);
-
-       /* non-set bits correspond to the block must be erased */
-       for (i = 0; i < nr_blks; i++) {
-               switch (blks[i]) {
-               case NVM_BLK_T_FREE:
-                       if (flags & NVM_FACTORY_ERASE_ONLY_USER)
-                               set_bit(i, &blk_bitmap[lunoff]);
-                       break;
-               case NVM_BLK_T_HOST:
-                       if (!(flags & NVM_FACTORY_RESET_HOST_BLKS))
-                               set_bit(i, &blk_bitmap[lunoff]);
-                       break;
-               case NVM_BLK_T_GRWN_BAD:
-                       if (!(flags & NVM_FACTORY_RESET_GRWN_BBLKS))
-                               set_bit(i, &blk_bitmap[lunoff]);
-                       break;
-               default:
-                       set_bit(i, &blk_bitmap[lunoff]);
-                       break;
-               }
-       }
-
-       return 0;
-}
-
-static int nvm_fact_get_blks(struct nvm_dev *dev, struct ppa_addr *erase_list,
-                                       int max_ppas, unsigned long *blk_bitmap)
-{
-       struct nvm_geo *geo = &dev->geo;
-       struct ppa_addr ppa;
-       int ch, lun, blkid, idx, done = 0, ppa_cnt = 0;
-       unsigned long *offset;
-
-       while (!done) {
-               done = 1;
-               nvm_for_each_lun_ppa(geo, ppa, ch, lun) {
-                       idx = factory_blk_offset(geo, ppa);
-                       offset = &blk_bitmap[idx];
-
-                       blkid = find_first_zero_bit(offset, geo->blks_per_lun);
-                       if (blkid >= geo->blks_per_lun)
-                               continue;
-                       set_bit(blkid, offset);
-
-                       ppa.g.blk = blkid;
-                       pr_debug("nvm: erase ppa (%u %u %u)\n",
-                                                       ppa.g.ch,
-                                                       ppa.g.lun,
-                                                       ppa.g.blk);
-
-                       erase_list[ppa_cnt] = ppa;
-                       ppa_cnt++;
-                       done = 0;
-
-                       if (ppa_cnt == max_ppas)
-                               return ppa_cnt;
-               }
-       }
-
-       return ppa_cnt;
-}
-
-static int nvm_fact_select_blks(struct nvm_dev *dev, unsigned long *blk_bitmap,
-                                                               int flags)
-{
-       struct nvm_geo *geo = &dev->geo;
-       struct ppa_addr ppa;
-       int ch, lun, nr_blks, ret = 0;
-       u8 *blks;
-
-       nr_blks = geo->blks_per_lun * geo->plane_mode;
-       blks = kmalloc(nr_blks, GFP_KERNEL);
-       if (!blks)
-               return -ENOMEM;
-
-       nvm_for_each_lun_ppa(geo, ppa, ch, lun) {
-               ret = nvm_get_bb_tbl(dev, ppa, blks);
-               if (ret)
-                       pr_err("nvm: failed bb tbl for ch%u lun%u\n",
-                                                       ppa.g.ch, ppa.g.blk);
-
-               ret = nvm_factory_blks(dev, ppa, blks, nr_blks, blk_bitmap,
-                                                                       flags);
-               if (ret)
-                       break;
-       }
-
-       kfree(blks);
-       return ret;
-}
-
-int nvm_dev_factory(struct nvm_dev *dev, int flags)
-{
-       struct nvm_geo *geo = &dev->geo;
-       struct ppa_addr *ppas;
-       int ppa_cnt, ret = -ENOMEM;
-       int max_ppas = dev->ops->max_phys_sect / geo->nr_planes;
-       struct ppa_addr sysblk_ppas[MAX_SYSBLKS];
-       struct sysblk_scan s;
-       unsigned long *blk_bitmap;
-
-       blk_bitmap = kzalloc(factory_nblks(geo->blks_per_lun) * geo->nr_luns,
-                                                               GFP_KERNEL);
-       if (!blk_bitmap)
-               return ret;
-
-       ppas = kcalloc(max_ppas, sizeof(struct ppa_addr), GFP_KERNEL);
-       if (!ppas)
-               goto err_blks;
-
-       /* create list of blks to be erased */
-       ret = nvm_fact_select_blks(dev, blk_bitmap, flags);
-       if (ret)
-               goto err_ppas;
-
-       /* continue to erase until list of blks until empty */
-       while ((ppa_cnt =
-                       nvm_fact_get_blks(dev, ppas, max_ppas, blk_bitmap)) > 0)
-               nvm_erase_ppa(dev, ppas, ppa_cnt, 0);
-
-       /* mark host reserved blocks free */
-       if (flags & NVM_FACTORY_RESET_HOST_BLKS) {
-               nvm_setup_sysblk_scan(dev, &s, sysblk_ppas);
-               mutex_lock(&dev->mlock);
-               ret = nvm_get_all_sysblks(dev, &s, sysblk_ppas, 0);
-               if (!ret)
-                       ret = nvm_sysblk_set_bb_tbl(dev, &s, NVM_BLK_T_FREE);
-               mutex_unlock(&dev->mlock);
-       }
-err_ppas:
-       kfree(ppas);
-err_blks:
-       kfree(blk_bitmap);
-       return ret;
-}
-EXPORT_SYMBOL(nvm_dev_factory);
index 76d20875503c17c6f5956d7f7bfde4eaa90ffbcd..709c9cc34369fe5c0e0b206673debfcf0c3efe4f 100644 (file)
@@ -666,7 +666,7 @@ static inline struct search *search_alloc(struct bio *bio,
        s->iop.write_prio       = 0;
        s->iop.error            = 0;
        s->iop.flags            = 0;
-       s->iop.flush_journal    = (bio->bi_opf & (REQ_PREFLUSH|REQ_FUA)) != 0;
+       s->iop.flush_journal    = op_is_flush(bio->bi_opf);
        s->iop.wq               = bcache_wq;
 
        return s;
@@ -1009,7 +1009,7 @@ static int cached_dev_congested(void *data, int bits)
        struct request_queue *q = bdev_get_queue(dc->bdev);
        int ret = 0;
 
-       if (bdi_congested(&q->backing_dev_info, bits))
+       if (bdi_congested(q->backing_dev_info, bits))
                return 1;
 
        if (cached_dev_get(dc)) {
@@ -1018,7 +1018,7 @@ static int cached_dev_congested(void *data, int bits)
 
                for_each_cache(ca, d->c, i) {
                        q = bdev_get_queue(ca->bdev);
-                       ret |= bdi_congested(&q->backing_dev_info, bits);
+                       ret |= bdi_congested(q->backing_dev_info, bits);
                }
 
                cached_dev_put(dc);
@@ -1032,7 +1032,7 @@ void bch_cached_dev_request_init(struct cached_dev *dc)
        struct gendisk *g = dc->disk.disk;
 
        g->queue->make_request_fn               = cached_dev_make_request;
-       g->queue->backing_dev_info.congested_fn = cached_dev_congested;
+       g->queue->backing_dev_info->congested_fn = cached_dev_congested;
        dc->disk.cache_miss                     = cached_dev_cache_miss;
        dc->disk.ioctl                          = cached_dev_ioctl;
 }
@@ -1125,7 +1125,7 @@ static int flash_dev_congested(void *data, int bits)
 
        for_each_cache(ca, d->c, i) {
                q = bdev_get_queue(ca->bdev);
-               ret |= bdi_congested(&q->backing_dev_info, bits);
+               ret |= bdi_congested(q->backing_dev_info, bits);
        }
 
        return ret;
@@ -1136,7 +1136,7 @@ void bch_flash_dev_request_init(struct bcache_device *d)
        struct gendisk *g = d->disk;
 
        g->queue->make_request_fn               = flash_dev_make_request;
-       g->queue->backing_dev_info.congested_fn = flash_dev_congested;
+       g->queue->backing_dev_info->congested_fn = flash_dev_congested;
        d->cache_miss                           = flash_dev_cache_miss;
        d->ioctl                                = flash_dev_ioctl;
 }
index 3a19cbc8b230e5a7b77cafa89427b8e282c251dc..85e3f21c251485ecfd56780110896c05c8429cef 100644 (file)
@@ -807,7 +807,7 @@ static int bcache_device_init(struct bcache_device *d, unsigned block_size,
        blk_queue_make_request(q, NULL);
        d->disk->queue                  = q;
        q->queuedata                    = d;
-       q->backing_dev_info.congested_data = d;
+       q->backing_dev_info->congested_data = d;
        q->limits.max_hw_sectors        = UINT_MAX;
        q->limits.max_sectors           = UINT_MAX;
        q->limits.max_segment_size      = UINT_MAX;
@@ -1132,9 +1132,9 @@ static int cached_dev_init(struct cached_dev *dc, unsigned block_size)
        set_capacity(dc->disk.disk,
                     dc->bdev->bd_part->nr_sects - dc->sb.data_offset);
 
-       dc->disk.disk->queue->backing_dev_info.ra_pages =
-               max(dc->disk.disk->queue->backing_dev_info.ra_pages,
-                   q->backing_dev_info.ra_pages);
+       dc->disk.disk->queue->backing_dev_info->ra_pages =
+               max(dc->disk.disk->queue->backing_dev_info->ra_pages,
+                   q->backing_dev_info->ra_pages);
 
        bch_cached_dev_request_init(dc);
        bch_cached_dev_writeback_init(dc);
index 624fe4319b24ad0f338e912a07a5040ad91ad4c9..e4c2c1a1e9933282fa2b971999270199c8d9c224 100644 (file)
@@ -25,7 +25,7 @@
  * defines a range of metadata versions that this module can handle.
  */
 #define MIN_CACHE_VERSION 1
-#define MAX_CACHE_VERSION 1
+#define MAX_CACHE_VERSION 2
 
 #define CACHE_METADATA_CACHE_SIZE 64
 
@@ -55,6 +55,7 @@ enum mapping_bits {
 
        /*
         * The data on the cache is different from that on the origin.
+        * This flag is only used by metadata format 1.
         */
        M_DIRTY = 2
 };
@@ -93,12 +94,18 @@ struct cache_disk_superblock {
        __le32 write_misses;
 
        __le32 policy_version[CACHE_POLICY_VERSION_SIZE];
+
+       /*
+        * Metadata format 2 fields.
+        */
+       __le64 dirty_root;
 } __packed;
 
 struct dm_cache_metadata {
        atomic_t ref_count;
        struct list_head list;
 
+       unsigned version;
        struct block_device *bdev;
        struct dm_block_manager *bm;
        struct dm_space_map *metadata_sm;
@@ -141,12 +148,19 @@ struct dm_cache_metadata {
         */
        bool fail_io:1;
 
+       /*
+        * Metadata format 2 fields.
+        */
+       dm_block_t dirty_root;
+       struct dm_disk_bitset dirty_info;
+
        /*
         * These structures are used when loading metadata.  They're too
         * big to put on the stack.
         */
        struct dm_array_cursor mapping_cursor;
        struct dm_array_cursor hint_cursor;
+       struct dm_bitset_cursor dirty_cursor;
 };
 
 /*-------------------------------------------------------------------
@@ -170,6 +184,7 @@ static void sb_prepare_for_write(struct dm_block_validator *v,
 static int check_metadata_version(struct cache_disk_superblock *disk_super)
 {
        uint32_t metadata_version = le32_to_cpu(disk_super->version);
+
        if (metadata_version < MIN_CACHE_VERSION || metadata_version > MAX_CACHE_VERSION) {
                DMERR("Cache metadata version %u found, but only versions between %u and %u supported.",
                      metadata_version, MIN_CACHE_VERSION, MAX_CACHE_VERSION);
@@ -310,6 +325,11 @@ static void __copy_sm_root(struct dm_cache_metadata *cmd,
               sizeof(cmd->metadata_space_map_root));
 }
 
+static bool separate_dirty_bits(struct dm_cache_metadata *cmd)
+{
+       return cmd->version >= 2;
+}
+
 static int __write_initial_superblock(struct dm_cache_metadata *cmd)
 {
        int r;
@@ -341,7 +361,7 @@ static int __write_initial_superblock(struct dm_cache_metadata *cmd)
        disk_super->flags = 0;
        memset(disk_super->uuid, 0, sizeof(disk_super->uuid));
        disk_super->magic = cpu_to_le64(CACHE_SUPERBLOCK_MAGIC);
-       disk_super->version = cpu_to_le32(MAX_CACHE_VERSION);
+       disk_super->version = cpu_to_le32(cmd->version);
        memset(disk_super->policy_name, 0, sizeof(disk_super->policy_name));
        memset(disk_super->policy_version, 0, sizeof(disk_super->policy_version));
        disk_super->policy_hint_size = 0;
@@ -362,6 +382,9 @@ static int __write_initial_superblock(struct dm_cache_metadata *cmd)
        disk_super->write_hits = cpu_to_le32(0);
        disk_super->write_misses = cpu_to_le32(0);
 
+       if (separate_dirty_bits(cmd))
+               disk_super->dirty_root = cpu_to_le64(cmd->dirty_root);
+
        return dm_tm_commit(cmd->tm, sblock);
 }
 
@@ -382,6 +405,13 @@ static int __format_metadata(struct dm_cache_metadata *cmd)
        if (r < 0)
                goto bad;
 
+       if (separate_dirty_bits(cmd)) {
+               dm_disk_bitset_init(cmd->tm, &cmd->dirty_info);
+               r = dm_bitset_empty(&cmd->dirty_info, &cmd->dirty_root);
+               if (r < 0)
+                       goto bad;
+       }
+
        dm_disk_bitset_init(cmd->tm, &cmd->discard_info);
        r = dm_bitset_empty(&cmd->discard_info, &cmd->discard_root);
        if (r < 0)
@@ -407,9 +437,10 @@ bad:
 static int __check_incompat_features(struct cache_disk_superblock *disk_super,
                                     struct dm_cache_metadata *cmd)
 {
-       uint32_t features;
+       uint32_t incompat_flags, features;
 
-       features = le32_to_cpu(disk_super->incompat_flags) & ~DM_CACHE_FEATURE_INCOMPAT_SUPP;
+       incompat_flags = le32_to_cpu(disk_super->incompat_flags);
+       features = incompat_flags & ~DM_CACHE_FEATURE_INCOMPAT_SUPP;
        if (features) {
                DMERR("could not access metadata due to unsupported optional features (%lx).",
                      (unsigned long)features);
@@ -470,6 +501,7 @@ static int __open_metadata(struct dm_cache_metadata *cmd)
        }
 
        __setup_mapping_info(cmd);
+       dm_disk_bitset_init(cmd->tm, &cmd->dirty_info);
        dm_disk_bitset_init(cmd->tm, &cmd->discard_info);
        sb_flags = le32_to_cpu(disk_super->flags);
        cmd->clean_when_opened = test_bit(CLEAN_SHUTDOWN, &sb_flags);
@@ -548,6 +580,7 @@ static unsigned long clear_clean_shutdown(unsigned long flags)
 static void read_superblock_fields(struct dm_cache_metadata *cmd,
                                   struct cache_disk_superblock *disk_super)
 {
+       cmd->version = le32_to_cpu(disk_super->version);
        cmd->flags = le32_to_cpu(disk_super->flags);
        cmd->root = le64_to_cpu(disk_super->mapping_root);
        cmd->hint_root = le64_to_cpu(disk_super->hint_root);
@@ -567,6 +600,9 @@ static void read_superblock_fields(struct dm_cache_metadata *cmd,
        cmd->stats.write_hits = le32_to_cpu(disk_super->write_hits);
        cmd->stats.write_misses = le32_to_cpu(disk_super->write_misses);
 
+       if (separate_dirty_bits(cmd))
+               cmd->dirty_root = le64_to_cpu(disk_super->dirty_root);
+
        cmd->changed = false;
 }
 
@@ -625,6 +661,13 @@ static int __commit_transaction(struct dm_cache_metadata *cmd,
         */
        BUILD_BUG_ON(sizeof(struct cache_disk_superblock) > 512);
 
+       if (separate_dirty_bits(cmd)) {
+               r = dm_bitset_flush(&cmd->dirty_info, cmd->dirty_root,
+                                   &cmd->dirty_root);
+               if (r)
+                       return r;
+       }
+
        r = dm_bitset_flush(&cmd->discard_info, cmd->discard_root,
                            &cmd->discard_root);
        if (r)
@@ -649,6 +692,8 @@ static int __commit_transaction(struct dm_cache_metadata *cmd,
                update_flags(disk_super, mutator);
 
        disk_super->mapping_root = cpu_to_le64(cmd->root);
+       if (separate_dirty_bits(cmd))
+               disk_super->dirty_root = cpu_to_le64(cmd->dirty_root);
        disk_super->hint_root = cpu_to_le64(cmd->hint_root);
        disk_super->discard_root = cpu_to_le64(cmd->discard_root);
        disk_super->discard_block_size = cpu_to_le64(cmd->discard_block_size);
@@ -698,7 +743,8 @@ static void unpack_value(__le64 value_le, dm_oblock_t *block, unsigned *flags)
 static struct dm_cache_metadata *metadata_open(struct block_device *bdev,
                                               sector_t data_block_size,
                                               bool may_format_device,
-                                              size_t policy_hint_size)
+                                              size_t policy_hint_size,
+                                              unsigned metadata_version)
 {
        int r;
        struct dm_cache_metadata *cmd;
@@ -709,6 +755,7 @@ static struct dm_cache_metadata *metadata_open(struct block_device *bdev,
                return ERR_PTR(-ENOMEM);
        }
 
+       cmd->version = metadata_version;
        atomic_set(&cmd->ref_count, 1);
        init_rwsem(&cmd->root_lock);
        cmd->bdev = bdev;
@@ -757,7 +804,8 @@ static struct dm_cache_metadata *lookup(struct block_device *bdev)
 static struct dm_cache_metadata *lookup_or_open(struct block_device *bdev,
                                                sector_t data_block_size,
                                                bool may_format_device,
-                                               size_t policy_hint_size)
+                                               size_t policy_hint_size,
+                                               unsigned metadata_version)
 {
        struct dm_cache_metadata *cmd, *cmd2;
 
@@ -768,7 +816,8 @@ static struct dm_cache_metadata *lookup_or_open(struct block_device *bdev,
        if (cmd)
                return cmd;
 
-       cmd = metadata_open(bdev, data_block_size, may_format_device, policy_hint_size);
+       cmd = metadata_open(bdev, data_block_size, may_format_device,
+                           policy_hint_size, metadata_version);
        if (!IS_ERR(cmd)) {
                mutex_lock(&table_lock);
                cmd2 = lookup(bdev);
@@ -800,10 +849,11 @@ static bool same_params(struct dm_cache_metadata *cmd, sector_t data_block_size)
 struct dm_cache_metadata *dm_cache_metadata_open(struct block_device *bdev,
                                                 sector_t data_block_size,
                                                 bool may_format_device,
-                                                size_t policy_hint_size)
+                                                size_t policy_hint_size,
+                                                unsigned metadata_version)
 {
-       struct dm_cache_metadata *cmd = lookup_or_open(bdev, data_block_size,
-                                                      may_format_device, policy_hint_size);
+       struct dm_cache_metadata *cmd = lookup_or_open(bdev, data_block_size, may_format_device,
+                                                      policy_hint_size, metadata_version);
 
        if (!IS_ERR(cmd) && !same_params(cmd, data_block_size)) {
                dm_cache_metadata_close(cmd);
@@ -829,8 +879,8 @@ void dm_cache_metadata_close(struct dm_cache_metadata *cmd)
 /*
  * Checks that the given cache block is either unmapped or clean.
  */
-static int block_unmapped_or_clean(struct dm_cache_metadata *cmd, dm_cblock_t b,
-                                  bool *result)
+static int block_clean_combined_dirty(struct dm_cache_metadata *cmd, dm_cblock_t b,
+                                     bool *result)
 {
        int r;
        __le64 value;
@@ -838,10 +888,8 @@ static int block_unmapped_or_clean(struct dm_cache_metadata *cmd, dm_cblock_t b,
        unsigned flags;
 
        r = dm_array_get_value(&cmd->info, cmd->root, from_cblock(b), &value);
-       if (r) {
-               DMERR("block_unmapped_or_clean failed");
+       if (r)
                return r;
-       }
 
        unpack_value(value, &ob, &flags);
        *result = !((flags & M_VALID) && (flags & M_DIRTY));
@@ -849,17 +897,19 @@ static int block_unmapped_or_clean(struct dm_cache_metadata *cmd, dm_cblock_t b,
        return 0;
 }
 
-static int blocks_are_unmapped_or_clean(struct dm_cache_metadata *cmd,
-                                       dm_cblock_t begin, dm_cblock_t end,
-                                       bool *result)
+static int blocks_are_clean_combined_dirty(struct dm_cache_metadata *cmd,
+                                          dm_cblock_t begin, dm_cblock_t end,
+                                          bool *result)
 {
        int r;
        *result = true;
 
        while (begin != end) {
-               r = block_unmapped_or_clean(cmd, begin, result);
-               if (r)
+               r = block_clean_combined_dirty(cmd, begin, result);
+               if (r) {
+                       DMERR("block_clean_combined_dirty failed");
                        return r;
+               }
 
                if (!*result) {
                        DMERR("cache block %llu is dirty",
@@ -873,6 +923,67 @@ static int blocks_are_unmapped_or_clean(struct dm_cache_metadata *cmd,
        return 0;
 }
 
+static int blocks_are_clean_separate_dirty(struct dm_cache_metadata *cmd,
+                                          dm_cblock_t begin, dm_cblock_t end,
+                                          bool *result)
+{
+       int r;
+       bool dirty_flag;
+       *result = true;
+
+       r = dm_bitset_cursor_begin(&cmd->dirty_info, cmd->dirty_root,
+                                  from_cblock(begin), &cmd->dirty_cursor);
+       if (r) {
+               DMERR("%s: dm_bitset_cursor_begin for dirty failed", __func__);
+               return r;
+       }
+
+       r = dm_bitset_cursor_skip(&cmd->dirty_cursor, from_cblock(begin));
+       if (r) {
+               DMERR("%s: dm_bitset_cursor_skip for dirty failed", __func__);
+               dm_bitset_cursor_end(&cmd->dirty_cursor);
+               return r;
+       }
+
+       while (begin != end) {
+               /*
+                * We assume that unmapped blocks have their dirty bit
+                * cleared.
+                */
+               dirty_flag = dm_bitset_cursor_get_value(&cmd->dirty_cursor);
+               if (dirty_flag) {
+                       DMERR("%s: cache block %llu is dirty", __func__,
+                             (unsigned long long) from_cblock(begin));
+                       dm_bitset_cursor_end(&cmd->dirty_cursor);
+                       *result = false;
+                       return 0;
+               }
+
+               r = dm_bitset_cursor_next(&cmd->dirty_cursor);
+               if (r) {
+                       DMERR("%s: dm_bitset_cursor_next for dirty failed", __func__);
+                       dm_bitset_cursor_end(&cmd->dirty_cursor);
+                       return r;
+               }
+
+               begin = to_cblock(from_cblock(begin) + 1);
+       }
+
+       dm_bitset_cursor_end(&cmd->dirty_cursor);
+
+       return 0;
+}
+
+static int blocks_are_unmapped_or_clean(struct dm_cache_metadata *cmd,
+                                       dm_cblock_t begin, dm_cblock_t end,
+                                       bool *result)
+{
+       if (separate_dirty_bits(cmd))
+               return blocks_are_clean_separate_dirty(cmd, begin, end, result);
+       else
+               return blocks_are_clean_combined_dirty(cmd, begin, end, result);
+}
+
 static bool cmd_write_lock(struct dm_cache_metadata *cmd)
 {
        down_write(&cmd->root_lock);
@@ -950,8 +1061,18 @@ int dm_cache_resize(struct dm_cache_metadata *cmd, dm_cblock_t new_cache_size)
        r = dm_array_resize(&cmd->info, cmd->root, from_cblock(cmd->cache_blocks),
                            from_cblock(new_cache_size),
                            &null_mapping, &cmd->root);
-       if (!r)
-               cmd->cache_blocks = new_cache_size;
+       if (r)
+               goto out;
+
+       if (separate_dirty_bits(cmd)) {
+               r = dm_bitset_resize(&cmd->dirty_info, cmd->dirty_root,
+                                    from_cblock(cmd->cache_blocks), from_cblock(new_cache_size),
+                                    false, &cmd->dirty_root);
+               if (r)
+                       goto out;
+       }
+
+       cmd->cache_blocks = new_cache_size;
        cmd->changed = true;
 
 out:
@@ -995,14 +1116,6 @@ static int __clear_discard(struct dm_cache_metadata *cmd, dm_dblock_t b)
                                   from_dblock(b), &cmd->discard_root);
 }
 
-static int __is_discarded(struct dm_cache_metadata *cmd, dm_dblock_t b,
-                         bool *is_discarded)
-{
-       return dm_bitset_test_bit(&cmd->discard_info, cmd->discard_root,
-                                 from_dblock(b), &cmd->discard_root,
-                                 is_discarded);
-}
-
 static int __discard(struct dm_cache_metadata *cmd,
                     dm_dblock_t dblock, bool discard)
 {
@@ -1032,22 +1145,38 @@ static int __load_discards(struct dm_cache_metadata *cmd,
                           load_discard_fn fn, void *context)
 {
        int r = 0;
-       dm_block_t b;
-       bool discard;
+       uint32_t b;
+       struct dm_bitset_cursor c;
 
-       for (b = 0; b < from_dblock(cmd->discard_nr_blocks); b++) {
-               dm_dblock_t dblock = to_dblock(b);
+       if (from_dblock(cmd->discard_nr_blocks) == 0)
+               /* nothing to do */
+               return 0;
 
-               if (cmd->clean_when_opened) {
-                       r = __is_discarded(cmd, dblock, &discard);
-                       if (r)
-                               return r;
-               } else
-                       discard = false;
+       if (cmd->clean_when_opened) {
+               r = dm_bitset_flush(&cmd->discard_info, cmd->discard_root, &cmd->discard_root);
+               if (r)
+                       return r;
 
-               r = fn(context, cmd->discard_block_size, dblock, discard);
+               r = dm_bitset_cursor_begin(&cmd->discard_info, cmd->discard_root,
+                                          from_dblock(cmd->discard_nr_blocks), &c);
                if (r)
-                       break;
+                       return r;
+
+               for (b = 0; b < from_dblock(cmd->discard_nr_blocks); b++) {
+                       r = fn(context, cmd->discard_block_size, to_dblock(b),
+                              dm_bitset_cursor_get_value(&c));
+                       if (r)
+                               break;
+               }
+
+               dm_bitset_cursor_end(&c);
+
+       } else {
+               for (b = 0; b < from_dblock(cmd->discard_nr_blocks); b++) {
+                       r = fn(context, cmd->discard_block_size, to_dblock(b), false);
+                       if (r)
+                               return r;
+               }
        }
 
        return r;
@@ -1177,11 +1306,11 @@ static bool hints_array_available(struct dm_cache_metadata *cmd,
                hints_array_initialized(cmd);
 }
 
-static int __load_mapping(struct dm_cache_metadata *cmd,
-                         uint64_t cb, bool hints_valid,
-                         struct dm_array_cursor *mapping_cursor,
-                         struct dm_array_cursor *hint_cursor,
-                         load_mapping_fn fn, void *context)
+static int __load_mapping_v1(struct dm_cache_metadata *cmd,
+                            uint64_t cb, bool hints_valid,
+                            struct dm_array_cursor *mapping_cursor,
+                            struct dm_array_cursor *hint_cursor,
+                            load_mapping_fn fn, void *context)
 {
        int r = 0;
 
@@ -1206,8 +1335,51 @@ static int __load_mapping(struct dm_cache_metadata *cmd,
 
                r = fn(context, oblock, to_cblock(cb), flags & M_DIRTY,
                       le32_to_cpu(hint), hints_valid);
-               if (r)
-                       DMERR("policy couldn't load cblock");
+               if (r) {
+                       DMERR("policy couldn't load cache block %llu",
+                             (unsigned long long) from_cblock(to_cblock(cb)));
+               }
+       }
+
+       return r;
+}
+
+static int __load_mapping_v2(struct dm_cache_metadata *cmd,
+                            uint64_t cb, bool hints_valid,
+                            struct dm_array_cursor *mapping_cursor,
+                            struct dm_array_cursor *hint_cursor,
+                            struct dm_bitset_cursor *dirty_cursor,
+                            load_mapping_fn fn, void *context)
+{
+       int r = 0;
+
+       __le64 mapping;
+       __le32 hint = 0;
+
+       __le64 *mapping_value_le;
+       __le32 *hint_value_le;
+
+       dm_oblock_t oblock;
+       unsigned flags;
+       bool dirty;
+
+       dm_array_cursor_get_value(mapping_cursor, (void **) &mapping_value_le);
+       memcpy(&mapping, mapping_value_le, sizeof(mapping));
+       unpack_value(mapping, &oblock, &flags);
+
+       if (flags & M_VALID) {
+               if (hints_valid) {
+                       dm_array_cursor_get_value(hint_cursor, (void **) &hint_value_le);
+                       memcpy(&hint, hint_value_le, sizeof(hint));
+               }
+
+               dirty = dm_bitset_cursor_get_value(dirty_cursor);
+               r = fn(context, oblock, to_cblock(cb), dirty,
+                      le32_to_cpu(hint), hints_valid);
+               if (r) {
+                       DMERR("policy couldn't load cache block %llu",
+                             (unsigned long long) from_cblock(to_cblock(cb)));
+               }
        }
 
        return r;
@@ -1238,10 +1410,28 @@ static int __load_mappings(struct dm_cache_metadata *cmd,
                }
        }
 
+       if (separate_dirty_bits(cmd)) {
+               r = dm_bitset_cursor_begin(&cmd->dirty_info, cmd->dirty_root,
+                                          from_cblock(cmd->cache_blocks),
+                                          &cmd->dirty_cursor);
+               if (r) {
+                       dm_array_cursor_end(&cmd->hint_cursor);
+                       dm_array_cursor_end(&cmd->mapping_cursor);
+                       return r;
+               }
+       }
+
        for (cb = 0; ; cb++) {
-               r = __load_mapping(cmd, cb, hints_valid,
-                                  &cmd->mapping_cursor, &cmd->hint_cursor,
-                                  fn, context);
+               if (separate_dirty_bits(cmd))
+                       r = __load_mapping_v2(cmd, cb, hints_valid,
+                                             &cmd->mapping_cursor,
+                                             &cmd->hint_cursor,
+                                             &cmd->dirty_cursor,
+                                             fn, context);
+               else
+                       r = __load_mapping_v1(cmd, cb, hints_valid,
+                                             &cmd->mapping_cursor, &cmd->hint_cursor,
+                                             fn, context);
                if (r)
                        goto out;
 
@@ -1264,12 +1454,23 @@ static int __load_mappings(struct dm_cache_metadata *cmd,
                                goto out;
                        }
                }
+
+               if (separate_dirty_bits(cmd)) {
+                       r = dm_bitset_cursor_next(&cmd->dirty_cursor);
+                       if (r) {
+                               DMERR("dm_bitset_cursor_next for dirty failed");
+                               goto out;
+                       }
+               }
        }
 out:
        dm_array_cursor_end(&cmd->mapping_cursor);
        if (hints_valid)
                dm_array_cursor_end(&cmd->hint_cursor);
 
+       if (separate_dirty_bits(cmd))
+               dm_bitset_cursor_end(&cmd->dirty_cursor);
+
        return r;
 }
 
@@ -1352,13 +1553,55 @@ static int __dirty(struct dm_cache_metadata *cmd, dm_cblock_t cblock, bool dirty
 
 }
 
-int dm_cache_set_dirty(struct dm_cache_metadata *cmd,
-                      dm_cblock_t cblock, bool dirty)
+static int __set_dirty_bits_v1(struct dm_cache_metadata *cmd, unsigned nr_bits, unsigned long *bits)
+{
+       int r;
+       unsigned i;
+       for (i = 0; i < nr_bits; i++) {
+               r = __dirty(cmd, to_cblock(i), test_bit(i, bits));
+               if (r)
+                       return r;
+       }
+
+       return 0;
+}
+
+static int is_dirty_callback(uint32_t index, bool *value, void *context)
+{
+       unsigned long *bits = context;
+       *value = test_bit(index, bits);
+       return 0;
+}
+
+static int __set_dirty_bits_v2(struct dm_cache_metadata *cmd, unsigned nr_bits, unsigned long *bits)
+{
+       int r = 0;
+
+       /* nr_bits is really just a sanity check */
+       if (nr_bits != from_cblock(cmd->cache_blocks)) {
+               DMERR("dirty bitset is wrong size");
+               return -EINVAL;
+       }
+
+       r = dm_bitset_del(&cmd->dirty_info, cmd->dirty_root);
+       if (r)
+               return r;
+
+       cmd->changed = true;
+       return dm_bitset_new(&cmd->dirty_info, &cmd->dirty_root, nr_bits, is_dirty_callback, bits);
+}
+
+int dm_cache_set_dirty_bits(struct dm_cache_metadata *cmd,
+                           unsigned nr_bits,
+                           unsigned long *bits)
 {
        int r;
 
        WRITE_LOCK(cmd);
-       r = __dirty(cmd, cblock, dirty);
+       if (separate_dirty_bits(cmd))
+               r = __set_dirty_bits_v2(cmd, nr_bits, bits);
+       else
+               r = __set_dirty_bits_v1(cmd, nr_bits, bits);
        WRITE_UNLOCK(cmd);
 
        return r;
index 8528744195e53aeecbbe52688b8ae40d2200c339..4f07c08cf1070ca0872348283f33da58c80d53e9 100644 (file)
  * As these various flags are defined they should be added to the
  * following masks.
  */
+
 #define DM_CACHE_FEATURE_COMPAT_SUPP     0UL
 #define DM_CACHE_FEATURE_COMPAT_RO_SUPP          0UL
 #define DM_CACHE_FEATURE_INCOMPAT_SUPP   0UL
 
 /*
- * Reopens or creates a new, empty metadata volume.
- * Returns an ERR_PTR on failure.
+ * Reopens or creates a new, empty metadata volume.  Returns an ERR_PTR on
+ * failure.  If reopening then features must match.
  */
 struct dm_cache_metadata *dm_cache_metadata_open(struct block_device *bdev,
                                                 sector_t data_block_size,
                                                 bool may_format_device,
-                                                size_t policy_hint_size);
+                                                size_t policy_hint_size,
+                                                unsigned metadata_version);
 
 void dm_cache_metadata_close(struct dm_cache_metadata *cmd);
 
@@ -91,7 +93,8 @@ int dm_cache_load_mappings(struct dm_cache_metadata *cmd,
                           load_mapping_fn fn,
                           void *context);
 
-int dm_cache_set_dirty(struct dm_cache_metadata *cmd, dm_cblock_t cblock, bool dirty);
+int dm_cache_set_dirty_bits(struct dm_cache_metadata *cmd,
+                           unsigned nr_bits, unsigned long *bits);
 
 struct dm_cache_statistics {
        uint32_t read_hits;
index e04c61e0839e64192f7f6efdcef969dd449ca2d0..9c689b34e6e792105d64f2bb4835e11e37c91578 100644 (file)
@@ -179,6 +179,7 @@ enum cache_io_mode {
 struct cache_features {
        enum cache_metadata_mode mode;
        enum cache_io_mode io_mode;
+       unsigned metadata_version;
 };
 
 struct cache_stats {
@@ -248,7 +249,7 @@ struct cache {
        /*
         * Fields for converting from sectors to blocks.
         */
-       uint32_t sectors_per_block;
+       sector_t sectors_per_block;
        int sectors_per_block_shift;
 
        spinlock_t lock;
@@ -787,8 +788,7 @@ static void check_if_tick_bio_needed(struct cache *cache, struct bio *bio)
        struct per_bio_data *pb = get_per_bio_data(bio, pb_data_size);
 
        spin_lock_irqsave(&cache->lock, flags);
-       if (cache->need_tick_bio &&
-           !(bio->bi_opf & (REQ_FUA | REQ_PREFLUSH)) &&
+       if (cache->need_tick_bio && !op_is_flush(bio->bi_opf) &&
            bio_op(bio) != REQ_OP_DISCARD) {
                pb->tick = true;
                cache->need_tick_bio = false;
@@ -828,11 +828,6 @@ static dm_oblock_t get_bio_block(struct cache *cache, struct bio *bio)
        return to_oblock(block_nr);
 }
 
-static int bio_triggers_commit(struct cache *cache, struct bio *bio)
-{
-       return bio->bi_opf & (REQ_PREFLUSH | REQ_FUA);
-}
-
 /*
  * You must increment the deferred set whilst the prison cell is held.  To
  * encourage this, we ask for 'cell' to be passed in.
@@ -884,7 +879,7 @@ static void issue(struct cache *cache, struct bio *bio)
 {
        unsigned long flags;
 
-       if (!bio_triggers_commit(cache, bio)) {
+       if (!op_is_flush(bio->bi_opf)) {
                accounted_request(cache, bio);
                return;
        }
@@ -1069,8 +1064,7 @@ static void dec_io_migrations(struct cache *cache)
 
 static bool discard_or_flush(struct bio *bio)
 {
-       return bio_op(bio) == REQ_OP_DISCARD ||
-              bio->bi_opf & (REQ_PREFLUSH | REQ_FUA);
+       return bio_op(bio) == REQ_OP_DISCARD || op_is_flush(bio->bi_opf);
 }
 
 static void __cell_defer(struct cache *cache, struct dm_bio_prison_cell *cell)
@@ -2291,7 +2285,7 @@ static void do_waker(struct work_struct *ws)
 static int is_congested(struct dm_dev *dev, int bdi_bits)
 {
        struct request_queue *q = bdev_get_queue(dev->bdev);
-       return bdi_congested(&q->backing_dev_info, bdi_bits);
+       return bdi_congested(q->backing_dev_info, bdi_bits);
 }
 
 static int cache_is_congested(struct dm_target_callbacks *cb, int bdi_bits)
@@ -2541,13 +2535,14 @@ static void init_features(struct cache_features *cf)
 {
        cf->mode = CM_WRITE;
        cf->io_mode = CM_IO_WRITEBACK;
+       cf->metadata_version = 1;
 }
 
 static int parse_features(struct cache_args *ca, struct dm_arg_set *as,
                          char **error)
 {
        static struct dm_arg _args[] = {
-               {0, 1, "Invalid number of cache feature arguments"},
+               {0, 2, "Invalid number of cache feature arguments"},
        };
 
        int r;
@@ -2573,6 +2568,9 @@ static int parse_features(struct cache_args *ca, struct dm_arg_set *as,
                else if (!strcasecmp(arg, "passthrough"))
                        cf->io_mode = CM_IO_PASSTHROUGH;
 
+               else if (!strcasecmp(arg, "metadata2"))
+                       cf->metadata_version = 2;
+
                else {
                        *error = "Unrecognised cache feature requested";
                        return -EINVAL;
@@ -2827,7 +2825,8 @@ static int cache_create(struct cache_args *ca, struct cache **result)
 
        cmd = dm_cache_metadata_open(cache->metadata_dev->bdev,
                                     ca->block_size, may_format,
-                                    dm_cache_policy_get_hint_size(cache->policy));
+                                    dm_cache_policy_get_hint_size(cache->policy),
+                                    ca->features.metadata_version);
        if (IS_ERR(cmd)) {
                *error = "Error creating metadata object";
                r = PTR_ERR(cmd);
@@ -3172,21 +3171,16 @@ static int cache_end_io(struct dm_target *ti, struct bio *bio, int error)
 
 static int write_dirty_bitset(struct cache *cache)
 {
-       unsigned i, r;
+       int r;
 
        if (get_cache_mode(cache) >= CM_READ_ONLY)
                return -EINVAL;
 
-       for (i = 0; i < from_cblock(cache->cache_size); i++) {
-               r = dm_cache_set_dirty(cache->cmd, to_cblock(i),
-                                      is_dirty(cache, to_cblock(i)));
-               if (r) {
-                       metadata_operation_failed(cache, "dm_cache_set_dirty", r);
-                       return r;
-               }
-       }
+       r = dm_cache_set_dirty_bits(cache->cmd, from_cblock(cache->cache_size), cache->dirty_bitset);
+       if (r)
+               metadata_operation_failed(cache, "dm_cache_set_dirty_bits", r);
 
-       return 0;
+       return r;
 }
 
 static int write_discard_bitset(struct cache *cache)
@@ -3547,11 +3541,11 @@ static void cache_status(struct dm_target *ti, status_type_t type,
 
                residency = policy_residency(cache->policy);
 
-               DMEMIT("%u %llu/%llu %u %llu/%llu %u %u %u %u %u %u %lu ",
+               DMEMIT("%u %llu/%llu %llu %llu/%llu %u %u %u %u %u %u %lu ",
                       (unsigned)DM_CACHE_METADATA_BLOCK_SIZE,
                       (unsigned long long)(nr_blocks_metadata - nr_free_blocks_metadata),
                       (unsigned long long)nr_blocks_metadata,
-                      cache->sectors_per_block,
+                      (unsigned long long)cache->sectors_per_block,
                       (unsigned long long) from_cblock(residency),
                       (unsigned long long) from_cblock(cache->cache_size),
                       (unsigned) atomic_read(&cache->stats.read_hit),
@@ -3562,14 +3556,19 @@ static void cache_status(struct dm_target *ti, status_type_t type,
                       (unsigned) atomic_read(&cache->stats.promotion),
                       (unsigned long) atomic_read(&cache->nr_dirty));
 
+               if (cache->features.metadata_version == 2)
+                       DMEMIT("2 metadata2 ");
+               else
+                       DMEMIT("1 ");
+
                if (writethrough_mode(&cache->features))
-                       DMEMIT("writethrough ");
+                       DMEMIT("writethrough ");
 
                else if (passthrough_mode(&cache->features))
-                       DMEMIT("passthrough ");
+                       DMEMIT("passthrough ");
 
                else if (writeback_mode(&cache->features))
-                       DMEMIT("writeback ");
+                       DMEMIT("writeback ");
 
                else {
                        DMERR("%s: internal error: unknown io mode: %d",
@@ -3817,7 +3816,7 @@ static void cache_io_hints(struct dm_target *ti, struct queue_limits *limits)
 
 static struct target_type cache_target = {
        .name = "cache",
-       .version = {1, 9, 0},
+       .version = {1, 10, 0},
        .module = THIS_MODULE,
        .ctr = cache_ctr,
        .dtr = cache_dtr,
index 40ceba1fe8be28d77ccf82af75a3f0e0eac09499..136fda3ff9e55d46a2ef686e8655ba50754d5c20 100644 (file)
@@ -92,7 +92,6 @@ struct mapped_device {
         * io objects are allocated from here.
         */
        mempool_t *io_pool;
-       mempool_t *rq_pool;
 
        struct bio_set *bs;
 
index bf2b2676cb8af7c936b401c64895f9e499e80543..9fab33b113c49f1d0dca156b6f5bf4cc238d05f2 100644 (file)
@@ -1379,7 +1379,7 @@ static void stop_worker(struct era *era)
 static int dev_is_congested(struct dm_dev *dev, int bdi_bits)
 {
        struct request_queue *q = bdev_get_queue(dev->bdev);
-       return bdi_congested(&q->backing_dev_info, bdi_bits);
+       return bdi_congested(q->backing_dev_info, bdi_bits);
 }
 
 static int era_is_congested(struct dm_target_callbacks *cb, int bdi_bits)
index 3570bcb7a4a4e5cade63c39b9071ed610da1e4ae..7f223dbed49f61d5797d4edba728989c9e435d3d 100644 (file)
@@ -92,12 +92,6 @@ struct multipath {
 
        unsigned queue_mode;
 
-       /*
-        * We must use a mempool of dm_mpath_io structs so that we
-        * can resubmit bios on error.
-        */
-       mempool_t *mpio_pool;
-
        struct mutex work_mutex;
        struct work_struct trigger_event;
 
@@ -115,8 +109,6 @@ struct dm_mpath_io {
 
 typedef int (*action_fn) (struct pgpath *pgpath);
 
-static struct kmem_cache *_mpio_cache;
-
 static struct workqueue_struct *kmultipathd, *kmpath_handlerd;
 static void trigger_event(struct work_struct *work);
 static void activate_path(struct work_struct *work);
@@ -209,7 +201,6 @@ static struct multipath *alloc_multipath(struct dm_target *ti)
                init_waitqueue_head(&m->pg_init_wait);
                mutex_init(&m->work_mutex);
 
-               m->mpio_pool = NULL;
                m->queue_mode = DM_TYPE_NONE;
 
                m->ti = ti;
@@ -229,16 +220,7 @@ static int alloc_multipath_stage2(struct dm_target *ti, struct multipath *m)
                        m->queue_mode = DM_TYPE_MQ_REQUEST_BASED;
                else
                        m->queue_mode = DM_TYPE_REQUEST_BASED;
-       }
-
-       if (m->queue_mode == DM_TYPE_REQUEST_BASED) {
-               unsigned min_ios = dm_get_reserved_rq_based_ios();
-
-               m->mpio_pool = mempool_create_slab_pool(min_ios, _mpio_cache);
-               if (!m->mpio_pool)
-                       return -ENOMEM;
-       }
-       else if (m->queue_mode == DM_TYPE_BIO_BASED) {
+       } else if (m->queue_mode == DM_TYPE_BIO_BASED) {
                INIT_WORK(&m->process_queued_bios, process_queued_bios);
                /*
                 * bio-based doesn't support any direct scsi_dh management;
@@ -263,7 +245,6 @@ static void free_multipath(struct multipath *m)
 
        kfree(m->hw_handler_name);
        kfree(m->hw_handler_params);
-       mempool_destroy(m->mpio_pool);
        kfree(m);
 }
 
@@ -272,38 +253,6 @@ static struct dm_mpath_io *get_mpio(union map_info *info)
        return info->ptr;
 }
 
-static struct dm_mpath_io *set_mpio(struct multipath *m, union map_info *info)
-{
-       struct dm_mpath_io *mpio;
-
-       if (!m->mpio_pool) {
-               /* Use blk-mq pdu memory requested via per_io_data_size */
-               mpio = get_mpio(info);
-               memset(mpio, 0, sizeof(*mpio));
-               return mpio;
-       }
-
-       mpio = mempool_alloc(m->mpio_pool, GFP_ATOMIC);
-       if (!mpio)
-               return NULL;
-
-       memset(mpio, 0, sizeof(*mpio));
-       info->ptr = mpio;
-
-       return mpio;
-}
-
-static void clear_request_fn_mpio(struct multipath *m, union map_info *info)
-{
-       /* Only needed for non blk-mq (.request_fn) multipath */
-       if (m->mpio_pool) {
-               struct dm_mpath_io *mpio = info->ptr;
-
-               info->ptr = NULL;
-               mempool_free(mpio, m->mpio_pool);
-       }
-}
-
 static size_t multipath_per_bio_data_size(void)
 {
        return sizeof(struct dm_mpath_io) + sizeof(struct dm_bio_details);
@@ -530,16 +479,17 @@ static bool must_push_back_bio(struct multipath *m)
 /*
  * Map cloned requests (request-based multipath)
  */
-static int __multipath_map(struct dm_target *ti, struct request *clone,
-                          union map_info *map_context,
-                          struct request *rq, struct request **__clone)
+static int multipath_clone_and_map(struct dm_target *ti, struct request *rq,
+                                  union map_info *map_context,
+                                  struct request **__clone)
 {
        struct multipath *m = ti->private;
        int r = DM_MAPIO_REQUEUE;
-       size_t nr_bytes = clone ? blk_rq_bytes(clone) : blk_rq_bytes(rq);
+       size_t nr_bytes = blk_rq_bytes(rq);
        struct pgpath *pgpath;
        struct block_device *bdev;
-       struct dm_mpath_io *mpio;
+       struct dm_mpath_io *mpio = get_mpio(map_context);
+       struct request *clone;
 
        /* Do we need to select a new pgpath? */
        pgpath = lockless_dereference(m->current_pgpath);
@@ -556,42 +506,23 @@ static int __multipath_map(struct dm_target *ti, struct request *clone,
                return r;
        }
 
-       mpio = set_mpio(m, map_context);
-       if (!mpio)
-               /* ENOMEM, requeue */
-               return r;
-
+       memset(mpio, 0, sizeof(*mpio));
        mpio->pgpath = pgpath;
        mpio->nr_bytes = nr_bytes;
 
        bdev = pgpath->path.dev->bdev;
 
-       if (clone) {
-               /*
-                * Old request-based interface: allocated clone is passed in.
-                * Used by: .request_fn stacked on .request_fn path(s).
-                */
-               clone->q = bdev_get_queue(bdev);
-               clone->rq_disk = bdev->bd_disk;
-               clone->cmd_flags |= REQ_FAILFAST_TRANSPORT;
-       } else {
-               /*
-                * blk-mq request-based interface; used by both:
-                * .request_fn stacked on blk-mq path(s) and
-                * blk-mq stacked on blk-mq path(s).
-                */
-               clone = blk_mq_alloc_request(bdev_get_queue(bdev),
-                                            rq_data_dir(rq), BLK_MQ_REQ_NOWAIT);
-               if (IS_ERR(clone)) {
-                       /* EBUSY, ENODEV or EWOULDBLOCK: requeue */
-                       clear_request_fn_mpio(m, map_context);
-                       return r;
-               }
-               clone->bio = clone->biotail = NULL;
-               clone->rq_disk = bdev->bd_disk;
-               clone->cmd_flags |= REQ_FAILFAST_TRANSPORT;
-               *__clone = clone;
+       clone = blk_get_request(bdev_get_queue(bdev),
+                       rq->cmd_flags | REQ_NOMERGE,
+                       GFP_ATOMIC);
+       if (IS_ERR(clone)) {
+               /* EBUSY, ENODEV or EWOULDBLOCK: requeue */
+               return r;
        }
+       clone->bio = clone->biotail = NULL;
+       clone->rq_disk = bdev->bd_disk;
+       clone->cmd_flags |= REQ_FAILFAST_TRANSPORT;
+       *__clone = clone;
 
        if (pgpath->pg->ps.type->start_io)
                pgpath->pg->ps.type->start_io(&pgpath->pg->ps,
@@ -600,22 +531,9 @@ static int __multipath_map(struct dm_target *ti, struct request *clone,
        return DM_MAPIO_REMAPPED;
 }
 
-static int multipath_map(struct dm_target *ti, struct request *clone,
-                        union map_info *map_context)
-{
-       return __multipath_map(ti, clone, map_context, NULL, NULL);
-}
-
-static int multipath_clone_and_map(struct dm_target *ti, struct request *rq,
-                                  union map_info *map_context,
-                                  struct request **clone)
-{
-       return __multipath_map(ti, NULL, map_context, rq, clone);
-}
-
 static void multipath_release_clone(struct request *clone)
 {
-       blk_mq_free_request(clone);
+       blk_put_request(clone);
 }
 
 /*
@@ -1187,7 +1105,7 @@ static int multipath_ctr(struct dm_target *ti, unsigned argc, char **argv)
        ti->num_write_same_bios = 1;
        if (m->queue_mode == DM_TYPE_BIO_BASED)
                ti->per_io_data_size = multipath_per_bio_data_size();
-       else if (m->queue_mode == DM_TYPE_MQ_REQUEST_BASED)
+       else
                ti->per_io_data_size = sizeof(struct dm_mpath_io);
 
        return 0;
@@ -1610,7 +1528,6 @@ static int multipath_end_io(struct dm_target *ti, struct request *clone,
                if (ps->type->end_io)
                        ps->type->end_io(ps, &pgpath->path, mpio->nr_bytes);
        }
-       clear_request_fn_mpio(m, map_context);
 
        return r;
 }
@@ -2060,7 +1977,6 @@ static struct target_type multipath_target = {
        .module = THIS_MODULE,
        .ctr = multipath_ctr,
        .dtr = multipath_dtr,
-       .map_rq = multipath_map,
        .clone_and_map_rq = multipath_clone_and_map,
        .release_clone_rq = multipath_release_clone,
        .rq_end_io = multipath_end_io,
@@ -2080,11 +1996,6 @@ static int __init dm_multipath_init(void)
 {
        int r;
 
-       /* allocate a slab for the dm_mpath_ios */
-       _mpio_cache = KMEM_CACHE(dm_mpath_io, 0);
-       if (!_mpio_cache)
-               return -ENOMEM;
-
        r = dm_register_target(&multipath_target);
        if (r < 0) {
                DMERR("request-based register failed %d", r);
@@ -2120,8 +2031,6 @@ bad_alloc_kmpath_handlerd:
 bad_alloc_kmultipathd:
        dm_unregister_target(&multipath_target);
 bad_register_target:
-       kmem_cache_destroy(_mpio_cache);
-
        return r;
 }
 
@@ -2131,7 +2040,6 @@ static void __exit dm_multipath_exit(void)
        destroy_workqueue(kmultipathd);
 
        dm_unregister_target(&multipath_target);
-       kmem_cache_destroy(_mpio_cache);
 }
 
 module_init(dm_multipath_init);
index b8f978e551d7f05f128b1fdd59d5ead16e30f89f..5c9e95d66f3b64d14355a91abd936eb5f3c46440 100644 (file)
  */
 #define        MIN_FREE_RESHAPE_SPACE to_sector(4*4096)
 
+/*
+ * Minimum journal space 4 MiB in sectors.
+ */
+#define        MIN_RAID456_JOURNAL_SPACE (4*2048)
+
 static bool devices_handle_discard_safely = false;
 
 /*
@@ -73,6 +78,9 @@ struct raid_dev {
 #define __CTR_FLAG_DATA_OFFSET         13 /* 2 */ /* Only with reshapable raid4/5/6/10! */
 #define __CTR_FLAG_RAID10_USE_NEAR_SETS 14 /* 2 */ /* Only with raid10! */
 
+/* New for v1.10.0 */
+#define __CTR_FLAG_JOURNAL_DEV         15 /* 2 */ /* Only with raid4/5/6! */
+
 /*
  * Flags for rs->ctr_flags field.
  */
@@ -91,6 +99,7 @@ struct raid_dev {
 #define CTR_FLAG_DELTA_DISKS           (1 << __CTR_FLAG_DELTA_DISKS)
 #define CTR_FLAG_DATA_OFFSET           (1 << __CTR_FLAG_DATA_OFFSET)
 #define CTR_FLAG_RAID10_USE_NEAR_SETS  (1 << __CTR_FLAG_RAID10_USE_NEAR_SETS)
+#define CTR_FLAG_JOURNAL_DEV           (1 << __CTR_FLAG_JOURNAL_DEV)
 
 /*
  * Definitions of various constructor flags to
@@ -163,7 +172,8 @@ struct raid_dev {
                                 CTR_FLAG_STRIPE_CACHE | \
                                 CTR_FLAG_REGION_SIZE | \
                                 CTR_FLAG_DELTA_DISKS | \
-                                CTR_FLAG_DATA_OFFSET)
+                                CTR_FLAG_DATA_OFFSET | \
+                                CTR_FLAG_JOURNAL_DEV)
 
 #define RAID6_VALID_FLAGS      (CTR_FLAG_SYNC | \
                                 CTR_FLAG_REBUILD | \
@@ -173,7 +183,8 @@ struct raid_dev {
                                 CTR_FLAG_STRIPE_CACHE | \
                                 CTR_FLAG_REGION_SIZE | \
                                 CTR_FLAG_DELTA_DISKS | \
-                                CTR_FLAG_DATA_OFFSET)
+                                CTR_FLAG_DATA_OFFSET | \
+                                CTR_FLAG_JOURNAL_DEV)
 /* ...valid options definitions per raid level */
 
 /*
@@ -222,6 +233,12 @@ struct raid_set {
        struct raid_type *raid_type;
        struct dm_target_callbacks callbacks;
 
+       /* Optional raid4/5/6 journal device */
+       struct journal_dev {
+               struct dm_dev *dev;
+               struct md_rdev rdev;
+       } journal_dev;
+
        struct raid_dev dev[0];
 };
 
@@ -306,6 +323,7 @@ static struct arg_name_flag {
        { CTR_FLAG_DATA_OFFSET, "data_offset"},
        { CTR_FLAG_DELTA_DISKS, "delta_disks"},
        { CTR_FLAG_RAID10_USE_NEAR_SETS, "raid10_use_near_sets"},
+       { CTR_FLAG_JOURNAL_DEV, "journal_dev" },
 };
 
 /* Return argument name string for given @flag */
@@ -370,7 +388,7 @@ static bool rs_is_reshapable(struct raid_set *rs)
 /* Return true, if raid set in @rs is recovering */
 static bool rs_is_recovering(struct raid_set *rs)
 {
-       return rs->md.recovery_cp < rs->dev[0].rdev.sectors;
+       return rs->md.recovery_cp < rs->md.dev_sectors;
 }
 
 /* Return true, if raid set in @rs is reshaping */
@@ -627,7 +645,8 @@ static void rs_set_capacity(struct raid_set *rs)
         * is unintended in case of out-of-place reshaping
         */
        rdev_for_each(rdev, mddev)
-               rdev->sectors = mddev->dev_sectors;
+               if (!test_bit(Journal, &rdev->flags))
+                       rdev->sectors = mddev->dev_sectors;
 
        set_capacity(gendisk, mddev->array_sectors);
        revalidate_disk(gendisk);
@@ -713,6 +732,11 @@ static void raid_set_free(struct raid_set *rs)
 {
        int i;
 
+       if (rs->journal_dev.dev) {
+               md_rdev_clear(&rs->journal_dev.rdev);
+               dm_put_device(rs->ti, rs->journal_dev.dev);
+       }
+
        for (i = 0; i < rs->raid_disks; i++) {
                if (rs->dev[i].meta_dev)
                        dm_put_device(rs->ti, rs->dev[i].meta_dev);
@@ -760,10 +784,11 @@ static int parse_dev_params(struct raid_set *rs, struct dm_arg_set *as)
                rs->dev[i].data_dev = NULL;
 
                /*
-                * There are no offsets, since there is a separate device
-                * for data and metadata.
+                * There are no offsets initially.
+                * Out of place reshape will set them accordingly.
                 */
                rs->dev[i].rdev.data_offset = 0;
+               rs->dev[i].rdev.new_data_offset = 0;
                rs->dev[i].rdev.mddev = &rs->md;
 
                arg = dm_shift_arg(as);
@@ -821,6 +846,9 @@ static int parse_dev_params(struct raid_set *rs, struct dm_arg_set *as)
                        rebuild++;
        }
 
+       if (rs->journal_dev.dev)
+               list_add_tail(&rs->journal_dev.rdev.same_set, &rs->md.disks);
+
        if (metadata_available) {
                rs->md.external = 0;
                rs->md.persistent = 1;
@@ -1026,6 +1054,8 @@ too_many:
  *    [max_write_behind <sectors>]     See '-write-behind=' (man mdadm)
  *    [stripe_cache <sectors>]         Stripe cache size for higher RAIDs
  *    [region_size <sectors>]          Defines granularity of bitmap
+ *    [journal_dev <dev>]              raid4/5/6 journaling deviice
+ *                                     (i.e. write hole closing log)
  *
  * RAID10-only options:
  *    [raid10_copies <# copies>]       Number of copies.  (Default: 2)
@@ -1133,7 +1163,7 @@ static int parse_raid_params(struct raid_set *rs, struct dm_arg_set *as,
                /*
                 * Parameters that take a string value are checked here.
                 */
-
+               /* "raid10_format {near|offset|far} */
                if (!strcasecmp(key, dm_raid_arg_name_by_flag(CTR_FLAG_RAID10_FORMAT))) {
                        if (test_and_set_bit(__CTR_FLAG_RAID10_FORMAT, &rs->ctr_flags)) {
                                rs->ti->error = "Only one 'raid10_format' argument pair allowed";
@@ -1151,6 +1181,41 @@ static int parse_raid_params(struct raid_set *rs, struct dm_arg_set *as,
                        continue;
                }
 
+               /* "journal_dev dev" */
+               if (!strcasecmp(key, dm_raid_arg_name_by_flag(CTR_FLAG_JOURNAL_DEV))) {
+                       int r;
+                       struct md_rdev *jdev;
+
+                       if (test_and_set_bit(__CTR_FLAG_JOURNAL_DEV, &rs->ctr_flags)) {
+                               rs->ti->error = "Only one raid4/5/6 set journaling device allowed";
+                               return -EINVAL;
+                       }
+                       if (!rt_is_raid456(rt)) {
+                               rs->ti->error = "'journal_dev' is an invalid parameter for this RAID type";
+                               return -EINVAL;
+                       }
+                       r = dm_get_device(rs->ti, arg, dm_table_get_mode(rs->ti->table),
+                                         &rs->journal_dev.dev);
+                       if (r) {
+                               rs->ti->error = "raid4/5/6 journal device lookup failure";
+                               return r;
+                       }
+                       jdev = &rs->journal_dev.rdev;
+                       md_rdev_init(jdev);
+                       jdev->mddev = &rs->md;
+                       jdev->bdev = rs->journal_dev.dev->bdev;
+                       jdev->sectors = to_sector(i_size_read(jdev->bdev->bd_inode));
+                       if (jdev->sectors < MIN_RAID456_JOURNAL_SPACE) {
+                               rs->ti->error = "No space for raid4/5/6 journal";
+                               return -ENOSPC;
+                       }
+                       set_bit(Journal, &jdev->flags);
+                       continue;
+               }
+
+               /*
+                * Parameters with number values from here on.
+                */
                if (kstrtoint(arg, 10, &value) < 0) {
                        rs->ti->error = "Bad numerical argument given in raid params";
                        return -EINVAL;
@@ -1425,6 +1490,25 @@ static unsigned int rs_data_stripes(struct raid_set *rs)
        return rs->raid_disks - rs->raid_type->parity_devs;
 }
 
+/*
+ * Retrieve rdev->sectors from any valid raid device of @rs
+ * to allow userpace to pass in arbitray "- -" device tupples.
+ */
+static sector_t __rdev_sectors(struct raid_set *rs)
+{
+       int i;
+
+       for (i = 0; i < rs->md.raid_disks; i++) {
+               struct md_rdev *rdev = &rs->dev[i].rdev;
+
+               if (!test_bit(Journal, &rdev->flags) &&
+                   rdev->bdev && rdev->sectors)
+                       return rdev->sectors;
+       }
+
+       BUG(); /* Constructor ensures we got some. */
+}
+
 /* Calculate the sectors per device and per array used for @rs */
 static int rs_set_dev_and_array_sectors(struct raid_set *rs, bool use_mddev)
 {
@@ -1468,7 +1552,8 @@ static int rs_set_dev_and_array_sectors(struct raid_set *rs, bool use_mddev)
                array_sectors = (data_stripes + delta_disks) * dev_sectors;
 
        rdev_for_each(rdev, mddev)
-               rdev->sectors = dev_sectors;
+               if (!test_bit(Journal, &rdev->flags))
+                       rdev->sectors = dev_sectors;
 
        mddev->array_sectors = array_sectors;
        mddev->dev_sectors = dev_sectors;
@@ -1510,9 +1595,9 @@ static void rs_setup_recovery(struct raid_set *rs, sector_t dev_sectors)
        else if (dev_sectors == MaxSector)
                /* Prevent recovery */
                __rs_setup_recovery(rs, MaxSector);
-       else if (rs->dev[0].rdev.sectors < dev_sectors)
+       else if (__rdev_sectors(rs) < dev_sectors)
                /* Grown raid set */
-               __rs_setup_recovery(rs, rs->dev[0].rdev.sectors);
+               __rs_setup_recovery(rs, __rdev_sectors(rs));
        else
                __rs_setup_recovery(rs, MaxSector);
 }
@@ -1851,18 +1936,21 @@ static int rs_check_reshape(struct raid_set *rs)
        return -EPERM;
 }
 
-static int read_disk_sb(struct md_rdev *rdev, int size)
+static int read_disk_sb(struct md_rdev *rdev, int size, bool force_reload)
 {
        BUG_ON(!rdev->sb_page);
 
-       if (rdev->sb_loaded)
+       if (rdev->sb_loaded && !force_reload)
                return 0;
 
+       rdev->sb_loaded = 0;
+
        if (!sync_page_io(rdev, 0, size, rdev->sb_page, REQ_OP_READ, 0, true)) {
                DMERR("Failed to read superblock of device at position %d",
                      rdev->raid_disk);
                md_error(rdev->mddev, rdev);
-               return -EINVAL;
+               set_bit(Faulty, &rdev->flags);
+               return -EIO;
        }
 
        rdev->sb_loaded = 1;
@@ -1990,7 +2078,7 @@ static int super_load(struct md_rdev *rdev, struct md_rdev *refdev)
                return -EINVAL;
        }
 
-       r = read_disk_sb(rdev, rdev->sb_size);
+       r = read_disk_sb(rdev, rdev->sb_size, false);
        if (r)
                return r;
 
@@ -2146,6 +2234,9 @@ static int super_init_validation(struct raid_set *rs, struct md_rdev *rdev)
         */
        d = 0;
        rdev_for_each(r, mddev) {
+               if (test_bit(Journal, &rdev->flags))
+                       continue;
+
                if (test_bit(FirstUse, &r->flags))
                        new_devs++;
 
@@ -2201,7 +2292,8 @@ static int super_init_validation(struct raid_set *rs, struct md_rdev *rdev)
         */
        sb_retrieve_failed_devices(sb, failed_devices);
        rdev_for_each(r, mddev) {
-               if (!r->sb_page)
+               if (test_bit(Journal, &rdev->flags) ||
+                   !r->sb_page)
                        continue;
                sb2 = page_address(r->sb_page);
                sb2->failed_devices = 0;
@@ -2253,7 +2345,7 @@ static int super_validate(struct raid_set *rs, struct md_rdev *rdev)
        struct mddev *mddev = &rs->md;
        struct dm_raid_superblock *sb;
 
-       if (rs_is_raid0(rs) || !rdev->sb_page)
+       if (rs_is_raid0(rs) || !rdev->sb_page || rdev->raid_disk < 0)
                return 0;
 
        sb = page_address(rdev->sb_page);
@@ -2278,7 +2370,7 @@ static int super_validate(struct raid_set *rs, struct md_rdev *rdev)
 
        /* Enable bitmap creation for RAID levels != 0 */
        mddev->bitmap_info.offset = rt_is_raid0(rs->raid_type) ? 0 : to_sector(4096);
-       rdev->mddev->bitmap_info.default_offset = mddev->bitmap_info.offset;
+       mddev->bitmap_info.default_offset = mddev->bitmap_info.offset;
 
        if (!test_and_clear_bit(FirstUse, &rdev->flags)) {
                /* Retrieve device size stored in superblock to be prepared for shrink */
@@ -2316,21 +2408,22 @@ static int super_validate(struct raid_set *rs, struct md_rdev *rdev)
 static int analyse_superblocks(struct dm_target *ti, struct raid_set *rs)
 {
        int r;
-       struct raid_dev *dev;
-       struct md_rdev *rdev, *tmp, *freshest;
+       struct md_rdev *rdev, *freshest;
        struct mddev *mddev = &rs->md;
 
        freshest = NULL;
-       rdev_for_each_safe(rdev, tmp, mddev) {
+       rdev_for_each(rdev, mddev) {
+               if (test_bit(Journal, &rdev->flags))
+                       continue;
+
                /*
                 * Skipping super_load due to CTR_FLAG_SYNC will cause
                 * the array to undergo initialization again as
                 * though it were new.  This is the intended effect
                 * of the "sync" directive.
                 *
-                * When reshaping capability is added, we must ensure
-                * that the "sync" directive is disallowed during the
-                * reshape.
+                * With reshaping capability added, we must ensure that
+                * that the "sync" directive is disallowed during the reshape.
                 */
                if (test_bit(__CTR_FLAG_SYNC, &rs->ctr_flags))
                        continue;
@@ -2347,6 +2440,7 @@ static int analyse_superblocks(struct dm_target *ti, struct raid_set *rs)
                case 0:
                        break;
                default:
+                       /* This is a failure to read the superblock from the metadata device. */
                        /*
                         * We have to keep any raid0 data/metadata device pairs or
                         * the MD raid0 personality will fail to start the array.
@@ -2354,33 +2448,16 @@ static int analyse_superblocks(struct dm_target *ti, struct raid_set *rs)
                        if (rs_is_raid0(rs))
                                continue;
 
-                       dev = container_of(rdev, struct raid_dev, rdev);
-                       if (dev->meta_dev)
-                               dm_put_device(ti, dev->meta_dev);
-
-                       dev->meta_dev = NULL;
-                       rdev->meta_bdev = NULL;
-
-                       if (rdev->sb_page)
-                               put_page(rdev->sb_page);
-
-                       rdev->sb_page = NULL;
-
-                       rdev->sb_loaded = 0;
-
                        /*
-                        * We might be able to salvage the data device
-                        * even though the meta device has failed.  For
-                        * now, we behave as though '- -' had been
-                        * set for this device in the table.
+                        * We keep the dm_devs to be able to emit the device tuple
+                        * properly on the table line in raid_status() (rather than
+                        * mistakenly acting as if '- -' got passed into the constructor).
+                        *
+                        * The rdev has to stay on the same_set list to allow for
+                        * the attempt to restore faulty devices on second resume.
                         */
-                       if (dev->data_dev)
-                               dm_put_device(ti, dev->data_dev);
-
-                       dev->data_dev = NULL;
-                       rdev->bdev = NULL;
-
-                       list_del(&rdev->same_set);
+                       rdev->raid_disk = rdev->saved_raid_disk = -1;
+                       break;
                }
        }
 
@@ -2401,7 +2478,9 @@ static int analyse_superblocks(struct dm_target *ti, struct raid_set *rs)
                return -EINVAL;
 
        rdev_for_each(rdev, mddev)
-               if ((rdev != freshest) && super_validate(rs, rdev))
+               if (!test_bit(Journal, &rdev->flags) &&
+                   rdev != freshest &&
+                   super_validate(rs, rdev))
                        return -EINVAL;
        return 0;
 }
@@ -2488,10 +2567,12 @@ static int rs_adjust_data_offsets(struct raid_set *rs)
                return -ENOSPC;
        }
 out:
-       /* Adjust data offsets on all rdevs */
+       /* Adjust data offsets on all rdevs but on any raid4/5/6 journal device */
        rdev_for_each(rdev, &rs->md) {
-               rdev->data_offset = data_offset;
-               rdev->new_data_offset = new_data_offset;
+               if (!test_bit(Journal, &rdev->flags)) {
+                       rdev->data_offset = data_offset;
+                       rdev->new_data_offset = new_data_offset;
+               }
        }
 
        return 0;
@@ -2504,8 +2585,10 @@ static void __reorder_raid_disk_indexes(struct raid_set *rs)
        struct md_rdev *rdev;
 
        rdev_for_each(rdev, &rs->md) {
-               rdev->raid_disk = i++;
-               rdev->saved_raid_disk = rdev->new_raid_disk = -1;
+               if (!test_bit(Journal, &rdev->flags)) {
+                       rdev->raid_disk = i++;
+                       rdev->saved_raid_disk = rdev->new_raid_disk = -1;
+               }
        }
 }
 
@@ -2845,7 +2928,7 @@ static int raid_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        if (r)
                goto bad;
 
-       calculated_dev_sectors = rs->dev[0].rdev.sectors;
+       calculated_dev_sectors = rs->md.dev_sectors;
 
        /*
         * Backup any new raid set level, layout, ...
@@ -2858,7 +2941,7 @@ static int raid_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        if (r)
                goto bad;
 
-       resize = calculated_dev_sectors != rs->dev[0].rdev.sectors;
+       resize = calculated_dev_sectors != __rdev_sectors(rs);
 
        INIT_WORK(&rs->md.event_work, do_table_event);
        ti->private = rs;
@@ -2902,6 +2985,13 @@ static int raid_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                        goto bad;
                }
 
+               /* We can't takeover a journaled raid4/5/6 */
+               if (test_bit(__CTR_FLAG_JOURNAL_DEV, &rs->ctr_flags)) {
+                       ti->error = "Can't takeover a journaled raid4/5/6 set";
+                       r = -EPERM;
+                       goto bad;
+               }
+
                /*
                 * If a takeover is needed, userspace sets any additional
                 * devices to rebuild and we can check for a valid request here.
@@ -2923,6 +3013,18 @@ static int raid_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                rs_setup_recovery(rs, MaxSector);
                rs_set_new(rs);
        } else if (rs_reshape_requested(rs)) {
+               /*
+                * No need to check for 'ongoing' takeover here, because takeover
+                * is an instant operation as oposed to an ongoing reshape.
+                */
+
+               /* We can't reshape a journaled raid4/5/6 */
+               if (test_bit(__CTR_FLAG_JOURNAL_DEV, &rs->ctr_flags)) {
+                       ti->error = "Can't reshape a journaled raid4/5/6 set";
+                       r = -EPERM;
+                       goto bad;
+               }
+
                /*
                  * We can only prepare for a reshape here, because the
                  * raid set needs to run to provide the repective reshape
@@ -3071,18 +3173,23 @@ static const char *decipher_sync_action(struct mddev *mddev)
 }
 
 /*
- * Return status string @rdev
+ * Return status string for @rdev
  *
  * Status characters:
  *
- *  'D' = Dead/Failed device
+ *  'D' = Dead/Failed raid set component or raid4/5/6 journal device
  *  'a' = Alive but not in-sync
- *  'A' = Alive and in-sync
+ *  'A' = Alive and in-sync raid set component or alive raid4/5/6 journal device
+ *  '-' = Non-existing device (i.e. uspace passed '- -' into the ctr)
  */
 static const char *__raid_dev_status(struct md_rdev *rdev, bool array_in_sync)
 {
-       if (test_bit(Faulty, &rdev->flags))
+       if (!rdev->bdev)
+               return "-";
+       else if (test_bit(Faulty, &rdev->flags))
                return "D";
+       else if (test_bit(Journal, &rdev->flags))
+               return "A";
        else if (!array_in_sync || !test_bit(In_sync, &rdev->flags))
                return "a";
        else
@@ -3151,7 +3258,8 @@ static sector_t rs_get_progress(struct raid_set *rs,
                         * being initialized.
                         */
                        rdev_for_each(rdev, mddev)
-                               if (!test_bit(In_sync, &rdev->flags))
+                               if (!test_bit(Journal, &rdev->flags) &&
+                                   !test_bit(In_sync, &rdev->flags))
                                        *array_in_sync = true;
 #if 0
                        r = 0; /* HM FIXME: TESTME: https://bugzilla.redhat.com/show_bug.cgi?id=1210637 ? */
@@ -3183,7 +3291,6 @@ static void raid_status(struct dm_target *ti, status_type_t type,
        sector_t progress, resync_max_sectors, resync_mismatches;
        const char *sync_action;
        struct raid_type *rt;
-       struct md_rdev *rdev;
 
        switch (type) {
        case STATUSTYPE_INFO:
@@ -3204,9 +3311,9 @@ static void raid_status(struct dm_target *ti, status_type_t type,
                                    atomic64_read(&mddev->resync_mismatches) : 0;
                sync_action = decipher_sync_action(&rs->md);
 
-               /* HM FIXME: do we want another state char for raid0? It shows 'D' or 'A' now */
-               rdev_for_each(rdev, mddev)
-                       DMEMIT(__raid_dev_status(rdev, array_in_sync));
+               /* HM FIXME: do we want another state char for raid0? It shows 'D'/'A'/'-' now */
+               for (i = 0; i < rs->raid_disks; i++)
+                       DMEMIT(__raid_dev_status(&rs->dev[i].rdev, array_in_sync));
 
                /*
                 * In-sync/Reshape ratio:
@@ -3252,6 +3359,12 @@ static void raid_status(struct dm_target *ti, status_type_t type,
                 * so retrieving it from the first raid disk is sufficient.
                 */
                DMEMIT(" %llu", (unsigned long long) rs->dev[0].rdev.data_offset);
+
+               /*
+                * v1.10.0+:
+                */
+               DMEMIT(" %s", test_bit(__CTR_FLAG_JOURNAL_DEV, &rs->ctr_flags) ?
+                             __raid_dev_status(&rs->journal_dev.rdev, 0) : "-");
                break;
 
        case STATUSTYPE_TABLE:
@@ -3265,7 +3378,8 @@ static void raid_status(struct dm_target *ti, status_type_t type,
                raid_param_cnt += rebuild_disks * 2 +
                                  write_mostly_params +
                                  hweight32(rs->ctr_flags & CTR_FLAG_OPTIONS_NO_ARGS) +
-                                 hweight32(rs->ctr_flags & CTR_FLAG_OPTIONS_ONE_ARG) * 2;
+                                 hweight32(rs->ctr_flags & CTR_FLAG_OPTIONS_ONE_ARG) * 2 +
+                                 (test_bit(__CTR_FLAG_JOURNAL_DEV, &rs->ctr_flags) ? 2 : 0);
                /* Emit table line */
                DMEMIT("%s %u %u", rs->raid_type->name, raid_param_cnt, mddev->new_chunk_sectors);
                if (test_bit(__CTR_FLAG_RAID10_FORMAT, &rs->ctr_flags))
@@ -3312,6 +3426,9 @@ static void raid_status(struct dm_target *ti, status_type_t type,
                if (test_bit(__CTR_FLAG_MIN_RECOVERY_RATE, &rs->ctr_flags))
                        DMEMIT(" %s %d", dm_raid_arg_name_by_flag(CTR_FLAG_MIN_RECOVERY_RATE),
                                         mddev->sync_speed_min);
+               if (test_bit(__CTR_FLAG_JOURNAL_DEV, &rs->ctr_flags))
+                       DMEMIT(" %s %s", dm_raid_arg_name_by_flag(CTR_FLAG_JOURNAL_DEV),
+                                       __get_dev_name(rs->journal_dev.dev));
                DMEMIT(" %d", rs->raid_disks);
                for (i = 0; i < rs->raid_disks; i++)
                        DMEMIT(" %s %s", __get_dev_name(rs->dev[i].meta_dev),
@@ -3347,10 +3464,11 @@ static int raid_message(struct dm_target *ti, unsigned int argc, char **argv)
        else {
                if (!strcasecmp(argv[0], "check"))
                        set_bit(MD_RECOVERY_CHECK, &mddev->recovery);
-               else if (!!strcasecmp(argv[0], "repair"))
+               else if (!strcasecmp(argv[0], "repair")) {
+                       set_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
+                       set_bit(MD_RECOVERY_SYNC, &mddev->recovery);
+               } else
                        return -EINVAL;
-               set_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
-               set_bit(MD_RECOVERY_SYNC, &mddev->recovery);
        }
        if (mddev->ro == 2) {
                /* A write to sync_action is enough to justify
@@ -3427,11 +3545,14 @@ static void attempt_restore_of_faulty_devices(struct raid_set *rs)
 
        memset(cleared_failed_devices, 0, sizeof(cleared_failed_devices));
 
-       for (i = 0; i < rs->md.raid_disks; i++) {
+       for (i = 0; i < mddev->raid_disks; i++) {
                r = &rs->dev[i].rdev;
-               if (test_bit(Faulty, &r->flags) && r->sb_page &&
-                   sync_page_io(r, 0, r->sb_size, r->sb_page,
-                                REQ_OP_READ, 0, true)) {
+               /* HM FIXME: enhance journal device recovery processing */
+               if (test_bit(Journal, &r->flags))
+                       continue;
+
+               if (test_bit(Faulty, &r->flags) &&
+                   r->meta_bdev && !read_disk_sb(r, r->sb_size, true)) {
                        DMINFO("Faulty %s device #%d has readable super block."
                               "  Attempting to revive it.",
                               rs->raid_type->name, i);
@@ -3445,22 +3566,26 @@ static void attempt_restore_of_faulty_devices(struct raid_set *rs)
                         * '>= 0' - meaning we must call this function
                         * ourselves.
                         */
-                       if ((r->raid_disk >= 0) &&
-                           (mddev->pers->hot_remove_disk(mddev, r) != 0))
-                               /* Failed to revive this device, try next */
-                               continue;
-
-                       r->raid_disk = i;
-                       r->saved_raid_disk = i;
                        flags = r->flags;
+                       clear_bit(In_sync, &r->flags); /* Mandatory for hot remove. */
+                       if (r->raid_disk >= 0) {
+                               if (mddev->pers->hot_remove_disk(mddev, r)) {
+                                       /* Failed to revive this device, try next */
+                                       r->flags = flags;
+                                       continue;
+                               }
+                       } else
+                               r->raid_disk = r->saved_raid_disk = i;
+
                        clear_bit(Faulty, &r->flags);
                        clear_bit(WriteErrorSeen, &r->flags);
-                       clear_bit(In_sync, &r->flags);
+
                        if (mddev->pers->hot_add_disk(mddev, r)) {
-                               r->raid_disk = -1;
-                               r->saved_raid_disk = -1;
+                               /* Failed to revive this device, try next */
+                               r->raid_disk = r->saved_raid_disk = -1;
                                r->flags = flags;
                        } else {
+                               clear_bit(In_sync, &r->flags);
                                r->recovery_offset = 0;
                                set_bit(i, (void *) cleared_failed_devices);
                                cleared = true;
@@ -3473,6 +3598,9 @@ static void attempt_restore_of_faulty_devices(struct raid_set *rs)
                uint64_t failed_devices[DISKS_ARRAY_ELEMS];
 
                rdev_for_each(r, &rs->md) {
+                       if (test_bit(Journal, &r->flags))
+                               continue;
+
                        sb = page_address(r->sb_page);
                        sb_retrieve_failed_devices(sb, failed_devices);
 
@@ -3651,7 +3779,7 @@ static void raid_resume(struct dm_target *ti)
 
 static struct target_type raid_target = {
        .name = "raid",
-       .version = {1, 9, 1},
+       .version = {1, 10, 0},
        .module = THIS_MODULE,
        .ctr = raid_ctr,
        .dtr = raid_dtr,
index 6c25213ab38c8d271ff58e093adee523571443ed..bdbb7e6e8212bfc050cadbfa42cb1fbabe03bc54 100644 (file)
@@ -17,8 +17,8 @@
 #include <linux/module.h>
 
 #define DM_MSG_PREFIX "multipath round-robin"
-#define RR_MIN_IO     1000
-#define RR_VERSION    "1.1.0"
+#define RR_MIN_IO     1
+#define RR_VERSION    "1.2.0"
 
 /*-----------------------------------------------------------------
  * Path-handling code, paths are held in lists
@@ -47,44 +47,19 @@ struct selector {
        struct list_head valid_paths;
        struct list_head invalid_paths;
        spinlock_t lock;
-       struct dm_path * __percpu *current_path;
-       struct percpu_counter repeat_count;
 };
 
-static void set_percpu_current_path(struct selector *s, struct dm_path *path)
-{
-       int cpu;
-
-       for_each_possible_cpu(cpu)
-               *per_cpu_ptr(s->current_path, cpu) = path;
-}
-
 static struct selector *alloc_selector(void)
 {
        struct selector *s = kmalloc(sizeof(*s), GFP_KERNEL);
 
-       if (!s)
-               return NULL;
-
-       INIT_LIST_HEAD(&s->valid_paths);
-       INIT_LIST_HEAD(&s->invalid_paths);
-       spin_lock_init(&s->lock);
-
-       s->current_path = alloc_percpu(struct dm_path *);
-       if (!s->current_path)
-               goto out_current_path;
-       set_percpu_current_path(s, NULL);
-
-       if (percpu_counter_init(&s->repeat_count, 0, GFP_KERNEL))
-               goto out_repeat_count;
+       if (s) {
+               INIT_LIST_HEAD(&s->valid_paths);
+               INIT_LIST_HEAD(&s->invalid_paths);
+               spin_lock_init(&s->lock);
+       }
 
        return s;
-
-out_repeat_count:
-       free_percpu(s->current_path);
-out_current_path:
-       kfree(s);
-       return NULL;;
 }
 
 static int rr_create(struct path_selector *ps, unsigned argc, char **argv)
@@ -105,8 +80,6 @@ static void rr_destroy(struct path_selector *ps)
 
        free_paths(&s->valid_paths);
        free_paths(&s->invalid_paths);
-       free_percpu(s->current_path);
-       percpu_counter_destroy(&s->repeat_count);
        kfree(s);
        ps->context = NULL;
 }
@@ -157,6 +130,11 @@ static int rr_add_path(struct path_selector *ps, struct dm_path *path,
                return -EINVAL;
        }
 
+       if (repeat_count > 1) {
+               DMWARN_LIMIT("repeat_count > 1 is deprecated, using 1 instead");
+               repeat_count = 1;
+       }
+
        /* allocate the path */
        pi = kmalloc(sizeof(*pi), GFP_KERNEL);
        if (!pi) {
@@ -183,9 +161,6 @@ static void rr_fail_path(struct path_selector *ps, struct dm_path *p)
        struct path_info *pi = p->pscontext;
 
        spin_lock_irqsave(&s->lock, flags);
-       if (p == *this_cpu_ptr(s->current_path))
-               set_percpu_current_path(s, NULL);
-
        list_move(&pi->list, &s->invalid_paths);
        spin_unlock_irqrestore(&s->lock, flags);
 }
@@ -208,29 +183,15 @@ static struct dm_path *rr_select_path(struct path_selector *ps, size_t nr_bytes)
        unsigned long flags;
        struct selector *s = ps->context;
        struct path_info *pi = NULL;
-       struct dm_path *current_path = NULL;
-
-       local_irq_save(flags);
-       current_path = *this_cpu_ptr(s->current_path);
-       if (current_path) {
-               percpu_counter_dec(&s->repeat_count);
-               if (percpu_counter_read_positive(&s->repeat_count) > 0) {
-                       local_irq_restore(flags);
-                       return current_path;
-               }
-       }
 
-       spin_lock(&s->lock);
+       spin_lock_irqsave(&s->lock, flags);
        if (!list_empty(&s->valid_paths)) {
                pi = list_entry(s->valid_paths.next, struct path_info, list);
                list_move_tail(&pi->list, &s->valid_paths);
-               percpu_counter_set(&s->repeat_count, pi->repeat_count);
-               set_percpu_current_path(s, pi->path);
-               current_path = pi->path;
        }
        spin_unlock_irqrestore(&s->lock, flags);
 
-       return current_path;
+       return pi ? pi->path : NULL;
 }
 
 static struct path_selector_type rr_ps = {
index 6e702fc69a83cb27f6bc1792d4871ad18d708f71..67d76f21fecd9a6e48d73861a19ef8c41914e0dd 100644 (file)
@@ -109,28 +109,6 @@ void dm_stop_queue(struct request_queue *q)
                dm_mq_stop_queue(q);
 }
 
-static struct dm_rq_target_io *alloc_old_rq_tio(struct mapped_device *md,
-                                               gfp_t gfp_mask)
-{
-       return mempool_alloc(md->io_pool, gfp_mask);
-}
-
-static void free_old_rq_tio(struct dm_rq_target_io *tio)
-{
-       mempool_free(tio, tio->md->io_pool);
-}
-
-static struct request *alloc_old_clone_request(struct mapped_device *md,
-                                              gfp_t gfp_mask)
-{
-       return mempool_alloc(md->rq_pool, gfp_mask);
-}
-
-static void free_old_clone_request(struct mapped_device *md, struct request *rq)
-{
-       mempool_free(rq, md->rq_pool);
-}
-
 /*
  * Partial completion handling for request-based dm
  */
@@ -185,7 +163,7 @@ static void end_clone_bio(struct bio *clone)
 
 static struct dm_rq_target_io *tio_from_request(struct request *rq)
 {
-       return (rq->q->mq_ops ? blk_mq_rq_to_pdu(rq) : rq->special);
+       return blk_mq_rq_to_pdu(rq);
 }
 
 static void rq_end_stats(struct mapped_device *md, struct request *orig)
@@ -233,31 +211,6 @@ static void rq_completed(struct mapped_device *md, int rw, bool run_queue)
        dm_put(md);
 }
 
-static void free_rq_clone(struct request *clone)
-{
-       struct dm_rq_target_io *tio = clone->end_io_data;
-       struct mapped_device *md = tio->md;
-
-       blk_rq_unprep_clone(clone);
-
-       /*
-        * It is possible for a clone_old_rq() allocated clone to
-        * get passed in -- it may not yet have a request_queue.
-        * This is known to occur if the error target replaces
-        * a multipath target that has a request_fn queue stacked
-        * on blk-mq queue(s).
-        */
-       if (clone->q && clone->q->mq_ops)
-               /* stacked on blk-mq queue(s) */
-               tio->ti->type->release_clone_rq(clone);
-       else if (!md->queue->mq_ops)
-               /* request_fn queue stacked on request_fn queue(s) */
-               free_old_clone_request(md, clone);
-
-       if (!md->queue->mq_ops)
-               free_old_rq_tio(tio);
-}
-
 /*
  * Complete the clone and the original request.
  * Must be called without clone's queue lock held,
@@ -270,20 +223,9 @@ static void dm_end_request(struct request *clone, int error)
        struct mapped_device *md = tio->md;
        struct request *rq = tio->orig;
 
-       if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
-               rq->errors = clone->errors;
-               rq->resid_len = clone->resid_len;
-
-               if (rq->sense)
-                       /*
-                        * We are using the sense buffer of the original
-                        * request.
-                        * So setting the length of the sense data is enough.
-                        */
-                       rq->sense_len = clone->sense_len;
-       }
+       blk_rq_unprep_clone(clone);
+       tio->ti->type->release_clone_rq(clone);
 
-       free_rq_clone(clone);
        rq_end_stats(md, rq);
        if (!rq->q->mq_ops)
                blk_end_request_all(rq, error);
@@ -292,22 +234,6 @@ static void dm_end_request(struct request *clone, int error)
        rq_completed(md, rw, true);
 }
 
-static void dm_unprep_request(struct request *rq)
-{
-       struct dm_rq_target_io *tio = tio_from_request(rq);
-       struct request *clone = tio->clone;
-
-       if (!rq->q->mq_ops) {
-               rq->special = NULL;
-               rq->rq_flags &= ~RQF_DONTPREP;
-       }
-
-       if (clone)
-               free_rq_clone(clone);
-       else if (!tio->md->queue->mq_ops)
-               free_old_rq_tio(tio);
-}
-
 /*
  * Requeue the original request of a clone.
  */
@@ -346,7 +272,10 @@ static void dm_requeue_original_request(struct dm_rq_target_io *tio, bool delay_
        int rw = rq_data_dir(rq);
 
        rq_end_stats(md, rq);
-       dm_unprep_request(rq);
+       if (tio->clone) {
+               blk_rq_unprep_clone(tio->clone);
+               tio->ti->type->release_clone_rq(tio->clone);
+       }
 
        if (!rq->q->mq_ops)
                dm_old_requeue_request(rq);
@@ -401,14 +330,11 @@ static void dm_softirq_done(struct request *rq)
        if (!clone) {
                rq_end_stats(tio->md, rq);
                rw = rq_data_dir(rq);
-               if (!rq->q->mq_ops) {
+               if (!rq->q->mq_ops)
                        blk_end_request_all(rq, tio->error);
-                       rq_completed(tio->md, rw, false);
-                       free_old_rq_tio(tio);
-               } else {
+               else
                        blk_mq_end_request(rq, tio->error);
-                       rq_completed(tio->md, rw, false);
-               }
+               rq_completed(tio->md, rw, false);
                return;
        }
 
@@ -452,16 +378,6 @@ static void end_clone_request(struct request *clone, int error)
 {
        struct dm_rq_target_io *tio = clone->end_io_data;
 
-       if (!clone->q->mq_ops) {
-               /*
-                * For just cleaning up the information of the queue in which
-                * the clone was dispatched.
-                * The clone is *NOT* freed actually here because it is alloced
-                * from dm own mempool (RQF_ALLOCED isn't set).
-                */
-               __blk_put_request(clone->q, clone);
-       }
-
        /*
         * Actual request completion is done in a softirq context which doesn't
         * hold the clone's queue lock.  Otherwise, deadlock could occur because:
@@ -511,9 +427,6 @@ static int setup_clone(struct request *clone, struct request *rq,
        if (r)
                return r;
 
-       clone->cmd = rq->cmd;
-       clone->cmd_len = rq->cmd_len;
-       clone->sense = rq->sense;
        clone->end_io = end_clone_request;
        clone->end_io_data = tio;
 
@@ -522,28 +435,6 @@ static int setup_clone(struct request *clone, struct request *rq,
        return 0;
 }
 
-static struct request *clone_old_rq(struct request *rq, struct mapped_device *md,
-                                   struct dm_rq_target_io *tio, gfp_t gfp_mask)
-{
-       /*
-        * Create clone for use with .request_fn request_queue
-        */
-       struct request *clone;
-
-       clone = alloc_old_clone_request(md, gfp_mask);
-       if (!clone)
-               return NULL;
-
-       blk_rq_init(NULL, clone);
-       if (setup_clone(clone, rq, tio, gfp_mask)) {
-               /* -ENOMEM */
-               free_old_clone_request(md, clone);
-               return NULL;
-       }
-
-       return clone;
-}
-
 static void map_tio_request(struct kthread_work *work);
 
 static void init_tio(struct dm_rq_target_io *tio, struct request *rq,
@@ -565,60 +456,6 @@ static void init_tio(struct dm_rq_target_io *tio, struct request *rq,
                kthread_init_work(&tio->work, map_tio_request);
 }
 
-static struct dm_rq_target_io *dm_old_prep_tio(struct request *rq,
-                                              struct mapped_device *md,
-                                              gfp_t gfp_mask)
-{
-       struct dm_rq_target_io *tio;
-       int srcu_idx;
-       struct dm_table *table;
-
-       tio = alloc_old_rq_tio(md, gfp_mask);
-       if (!tio)
-               return NULL;
-
-       init_tio(tio, rq, md);
-
-       table = dm_get_live_table(md, &srcu_idx);
-       /*
-        * Must clone a request if this .request_fn DM device
-        * is stacked on .request_fn device(s).
-        */
-       if (!dm_table_all_blk_mq_devices(table)) {
-               if (!clone_old_rq(rq, md, tio, gfp_mask)) {
-                       dm_put_live_table(md, srcu_idx);
-                       free_old_rq_tio(tio);
-                       return NULL;
-               }
-       }
-       dm_put_live_table(md, srcu_idx);
-
-       return tio;
-}
-
-/*
- * Called with the queue lock held.
- */
-static int dm_old_prep_fn(struct request_queue *q, struct request *rq)
-{
-       struct mapped_device *md = q->queuedata;
-       struct dm_rq_target_io *tio;
-
-       if (unlikely(rq->special)) {
-               DMWARN("Already has something in rq->special.");
-               return BLKPREP_KILL;
-       }
-
-       tio = dm_old_prep_tio(rq, md, GFP_ATOMIC);
-       if (!tio)
-               return BLKPREP_DEFER;
-
-       rq->special = tio;
-       rq->rq_flags |= RQF_DONTPREP;
-
-       return BLKPREP_OK;
-}
-
 /*
  * Returns:
  * DM_MAPIO_*       : the request has been processed as indicated
@@ -633,31 +470,18 @@ static int map_request(struct dm_rq_target_io *tio)
        struct request *rq = tio->orig;
        struct request *clone = NULL;
 
-       if (tio->clone) {
-               clone = tio->clone;
-               r = ti->type->map_rq(ti, clone, &tio->info);
-               if (r == DM_MAPIO_DELAY_REQUEUE)
-                       return DM_MAPIO_REQUEUE; /* .request_fn requeue is always immediate */
-       } else {
-               r = ti->type->clone_and_map_rq(ti, rq, &tio->info, &clone);
-               if (r < 0) {
-                       /* The target wants to complete the I/O */
-                       dm_kill_unmapped_request(rq, r);
-                       return r;
-               }
-               if (r == DM_MAPIO_REMAPPED &&
-                   setup_clone(clone, rq, tio, GFP_ATOMIC)) {
-                       /* -ENOMEM */
-                       ti->type->release_clone_rq(clone);
-                       return DM_MAPIO_REQUEUE;
-               }
-       }
-
+       r = ti->type->clone_and_map_rq(ti, rq, &tio->info, &clone);
        switch (r) {
        case DM_MAPIO_SUBMITTED:
                /* The target has taken the I/O to submit by itself later */
                break;
        case DM_MAPIO_REMAPPED:
+               if (setup_clone(clone, rq, tio, GFP_ATOMIC)) {
+                       /* -ENOMEM */
+                       ti->type->release_clone_rq(clone);
+                       return DM_MAPIO_REQUEUE;
+               }
+
                /* The target has remapped the I/O so dispatch it */
                trace_block_rq_remap(clone->q, clone, disk_devt(dm_disk(md)),
                                     blk_rq_pos(rq));
@@ -716,6 +540,29 @@ static void dm_start_request(struct mapped_device *md, struct request *orig)
        dm_get(md);
 }
 
+static int __dm_rq_init_rq(struct mapped_device *md, struct request *rq)
+{
+       struct dm_rq_target_io *tio = blk_mq_rq_to_pdu(rq);
+
+       /*
+        * Must initialize md member of tio, otherwise it won't
+        * be available in dm_mq_queue_rq.
+        */
+       tio->md = md;
+
+       if (md->init_tio_pdu) {
+               /* target-specific per-io data is immediately after the tio */
+               tio->info.ptr = tio + 1;
+       }
+
+       return 0;
+}
+
+static int dm_rq_init_rq(struct request_queue *q, struct request *rq, gfp_t gfp)
+{
+       return __dm_rq_init_rq(q->rq_alloc_data, rq);
+}
+
 static void map_tio_request(struct kthread_work *work)
 {
        struct dm_rq_target_io *tio = container_of(work, struct dm_rq_target_io, work);
@@ -814,6 +661,7 @@ static void dm_old_request_fn(struct request_queue *q)
                dm_start_request(md, rq);
 
                tio = tio_from_request(rq);
+               init_tio(tio, rq, md);
                /* Establish tio->ti before queuing work (map_tio_request) */
                tio->ti = ti;
                kthread_queue_work(&md->kworker, &tio->work);
@@ -824,10 +672,23 @@ static void dm_old_request_fn(struct request_queue *q)
 /*
  * Fully initialize a .request_fn request-based queue.
  */
-int dm_old_init_request_queue(struct mapped_device *md)
+int dm_old_init_request_queue(struct mapped_device *md, struct dm_table *t)
 {
+       struct dm_target *immutable_tgt;
+
        /* Fully initialize the queue */
-       if (!blk_init_allocated_queue(md->queue, dm_old_request_fn, NULL))
+       md->queue->cmd_size = sizeof(struct dm_rq_target_io);
+       md->queue->rq_alloc_data = md;
+       md->queue->request_fn = dm_old_request_fn;
+       md->queue->init_rq_fn = dm_rq_init_rq;
+
+       immutable_tgt = dm_table_get_immutable_target(t);
+       if (immutable_tgt && immutable_tgt->per_io_data_size) {
+               /* any target-specific per-io data is immediately after the tio */
+               md->queue->cmd_size += immutable_tgt->per_io_data_size;
+               md->init_tio_pdu = true;
+       }
+       if (blk_init_allocated_queue(md->queue) < 0)
                return -EINVAL;
 
        /* disable dm_old_request_fn's merge heuristic by default */
@@ -835,7 +696,6 @@ int dm_old_init_request_queue(struct mapped_device *md)
 
        dm_init_normal_md_queue(md);
        blk_queue_softirq_done(md->queue, dm_softirq_done);
-       blk_queue_prep_rq(md->queue, dm_old_prep_fn);
 
        /* Initialize the request-based DM worker thread */
        kthread_init_worker(&md->kworker);
@@ -856,21 +716,7 @@ static int dm_mq_init_request(void *data, struct request *rq,
                       unsigned int hctx_idx, unsigned int request_idx,
                       unsigned int numa_node)
 {
-       struct mapped_device *md = data;
-       struct dm_rq_target_io *tio = blk_mq_rq_to_pdu(rq);
-
-       /*
-        * Must initialize md member of tio, otherwise it won't
-        * be available in dm_mq_queue_rq.
-        */
-       tio->md = md;
-
-       if (md->init_tio_pdu) {
-               /* target-specific per-io data is immediately after the tio */
-               tio->info.ptr = tio + 1;
-       }
-
-       return 0;
+       return __dm_rq_init_rq(data, rq);
 }
 
 static int dm_mq_queue_rq(struct blk_mq_hw_ctx *hctx,
index 4da06cae7badf77d3afd11460ff61af53c61a6ce..f0020d21b95fcd52f9843ee4045cb11c3253a3dc 100644 (file)
@@ -48,7 +48,7 @@ struct dm_rq_clone_bio_info {
 bool dm_use_blk_mq_default(void);
 bool dm_use_blk_mq(struct mapped_device *md);
 
-int dm_old_init_request_queue(struct mapped_device *md);
+int dm_old_init_request_queue(struct mapped_device *md, struct dm_table *t);
 int dm_mq_init_request_queue(struct mapped_device *md, struct dm_table *t);
 void dm_mq_cleanup_mapped_device(struct mapped_device *md);
 
index 38b05f23b96c0be81fb3d53905d093b5c33919fc..0250e7e521abcbae456b0552e774d47f507f3dc3 100644 (file)
@@ -175,6 +175,7 @@ static void dm_stat_free(struct rcu_head *head)
        int cpu;
        struct dm_stat *s = container_of(head, struct dm_stat, rcu_head);
 
+       kfree(s->histogram_boundaries);
        kfree(s->program_id);
        kfree(s->aux_data);
        for_each_possible_cpu(cpu) {
index 0a427de23ed2c6a01fa183738705b8c8f6e3e099..3ad16d9c9d5aae956afc7b3c7ab820b4f52de4ed 100644 (file)
@@ -1750,7 +1750,7 @@ int dm_table_any_congested(struct dm_table *t, int bdi_bits)
                char b[BDEVNAME_SIZE];
 
                if (likely(q))
-                       r |= bdi_congested(&q->backing_dev_info, bdi_bits);
+                       r |= bdi_congested(q->backing_dev_info, bdi_bits);
                else
                        DMWARN_LIMIT("%s: any_congested: nonexistent device %s",
                                     dm_device_name(t->md),
index 710ae28fd618256ea0b1da6fc34c40ae6e473066..43d3445b121d79adb4344221d4d2cb3b27492bc5 100644 (file)
@@ -131,12 +131,6 @@ static int io_err_map(struct dm_target *tt, struct bio *bio)
        return -EIO;
 }
 
-static int io_err_map_rq(struct dm_target *ti, struct request *clone,
-                        union map_info *map_context)
-{
-       return -EIO;
-}
-
 static int io_err_clone_and_map_rq(struct dm_target *ti, struct request *rq,
                                   union map_info *map_context,
                                   struct request **clone)
@@ -161,7 +155,6 @@ static struct target_type error_target = {
        .ctr  = io_err_ctr,
        .dtr  = io_err_dtr,
        .map  = io_err_map,
-       .map_rq = io_err_map_rq,
        .clone_and_map_rq = io_err_clone_and_map_rq,
        .release_clone_rq = io_err_release_clone_rq,
        .direct_access = io_err_direct_access,
index d1c05c12a9db3851f0f8dfafee26b3853e25a666..2b266a2b5035b9fa699eb1afdf4c5dc53da54c66 100644 (file)
@@ -699,7 +699,7 @@ static void remap_to_origin(struct thin_c *tc, struct bio *bio)
 
 static int bio_triggers_commit(struct thin_c *tc, struct bio *bio)
 {
-       return (bio->bi_opf & (REQ_PREFLUSH | REQ_FUA)) &&
+       return op_is_flush(bio->bi_opf) &&
                dm_thin_changed_this_transaction(tc->td);
 }
 
@@ -870,8 +870,7 @@ static void __inc_remap_and_issue_cell(void *context,
        struct bio *bio;
 
        while ((bio = bio_list_pop(&cell->bios))) {
-               if (bio->bi_opf & (REQ_PREFLUSH | REQ_FUA) ||
-                   bio_op(bio) == REQ_OP_DISCARD)
+               if (op_is_flush(bio->bi_opf) || bio_op(bio) == REQ_OP_DISCARD)
                        bio_list_add(&info->defer_bios, bio);
                else {
                        inc_all_io_entry(info->tc->pool, bio);
@@ -1716,9 +1715,8 @@ static void __remap_and_issue_shared_cell(void *context,
        struct bio *bio;
 
        while ((bio = bio_list_pop(&cell->bios))) {
-               if ((bio_data_dir(bio) == WRITE) ||
-                   (bio->bi_opf & (REQ_PREFLUSH | REQ_FUA) ||
-                    bio_op(bio) == REQ_OP_DISCARD))
+               if (bio_data_dir(bio) == WRITE || op_is_flush(bio->bi_opf) ||
+                   bio_op(bio) == REQ_OP_DISCARD)
                        bio_list_add(&info->defer_bios, bio);
                else {
                        struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));;
@@ -2635,8 +2633,7 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio)
                return DM_MAPIO_SUBMITTED;
        }
 
-       if (bio->bi_opf & (REQ_PREFLUSH | REQ_FUA) ||
-           bio_op(bio) == REQ_OP_DISCARD) {
+       if (op_is_flush(bio->bi_opf) || bio_op(bio) == REQ_OP_DISCARD) {
                thin_defer_bio_with_throttle(tc, bio);
                return DM_MAPIO_SUBMITTED;
        }
@@ -2714,7 +2711,7 @@ static int pool_is_congested(struct dm_target_callbacks *cb, int bdi_bits)
                return 1;
 
        q = bdev_get_queue(pt->data_dev->bdev);
-       return bdi_congested(&q->backing_dev_info, bdi_bits);
+       return bdi_congested(q->backing_dev_info, bdi_bits);
 }
 
 static void requeue_bios(struct pool *pool)
index 3086da5664f37fe50a0679c8fe23affcc6d80511..9f37d7fc2786ca7d0304d5711cb39a853efe8b37 100644 (file)
@@ -91,7 +91,6 @@ static int dm_numa_node = DM_NUMA_NODE;
  */
 struct dm_md_mempools {
        mempool_t *io_pool;
-       mempool_t *rq_pool;
        struct bio_set *bs;
 };
 
@@ -466,13 +465,16 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode,
 
        if (r > 0) {
                /*
-                * Target determined this ioctl is being issued against
-                * a logical partition of the parent bdev; so extra
-                * validation is needed.
+                * Target determined this ioctl is being issued against a
+                * subset of the parent bdev; require extra privileges.
                 */
-               r = scsi_verify_blk_ioctl(NULL, cmd);
-               if (r)
+               if (!capable(CAP_SYS_RAWIO)) {
+                       DMWARN_LIMIT(
+       "%s: sending ioctl %x to DM device without required privilege.",
+                               current->comm, cmd);
+                       r = -ENOIOCTLCMD;
                        goto out;
+               }
        }
 
        r =  __blkdev_driver_ioctl(bdev, mode, cmd, arg);
@@ -972,10 +974,61 @@ void dm_accept_partial_bio(struct bio *bio, unsigned n_sectors)
 }
 EXPORT_SYMBOL_GPL(dm_accept_partial_bio);
 
+/*
+ * Flush current->bio_list when the target map method blocks.
+ * This fixes deadlocks in snapshot and possibly in other targets.
+ */
+struct dm_offload {
+       struct blk_plug plug;
+       struct blk_plug_cb cb;
+};
+
+static void flush_current_bio_list(struct blk_plug_cb *cb, bool from_schedule)
+{
+       struct dm_offload *o = container_of(cb, struct dm_offload, cb);
+       struct bio_list list;
+       struct bio *bio;
+
+       INIT_LIST_HEAD(&o->cb.list);
+
+       if (unlikely(!current->bio_list))
+               return;
+
+       list = *current->bio_list;
+       bio_list_init(current->bio_list);
+
+       while ((bio = bio_list_pop(&list))) {
+               struct bio_set *bs = bio->bi_pool;
+               if (unlikely(!bs) || bs == fs_bio_set) {
+                       bio_list_add(current->bio_list, bio);
+                       continue;
+               }
+
+               spin_lock(&bs->rescue_lock);
+               bio_list_add(&bs->rescue_list, bio);
+               queue_work(bs->rescue_workqueue, &bs->rescue_work);
+               spin_unlock(&bs->rescue_lock);
+       }
+}
+
+static void dm_offload_start(struct dm_offload *o)
+{
+       blk_start_plug(&o->plug);
+       o->cb.callback = flush_current_bio_list;
+       list_add(&o->cb.list, &current->plug->cb_list);
+}
+
+static void dm_offload_end(struct dm_offload *o)
+{
+       list_del(&o->cb.list);
+       blk_finish_plug(&o->plug);
+}
+
 static void __map_bio(struct dm_target_io *tio)
 {
        int r;
        sector_t sector;
+       struct dm_offload o;
        struct bio *clone = &tio->clone;
        struct dm_target *ti = tio->ti;
 
@@ -988,7 +1041,11 @@ static void __map_bio(struct dm_target_io *tio)
         */
        atomic_inc(&tio->io->io_count);
        sector = clone->bi_iter.bi_sector;
+
+       dm_offload_start(&o);
        r = ti->type->map(ti, clone);
+       dm_offload_end(&o);
+
        if (r == DM_MAPIO_REMAPPED) {
                /* the bio has been remapped so dispatch it */
 
@@ -1314,7 +1371,7 @@ static int dm_any_congested(void *congested_data, int bdi_bits)
                         * With request-based DM we only need to check the
                         * top-level queue for congestion.
                         */
-                       r = md->queue->backing_dev_info.wb.state & bdi_bits;
+                       r = md->queue->backing_dev_info->wb.state & bdi_bits;
                } else {
                        map = dm_get_live_table_fast(md);
                        if (map)
@@ -1397,7 +1454,7 @@ void dm_init_md_queue(struct mapped_device *md)
         * - must do so here (in alloc_dev callchain) before queue is used
         */
        md->queue->queuedata = md;
-       md->queue->backing_dev_info.congested_data = md;
+       md->queue->backing_dev_info->congested_data = md;
 }
 
 void dm_init_normal_md_queue(struct mapped_device *md)
@@ -1408,7 +1465,7 @@ void dm_init_normal_md_queue(struct mapped_device *md)
        /*
         * Initialize aspects of queue that aren't relevant for blk-mq
         */
-       md->queue->backing_dev_info.congested_fn = dm_any_congested;
+       md->queue->backing_dev_info->congested_fn = dm_any_congested;
        blk_queue_bounce_limit(md->queue, BLK_BOUNCE_ANY);
 }
 
@@ -1419,7 +1476,6 @@ static void cleanup_mapped_device(struct mapped_device *md)
        if (md->kworker_task)
                kthread_stop(md->kworker_task);
        mempool_destroy(md->io_pool);
-       mempool_destroy(md->rq_pool);
        if (md->bs)
                bioset_free(md->bs);
 
@@ -1595,12 +1651,10 @@ static void __bind_mempools(struct mapped_device *md, struct dm_table *t)
                goto out;
        }
 
-       BUG_ON(!p || md->io_pool || md->rq_pool || md->bs);
+       BUG_ON(!p || md->io_pool || md->bs);
 
        md->io_pool = p->io_pool;
        p->io_pool = NULL;
-       md->rq_pool = p->rq_pool;
-       p->rq_pool = NULL;
        md->bs = p->bs;
        p->bs = NULL;
 
@@ -1777,7 +1831,7 @@ int dm_setup_md_queue(struct mapped_device *md, struct dm_table *t)
 
        switch (type) {
        case DM_TYPE_REQUEST_BASED:
-               r = dm_old_init_request_queue(md);
+               r = dm_old_init_request_queue(md, t);
                if (r) {
                        DMERR("Cannot initialize queue for request-based mapped device");
                        return r;
@@ -2493,7 +2547,6 @@ struct dm_md_mempools *dm_alloc_md_mempools(struct mapped_device *md, unsigned t
                                            unsigned integrity, unsigned per_io_data_size)
 {
        struct dm_md_mempools *pools = kzalloc_node(sizeof(*pools), GFP_KERNEL, md->numa_node_id);
-       struct kmem_cache *cachep = NULL;
        unsigned int pool_size = 0;
        unsigned int front_pad;
 
@@ -2503,20 +2556,16 @@ struct dm_md_mempools *dm_alloc_md_mempools(struct mapped_device *md, unsigned t
        switch (type) {
        case DM_TYPE_BIO_BASED:
        case DM_TYPE_DAX_BIO_BASED:
-               cachep = _io_cache;
                pool_size = dm_get_reserved_bio_based_ios();
                front_pad = roundup(per_io_data_size, __alignof__(struct dm_target_io)) + offsetof(struct dm_target_io, clone);
+       
+               pools->io_pool = mempool_create_slab_pool(pool_size, _io_cache);
+               if (!pools->io_pool)
+                       goto out;
                break;
        case DM_TYPE_REQUEST_BASED:
-               cachep = _rq_tio_cache;
-               pool_size = dm_get_reserved_rq_based_ios();
-               pools->rq_pool = mempool_create_slab_pool(pool_size, _rq_cache);
-               if (!pools->rq_pool)
-                       goto out;
-               /* fall through to setup remaining rq-based pools */
        case DM_TYPE_MQ_REQUEST_BASED:
-               if (!pool_size)
-                       pool_size = dm_get_reserved_rq_based_ios();
+               pool_size = dm_get_reserved_rq_based_ios();
                front_pad = offsetof(struct dm_rq_clone_bio_info, clone);
                /* per_io_data_size is used for blk-mq pdu at queue allocation */
                break;
@@ -2524,12 +2573,6 @@ struct dm_md_mempools *dm_alloc_md_mempools(struct mapped_device *md, unsigned t
                BUG();
        }
 
-       if (cachep) {
-               pools->io_pool = mempool_create_slab_pool(pool_size, cachep);
-               if (!pools->io_pool)
-                       goto out;
-       }
-
        pools->bs = bioset_create_nobvec(pool_size, front_pad);
        if (!pools->bs)
                goto out;
@@ -2551,7 +2594,6 @@ void dm_free_md_mempools(struct dm_md_mempools *pools)
                return;
 
        mempool_destroy(pools->io_pool);
-       mempool_destroy(pools->rq_pool);
 
        if (pools->bs)
                bioset_free(pools->bs);
index f0aad08b96544fe11bcb8724cd7167863bc76a82..f298b01f7ab305dd5665875c0119edbd18f93113 100644 (file)
@@ -95,8 +95,7 @@ int dm_setup_md_queue(struct mapped_device *md, struct dm_table *t);
 /*
  * To check whether the target type is request-based or not (bio-based).
  */
-#define dm_target_request_based(t) (((t)->type->map_rq != NULL) || \
-                                   ((t)->type->clone_and_map_rq != NULL))
+#define dm_target_request_based(t) ((t)->type->clone_and_map_rq != NULL)
 
 /*
  * To check whether the target type is a hybrid (capable of being
index 5975c99156841ecd25f1210457e6612dc4191227..f1c7bbac31a580bb6f708b614696f17404badc0d 100644 (file)
@@ -62,7 +62,7 @@ static int linear_congested(struct mddev *mddev, int bits)
 
        for (i = 0; i < mddev->raid_disks && !ret ; i++) {
                struct request_queue *q = bdev_get_queue(conf->disks[i].rdev->bdev);
-               ret |= bdi_congested(&q->backing_dev_info, bits);
+               ret |= bdi_congested(q->backing_dev_info, bits);
        }
 
        return ret;
index 01175dac0db6361f04cd1bcad910a59202cc276d..ba485dcf1064dd463bdb93edd85157b247d0fcb5 100644 (file)
@@ -5346,8 +5346,8 @@ int md_run(struct mddev *mddev)
                        queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mddev->queue);
                else
                        queue_flag_clear_unlocked(QUEUE_FLAG_NONROT, mddev->queue);
-               mddev->queue->backing_dev_info.congested_data = mddev;
-               mddev->queue->backing_dev_info.congested_fn = md_congested;
+               mddev->queue->backing_dev_info->congested_data = mddev;
+               mddev->queue->backing_dev_info->congested_fn = md_congested;
        }
        if (pers->sync_request) {
                if (mddev->kobj.sd &&
@@ -5704,7 +5704,7 @@ static int do_md_stop(struct mddev *mddev, int mode,
 
                __md_stop_writes(mddev);
                __md_stop(mddev);
-               mddev->queue->backing_dev_info.congested_fn = NULL;
+               mddev->queue->backing_dev_info->congested_fn = NULL;
 
                /* tell userspace to handle 'inactive' */
                sysfs_notify_dirent_safe(mddev->sysfs_state);
index aa8c4e5c1ee28f3c5302eb64f525c6ece820c0e7..d457afa672d57a172965aa000913fa6ff6625878 100644 (file)
@@ -169,7 +169,7 @@ static int multipath_congested(struct mddev *mddev, int bits)
                if (rdev && !test_bit(Faulty, &rdev->flags)) {
                        struct request_queue *q = bdev_get_queue(rdev->bdev);
 
-                       ret |= bdi_congested(&q->backing_dev_info, bits);
+                       ret |= bdi_congested(q->backing_dev_info, bits);
                        /* Just like multipath_map, we just check the
                         * first available device
                         */
index 7938cd21fa4c70c673e6d7b076f2c631b8ca77e8..185dc60360b55f8916f0a8f3cc93e0e44104a0fa 100644 (file)
@@ -976,6 +976,27 @@ int dm_array_cursor_next(struct dm_array_cursor *c)
 }
 EXPORT_SYMBOL_GPL(dm_array_cursor_next);
 
+int dm_array_cursor_skip(struct dm_array_cursor *c, uint32_t count)
+{
+       int r;
+
+       do {
+               uint32_t remaining = le32_to_cpu(c->ab->nr_entries) - c->index;
+
+               if (count < remaining) {
+                       c->index += count;
+                       return 0;
+               }
+
+               count -= remaining;
+               r = dm_array_cursor_next(c);
+
+       } while (!r);
+
+       return r;
+}
+EXPORT_SYMBOL_GPL(dm_array_cursor_skip);
+
 void dm_array_cursor_get_value(struct dm_array_cursor *c, void **value_le)
 {
        *value_le = element_at(c->info, c->ab, c->index);
index 27ee49a5547317af5275ad2a3c4820736b330322..d7d2d579c662cebedbdf41eef9882480f4541cad 100644 (file)
@@ -207,6 +207,7 @@ void dm_array_cursor_end(struct dm_array_cursor *c);
 
 uint32_t dm_array_cursor_index(struct dm_array_cursor *c);
 int dm_array_cursor_next(struct dm_array_cursor *c);
+int dm_array_cursor_skip(struct dm_array_cursor *c, uint32_t count);
 
 /*
  * value_le is only valid while the cursor points at the current value.
index 36f7cc2c7109b45b77a1ff27e1f7b1a146dbfcf1..b7208d82e748a0992081e8e4fae88a6a3d306978 100644 (file)
@@ -39,6 +39,48 @@ int dm_bitset_empty(struct dm_disk_bitset *info, dm_block_t *root)
 }
 EXPORT_SYMBOL_GPL(dm_bitset_empty);
 
+struct packer_context {
+       bit_value_fn fn;
+       unsigned nr_bits;
+       void *context;
+};
+
+static int pack_bits(uint32_t index, void *value, void *context)
+{
+       int r;
+       struct packer_context *p = context;
+       unsigned bit, nr = min(64u, p->nr_bits - (index * 64));
+       uint64_t word = 0;
+       bool bv;
+
+       for (bit = 0; bit < nr; bit++) {
+               r = p->fn(index * 64 + bit, &bv, p->context);
+               if (r)
+                       return r;
+
+               if (bv)
+                       set_bit(bit, (unsigned long *) &word);
+               else
+                       clear_bit(bit, (unsigned long *) &word);
+       }
+
+       *((__le64 *) value) = cpu_to_le64(word);
+
+       return 0;
+}
+
+int dm_bitset_new(struct dm_disk_bitset *info, dm_block_t *root,
+                 uint32_t size, bit_value_fn fn, void *context)
+{
+       struct packer_context p;
+       p.fn = fn;
+       p.nr_bits = size;
+       p.context = context;
+
+       return dm_array_new(&info->array_info, root, dm_div_up(size, 64), pack_bits, &p);
+}
+EXPORT_SYMBOL_GPL(dm_bitset_new);
+
 int dm_bitset_resize(struct dm_disk_bitset *info, dm_block_t root,
                     uint32_t old_nr_entries, uint32_t new_nr_entries,
                     bool default_value, dm_block_t *new_root)
@@ -168,4 +210,108 @@ int dm_bitset_test_bit(struct dm_disk_bitset *info, dm_block_t root,
 }
 EXPORT_SYMBOL_GPL(dm_bitset_test_bit);
 
+static int cursor_next_array_entry(struct dm_bitset_cursor *c)
+{
+       int r;
+       __le64 *value;
+
+       r = dm_array_cursor_next(&c->cursor);
+       if (r)
+               return r;
+
+       dm_array_cursor_get_value(&c->cursor, (void **) &value);
+       c->array_index++;
+       c->bit_index = 0;
+       c->current_bits = le64_to_cpu(*value);
+       return 0;
+}
+
+int dm_bitset_cursor_begin(struct dm_disk_bitset *info,
+                          dm_block_t root, uint32_t nr_entries,
+                          struct dm_bitset_cursor *c)
+{
+       int r;
+       __le64 *value;
+
+       if (!nr_entries)
+               return -ENODATA;
+
+       c->info = info;
+       c->entries_remaining = nr_entries;
+
+       r = dm_array_cursor_begin(&info->array_info, root, &c->cursor);
+       if (r)
+               return r;
+
+       dm_array_cursor_get_value(&c->cursor, (void **) &value);
+       c->array_index = 0;
+       c->bit_index = 0;
+       c->current_bits = le64_to_cpu(*value);
+
+       return r;
+}
+EXPORT_SYMBOL_GPL(dm_bitset_cursor_begin);
+
+void dm_bitset_cursor_end(struct dm_bitset_cursor *c)
+{
+       return dm_array_cursor_end(&c->cursor);
+}
+EXPORT_SYMBOL_GPL(dm_bitset_cursor_end);
+
+int dm_bitset_cursor_next(struct dm_bitset_cursor *c)
+{
+       int r = 0;
+
+       if (!c->entries_remaining)
+               return -ENODATA;
+
+       c->entries_remaining--;
+       if (++c->bit_index > 63)
+               r = cursor_next_array_entry(c);
+
+       return r;
+}
+EXPORT_SYMBOL_GPL(dm_bitset_cursor_next);
+
+int dm_bitset_cursor_skip(struct dm_bitset_cursor *c, uint32_t count)
+{
+       int r;
+       __le64 *value;
+       uint32_t nr_array_skip;
+       uint32_t remaining_in_word = 64 - c->bit_index;
+
+       if (c->entries_remaining < count)
+               return -ENODATA;
+
+       if (count < remaining_in_word) {
+               c->bit_index += count;
+               c->entries_remaining -= count;
+               return 0;
+
+       } else {
+               c->entries_remaining -= remaining_in_word;
+               count -= remaining_in_word;
+       }
+
+       nr_array_skip = (count / 64) + 1;
+       r = dm_array_cursor_skip(&c->cursor, nr_array_skip);
+       if (r)
+               return r;
+
+       dm_array_cursor_get_value(&c->cursor, (void **) &value);
+       c->entries_remaining -= count;
+       c->array_index += nr_array_skip;
+       c->bit_index = count & 63;
+       c->current_bits = le64_to_cpu(*value);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(dm_bitset_cursor_skip);
+
+bool dm_bitset_cursor_get_value(struct dm_bitset_cursor *c)
+{
+       return test_bit(c->bit_index, (unsigned long *) &c->current_bits);
+}
+EXPORT_SYMBOL_GPL(dm_bitset_cursor_get_value);
+
 /*----------------------------------------------------------------*/
index c2287d672ef5ed4735b91fe9fac3f708c9b7df64..df888da04ee1301b98a2e6bc0653c70aefe15aa8 100644 (file)
@@ -92,6 +92,22 @@ void dm_disk_bitset_init(struct dm_transaction_manager *tm,
  */
 int dm_bitset_empty(struct dm_disk_bitset *info, dm_block_t *new_root);
 
+/*
+ * Creates a new bitset populated with values provided by a callback
+ * function.  This is more efficient than creating an empty bitset,
+ * resizing, and then setting values since that process incurs a lot of
+ * copying.
+ *
+ * info - describes the array
+ * root - the root block of the array on disk
+ * size - the number of entries in the array
+ * fn - the callback
+ * context - passed to the callback
+ */
+typedef int (*bit_value_fn)(uint32_t index, bool *value, void *context);
+int dm_bitset_new(struct dm_disk_bitset *info, dm_block_t *root,
+                 uint32_t size, bit_value_fn fn, void *context);
+
 /*
  * Resize the bitset.
  *
@@ -161,6 +177,29 @@ int dm_bitset_test_bit(struct dm_disk_bitset *info, dm_block_t root,
 int dm_bitset_flush(struct dm_disk_bitset *info, dm_block_t root,
                    dm_block_t *new_root);
 
+struct dm_bitset_cursor {
+       struct dm_disk_bitset *info;
+       struct dm_array_cursor cursor;
+
+       uint32_t entries_remaining;
+       uint32_t array_index;
+       uint32_t bit_index;
+       uint64_t current_bits;
+};
+
+/*
+ * Make sure you've flush any dm_disk_bitset and updated the root before
+ * using this.
+ */
+int dm_bitset_cursor_begin(struct dm_disk_bitset *info,
+                          dm_block_t root, uint32_t nr_entries,
+                          struct dm_bitset_cursor *c);
+void dm_bitset_cursor_end(struct dm_bitset_cursor *c);
+
+int dm_bitset_cursor_next(struct dm_bitset_cursor *c);
+int dm_bitset_cursor_skip(struct dm_bitset_cursor *c, uint32_t count);
+bool dm_bitset_cursor_get_value(struct dm_bitset_cursor *c);
+
 /*----------------------------------------------------------------*/
 
 #endif /* _LINUX_DM_BITSET_H */
index 758d90cc2733a248f8b9b1d22cc77e2ed6dee3e1..0863905dee028c536a9278edba3eba89371d01be 100644 (file)
@@ -462,7 +462,7 @@ int dm_bm_read_lock(struct dm_block_manager *bm, dm_block_t b,
        int r;
 
        p = dm_bufio_read(bm->bufio, b, (struct dm_buffer **) result);
-       if (IS_ERR(p))
+       if (unlikely(IS_ERR(p)))
                return PTR_ERR(p);
 
        aux = dm_bufio_get_aux_data(to_buffer(*result));
@@ -498,7 +498,7 @@ int dm_bm_write_lock(struct dm_block_manager *bm,
                return -EPERM;
 
        p = dm_bufio_read(bm->bufio, b, (struct dm_buffer **) result);
-       if (IS_ERR(p))
+       if (unlikely(IS_ERR(p)))
                return PTR_ERR(p);
 
        aux = dm_bufio_get_aux_data(to_buffer(*result));
@@ -531,7 +531,7 @@ int dm_bm_read_try_lock(struct dm_block_manager *bm,
        int r;
 
        p = dm_bufio_get(bm->bufio, b, (struct dm_buffer **) result);
-       if (IS_ERR(p))
+       if (unlikely(IS_ERR(p)))
                return PTR_ERR(p);
        if (unlikely(!p))
                return -EWOULDBLOCK;
@@ -567,7 +567,7 @@ int dm_bm_write_lock_zero(struct dm_block_manager *bm,
                return -EPERM;
 
        p = dm_bufio_new(bm->bufio, b, (struct dm_buffer **) result);
-       if (IS_ERR(p))
+       if (unlikely(IS_ERR(p)))
                return PTR_ERR(p);
 
        memset(p, 0, dm_bm_block_size(bm));
index 20a40329d84abd46c7491936e974967bd2bfd0d4..02e2ee0d8a00bbff8fdd026e1ab059af06730faf 100644 (file)
@@ -272,7 +272,12 @@ int dm_btree_del(struct dm_btree_info *info, dm_block_t root)
        int r;
        struct del_stack *s;
 
-       s = kmalloc(sizeof(*s), GFP_NOIO);
+       /*
+        * dm_btree_del() is called via an ioctl, as such should be
+        * considered an FS op.  We can't recurse back into the FS, so we
+        * allocate GFP_NOFS.
+        */
+       s = kmalloc(sizeof(*s), GFP_NOFS);
        if (!s)
                return -ENOMEM;
        s->info = info;
@@ -1139,6 +1144,17 @@ int dm_btree_cursor_next(struct dm_btree_cursor *c)
 }
 EXPORT_SYMBOL_GPL(dm_btree_cursor_next);
 
+int dm_btree_cursor_skip(struct dm_btree_cursor *c, uint32_t count)
+{
+       int r = 0;
+
+       while (count-- && !r)
+               r = dm_btree_cursor_next(c);
+
+       return r;
+}
+EXPORT_SYMBOL_GPL(dm_btree_cursor_skip);
+
 int dm_btree_cursor_get_value(struct dm_btree_cursor *c, uint64_t *key, void *value_le)
 {
        if (c->depth) {
index db9bd26adf31f54f78ba7470658a1fa8bcf067ac..3dc5bb1a4748b51059e3fe728ea858f46db44c29 100644 (file)
@@ -209,6 +209,7 @@ int dm_btree_cursor_begin(struct dm_btree_info *info, dm_block_t root,
                          bool prefetch_leaves, struct dm_btree_cursor *c);
 void dm_btree_cursor_end(struct dm_btree_cursor *c);
 int dm_btree_cursor_next(struct dm_btree_cursor *c);
+int dm_btree_cursor_skip(struct dm_btree_cursor *c, uint32_t count);
 int dm_btree_cursor_get_value(struct dm_btree_cursor *c, uint64_t *key, void *value_le);
 
 #endif /* _LINUX_DM_BTREE_H */
index 4c28608a0c94938d7925fbd63ab51e152c0f2a2c..829b4ce057d8cbaa873a6cfdd2cbc1ed934b5e18 100644 (file)
@@ -626,13 +626,19 @@ int sm_ll_open_metadata(struct ll_disk *ll, struct dm_transaction_manager *tm,
                        void *root_le, size_t len)
 {
        int r;
-       struct disk_sm_root *smr = root_le;
+       struct disk_sm_root smr;
 
        if (len < sizeof(struct disk_sm_root)) {
                DMERR("sm_metadata root too small");
                return -ENOMEM;
        }
 
+       /*
+        * We don't know the alignment of the root_le buffer, so need to
+        * copy into a new structure.
+        */
+       memcpy(&smr, root_le, sizeof(smr));
+
        r = sm_ll_init(ll, tm);
        if (r < 0)
                return r;
@@ -644,10 +650,10 @@ int sm_ll_open_metadata(struct ll_disk *ll, struct dm_transaction_manager *tm,
        ll->max_entries = metadata_ll_max_entries;
        ll->commit = metadata_ll_commit;
 
-       ll->nr_blocks = le64_to_cpu(smr->nr_blocks);
-       ll->nr_allocated = le64_to_cpu(smr->nr_allocated);
-       ll->bitmap_root = le64_to_cpu(smr->bitmap_root);
-       ll->ref_count_root = le64_to_cpu(smr->ref_count_root);
+       ll->nr_blocks = le64_to_cpu(smr.nr_blocks);
+       ll->nr_allocated = le64_to_cpu(smr.nr_allocated);
+       ll->bitmap_root = le64_to_cpu(smr.bitmap_root);
+       ll->ref_count_root = le64_to_cpu(smr.ref_count_root);
 
        return ll->open_index(ll);
 }
index 20557e2c60c6236bf16cc35e33d3f9eb0e318779..4aed69d9dd17ca1c4f9aa055699f53764a681ccb 100644 (file)
@@ -544,7 +544,7 @@ static int sm_metadata_copy_root(struct dm_space_map *sm, void *where_le, size_t
 
 static int sm_metadata_extend(struct dm_space_map *sm, dm_block_t extra_blocks);
 
-static struct dm_space_map ops = {
+static const struct dm_space_map ops = {
        .destroy = sm_metadata_destroy,
        .extend = sm_metadata_extend,
        .get_nr_blocks = sm_metadata_get_nr_blocks,
@@ -671,7 +671,7 @@ static int sm_bootstrap_copy_root(struct dm_space_map *sm, void *where,
        return -EINVAL;
 }
 
-static struct dm_space_map bootstrap_ops = {
+static const struct dm_space_map bootstrap_ops = {
        .destroy = sm_bootstrap_destroy,
        .extend = sm_bootstrap_extend,
        .get_nr_blocks = sm_bootstrap_get_nr_blocks,
index 848365d474f3a3bca26168ac3619f2c52edd7618..d6585239bff22809edbcaf3881dc2f2ae0a2f41e 100644 (file)
@@ -41,7 +41,7 @@ static int raid0_congested(struct mddev *mddev, int bits)
        for (i = 0; i < raid_disks && !ret ; i++) {
                struct request_queue *q = bdev_get_queue(devlist[i]->bdev);
 
-               ret |= bdi_congested(&q->backing_dev_info, bits);
+               ret |= bdi_congested(q->backing_dev_info, bits);
        }
        return ret;
 }
@@ -420,8 +420,8 @@ static int raid0_run(struct mddev *mddev)
                 */
                int stripe = mddev->raid_disks *
                        (mddev->chunk_sectors << 9) / PAGE_SIZE;
-               if (mddev->queue->backing_dev_info.ra_pages < 2* stripe)
-                       mddev->queue->backing_dev_info.ra_pages = 2* stripe;
+               if (mddev->queue->backing_dev_info->ra_pages < 2* stripe)
+                       mddev->queue->backing_dev_info->ra_pages = 2* stripe;
        }
 
        dump_zones(mddev);
index 7b0f647bcccb513b6650136cddd51bc0ebec796a..830ff2b203463ef075d53a6c7a2ae22e0ec2c7d9 100644 (file)
@@ -744,9 +744,9 @@ static int raid1_congested(struct mddev *mddev, int bits)
                         * non-congested targets, it can be removed
                         */
                        if ((bits & (1 << WB_async_congested)) || 1)
-                               ret |= bdi_congested(&q->backing_dev_info, bits);
+                               ret |= bdi_congested(q->backing_dev_info, bits);
                        else
-                               ret &= bdi_congested(&q->backing_dev_info, bits);
+                               ret &= bdi_congested(q->backing_dev_info, bits);
                }
        }
        rcu_read_unlock();
@@ -1170,10 +1170,6 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
        int i, disks;
        struct bitmap *bitmap = mddev->bitmap;
        unsigned long flags;
-       const int op = bio_op(bio);
-       const unsigned long do_sync = (bio->bi_opf & REQ_SYNC);
-       const unsigned long do_flush_fua = (bio->bi_opf &
-                                               (REQ_PREFLUSH | REQ_FUA));
        struct md_rdev *blocked_rdev;
        struct blk_plug_cb *cb;
        struct raid1_plug_cb *plug = NULL;
@@ -1389,7 +1385,8 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
                                   conf->mirrors[i].rdev->data_offset);
                mbio->bi_bdev = conf->mirrors[i].rdev->bdev;
                mbio->bi_end_io = raid1_end_write_request;
-               bio_set_op_attrs(mbio, op, do_flush_fua | do_sync);
+               mbio->bi_opf = bio_op(bio) |
+                       (bio->bi_opf & (REQ_SYNC | REQ_PREFLUSH | REQ_FUA));
                if (test_bit(FailFast, &conf->mirrors[i].rdev->flags) &&
                    !test_bit(WriteMostly, &conf->mirrors[i].rdev->flags) &&
                    conf->raid_disks - mddev->degraded > 1)
index 1920756828dfb3fd512e2cb5705f329f10324698..6bc5c2a85160e2654050716ef9270c1de3e903a3 100644 (file)
@@ -860,7 +860,7 @@ static int raid10_congested(struct mddev *mddev, int bits)
                if (rdev && !test_bit(Faulty, &rdev->flags)) {
                        struct request_queue *q = bdev_get_queue(rdev->bdev);
 
-                       ret |= bdi_congested(&q->backing_dev_info, bits);
+                       ret |= bdi_congested(q->backing_dev_info, bits);
                }
        }
        rcu_read_unlock();
@@ -3841,8 +3841,8 @@ static int raid10_run(struct mddev *mddev)
                 * maybe...
                 */
                stripe /= conf->geo.near_copies;
-               if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
-                       mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
+               if (mddev->queue->backing_dev_info->ra_pages < 2 * stripe)
+                       mddev->queue->backing_dev_info->ra_pages = 2 * stripe;
        }
 
        if (md_integrity_register(mddev))
@@ -4643,8 +4643,8 @@ static void end_reshape(struct r10conf *conf)
                int stripe = conf->geo.raid_disks *
                        ((conf->mddev->chunk_sectors << 9) / PAGE_SIZE);
                stripe /= conf->geo.near_copies;
-               if (conf->mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
-                       conf->mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
+               if (conf->mddev->queue->backing_dev_info->ra_pages < 2 * stripe)
+                       conf->mddev->queue->backing_dev_info->ra_pages = 2 * stripe;
        }
        conf->fullsync = 0;
 }
index 3c7e106c12a246046abc67c479f589d10966bce3..6214e699342c87d7cdcb83e385530dff808fa918 100644 (file)
@@ -6331,10 +6331,10 @@ raid5_store_skip_copy(struct mddev *mddev, const char *page, size_t len)
                mddev_suspend(mddev);
                conf->skip_copy = new;
                if (new)
-                       mddev->queue->backing_dev_info.capabilities |=
+                       mddev->queue->backing_dev_info->capabilities |=
                                BDI_CAP_STABLE_WRITES;
                else
-                       mddev->queue->backing_dev_info.capabilities &=
+                       mddev->queue->backing_dev_info->capabilities &=
                                ~BDI_CAP_STABLE_WRITES;
                mddev_resume(mddev);
        }
@@ -7153,8 +7153,8 @@ static int raid5_run(struct mddev *mddev)
                int data_disks = conf->previous_raid_disks - conf->max_degraded;
                int stripe = data_disks *
                        ((mddev->chunk_sectors << 9) / PAGE_SIZE);
-               if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
-                       mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
+               if (mddev->queue->backing_dev_info->ra_pages < 2 * stripe)
+                       mddev->queue->backing_dev_info->ra_pages = 2 * stripe;
 
                chunk_size = mddev->chunk_sectors << 9;
                blk_queue_io_min(mddev->queue, chunk_size);
@@ -7763,8 +7763,8 @@ static void end_reshape(struct r5conf *conf)
                        int data_disks = conf->raid_disks - conf->max_degraded;
                        int stripe = data_disks * ((conf->chunk_sectors << 9)
                                                   / PAGE_SIZE);
-                       if (conf->mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
-                               conf->mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
+                       if (conf->mddev->queue->backing_dev_info->ra_pages < 2 * stripe)
+                               conf->mddev->queue->backing_dev_info->ra_pages = 2 * stripe;
                }
        }
 }
index aca3ab83a8a142af696443857dcc1a8882689ac6..37217e205040e6748b5b8f7d955063d213ec94e6 100644 (file)
@@ -239,7 +239,7 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
 
 #if IS_REACHABLE(CONFIG_RC_CORE)
        /* Prepare the RC input device */
-       adap->rc = rc_allocate_device();
+       adap->rc = rc_allocate_device(RC_DRIVER_SCANCODE);
        if (!adap->rc) {
                pr_err("cec-%s: failed to allocate memory for rc_dev\n",
                       name);
@@ -259,7 +259,6 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
        adap->rc->input_id.vendor = 0;
        adap->rc->input_id.product = 0;
        adap->rc->input_id.version = 1;
-       adap->rc->driver_type = RC_DRIVER_SCANCODE;
        adap->rc->driver_name = CEC_NAME;
        adap->rc->allowed_protocols = RC_BIT_CEC;
        adap->rc->priv = adap;
index f5956402fc69dfcd88c9870abe5ea76e3d6e6d65..5f10151ecec94cf3b3dead5091fb01707998a504 100644 (file)
@@ -24,8 +24,7 @@
 
 /* Can we use the specified front-end?  Remember that if we are compiled
  * into the kernel we can't call code that's in modules.  */
-#define FE_SUPPORTED(fe) (defined(CONFIG_DVB_##fe) || \
-       (defined(CONFIG_DVB_##fe##_MODULE) && defined(MODULE)))
+#define FE_SUPPORTED(fe) IS_REACHABLE(CONFIG_DVB_ ## fe)
 
 #if FE_SUPPORTED(BCM3510) || (FE_SUPPORTED(CX24120) && FE_SUPPORTED(ISL6421))
 static int flexcop_fe_request_firmware(struct dvb_frontend *fe,
index 4338ab0043b4f73f6bb2731a42579a99f84d0094..2e0ab55cd67e1b8381fe7a0d4683a99d6aafac8d 100644 (file)
  * but WITHOUT 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 Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 
 #include "flexcop.h"
index 2725702eda7b97bccda06dd3768023a62b3392a7..81dce9a81bd30aa2fbbe83147da8de44630782c5 100644 (file)
  * but WITHOUT 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.
  */
 
 
index ca2f80c7740cd62baa90ff8511a07a02015b55f7..af6b2268db61dadd92a3e3ebd33d1c6c46f99716 100644 (file)
  *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
  *
  *  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 "sms-cards.h"
index bb3d733f092b5b79b0ac69181095fcb3ac689d39..e6264b4797b481b957f97b8ac655448a84a75313 100644 (file)
  *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
  *
  *  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 __SMS_CARDS_H__
index f3a42834d7d61e34f865420befaa63ad639775a2..e7a0d7798d5b249197b9e21cd0ae6f2066162d20 100644 (file)
  *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
  *
  *  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 "smscoreapi.h"
index 41f2a39399792e55fb6217163a6906ad66837229..7c898b06d85c33ddcb92cfce60b22e7208e8b343 100644 (file)
@@ -58,7 +58,7 @@ int sms_ir_init(struct smscore_device_t *coredev)
        struct rc_dev *dev;
 
        pr_debug("Allocating rc device\n");
-       dev = rc_allocate_device();
+       dev = rc_allocate_device(RC_DRIVER_IR_RAW);
        if (!dev)
                return -ENOMEM;
 
@@ -86,8 +86,7 @@ int sms_ir_init(struct smscore_device_t *coredev)
 #endif
 
        dev->priv = coredev;
-       dev->driver_type = RC_DRIVER_IR_RAW;
-       dev->allowed_protocols = RC_BIT_ALL;
+       dev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
        dev->map_name = sms_get_board(board_id)->rc_codes;
        dev->driver_name = MODULE_NAME;
 
index 11976031aff8df36763844b4844d7795c06efca0..6e1020227f9fe7d5f4843902509b6b3e845b01f5 100644 (file)
  * but WITHOUT 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.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index f8adf4506a45134796bb2139e772c599e52454dd..f854309ba8a5a385d9eec0fd9fca5e10f5177b9a 100644 (file)
  * 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 Lesser 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 __DEMUX_H
index 0c16bb21310109050f461979306408f7ca42866b..45e91add73ba003bafb78584f4c04f708daa4152 100644 (file)
  * 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 Lesser 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.
- *
  */
 
 #define pr_fmt(fmt) "dmxdev: " fmt
@@ -151,6 +147,7 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
 
        if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
                void *mem;
+
                if (!dvbdev->readers) {
                        mutex_unlock(&dmxdev->mutex);
                        return -EBUSY;
@@ -202,6 +199,7 @@ static int dvb_dvr_release(struct inode *inode, struct file *file)
                dvbdev->readers++;
                if (dmxdev->dvr_buffer.data) {
                        void *mem = dmxdev->dvr_buffer.data;
+                       /*memory barrier*/
                        mb();
                        spin_lock_irq(&dmxdev->lock);
                        dmxdev->dvr_buffer.data = NULL;
@@ -876,7 +874,7 @@ static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev,
        dvb_dmxdev_filter_stop(dmxdevfilter);
        dvb_dmxdev_filter_reset(dmxdevfilter);
 
-       if ((unsigned)params->pes_type > DMX_PES_OTHER)
+       if ((unsigned int)params->pes_type > DMX_PES_OTHER)
                return -EINVAL;
 
        dmxdevfilter->type = DMXDEV_TYPE_PES;
@@ -1125,7 +1123,7 @@ static int dvb_demux_release(struct inode *inode, struct file *file)
 
        mutex_lock(&dmxdev->mutex);
        dmxdev->dvbdev->users--;
-       if(dmxdev->dvbdev->users==1 && dmxdev->exit==1) {
+       if (dmxdev->dvbdev->users == 1 && dmxdev->exit == 1) {
                mutex_unlock(&dmxdev->mutex);
                wake_up(&dmxdev->dvbdev->wait_queue);
        } else
@@ -1263,14 +1261,14 @@ EXPORT_SYMBOL(dvb_dmxdev_init);
 
 void dvb_dmxdev_release(struct dmxdev *dmxdev)
 {
-       dmxdev->exit=1;
+       dmxdev->exit = 1;
        if (dmxdev->dvbdev->users > 1) {
                wait_event(dmxdev->dvbdev->wait_queue,
-                               dmxdev->dvbdev->users==1);
+                               dmxdev->dvbdev->users == 1);
        }
        if (dmxdev->dvr_dvbdev->users > 1) {
                wait_event(dmxdev->dvr_dvbdev->wait_queue,
-                               dmxdev->dvr_dvbdev->users==1);
+                               dmxdev->dvr_dvbdev->users == 1);
        }
 
        dvb_unregister_device(dmxdev->dvbdev);
index 48c6cf92ab994c896d9e0f2d155e532c0aa5c500..054fd4eb6192f6048573f6c6dbd1e7d8fdc2f019 100644 (file)
  * 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 Lesser 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 _DMXDEV_H_
index 779f4224b63e4f69b46c93a8db31ae010d6d6001..e200aa6f2d2f30782317d4b6f3ab9e71e3c0c9fd 100644 (file)
 #define USB_VID_GIGABYTE                       0x1044
 #define USB_VID_YUAN                           0x1164
 #define USB_VID_XTENSIONS                      0x1ae7
+#define USB_VID_ZYDAS                          0x0ace
 #define USB_VID_HUMAX_COEX                     0x10b9
 #define USB_VID_774                            0x7a69
 #define USB_VID_EVOLUTEPC                      0x1e59
 #define USB_VID_AZUREWAVE                      0x13d3
 #define USB_VID_TECHNISAT                      0x14f7
+#define USB_VID_HAMA                           0x147f
 
 /* Product IDs */
 #define USB_PID_ADSTECH_USB2_COLD                      0xa333
 #define USB_PID_SVEON_STV27                             0xd3af
 #define USB_PID_TURBOX_DTT_2000                         0xd3a4
 #define USB_PID_WINTV_SOLOHD                            0x0264
-#define USB_PID_EVOLVEO_XTRATV_STICK                   0xa115
+#define USB_PID_EVOLVEO_XTRATV_STICK                   0xa115
+#define USB_PID_HAMA_DVBT_HYBRID                       0x2758
 #endif
index fd893141211c49d699fc0c30da01a7eaaa417ba3..000d737ad8271fcd6596e1206c958d9f3b1dde45 100644 (file)
  * but WITHOUT 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.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  */
 
 #define pr_fmt(fmt) "dvb_ca_en50221: " fmt
index bbbff72bbb2af53c2fe255b7e0bc2836558edeed..4eac71e50c5f953a8ee738992b5b0c9de83454e2 100644 (file)
  * 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 Lesser 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.
- *
  */
 
 #define pr_fmt(fmt) "dvb_demux: " fmt
index 9235b008ea0ab4db1a539bdce137044a0382a4f7..6f572ca8d3393fd4731a10c5d69ffe66026a2e6e 100644 (file)
  * 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 Lesser 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 _DVB_DEMUX_H_
index db74cb74d271b23d7566b82ab51e50d819a3d2db..85ae3669aa668baa656ed396ddb4913583e48777 100644 (file)
  * but WITHOUT 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.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  */
 
 /* Enables DVBv3 compatibility bits at the headers */
@@ -2536,9 +2533,13 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
                fepriv->voltage = -1;
 
 #ifdef CONFIG_MEDIA_CONTROLLER_DVB
-               if (fe->dvb->mdev && fe->dvb->mdev->enable_source) {
-                       ret = fe->dvb->mdev->enable_source(dvbdev->entity,
+               if (fe->dvb->mdev) {
+                       mutex_lock(&fe->dvb->mdev->graph_mutex);
+                       if (fe->dvb->mdev->enable_source)
+                               ret = fe->dvb->mdev->enable_source(
+                                                          dvbdev->entity,
                                                           &fepriv->pipe);
+                       mutex_unlock(&fe->dvb->mdev->graph_mutex);
                        if (ret) {
                                dev_err(fe->dvb->device,
                                        "Tuner is busy. Error %d\n", ret);
@@ -2562,8 +2563,12 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
 
 err3:
 #ifdef CONFIG_MEDIA_CONTROLLER_DVB
-       if (fe->dvb->mdev && fe->dvb->mdev->disable_source)
-               fe->dvb->mdev->disable_source(dvbdev->entity);
+       if (fe->dvb->mdev) {
+               mutex_lock(&fe->dvb->mdev->graph_mutex);
+               if (fe->dvb->mdev->disable_source)
+                       fe->dvb->mdev->disable_source(dvbdev->entity);
+               mutex_unlock(&fe->dvb->mdev->graph_mutex);
+       }
 err2:
 #endif
        dvb_generic_release(inode, file);
@@ -2595,8 +2600,12 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
        if (dvbdev->users == -1) {
                wake_up(&fepriv->wait_queue);
 #ifdef CONFIG_MEDIA_CONTROLLER_DVB
-               if (fe->dvb->mdev && fe->dvb->mdev->disable_source)
-                       fe->dvb->mdev->disable_source(dvbdev->entity);
+               if (fe->dvb->mdev) {
+                       mutex_lock(&fe->dvb->mdev->graph_mutex);
+                       if (fe->dvb->mdev->disable_source)
+                               fe->dvb->mdev->disable_source(dvbdev->entity);
+                       mutex_unlock(&fe->dvb->mdev->graph_mutex);
+               }
 #endif
                if (fe->exit != DVB_FE_NO_EXIT)
                        wake_up(&dvbdev->wait_queue);
index beb7c93aa6cb3ab8da7bf714ff49aad9983ac1a5..a2e1810dd83a7245c0d121fbb54ed99913a92418 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
 #include <linux/bitops.h>
index 4d11d3529c143f5ad33bb93096fc75dd280c3087..8690ec42954d03bae4b2c65871c887bc26a1ee79 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
 #ifndef __DVB_MATH_H
index 8f11d7e459931bb5a8ed74569781dc83d4bd6422..9947b342633eec756ef64cfcd6b81d643105d5e5 100644 (file)
  * but WITHOUT 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.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  */
 
 /*
index ede78e8c8aa8ccf5783fea84663ea48f2c8f25be..e9b18aa03e02e600d1834e9fdc5ea4ee5afc9e72 100644 (file)
  * 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 Lesser 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 _DVB_NET_H_
index 5c4b5a1f604f439562385a6f83609edec4579b9d..2322af1b87429aab67454c4ca7f7f486ab9bf211 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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.
  */
 
 
index 38c844667789361d1385f6609b30fedade294bcd..41aad0f99d73c43fe1ab997e4fad93df6ba2b9ec 100644 (file)
  * 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 Lesser 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.
- *
  */
 
 #define pr_fmt(fmt) "dvbdev: " fmt
index 8c0a7b51555e4e7faa0d2919991592352d086426..49189392cf3b9c22907ff9ff17c610a4b86a4ff3 100644 (file)
  * 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 Lesser 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 _DVBDEV_H_
index c841fa1770bec376559d3292f262b41b3a78d5bb..e8c6554a47aa13761ca8016cb0cd7d066e38927a 100644 (file)
@@ -447,13 +447,6 @@ config DVB_EC100
        help
          Say Y when you want to support this frontend.
 
-config DVB_HD29L2
-       tristate "HDIC HD29L2"
-       depends on DVB_CORE && I2C
-       default m if !MEDIA_SUBDRV_AUTOSELECT
-       help
-         Say Y when you want to support this frontend.
-
 config DVB_STV0367
        tristate "ST STV0367 based"
        depends on DVB_CORE && I2C
@@ -513,6 +506,13 @@ config DVB_AS102_FE
        depends on DVB_CORE
        default DVB_AS102
 
+config DVB_ZD1301_DEMOD
+       tristate "ZyDAS ZD1301"
+       depends on DVB_CORE && I2C
+       default m if !MEDIA_SUBDRV_AUTOSELECT
+       help
+         Say Y when you want to support this frontend.
+
 config DVB_GP8PSK_FE
        tristate
        depends on DVB_CORE
@@ -619,7 +619,7 @@ config DVB_LGDT3305
 
 config DVB_LGDT3306A
        tristate "LG Electronics LGDT3306A based"
-       depends on DVB_CORE && I2C
+       depends on DVB_CORE && I2C && I2C_MUX
        default m if !MEDIA_SUBDRV_AUTOSELECT
        help
          An ATSC 8VSB and QAM-B 64/256 demodulator module. Say Y when you want
@@ -852,6 +852,7 @@ config DVB_M88RS2000
 config DVB_AF9033
        tristate "Afatech AF9033 DVB-T demodulator"
        depends on DVB_CORE && I2C
+       select REGMAP_I2C
        default m if !MEDIA_SUBDRV_AUTOSELECT
 
 config DVB_HORUS3A
index 93921a4eaa275997a5ed4178de1acb1a54409430..3fccaf34ef520acf4207710dbf15fd7c08cc62fa 100644 (file)
@@ -99,7 +99,6 @@ obj-$(CONFIG_DVB_MN88472) += mn88472.o
 obj-$(CONFIG_DVB_MN88473) += mn88473.o
 obj-$(CONFIG_DVB_ISL6423) += isl6423.o
 obj-$(CONFIG_DVB_EC100) += ec100.o
-obj-$(CONFIG_DVB_HD29L2) += hd29l2.o
 obj-$(CONFIG_DVB_DS3000) += ds3000.o
 obj-$(CONFIG_DVB_TS2020) += ts2020.o
 obj-$(CONFIG_DVB_MB86A16) += mb86a16.o
@@ -126,3 +125,4 @@ obj-$(CONFIG_DVB_TC90522) += tc90522.o
 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
index c6cb3bbc912a5b731d366d561ebff46bb8bfa97d..b978002af4d8afc76563e8e73235595a68a09e48 100644 (file)
  *    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 "af9013_priv.h"
index dcdd163ace8576e71d98e575959b3332227e6ba8..277112863719ed13d9ac7da4d00500d73b016330 100644 (file)
  *    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 AF9013_H
index 8b9392cfc00dd13ddfb6d6834bbe370e6b474438..31d6538abfaeb1e35c19bec40a85303c472e3fb1 100644 (file)
  *    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 AF9013_PRIV_H
index f8818028752e126ea53fd7399212a2a1698436f4..aaed7cfe5f6660d608084607c8d5d2afa5f1848e 100644 (file)
  *    but WITHOUT 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.
  */
 
 #include "af9033_priv.h"
 
-/* Max transfer size done by I2C transfer functions */
-#define MAX_XFER_SIZE  64
-
 struct af9033_dev {
        struct i2c_client *client;
+       struct regmap *regmap;
        struct dvb_frontend fe;
        struct af9033_config cfg;
        bool is_af9035;
@@ -43,146 +37,19 @@ struct af9033_dev {
        u64 total_block_count;
 };
 
-/* write multiple registers */
-static int af9033_wr_regs(struct af9033_dev *dev, u32 reg, const u8 *val,
-               int len)
-{
-       int ret;
-       u8 buf[MAX_XFER_SIZE];
-       struct i2c_msg msg[1] = {
-               {
-                       .addr = dev->client->addr,
-                       .flags = 0,
-                       .len = 3 + len,
-                       .buf = buf,
-               }
-       };
-
-       if (3 + len > sizeof(buf)) {
-               dev_warn(&dev->client->dev,
-                               "i2c wr reg=%04x: len=%d is too big!\n",
-                               reg, len);
-               return -EINVAL;
-       }
-
-       buf[0] = (reg >> 16) & 0xff;
-       buf[1] = (reg >>  8) & 0xff;
-       buf[2] = (reg >>  0) & 0xff;
-       memcpy(&buf[3], val, len);
-
-       ret = i2c_transfer(dev->client->adapter, msg, 1);
-       if (ret == 1) {
-               ret = 0;
-       } else {
-               dev_warn(&dev->client->dev, "i2c wr failed=%d reg=%06x len=%d\n",
-                               ret, reg, len);
-               ret = -EREMOTEIO;
-       }
-
-       return ret;
-}
-
-/* read multiple registers */
-static int af9033_rd_regs(struct af9033_dev *dev, u32 reg, u8 *val, int len)
-{
-       int ret;
-       u8 buf[3] = { (reg >> 16) & 0xff, (reg >> 8) & 0xff,
-                       (reg >> 0) & 0xff };
-       struct i2c_msg msg[2] = {
-               {
-                       .addr = dev->client->addr,
-                       .flags = 0,
-                       .len = sizeof(buf),
-                       .buf = buf
-               }, {
-                       .addr = dev->client->addr,
-                       .flags = I2C_M_RD,
-                       .len = len,
-                       .buf = val
-               }
-       };
-
-       ret = i2c_transfer(dev->client->adapter, msg, 2);
-       if (ret == 2) {
-               ret = 0;
-       } else {
-               dev_warn(&dev->client->dev, "i2c rd failed=%d reg=%06x len=%d\n",
-                               ret, reg, len);
-               ret = -EREMOTEIO;
-       }
-
-       return ret;
-}
-
-
-/* write single register */
-static int af9033_wr_reg(struct af9033_dev *dev, u32 reg, u8 val)
-{
-       return af9033_wr_regs(dev, reg, &val, 1);
-}
-
-/* read single register */
-static int af9033_rd_reg(struct af9033_dev *dev, u32 reg, u8 *val)
-{
-       return af9033_rd_regs(dev, reg, val, 1);
-}
-
-/* write single register with mask */
-static int af9033_wr_reg_mask(struct af9033_dev *dev, u32 reg, u8 val,
-               u8 mask)
-{
-       int ret;
-       u8 tmp;
-
-       /* no need for read if whole reg is written */
-       if (mask != 0xff) {
-               ret = af9033_rd_regs(dev, reg, &tmp, 1);
-               if (ret)
-                       return ret;
-
-               val &= mask;
-               tmp &= ~mask;
-               val |= tmp;
-       }
-
-       return af9033_wr_regs(dev, reg, &val, 1);
-}
-
-/* read single register with mask */
-static int af9033_rd_reg_mask(struct af9033_dev *dev, u32 reg, u8 *val,
-               u8 mask)
-{
-       int ret, i;
-       u8 tmp;
-
-       ret = af9033_rd_regs(dev, reg, &tmp, 1);
-       if (ret)
-               return ret;
-
-       tmp &= mask;
-
-       /* find position of the first bit */
-       for (i = 0; i < 8; i++) {
-               if ((mask >> i) & 0x01)
-                       break;
-       }
-       *val = tmp >> i;
-
-       return 0;
-}
-
-/* write reg val table using reg addr auto increment */
+/* Write reg val table using reg addr auto increment */
 static int af9033_wr_reg_val_tab(struct af9033_dev *dev,
-               const struct reg_val *tab, int tab_len)
+                                const struct reg_val *tab, int tab_len)
 {
+       struct i2c_client *client = dev->client;
 #define MAX_TAB_LEN 212
        int ret, i, j;
        u8 buf[1 + MAX_TAB_LEN];
 
-       dev_dbg(&dev->client->dev, "tab_len=%d\n", tab_len);
+       dev_dbg(&client->dev, "tab_len=%d\n", tab_len);
 
        if (tab_len > sizeof(buf)) {
-               dev_warn(&dev->client->dev, "tab len %d is too big\n", tab_len);
+               dev_warn(&client->dev, "tab len %d is too big\n", tab_len);
                return -EINVAL;
        }
 
@@ -190,8 +57,9 @@ static int af9033_wr_reg_val_tab(struct af9033_dev *dev,
                buf[j] = tab[i].val;
 
                if (i == tab_len - 1 || tab[i].reg != tab[i + 1].reg - 1) {
-                       ret = af9033_wr_regs(dev, tab[i].reg - j, buf, j + 1);
-                       if (ret < 0)
+                       ret = regmap_bulk_write(dev->regmap, tab[i].reg - j,
+                                               buf, j + 1);
+                       if (ret)
                                goto err;
 
                        j = 0;
@@ -201,47 +69,20 @@ static int af9033_wr_reg_val_tab(struct af9033_dev *dev,
        }
 
        return 0;
-
 err:
-       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
-
+       dev_dbg(&client->dev, "failed=%d\n", ret);
        return ret;
 }
 
-static u32 af9033_div(struct af9033_dev *dev, u32 a, u32 b, u32 x)
-{
-       u32 r = 0, c = 0, i;
-
-       dev_dbg(&dev->client->dev, "a=%d b=%d x=%d\n", a, b, x);
-
-       if (a > b) {
-               c = a / b;
-               a = a - c * b;
-       }
-
-       for (i = 0; i < x; i++) {
-               if (a >= b) {
-                       r += 1;
-                       a -= b;
-               }
-               a <<= 1;
-               r <<= 1;
-       }
-       r = (c << (u32)x) + r;
-
-       dev_dbg(&dev->client->dev, "a=%d b=%d x=%d r=%d r=%x\n", a, b, x, r, r);
-
-       return r;
-}
-
 static int af9033_init(struct dvb_frontend *fe)
 {
        struct af9033_dev *dev = fe->demodulator_priv;
+       struct i2c_client *client = dev->client;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int ret, i, len;
+       unsigned int utmp;
        const struct reg_val *init;
        u8 buf[4];
-       u32 adc_cw, clock_cw;
        struct reg_val_mask tab[] = {
                { 0x80fb24, 0x00, 0x08 },
                { 0x80004c, 0x00, 0xff },
@@ -271,80 +112,76 @@ static int af9033_init(struct dvb_frontend *fe)
                { 0x800045, dev->cfg.adc_multiplier, 0xff },
        };
 
-       /* program clock control */
-       clock_cw = af9033_div(dev, dev->cfg.clock, 1000000ul, 19ul);
-       buf[0] = (clock_cw >>  0) & 0xff;
-       buf[1] = (clock_cw >>  8) & 0xff;
-       buf[2] = (clock_cw >> 16) & 0xff;
-       buf[3] = (clock_cw >> 24) & 0xff;
-
-       dev_dbg(&dev->client->dev, "clock=%d clock_cw=%08x\n",
-                       dev->cfg.clock, clock_cw);
+       dev_dbg(&client->dev, "\n");
 
-       ret = af9033_wr_regs(dev, 0x800025, buf, 4);
-       if (ret < 0)
+       /* Main clk control */
+       utmp = div_u64((u64)dev->cfg.clock * 0x80000, 1000000);
+       buf[0] = (utmp >>  0) & 0xff;
+       buf[1] = (utmp >>  8) & 0xff;
+       buf[2] = (utmp >> 16) & 0xff;
+       buf[3] = (utmp >> 24) & 0xff;
+       ret = regmap_bulk_write(dev->regmap, 0x800025, buf, 4);
+       if (ret)
                goto err;
 
-       /* program ADC control */
+       dev_dbg(&client->dev, "clk=%u clk_cw=%08x\n", dev->cfg.clock, utmp);
+
+       /* ADC clk control */
        for (i = 0; i < ARRAY_SIZE(clock_adc_lut); i++) {
                if (clock_adc_lut[i].clock == dev->cfg.clock)
                        break;
        }
        if (i == ARRAY_SIZE(clock_adc_lut)) {
-               dev_err(&dev->client->dev,
-                       "Couldn't find ADC config for clock=%d\n",
+               dev_err(&client->dev, "Couldn't find ADC config for clock %d\n",
                        dev->cfg.clock);
                goto err;
        }
 
-       adc_cw = af9033_div(dev, clock_adc_lut[i].adc, 1000000ul, 19ul);
-       buf[0] = (adc_cw >>  0) & 0xff;
-       buf[1] = (adc_cw >>  8) & 0xff;
-       buf[2] = (adc_cw >> 16) & 0xff;
-
-       dev_dbg(&dev->client->dev, "adc=%d adc_cw=%06x\n",
-                       clock_adc_lut[i].adc, adc_cw);
-
-       ret = af9033_wr_regs(dev, 0x80f1cd, buf, 3);
-       if (ret < 0)
+       utmp = div_u64((u64)clock_adc_lut[i].adc * 0x80000, 1000000);
+       buf[0] = (utmp >>  0) & 0xff;
+       buf[1] = (utmp >>  8) & 0xff;
+       buf[2] = (utmp >> 16) & 0xff;
+       ret = regmap_bulk_write(dev->regmap, 0x80f1cd, buf, 3);
+       if (ret)
                goto err;
 
-       /* program register table */
+       dev_dbg(&client->dev, "adc=%u adc_cw=%06x\n",
+               clock_adc_lut[i].adc, utmp);
+
+       /* Config register table */
        for (i = 0; i < ARRAY_SIZE(tab); i++) {
-               ret = af9033_wr_reg_mask(dev, tab[i].reg, tab[i].val,
-                               tab[i].mask);
-               if (ret < 0)
+               ret = regmap_update_bits(dev->regmap, tab[i].reg, tab[i].mask,
+                                        tab[i].val);
+               if (ret)
                        goto err;
        }
 
-       /* clock output */
+       /* Demod clk output */
        if (dev->cfg.dyn0_clk) {
-               ret = af9033_wr_reg(dev, 0x80fba8, 0x00);
-               if (ret < 0)
+               ret = regmap_write(dev->regmap, 0x80fba8, 0x00);
+               if (ret)
                        goto err;
        }
 
-       /* settings for TS interface */
+       /* TS interface */
        if (dev->cfg.ts_mode == AF9033_TS_MODE_USB) {
-               ret = af9033_wr_reg_mask(dev, 0x80f9a5, 0x00, 0x01);
-               if (ret < 0)
+               ret = regmap_update_bits(dev->regmap, 0x80f9a5, 0x01, 0x00);
+               if (ret)
                        goto err;
-
-               ret = af9033_wr_reg_mask(dev, 0x80f9b5, 0x01, 0x01);
-               if (ret < 0)
+               ret = regmap_update_bits(dev->regmap, 0x80f9b5, 0x01, 0x01);
+               if (ret)
                        goto err;
        } else {
-               ret = af9033_wr_reg_mask(dev, 0x80f990, 0x00, 0x01);
-               if (ret < 0)
+               ret = regmap_update_bits(dev->regmap, 0x80f990, 0x01, 0x00);
+               if (ret)
                        goto err;
-
-               ret = af9033_wr_reg_mask(dev, 0x80f9b5, 0x00, 0x01);
-               if (ret < 0)
+               ret = regmap_update_bits(dev->regmap, 0x80f9b5, 0x01, 0x00);
+               if (ret)
                        goto err;
        }
 
-       /* load OFSM settings */
-       dev_dbg(&dev->client->dev, "load ofsm settings\n");
+       /* Demod core settings */
+       dev_dbg(&client->dev, "load ofsm settings\n");
        switch (dev->cfg.tuner) {
        case AF9033_TUNER_IT9135_38:
        case AF9033_TUNER_IT9135_51:
@@ -365,11 +202,11 @@ static int af9033_init(struct dvb_frontend *fe)
        }
 
        ret = af9033_wr_reg_val_tab(dev, init, len);
-       if (ret < 0)
+       if (ret)
                goto err;
 
-       /* load tuner specific settings */
-       dev_dbg(&dev->client->dev, "load tuner specific settings\n");
+       /* Demod tuner specific settings */
+       dev_dbg(&client->dev, "load tuner specific settings\n");
        switch (dev->cfg.tuner) {
        case AF9033_TUNER_TUA9001:
                len = ARRAY_SIZE(tuner_init_tua9001);
@@ -420,27 +257,25 @@ static int af9033_init(struct dvb_frontend *fe)
                init = tuner_init_it9135_62;
                break;
        default:
-               dev_dbg(&dev->client->dev, "unsupported tuner ID=%d\n",
-                               dev->cfg.tuner);
+               dev_dbg(&client->dev, "unsupported tuner ID=%d\n",
+                       dev->cfg.tuner);
                ret = -ENODEV;
                goto err;
        }
 
        ret = af9033_wr_reg_val_tab(dev, init, len);
-       if (ret < 0)
+       if (ret)
                goto err;
 
        if (dev->cfg.ts_mode == AF9033_TS_MODE_SERIAL) {
-               ret = af9033_wr_reg_mask(dev, 0x00d91c, 0x01, 0x01);
-               if (ret < 0)
+               ret = regmap_update_bits(dev->regmap, 0x00d91c, 0x01, 0x01);
+               if (ret)
                        goto err;
-
-               ret = af9033_wr_reg_mask(dev, 0x00d917, 0x00, 0x01);
-               if (ret < 0)
+               ret = regmap_update_bits(dev->regmap, 0x00d917, 0x01, 0x00);
+               if (ret)
                        goto err;
-
-               ret = af9033_wr_reg_mask(dev, 0x00d916, 0x00, 0x01);
-               if (ret < 0)
+               ret = regmap_update_bits(dev->regmap, 0x00d916, 0x01, 0x00);
+               if (ret)
                        goto err;
        }
 
@@ -448,13 +283,13 @@ static int af9033_init(struct dvb_frontend *fe)
        case AF9033_TUNER_IT9135_60:
        case AF9033_TUNER_IT9135_61:
        case AF9033_TUNER_IT9135_62:
-               ret = af9033_wr_reg(dev, 0x800000, 0x01);
-               if (ret < 0)
+               ret = regmap_write(dev->regmap, 0x800000, 0x01);
+               if (ret)
                        goto err;
        }
 
-       dev->bandwidth_hz = 0; /* force to program all parameters */
-       /* init stats here in order signal app which stats are supported */
+       dev->bandwidth_hz = 0; /* Force to program all parameters */
+       /* Init stats here in order signal app which stats are supported */
        c->strength.len = 1;
        c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
        c->cnr.len = 1;
@@ -469,68 +304,53 @@ static int af9033_init(struct dvb_frontend *fe)
        c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
 
        return 0;
-
 err:
-       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
-
+       dev_dbg(&client->dev, "failed=%d\n", ret);
        return ret;
 }
 
 static int af9033_sleep(struct dvb_frontend *fe)
 {
        struct af9033_dev *dev = fe->demodulator_priv;
-       int ret, i;
-       u8 tmp;
+       struct i2c_client *client = dev->client;
+       int ret;
+       unsigned int utmp;
 
-       ret = af9033_wr_reg(dev, 0x80004c, 1);
-       if (ret < 0)
-               goto err;
+       dev_dbg(&client->dev, "\n");
 
-       ret = af9033_wr_reg(dev, 0x800000, 0);
-       if (ret < 0)
+       ret = regmap_write(dev->regmap, 0x80004c, 0x01);
+       if (ret)
                goto err;
-
-       for (i = 100, tmp = 1; i && tmp; i--) {
-               ret = af9033_rd_reg(dev, 0x80004c, &tmp);
-               if (ret < 0)
-                       goto err;
-
-               usleep_range(200, 10000);
-       }
-
-       dev_dbg(&dev->client->dev, "loop=%d\n", i);
-
-       if (i == 0) {
-               ret = -ETIMEDOUT;
+       ret = regmap_write(dev->regmap, 0x800000, 0x00);
+       if (ret)
                goto err;
-       }
-
-       ret = af9033_wr_reg_mask(dev, 0x80fb24, 0x08, 0x08);
-       if (ret < 0)
+       ret = regmap_read_poll_timeout(dev->regmap, 0x80004c, utmp, utmp == 0,
+                                      5000, 1000000);
+       if (ret)
+               goto err;
+       ret = regmap_update_bits(dev->regmap, 0x80fb24, 0x08, 0x08);
+       if (ret)
                goto err;
 
-       /* prevent current leak (?) */
+       /* Prevent current leak by setting TS interface to parallel mode */
        if (dev->cfg.ts_mode == AF9033_TS_MODE_SERIAL) {
-               /* enable parallel TS */
-               ret = af9033_wr_reg_mask(dev, 0x00d917, 0x00, 0x01);
-               if (ret < 0)
+               /* Enable parallel TS */
+               ret = regmap_update_bits(dev->regmap, 0x00d917, 0x01, 0x00);
+               if (ret)
                        goto err;
-
-               ret = af9033_wr_reg_mask(dev, 0x00d916, 0x01, 0x01);
-               if (ret < 0)
+               ret = regmap_update_bits(dev->regmap, 0x00d916, 0x01, 0x01);
+               if (ret)
                        goto err;
        }
 
        return 0;
-
 err:
-       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
-
+       dev_dbg(&client->dev, "failed=%d\n", ret);
        return ret;
 }
 
 static int af9033_get_tune_settings(struct dvb_frontend *fe,
-               struct dvb_frontend_tune_settings *fesettings)
+                                   struct dvb_frontend_tune_settings *fesettings)
 {
        /* 800 => 2000 because IT9135 v2 is slow to gain lock */
        fesettings->min_delay_ms = 2000;
@@ -543,15 +363,17 @@ static int af9033_get_tune_settings(struct dvb_frontend *fe,
 static int af9033_set_frontend(struct dvb_frontend *fe)
 {
        struct af9033_dev *dev = fe->demodulator_priv;
+       struct i2c_client *client = dev->client;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-       int ret, i, spec_inv, sampling_freq;
+       int ret, i;
+       unsigned int utmp, adc_freq;
        u8 tmp, buf[3], bandwidth_reg_val;
-       u32 if_frequency, freq_cw, adc_freq;
+       u32 if_frequency;
 
-       dev_dbg(&dev->client->dev, "frequency=%d bandwidth_hz=%d\n",
-                       c->frequency, c->bandwidth_hz);
+       dev_dbg(&client->dev, "frequency=%u bandwidth_hz=%u\n",
+               c->frequency, c->bandwidth_hz);
 
-       /* check bandwidth */
+       /* Check bandwidth */
        switch (c->bandwidth_hz) {
        case 6000000:
                bandwidth_reg_val = 0x00;
@@ -563,105 +385,91 @@ static int af9033_set_frontend(struct dvb_frontend *fe)
                bandwidth_reg_val = 0x02;
                break;
        default:
-               dev_dbg(&dev->client->dev, "invalid bandwidth_hz\n");
+               dev_dbg(&client->dev, "invalid bandwidth_hz\n");
                ret = -EINVAL;
                goto err;
        }
 
-       /* program tuner */
+       /* Program tuner */
        if (fe->ops.tuner_ops.set_params)
                fe->ops.tuner_ops.set_params(fe);
 
-       /* program CFOE coefficients */
+       /* Coefficients */
        if (c->bandwidth_hz != dev->bandwidth_hz) {
                for (i = 0; i < ARRAY_SIZE(coeff_lut); i++) {
                        if (coeff_lut[i].clock == dev->cfg.clock &&
-                               coeff_lut[i].bandwidth_hz == c->bandwidth_hz) {
+                           coeff_lut[i].bandwidth_hz == c->bandwidth_hz) {
                                break;
                        }
                }
                if (i == ARRAY_SIZE(coeff_lut)) {
-                       dev_err(&dev->client->dev,
-                               "Couldn't find LUT config for clock=%d\n",
+                       dev_err(&client->dev,
+                               "Couldn't find config for clock %u\n",
                                dev->cfg.clock);
                        ret = -EINVAL;
                        goto err;
                }
 
-               ret = af9033_wr_regs(dev, 0x800001,
-                               coeff_lut[i].val, sizeof(coeff_lut[i].val));
+               ret = regmap_bulk_write(dev->regmap, 0x800001, coeff_lut[i].val,
+                                       sizeof(coeff_lut[i].val));
+               if (ret)
+                       goto err;
        }
 
-       /* program frequency control */
+       /* IF frequency control */
        if (c->bandwidth_hz != dev->bandwidth_hz) {
-               spec_inv = dev->cfg.spec_inv ? -1 : 1;
-
                for (i = 0; i < ARRAY_SIZE(clock_adc_lut); i++) {
                        if (clock_adc_lut[i].clock == dev->cfg.clock)
                                break;
                }
                if (i == ARRAY_SIZE(clock_adc_lut)) {
-                       dev_err(&dev->client->dev,
-                               "Couldn't find ADC clock for clock=%d\n",
+                       dev_err(&client->dev,
+                               "Couldn't find ADC clock for clock %u\n",
                                dev->cfg.clock);
                        ret = -EINVAL;
                        goto err;
                }
                adc_freq = clock_adc_lut[i].adc;
 
-               /* get used IF frequency */
+               if (dev->cfg.adc_multiplier == AF9033_ADC_MULTIPLIER_2X)
+                       adc_freq = 2 * adc_freq;
+
+               /* Get used IF frequency */
                if (fe->ops.tuner_ops.get_if_frequency)
                        fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency);
                else
                        if_frequency = 0;
 
-               sampling_freq = if_frequency;
-
-               while (sampling_freq > (adc_freq / 2))
-                       sampling_freq -= adc_freq;
-
-               if (sampling_freq >= 0)
-                       spec_inv *= -1;
-               else
-                       sampling_freq *= -1;
-
-               freq_cw = af9033_div(dev, sampling_freq, adc_freq, 23ul);
+               utmp = DIV_ROUND_CLOSEST_ULL((u64)if_frequency * 0x800000,
+                                            adc_freq);
 
-               if (spec_inv == -1)
-                       freq_cw = 0x800000 - freq_cw;
+               if (!dev->cfg.spec_inv && if_frequency)
+                       utmp = 0x800000 - utmp;
 
-               if (dev->cfg.adc_multiplier == AF9033_ADC_MULTIPLIER_2X)
-                       freq_cw /= 2;
-
-               buf[0] = (freq_cw >>  0) & 0xff;
-               buf[1] = (freq_cw >>  8) & 0xff;
-               buf[2] = (freq_cw >> 16) & 0x7f;
-
-               /* FIXME: there seems to be calculation error here... */
-               if (if_frequency == 0)
-                       buf[2] = 0;
-
-               ret = af9033_wr_regs(dev, 0x800029, buf, 3);
-               if (ret < 0)
+               buf[0] = (utmp >>  0) & 0xff;
+               buf[1] = (utmp >>  8) & 0xff;
+               buf[2] = (utmp >> 16) & 0xff;
+               ret = regmap_bulk_write(dev->regmap, 0x800029, buf, 3);
+               if (ret)
                        goto err;
 
+               dev_dbg(&client->dev, "if_frequency_cw=%06x\n", utmp);
+
                dev->bandwidth_hz = c->bandwidth_hz;
        }
 
-       ret = af9033_wr_reg_mask(dev, 0x80f904, bandwidth_reg_val, 0x03);
-       if (ret < 0)
+       ret = regmap_update_bits(dev->regmap, 0x80f904, 0x03,
+                                bandwidth_reg_val);
+       if (ret)
                goto err;
-
-       ret = af9033_wr_reg(dev, 0x800040, 0x00);
-       if (ret < 0)
+       ret = regmap_write(dev->regmap, 0x800040, 0x00);
+       if (ret)
                goto err;
-
-       ret = af9033_wr_reg(dev, 0x800047, 0x00);
-       if (ret < 0)
+       ret = regmap_write(dev->regmap, 0x800047, 0x00);
+       if (ret)
                goto err;
-
-       ret = af9033_wr_reg_mask(dev, 0x80f999, 0x00, 0x01);
-       if (ret < 0)
+       ret = regmap_update_bits(dev->regmap, 0x80f999, 0x01, 0x00);
+       if (ret)
                goto err;
 
        if (c->frequency <= 230000000)
@@ -669,19 +477,17 @@ static int af9033_set_frontend(struct dvb_frontend *fe)
        else
                tmp = 0x01; /* UHF */
 
-       ret = af9033_wr_reg(dev, 0x80004b, tmp);
-       if (ret < 0)
+       ret = regmap_write(dev->regmap, 0x80004b, tmp);
+       if (ret)
                goto err;
-
-       ret = af9033_wr_reg(dev, 0x800000, 0x00);
-       if (ret < 0)
+       /* Reset FSM */
+       ret = regmap_write(dev->regmap, 0x800000, 0x00);
+       if (ret)
                goto err;
 
        return 0;
-
 err:
-       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
-
+       dev_dbg(&client->dev, "failed=%d\n", ret);
        return ret;
 }
 
@@ -689,14 +495,15 @@ static int af9033_get_frontend(struct dvb_frontend *fe,
                               struct dtv_frontend_properties *c)
 {
        struct af9033_dev *dev = fe->demodulator_priv;
+       struct i2c_client *client = dev->client;
        int ret;
        u8 buf[8];
 
-       dev_dbg(&dev->client->dev, "\n");
+       dev_dbg(&client->dev, "\n");
 
-       /* read all needed registers */
-       ret = af9033_rd_regs(dev, 0x80f900, buf, sizeof(buf));
-       if (ret < 0)
+       /* Read all needed TPS registers */
+       ret = regmap_bulk_read(dev->regmap, 0x80f900, buf, 8);
+       if (ret)
                goto err;
 
        switch ((buf[0] >> 0) & 3) {
@@ -805,49 +612,49 @@ static int af9033_get_frontend(struct dvb_frontend *fe,
        }
 
        return 0;
-
 err:
-       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
-
+       dev_dbg(&client->dev, "failed=%d\n", ret);
        return ret;
 }
 
 static int af9033_read_status(struct dvb_frontend *fe, enum fe_status *status)
 {
        struct af9033_dev *dev = fe->demodulator_priv;
+       struct i2c_client *client = dev->client;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-       int ret, i, tmp = 0;
-       u8 u8tmp, buf[7];
+       int ret, tmp = 0;
+       u8 buf[7];
+       unsigned int utmp, utmp1;
 
-       dev_dbg(&dev->client->dev, "\n");
+       dev_dbg(&client->dev, "\n");
 
        *status = 0;
 
-       /* radio channel status, 0=no result, 1=has signal, 2=no signal */
-       ret = af9033_rd_reg(dev, 0x800047, &u8tmp);
-       if (ret < 0)
+       /* Radio channel status: 0=no result, 1=has signal, 2=no signal */
+       ret = regmap_read(dev->regmap, 0x800047, &utmp);
+       if (ret)
                goto err;
 
-       /* has signal */
-       if (u8tmp == 0x01)
+       /* Has signal */
+       if (utmp == 0x01)
                *status |= FE_HAS_SIGNAL;
 
-       if (u8tmp != 0x02) {
+       if (utmp != 0x02) {
                /* TPS lock */
-               ret = af9033_rd_reg_mask(dev, 0x80f5a9, &u8tmp, 0x01);
-               if (ret < 0)
+               ret = regmap_read(dev->regmap, 0x80f5a9, &utmp);
+               if (ret)
                        goto err;
 
-               if (u8tmp)
+               if ((utmp >> 0) & 0x01)
                        *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
                                        FE_HAS_VITERBI;
 
-               /* full lock */
-               ret = af9033_rd_reg_mask(dev, 0x80f999, &u8tmp, 0x01);
-               if (ret < 0)
+               /* Full lock */
+               ret = regmap_read(dev->regmap, 0x80f999, &utmp);
+               if (ret)
                        goto err;
 
-               if (u8tmp)
+               if ((utmp >> 0) & 0x01)
                        *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
                                        FE_HAS_VITERBI | FE_HAS_SYNC |
                                        FE_HAS_LOCK;
@@ -855,18 +662,18 @@ static int af9033_read_status(struct dvb_frontend *fe, enum fe_status *status)
 
        dev->fe_status = *status;
 
-       /* signal strength */
+       /* Signal strength */
        if (dev->fe_status & FE_HAS_SIGNAL) {
                if (dev->is_af9035) {
-                       ret = af9033_rd_reg(dev, 0x80004a, &u8tmp);
+                       ret = regmap_read(dev->regmap, 0x80004a, &utmp);
                        if (ret)
                                goto err;
-                       tmp = -u8tmp * 1000;
+                       tmp = -utmp * 1000;
                } else {
-                       ret = af9033_rd_reg(dev, 0x8000f7, &u8tmp);
+                       ret = regmap_read(dev->regmap, 0x8000f7, &utmp);
                        if (ret)
                                goto err;
-                       tmp = (u8tmp - 100) * 1000;
+                       tmp = (utmp - 100) * 1000;
                }
 
                c->strength.len = 1;
@@ -879,87 +686,101 @@ static int af9033_read_status(struct dvb_frontend *fe, enum fe_status *status)
 
        /* CNR */
        if (dev->fe_status & FE_HAS_VITERBI) {
-               u32 snr_val, snr_lut_size;
-               const struct val_snr *snr_lut = NULL;
-
-               /* read value */
-               ret = af9033_rd_regs(dev, 0x80002c, buf, 3);
+               /* Read raw SNR value */
+               ret = regmap_bulk_read(dev->regmap, 0x80002c, buf, 3);
                if (ret)
                        goto err;
 
-               snr_val = (buf[2] << 16) | (buf[1] << 8) | (buf[0] << 0);
+               utmp1 = buf[2] << 16 | buf[1] << 8 | buf[0] << 0;
 
-               /* read superframe number */
-               ret = af9033_rd_reg(dev, 0x80f78b, &u8tmp);
+               /* Read superframe number */
+               ret = regmap_read(dev->regmap, 0x80f78b, &utmp);
                if (ret)
                        goto err;
 
-               if (u8tmp)
-                       snr_val /= u8tmp;
+               if (utmp)
+                       utmp1 /= utmp;
 
-               /* read current transmission mode */
-               ret = af9033_rd_reg(dev, 0x80f900, &u8tmp);
+               /* Read current transmission mode */
+               ret = regmap_read(dev->regmap, 0x80f900, &utmp);
                if (ret)
                        goto err;
 
-               switch ((u8tmp >> 0) & 3) {
+               switch ((utmp >> 0) & 3) {
                case 0:
-                       snr_val *= 4;
+                       /* 2k */
+                       utmp1 *= 4;
                        break;
                case 1:
-                       snr_val *= 1;
+                       /* 8k */
+                       utmp1 *= 1;
                        break;
                case 2:
-                       snr_val *= 2;
+                       /* 4k */
+                       utmp1 *= 2;
                        break;
                default:
-                       snr_val *= 0;
+                       utmp1 *= 0;
                        break;
                }
 
-               /* read current modulation */
-               ret = af9033_rd_reg(dev, 0x80f903, &u8tmp);
+               /* Read current modulation */
+               ret = regmap_read(dev->regmap, 0x80f903, &utmp);
                if (ret)
                        goto err;
 
-               switch ((u8tmp >> 0) & 3) {
+               switch ((utmp >> 0) & 3) {
                case 0:
-                       snr_lut_size = ARRAY_SIZE(qpsk_snr_lut);
-                       snr_lut = qpsk_snr_lut;
+                       /*
+                        * 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:
-                       snr_lut_size = ARRAY_SIZE(qam16_snr_lut);
-                       snr_lut = qam16_snr_lut;
+                       /*
+                        * 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:
-                       snr_lut_size = ARRAY_SIZE(qam64_snr_lut);
-                       snr_lut = qam64_snr_lut;
+                       /*
+                        * 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:
-                       snr_lut_size = 0;
-                       tmp = 0;
+                       utmp1 = 0;
                        break;
                }
 
-               for (i = 0; i < snr_lut_size; i++) {
-                       tmp = snr_lut[i].snr * 1000;
-                       if (snr_val < snr_lut[i].val)
-                               break;
-               }
+               dev_dbg(&client->dev, "cnr=%u\n", utmp1);
 
-               c->cnr.len = 1;
                c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
-               c->cnr.stat[0].svalue = tmp;
+               c->cnr.stat[0].svalue = utmp1;
        } else {
-               c->cnr.len = 1;
                c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
        }
 
        /* UCB/PER/BER */
        if (dev->fe_status & FE_HAS_LOCK) {
-               /* outer FEC, 204 byte packets */
+               /* Outer FEC, 204 byte packets */
                u16 abort_packet_count, rsd_packet_count;
-               /* inner FEC, bits */
+               /* Inner FEC, bits */
                u32 rsd_bit_err_count;
 
                /*
@@ -967,7 +788,7 @@ static int af9033_read_status(struct dvb_frontend *fe, enum fe_status *status)
                 * (rsd_packet_count). Maybe it should be increased?
                 */
 
-               ret = af9033_rd_regs(dev, 0x800032, buf, 7);
+               ret = regmap_bulk_read(dev->regmap, 0x800032, buf, 7);
                if (ret)
                        goto err;
 
@@ -998,21 +819,22 @@ static int af9033_read_status(struct dvb_frontend *fe, enum fe_status *status)
        }
 
        return 0;
-
 err:
-       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
-
+       dev_dbg(&client->dev, "failed=%d\n", ret);
        return ret;
 }
 
 static int af9033_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
        struct af9033_dev *dev = fe->demodulator_priv;
+       struct i2c_client *client = dev->client;
        struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache;
        int ret;
-       u8 u8tmp;
+       unsigned int utmp;
+
+       dev_dbg(&client->dev, "\n");
 
-       /* use DVBv5 CNR */
+       /* Use DVBv5 CNR */
        if (c->cnr.stat[0].scale == FE_SCALE_DECIBEL) {
                /* Return 0.1 dB for AF9030 and 0-0xffff for IT9130. */
                if (dev->is_af9035) {
@@ -1022,13 +844,13 @@ static int af9033_read_snr(struct dvb_frontend *fe, u16 *snr)
                        /* 1000x => 1x (1 dB) */
                        *snr = div_s64(c->cnr.stat[0].svalue, 1000);
 
-                       /* read current modulation */
-                       ret = af9033_rd_reg(dev, 0x80f903, &u8tmp);
+                       /* Read current modulation */
+                       ret = regmap_read(dev->regmap, 0x80f903, &utmp);
                        if (ret)
                                goto err;
 
                        /* scale value to 0x0000-0xffff */
-                       switch ((u8tmp >> 0) & 3) {
+                       switch ((utmp >> 0) & 3) {
                        case 0:
                                *snr = *snr * 0xffff / 23;
                                break;
@@ -1047,35 +869,37 @@ static int af9033_read_snr(struct dvb_frontend *fe, u16 *snr)
        }
 
        return 0;
-
 err:
-       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
-
+       dev_dbg(&client->dev, "failed=%d\n", ret);
        return ret;
 }
 
 static int af9033_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
 {
        struct af9033_dev *dev = fe->demodulator_priv;
+       struct i2c_client *client = dev->client;
        struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache;
        int ret, tmp, power_real;
-       u8 u8tmp, gain_offset, buf[7];
+       unsigned int utmp;
+       u8 gain_offset, buf[7];
+
+       dev_dbg(&client->dev, "\n");
 
        if (dev->is_af9035) {
-               /* read signal strength of 0-100 scale */
-               ret = af9033_rd_reg(dev, 0x800048, &u8tmp);
-               if (ret < 0)
+               /* Read signal strength of 0-100 scale */
+               ret = regmap_read(dev->regmap, 0x800048, &utmp);
+               if (ret)
                        goto err;
 
-               /* scale value to 0x0000-0xffff */
-               *strength = u8tmp * 0xffff / 100;
+               /* Scale value to 0x0000-0xffff */
+               *strength = utmp * 0xffff / 100;
        } else {
-               ret = af9033_rd_reg(dev, 0x8000f7, &u8tmp);
-               if (ret < 0)
+               ret = regmap_read(dev->regmap, 0x8000f7, &utmp);
+               if (ret)
                        goto err;
 
-               ret = af9033_rd_regs(dev, 0x80f900, buf, 7);
-               if (ret < 0)
+               ret = regmap_bulk_read(dev->regmap, 0x80f900, buf, 7);
+               if (ret)
                        goto err;
 
                if (c->frequency <= 300000000)
@@ -1083,7 +907,7 @@ static int af9033_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
                else
                        gain_offset = 4; /* UHF */
 
-               power_real = (u8tmp - 100 - gain_offset) -
+               power_real = (utmp - 100 - gain_offset) -
                        power_reference[((buf[3] >> 0) & 3)][((buf[6] >> 0) & 7)];
 
                if (power_real < -15)
@@ -1097,15 +921,13 @@ static int af9033_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
                else
                        tmp = 100;
 
-               /* scale value to 0x0000-0xffff */
+               /* Scale value to 0x0000-0xffff */
                *strength = tmp * 0xffff / 100;
        }
 
        return 0;
-
 err:
-       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
-
+       dev_dbg(&client->dev, "failed=%d\n", ret);
        return ret;
 }
 
@@ -1124,82 +946,78 @@ static int af9033_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
        struct af9033_dev *dev = fe->demodulator_priv;
 
        *ucblocks = dev->error_block_count;
+
        return 0;
 }
 
 static int af9033_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
 {
        struct af9033_dev *dev = fe->demodulator_priv;
+       struct i2c_client *client = dev->client;
        int ret;
 
-       dev_dbg(&dev->client->dev, "enable=%d\n", enable);
+       dev_dbg(&client->dev, "enable=%d\n", enable);
 
-       ret = af9033_wr_reg_mask(dev, 0x00fa04, enable, 0x01);
-       if (ret < 0)
+       ret = regmap_update_bits(dev->regmap, 0x00fa04, 0x01, enable);
+       if (ret)
                goto err;
 
        return 0;
-
 err:
-       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
-
+       dev_dbg(&client->dev, "failed=%d\n", ret);
        return ret;
 }
 
 static int af9033_pid_filter_ctrl(struct dvb_frontend *fe, int onoff)
 {
        struct af9033_dev *dev = fe->demodulator_priv;
+       struct i2c_client *client = dev->client;
        int ret;
 
-       dev_dbg(&dev->client->dev, "onoff=%d\n", onoff);
+       dev_dbg(&client->dev, "onoff=%d\n", onoff);
 
-       ret = af9033_wr_reg_mask(dev, 0x80f993, onoff, 0x01);
-       if (ret < 0)
+       ret = regmap_update_bits(dev->regmap, 0x80f993, 0x01, onoff);
+       if (ret)
                goto err;
 
        return 0;
-
 err:
-       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
-
+       dev_dbg(&client->dev, "failed=%d\n", ret);
        return ret;
 }
 
 static int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid,
-               int onoff)
+                            int onoff)
 {
        struct af9033_dev *dev = fe->demodulator_priv;
+       struct i2c_client *client = dev->client;
        int ret;
        u8 wbuf[2] = {(pid >> 0) & 0xff, (pid >> 8) & 0xff};
 
-       dev_dbg(&dev->client->dev, "index=%d pid=%04x onoff=%d\n",
-                       index, pid, onoff);
+       dev_dbg(&client->dev, "index=%d pid=%04x onoff=%d\n",
+               index, pid, onoff);
 
        if (pid > 0x1fff)
                return 0;
 
-       ret = af9033_wr_regs(dev, 0x80f996, wbuf, 2);
-       if (ret < 0)
+       ret = regmap_bulk_write(dev->regmap, 0x80f996, wbuf, 2);
+       if (ret)
                goto err;
-
-       ret = af9033_wr_reg(dev, 0x80f994, onoff);
-       if (ret < 0)
+       ret = regmap_write(dev->regmap, 0x80f994, onoff);
+       if (ret)
                goto err;
-
-       ret = af9033_wr_reg(dev, 0x80f995, index);
-       if (ret < 0)
+       ret = regmap_write(dev->regmap, 0x80f995, index);
+       if (ret)
                goto err;
 
        return 0;
-
 err:
-       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
-
+       dev_dbg(&client->dev, "failed=%d\n", ret);
        return ret;
 }
 
 static const struct dvb_frontend_ops af9033_ops = {
-       .delsys = { SYS_DVBT },
+       .delsys = {SYS_DVBT},
        .info = {
                .name = "Afatech AF9033 (DVB-T)",
                .frequency_min = 174000000,
@@ -1240,35 +1058,57 @@ static const struct dvb_frontend_ops af9033_ops = {
 };
 
 static int af9033_probe(struct i2c_client *client,
-               const struct i2c_device_id *id)
+                       const struct i2c_device_id *id)
 {
        struct af9033_config *cfg = client->dev.platform_data;
        struct af9033_dev *dev;
        int ret;
        u8 buf[8];
        u32 reg;
+       static const struct regmap_config regmap_config = {
+               .reg_bits    =  24,
+               .val_bits    =  8,
+       };
 
-       /* allocate memory for the internal state */
-       dev = kzalloc(sizeof(struct af9033_dev), GFP_KERNEL);
-       if (dev == NULL) {
+       /* Allocate memory for the internal state */
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev) {
                ret = -ENOMEM;
-               dev_err(&client->dev, "Could not allocate memory for state\n");
                goto err;
        }
 
-       /* setup the state */
+       /* Setup the state */
        dev->client = client;
-       memcpy(&dev->cfg, cfg, sizeof(struct af9033_config));
+       memcpy(&dev->cfg, cfg, sizeof(dev->cfg));
+       switch (dev->cfg.ts_mode) {
+       case AF9033_TS_MODE_PARALLEL:
+               dev->ts_mode_parallel = true;
+               break;
+       case AF9033_TS_MODE_SERIAL:
+               dev->ts_mode_serial = true;
+               break;
+       case AF9033_TS_MODE_USB:
+               /* USB mode for AF9035 */
+       default:
+               break;
+       }
 
        if (dev->cfg.clock != 12000000) {
                ret = -ENODEV;
-               dev_err(&dev->client->dev,
-                               "unsupported clock %d Hz, only 12000000 Hz is supported currently\n",
-                               dev->cfg.clock);
+               dev_err(&client->dev,
+                       "Unsupported clock %u Hz. Only 12000000 Hz is supported currently\n",
+                       dev->cfg.clock);
+               goto err_kfree;
+       }
+
+       /* Create regmap */
+       dev->regmap = regmap_init_i2c(client, &regmap_config);
+       if (IS_ERR(dev->regmap)) {
+               ret = PTR_ERR(dev->regmap);
                goto err_kfree;
        }
 
-       /* firmware version */
+       /* Firmware version */
        switch (dev->cfg.tuner) {
        case AF9033_TUNER_IT9135_38:
        case AF9033_TUNER_IT9135_51:
@@ -1285,20 +1125,19 @@ static int af9033_probe(struct i2c_client *client,
                break;
        }
 
-       ret = af9033_rd_regs(dev, reg, &buf[0], 4);
-       if (ret < 0)
-               goto err_kfree;
-
-       ret = af9033_rd_regs(dev, 0x804191, &buf[4], 4);
-       if (ret < 0)
-               goto err_kfree;
+       ret = regmap_bulk_read(dev->regmap, reg, &buf[0], 4);
+       if (ret)
+               goto err_regmap_exit;
+       ret = regmap_bulk_read(dev->regmap, 0x804191, &buf[4], 4);
+       if (ret)
+               goto err_regmap_exit;
 
-       dev_info(&dev->client->dev,
-                       "firmware version: LINK %d.%d.%d.%d - OFDM %d.%d.%d.%d\n",
-                       buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6],
-                       buf[7]);
+       dev_info(&client->dev,
+                "firmware version: LINK %d.%d.%d.%d - OFDM %d.%d.%d.%d\n",
+                buf[0], buf[1], buf[2], buf[3],
+                buf[4], buf[5], buf[6], buf[7]);
 
-       /* sleep */
+       /* Sleep as chip seems to be partly active by default */
        switch (dev->cfg.tuner) {
        case AF9033_TUNER_IT9135_38:
        case AF9033_TUNER_IT9135_51:
@@ -1309,41 +1148,30 @@ static int af9033_probe(struct i2c_client *client,
                /* IT9135 did not like to sleep at that early */
                break;
        default:
-               ret = af9033_wr_reg(dev, 0x80004c, 1);
-               if (ret < 0)
-                       goto err_kfree;
-
-               ret = af9033_wr_reg(dev, 0x800000, 0);
-               if (ret < 0)
-                       goto err_kfree;
-       }
-
-       /* configure internal TS mode */
-       switch (dev->cfg.ts_mode) {
-       case AF9033_TS_MODE_PARALLEL:
-               dev->ts_mode_parallel = true;
-               break;
-       case AF9033_TS_MODE_SERIAL:
-               dev->ts_mode_serial = true;
-               break;
-       case AF9033_TS_MODE_USB:
-               /* usb mode for AF9035 */
-       default:
-               break;
+               ret = regmap_write(dev->regmap, 0x80004c, 0x01);
+               if (ret)
+                       goto err_regmap_exit;
+               ret = regmap_write(dev->regmap, 0x800000, 0x00);
+               if (ret)
+                       goto err_regmap_exit;
        }
 
-       /* create dvb_frontend */
-       memcpy(&dev->fe.ops, &af9033_ops, sizeof(struct dvb_frontend_ops));
+       /* Create dvb frontend */
+       memcpy(&dev->fe.ops, &af9033_ops, sizeof(dev->fe.ops));
        dev->fe.demodulator_priv = dev;
        *cfg->fe = &dev->fe;
        if (cfg->ops) {
                cfg->ops->pid_filter = af9033_pid_filter;
                cfg->ops->pid_filter_ctrl = af9033_pid_filter_ctrl;
        }
+       cfg->regmap = dev->regmap;
        i2c_set_clientdata(client, dev);
 
-       dev_info(&dev->client->dev, "Afatech AF9033 successfully attached\n");
+       dev_info(&client->dev, "Afatech AF9033 successfully attached\n");
+
        return 0;
+err_regmap_exit:
+       regmap_exit(dev->regmap);
 err_kfree:
        kfree(dev);
 err:
@@ -1355,10 +1183,9 @@ static int af9033_remove(struct i2c_client *client)
 {
        struct af9033_dev *dev = i2c_get_clientdata(client);
 
-       dev_dbg(&dev->client->dev, "\n");
+       dev_dbg(&client->dev, "\n");
 
-       dev->fe.ops.release = NULL;
-       dev->fe.demodulator_priv = NULL;
+       regmap_exit(dev->regmap);
        kfree(dev);
 
        return 0;
index 5b83e4f96297126ae5b3da337b6dc250645e91e8..8193f9805c4f8c9ce6d238192c453858588e750f 100644 (file)
  *    but WITHOUT 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.
  */
 
 #ifndef AF9033_H
 #define AF9033_H
 
 /*
- * I2C address (TODO: are these in 8-bit format?)
- * 0x38, 0x3a, 0x3c, 0x3e
+ * I2C address: 0x1c, 0x1d, 0x1e, 0x1f
  */
 struct af9033_config {
        /*
@@ -88,6 +83,12 @@ struct af9033_config {
         * returned by that driver
         */
        struct dvb_frontend **fe;
+
+       /*
+        * regmap for IT913x integrated tuner driver
+        * returned by that driver
+        */
+       struct regmap *regmap;
 };
 
 struct af9033_ops {
index 8e23275148edf80ee7f102dbc9d2ec6485c1afde..8799cda1ae143a8405c96fc0f87f7197a124bb41 100644 (file)
  *    but WITHOUT 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.
  */
 
 #ifndef AF9033_PRIV_H
@@ -25,6 +21,9 @@
 #include "dvb_frontend.h"
 #include "af9033.h"
 #include <linux/math64.h>
+#include <linux/regmap.h>
+#include <linux/kernel.h>
+#include "dvb_math.h"
 
 struct reg_val {
        u32 reg;
@@ -68,7 +67,7 @@ static const struct clock_adc clock_adc_lut[] = {
        { 12000000, 20250000 },
 };
 
-/* pre-calculated coeff lookup table */
+/* Pre-calculated coeff lookup table */
 static const struct coeff coeff_lut[] = {
        /* 12.000 MHz */
        { 12000000, 8000000, {
@@ -91,102 +90,9 @@ static const struct coeff coeff_lut[] = {
        },
 };
 
-/* QPSK SNR lookup table */
-static const struct val_snr qpsk_snr_lut[] = {
-       { 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 },
-       { 0x17a532, 15 },
-       { 0x180f94, 16 },
-       { 0x186ed2, 17 },
-       { 0x18b271, 18 },
-       { 0x18e118, 19 },
-       { 0x18ff4b, 20 },
-       { 0x190af1, 21 },
-       { 0x191451, 22 },
-       { 0xffffff, 23 },
-};
-
-/* QAM16 SNR lookup table */
-static const struct val_snr qam16_snr_lut[] = {
-       { 0x04f0d5,  0 },
-       { 0x05387a,  1 },
-       { 0x0573a4,  2 },
-       { 0x05a99e,  3 },
-       { 0x05cc80,  4 },
-       { 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 },
-       { 0x0bda6a, 20 },
-       { 0x0c0c75, 21 },
-       { 0x0c3f7d, 22 },
-       { 0x0c5e62, 23 },
-       { 0x0c6c31, 24 },
-       { 0x0c7925, 25 },
-       { 0xffffff, 26 },
-};
-
-/* QAM64 SNR lookup table */
-static const struct val_snr qam64_snr_lut[] = {
-       { 0x0256d0,  0 },
-       { 0x027a65,  1 },
-       { 0x029873,  2 },
-       { 0x02b7fe,  3 },
-       { 0x02cf1e,  4 },
-       { 0x02e234,  5 },
-       { 0x02f409,  6 },
-       { 0x030046,  7 },
-       { 0x030844,  8 },
-       { 0x030a02,  9 },
-       { 0x030cde, 10 },
-       { 0x031031, 11 },
-       { 0x03144c, 12 },
-       { 0x0315dd, 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 },
-       { 0x059feb, 27 },
-       { 0x05bf38, 28 },
-       { 0x05f78f, 29 },
-       { 0x0612c3, 30 },
-       { 0x0626be, 31 },
-       { 0xffffff, 32 },
-};
-
+/*
+ * Afatech AF9033 demod init
+ */
 static const struct reg_val ofsm_init[] = {
        { 0x800051, 0x01 },
        { 0x800070, 0x0a },
@@ -298,8 +204,10 @@ static const struct reg_val ofsm_init[] = {
        { 0x80fd8b, 0x00 },
 };
 
-/* Infineon TUA 9001 tuner init
-   AF9033_TUNER_TUA9001    = 0x27 */
+/*
+ * Infineon TUA 9001 tuner init
+ * AF9033_TUNER_TUA9001    = 0x27
+ */
 static const struct reg_val tuner_init_tua9001[] = {
        { 0x800046, 0x27 },
        { 0x800057, 0x00 },
@@ -340,8 +248,10 @@ static const struct reg_val tuner_init_tua9001[] = {
        { 0x80f1e6, 0x00 },
 };
 
-/* Fitipower fc0011 tuner init
-   AF9033_TUNER_FC0011    = 0x28 */
+/*
+ * Fitipower FC0011 tuner init
+ * AF9033_TUNER_FC0011    = 0x28
+ */
 static const struct reg_val tuner_init_fc0011[] = {
        { 0x800046, 0x28 },
        { 0x800057, 0x00 },
@@ -401,8 +311,10 @@ static const struct reg_val tuner_init_fc0011[] = {
        { 0x80f1e6, 0x00 },
 };
 
-/* Fitipower FC0012 tuner init
-   AF9033_TUNER_FC0012    = 0x2e */
+/*
+ * Fitipower FC0012 tuner init
+ * AF9033_TUNER_FC0012    = 0x2e
+ */
 static const struct reg_val tuner_init_fc0012[] = {
        { 0x800046, 0x2e },
        { 0x800057, 0x00 },
@@ -444,8 +356,10 @@ static const struct reg_val tuner_init_fc0012[] = {
        { 0x80f1e6, 0x00 },
 };
 
-/* MaxLinear MxL5007T tuner init
-   AF9033_TUNER_MXL5007T    = 0xa0 */
+/*
+ * MaxLinear MxL5007T tuner init
+ * AF9033_TUNER_MXL5007T    = 0xa0
+ */
 static const struct reg_val tuner_init_mxl5007t[] = {
        { 0x800046, 0x1b },
        { 0x800057, 0x01 },
@@ -479,8 +393,10 @@ static const struct reg_val tuner_init_mxl5007t[] = {
        { 0x80f1e6, 0x00 },
 };
 
-/* NXP TDA 18218HN tuner init
-   AF9033_TUNER_TDA18218    = 0xa1 */
+/*
+ * NXP TDA18218HN tuner init
+ * AF9033_TUNER_TDA18218    = 0xa1
+ */
 static const struct reg_val tuner_init_tda18218[] = {
        {0x800046, 0xa1},
        {0x800057, 0x01},
@@ -513,7 +429,10 @@ static const struct reg_val tuner_init_tda18218[] = {
        {0x80f1e6, 0x00},
 };
 
-/* FCI FC2580 tuner init */
+/*
+ * FCI FC2580 tuner init
+ * AF9033_TUNER_FC2580      = 0x32
+ */
 static const struct reg_val tuner_init_fc2580[] = {
        { 0x800046, 0x32 },
        { 0x800057, 0x01 },
@@ -551,6 +470,9 @@ static const struct reg_val tuner_init_fc2580[] = {
        { 0x80f1e6, 0x01 },
 };
 
+/*
+ * IT9133 AX demod init
+ */
 static const struct reg_val ofsm_init_it9135_v1[] = {
        { 0x800051, 0x01 },
        { 0x800070, 0x0a },
@@ -662,8 +584,10 @@ static const struct reg_val ofsm_init_it9135_v1[] = {
        { 0x80fd8b, 0x00 },
 };
 
-/* ITE Tech IT9135 Omega tuner init
-   AF9033_TUNER_IT9135_38   = 0x38 */
+/*
+ * ITE Tech IT9133 AX Omega tuner init
+ * AF9033_TUNER_IT9135_38   = 0x38
+ */
 static const struct reg_val tuner_init_it9135_38[] = {
        { 0x800043, 0x00 },
        { 0x800046, 0x38 },
@@ -879,8 +803,10 @@ static const struct reg_val tuner_init_it9135_38[] = {
        { 0x80fd8b, 0x00 },
 };
 
-/* ITE Tech IT9135 Omega LNA config 1 tuner init
-   AF9033_TUNER_IT9135_51   = 0x51 */
+/*
+ * ITE Tech IT9133 AX Omega LNA config 1 tuner init
+ * AF9033_TUNER_IT9135_51   = 0x51
+ */
 static const struct reg_val tuner_init_it9135_51[] = {
        { 0x800043, 0x00 },
        { 0x800046, 0x51 },
@@ -1096,8 +1022,10 @@ static const struct reg_val tuner_init_it9135_51[] = {
        { 0x80fd8b, 0x00 },
 };
 
-/* ITE Tech IT9135 Omega LNA config 2 tuner init
-   AF9033_TUNER_IT9135_52   = 0x52 */
+/*
+ * ITE Tech IT9133 AX Omega LNA config 2 tuner init
+ * AF9033_TUNER_IT9135_52   = 0x52
+ */
 static const struct reg_val tuner_init_it9135_52[] = {
        { 0x800043, 0x00 },
        { 0x800046, 0x52 },
@@ -1313,6 +1241,9 @@ static const struct reg_val tuner_init_it9135_52[] = {
        { 0x80fd8b, 0x00 },
 };
 
+/*
+ * ITE Tech IT9133 BX demod init
+ */
 static const struct reg_val ofsm_init_it9135_v2[] = {
        { 0x800051, 0x01 },
        { 0x800070, 0x0a },
@@ -1411,8 +1342,10 @@ static const struct reg_val ofsm_init_it9135_v2[] = {
        { 0x80fd8b, 0x00 },
 };
 
-/* ITE Tech IT9135 Omega v2 tuner init
-   AF9033_TUNER_IT9135_60   = 0x60 */
+/*
+ * ITE Tech IT9133 BX Omega tuner init
+ * AF9033_TUNER_IT9135_60   = 0x60
+ */
 static const struct reg_val tuner_init_it9135_60[] = {
        { 0x800043, 0x00 },
        { 0x800046, 0x60 },
@@ -1625,8 +1558,10 @@ static const struct reg_val tuner_init_it9135_60[] = {
        { 0x80fd8b, 0x00 },
 };
 
-/* ITE Tech IT9135 Omega v2 LNA config 1 tuner init
-   AF9033_TUNER_IT9135_61   = 0x61 */
+/*
+ * ITE Tech IT9133 BX Omega LNA config 1 tuner init
+ * AF9033_TUNER_IT9135_61   = 0x61
+ */
 static const struct reg_val tuner_init_it9135_61[] = {
        { 0x800043, 0x00 },
        { 0x800046, 0x61 },
@@ -1839,8 +1774,10 @@ static const struct reg_val tuner_init_it9135_61[] = {
        { 0x80fd8b, 0x00 },
 };
 
-/* ITE Tech IT9135 Omega v2 LNA config 2 tuner init
-   AF9033_TUNER_IT9135_62   = 0x62 */
+/*
+ * ITE Tech IT9133 BX Omega LNA config 2 tuner init
+ * AF9033_TUNER_IT9135_62   = 0x62
+ */
 static const struct reg_val tuner_init_it9135_62[] = {
        { 0x800043, 0x00 },
        { 0x800046, 0x62 },
index 07ce05578278fe6498d9342fc6363428106087e3..05850b32d6c6a81040dcb9aa215f470bd07b0ef1 100644 (file)
  *    but WITHOUT 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 <asm/div64.h>
index bb862387080f7f0607493050c06372b5e0bc2cf1..e146d394f4ed06a7c9abcd37fa76ef18ad56f6c2 100644 (file)
  *    but WITHOUT 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 __ATBM8830_H__
index d460058d497e7151ebfc2240c230cebd9aec98cf..f1399451d1b0ef546215d3e7b063b41db778dbff 100644 (file)
  *    but WITHOUT 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 __ATBM8830_PRIV_H
index add2463828061d4feccc4a8a335c49f4fa81f942..a2e771305008da18292a857ae9f0ad6b2e54f177 100644 (file)
  * but WITHOUT 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.
  */
 
 /* Developer notes:
index 961c2eb87c684a595ede26ac332a6889c8323309..b6a2d62de37950d428beb63f0ba8ab0fb0cf112c 100644 (file)
  * but WITHOUT 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 BCM3510_H
 #define BCM3510_H
index 67f24686c31b9dd3306bc51c5271d9af25a47e11..475e8381bf133c157412bbc88dec1211a17ec14f 100644 (file)
  * but WITHOUT 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 __BCM3510_PRIV_H__
 #define __BCM3510_PRIV_H__
index baaf89e768cf500ea96497d930dbfb1ac6004f30..1d6e8d33cd9204af97f8b577e8855e08ea24be5c 100644 (file)
  * 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.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  *
  *
  * the project's page is at https://linuxtv.org
index 4ad7661547415e1a0dc398bc8b59a2f59cb8f425..cb7cb2c5b9777856611a45ab0739960bf313f11a 100644 (file)
  * 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.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  *
  *
  * the project's page is at https://linuxtv.org
index 275c1782597d91a420939598e35324dab29a15bf..1c203eb27491d357148c4fbb226dd0ce482c8ac1 100644 (file)
  * 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.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  *
  *
  * the project's page is at https://linuxtv.org
index db44ebb7c56123e3e6486f89be229d4d466007a9..0118c2658cf780d4431032e6dd6bd0c510b93b5c 100644 (file)
  *  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/slab.h>
index 194c703611b459c9c3da2c89bdb68aa116638c4d..f013aca3a691e064ca1bbf7b1a9c9df06f24ede3 100644 (file)
  *  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 CX24113_H
index 8aed8cc9f93dda1f68fd53c005662c16f6c63710..4ae3d922a8e8a962c5c7e3fb34b3e524eee67cb8 100644 (file)
  *   but WITHOUT 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/slab.h>
@@ -653,7 +649,7 @@ static int cx24123_pll_tune(struct dvb_frontend *fe)
        dprintk("frequency=%i\n", p->frequency);
 
        if (cx24123_pll_calculate(fe) != 0) {
-               err("%s: cx24123_pll_calcutate failed\n", __func__);
+               err("%s: cx24123_pll_calculate failed\n", __func__);
                return -EINVAL;
        }
 
index 95267c6edb3a1357c463eabe4352ba40a9cc8319..f6ebbb47b9b2b9eedc62fa8789b969cae97fac04 100644 (file)
@@ -615,6 +615,7 @@ static int cxd2820r_probe(struct i2c_client *client,
        }
 
        priv->client[0] = client;
+       priv->fe.demodulator_priv = priv;
        priv->i2c = client->adapter;
        priv->ts_mode = pdata->ts_mode;
        priv->ts_clk_inv = pdata->ts_clk_inv;
@@ -697,7 +698,6 @@ static int cxd2820r_probe(struct i2c_client *client,
        memcpy(&priv->fe.ops, &cxd2820r_ops, sizeof(priv->fe.ops));
        if (!pdata->attach_in_use)
                priv->fe.ops.release = NULL;
-       priv->fe.demodulator_priv = priv;
        i2c_set_clientdata(client, priv);
 
        /* Setup callbacks */
index befc8172159d0309b2e804318674cd289467e301..d7614b8b8782c16caea5d810d6346f870ef533cd 100644 (file)
  *
  * 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 code is more or less generated from another driver, please
  * excuse some codingstyle oddities.
index fd3b33296b1574718f21d7ce9e4ffc2077195146..33af14df27bde93854afa2516845c8d6f971fe2f 100644 (file)
  *
  * 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 code is more or less generated from another driver, please
  * excuse some codingstyle oddities.
index a27c0001f2d6dfe4031eacda011c4e790288476f..3815ea515364554b7aa70320f0155d74a8c3de15 100644 (file)
@@ -805,13 +805,19 @@ static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
        return 0;
 }
 
-static void dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz)
+static int dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz)
 {
        u32 internal = dib7000p_get_internal_freq(state);
-       s32 unit_khz_dds_val = 67108864 / (internal);   /* 2**26 / Fsampling is the unit 1KHz offset */
+       s32 unit_khz_dds_val;
        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) {
+               pr_warn("DIB7000P: dib7000p_get_internal_freq returned 0\n");
+               return -1;
+       }
+       /* 2**26 / Fsampling is the unit 1KHz offset */
+       unit_khz_dds_val = 67108864 / (internal);
 
        dprintk("setting a frequency offset of %dkHz internal freq = %d invert = %d\n", offset_khz, internal, invert);
 
@@ -828,6 +834,7 @@ static void dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz)
                dib7000p_write_word(state, 21, (u16) (((dds >> 16) & 0x1ff) | (0 << 10) | (invert << 9)));
                dib7000p_write_word(state, 22, (u16) (dds & 0xffff));
        }
+       return 0;
 }
 
 static int dib7000p_agc_startup(struct dvb_frontend *demod)
@@ -867,7 +874,9 @@ static int dib7000p_agc_startup(struct dvb_frontend *demod)
                        frequency_offset = (s32)frequency_tuner / 1000 - ch->frequency / 1000;
                }
 
-               dib7000p_set_dds(state, frequency_offset);
+               if (dib7000p_set_dds(state, frequency_offset) < 0)
+                       return -1;
+
                ret = 7;
                (*agc_state)++;
                break;
index 8188062953afac9277c2e30f8649323c9eeb26aa..11e1ddeeef0a0b6493b4337523f756dbffaeb3fb 100644 (file)
  *  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 DRX39XXJ_H
index f0507cdbb5034f57d3b942675dcb57b1857a2438..1d4b89488ac49011645c1e03cc843b31803557d2 100644 (file)
  * 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
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  */
 
 #ifndef _DRXD_H_
index 5418b0b1dadc6acc7502bc5e70357aba93f3d0a8..4e1d8905e06ad20e7f6c6faccd1afaaedbfd9ad1 100644 (file)
  * 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
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  */
 
 /* TODO: generate this file with a script from a settings file */
index 41597e89941ce80fbe687577e2b1946ac2f62fe0..7d9f9fa7ab3ce2151cd20fc6a795df2c425c8dad 100644 (file)
  * 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
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  */
 
 #ifndef _DRXD_FIRM_H_
index 4143f0326684653041fc09bfb8133531a2dda79e..71910561005f40116de556b9701d8b9ec6d28f78 100644 (file)
  * 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
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  */
 
 #include <linux/kernel.h>
index 6bc553abf2152354ba5957c7eab8bcdc64c6d46c..8e5bd2e8de4043b90fade7139cbbcd1e870a6c6d 100644 (file)
  * 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
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  */
 
 #ifndef __DRX3973D_MAP__H__
index 146edf344dd8cd6b638085e4e8f4ab65dd4ba8e2..15d2cac588b14320b54676ef18e9aa3e0493512b 100644 (file)
  * 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
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index ef976eb233444bc3790eda024e2d8034e515599e..7bec3e028beec10e188fea4d9f53cc40556f8ddf 100644 (file)
  *  but WITHOUT 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.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index efc3c31a763503d0aeef62d2a02c4e51f21bb213..50b2b666ef6c2e7d8fac5142d22635b2cd801e17 100644 (file)
  *  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/module.h>
index 50f1af512b626dbc3a22bb26e66a0983ca38eb81..86dd7b9d1e57b849a7ec56b64912e222336d4596 100644 (file)
  *  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 DVB_DUMMY_FE_H
index d97ce21e26e1b67c9c41e15b6cca219ebce2022f..fa2a96d5f94ebc0a41dd163cbfe0586a693a9acb 100644 (file)
  *    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 "dvb_frontend.h"
index e894bdcf35a3a6fa8a4d5f1423a8788dafd91c5d..e43fe26654b2e701fc1d55928cb77fff7ffea3d9 100644 (file)
  *    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 EC100_H
diff --git a/drivers/media/dvb-frontends/hd29l2.c b/drivers/media/dvb-frontends/hd29l2.c
deleted file mode 100644 (file)
index 8b53633..0000000
+++ /dev/null
@@ -1,870 +0,0 @@
-/*
- * HDIC HD29L2 DMB-TH demodulator driver
- *
- * Copyright (C) 2011 Metropolia University of Applied Sciences, Electria R&D
- *
- * Author: Antti Palosaari <crope@iki.fi>
- *
- *    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 "hd29l2_priv.h"
-
-#define HD29L2_MAX_LEN (3)
-
-/* write multiple registers */
-static int hd29l2_wr_regs(struct hd29l2_priv *priv, u8 reg, u8 *val, int len)
-{
-       int ret;
-       u8 buf[2 + HD29L2_MAX_LEN];
-       struct i2c_msg msg[1] = {
-               {
-                       .addr = priv->cfg.i2c_addr,
-                       .flags = 0,
-                       .len = 2 + len,
-                       .buf = buf,
-               }
-       };
-
-       if (len > HD29L2_MAX_LEN)
-               return -EINVAL;
-       buf[0] = 0x00;
-       buf[1] = reg;
-       memcpy(&buf[2], val, len);
-
-       ret = i2c_transfer(priv->i2c, msg, 1);
-       if (ret == 1) {
-               ret = 0;
-       } else {
-               dev_warn(&priv->i2c->dev,
-                               "%s: i2c wr failed=%d reg=%02x len=%d\n",
-                               KBUILD_MODNAME, ret, reg, len);
-               ret = -EREMOTEIO;
-       }
-
-       return ret;
-}
-
-/* read multiple registers */
-static int hd29l2_rd_regs(struct hd29l2_priv *priv, u8 reg, u8 *val, int len)
-{
-       int ret;
-       u8 buf[2] = { 0x00, reg };
-       struct i2c_msg msg[2] = {
-               {
-                       .addr = priv->cfg.i2c_addr,
-                       .flags = 0,
-                       .len = 2,
-                       .buf = buf,
-               }, {
-                       .addr = priv->cfg.i2c_addr,
-                       .flags = I2C_M_RD,
-                       .len = len,
-                       .buf = val,
-               }
-       };
-
-       ret = i2c_transfer(priv->i2c, msg, 2);
-       if (ret == 2) {
-               ret = 0;
-       } else {
-               dev_warn(&priv->i2c->dev,
-                               "%s: i2c rd failed=%d reg=%02x len=%d\n",
-                               KBUILD_MODNAME, ret, reg, len);
-               ret = -EREMOTEIO;
-       }
-
-       return ret;
-}
-
-/* write single register */
-static int hd29l2_wr_reg(struct hd29l2_priv *priv, u8 reg, u8 val)
-{
-       return hd29l2_wr_regs(priv, reg, &val, 1);
-}
-
-/* read single register */
-static int hd29l2_rd_reg(struct hd29l2_priv *priv, u8 reg, u8 *val)
-{
-       return hd29l2_rd_regs(priv, reg, val, 1);
-}
-
-/* write single register with mask */
-static int hd29l2_wr_reg_mask(struct hd29l2_priv *priv, u8 reg, u8 val, u8 mask)
-{
-       int ret;
-       u8 tmp;
-
-       /* no need for read if whole reg is written */
-       if (mask != 0xff) {
-               ret = hd29l2_rd_regs(priv, reg, &tmp, 1);
-               if (ret)
-                       return ret;
-
-               val &= mask;
-               tmp &= ~mask;
-               val |= tmp;
-       }
-
-       return hd29l2_wr_regs(priv, reg, &val, 1);
-}
-
-/* read single register with mask */
-static int hd29l2_rd_reg_mask(struct hd29l2_priv *priv, u8 reg, u8 *val, u8 mask)
-{
-       int ret, i;
-       u8 tmp;
-
-       ret = hd29l2_rd_regs(priv, reg, &tmp, 1);
-       if (ret)
-               return ret;
-
-       tmp &= mask;
-
-       /* find position of the first bit */
-       for (i = 0; i < 8; i++) {
-               if ((mask >> i) & 0x01)
-                       break;
-       }
-       *val = tmp >> i;
-
-       return 0;
-}
-
-static int hd29l2_soft_reset(struct hd29l2_priv *priv)
-{
-       int ret;
-       u8 tmp;
-
-       ret = hd29l2_rd_reg(priv, 0x26, &tmp);
-       if (ret)
-               goto err;
-
-       ret = hd29l2_wr_reg(priv, 0x26, 0x0d);
-       if (ret)
-               goto err;
-
-       usleep_range(10000, 20000);
-
-       ret = hd29l2_wr_reg(priv, 0x26, tmp);
-       if (ret)
-               goto err;
-
-       return 0;
-err:
-       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-       return ret;
-}
-
-static int hd29l2_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
-       int ret, i;
-       struct hd29l2_priv *priv = fe->demodulator_priv;
-       u8 tmp;
-
-       dev_dbg(&priv->i2c->dev, "%s: enable=%d\n", __func__, enable);
-
-       /* set tuner address for demod */
-       if (!priv->tuner_i2c_addr_programmed && enable) {
-               /* no need to set tuner address every time, once is enough */
-               ret = hd29l2_wr_reg(priv, 0x9d, priv->cfg.tuner_i2c_addr << 1);
-               if (ret)
-                       goto err;
-
-               priv->tuner_i2c_addr_programmed = true;
-       }
-
-       /* open / close gate */
-       ret = hd29l2_wr_reg(priv, 0x9f, enable);
-       if (ret)
-               goto err;
-
-       /* wait demod ready */
-       for (i = 10; i; i--) {
-               ret = hd29l2_rd_reg(priv, 0x9e, &tmp);
-               if (ret)
-                       goto err;
-
-               if (tmp == enable)
-                       break;
-
-               usleep_range(5000, 10000);
-       }
-
-       dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i);
-
-       return ret;
-err:
-       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-       return ret;
-}
-
-static int hd29l2_read_status(struct dvb_frontend *fe, enum fe_status *status)
-{
-       int ret;
-       struct hd29l2_priv *priv = fe->demodulator_priv;
-       u8 buf[2];
-
-       *status = 0;
-
-       ret = hd29l2_rd_reg(priv, 0x05, &buf[0]);
-       if (ret)
-               goto err;
-
-       if (buf[0] & 0x01) {
-               /* full lock */
-               *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
-                       FE_HAS_SYNC | FE_HAS_LOCK;
-       } else {
-               ret = hd29l2_rd_reg(priv, 0x0d, &buf[1]);
-               if (ret)
-                       goto err;
-
-               if ((buf[1] & 0xfe) == 0x78)
-                       /* partial lock */
-                       *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
-                               FE_HAS_VITERBI | FE_HAS_SYNC;
-       }
-
-       priv->fe_status = *status;
-
-       return 0;
-err:
-       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-       return ret;
-}
-
-static int hd29l2_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
-       int ret;
-       struct hd29l2_priv *priv = fe->demodulator_priv;
-       u8 buf[2];
-       u16 tmp;
-
-       if (!(priv->fe_status & FE_HAS_LOCK)) {
-               *snr = 0;
-               ret = 0;
-               goto err;
-       }
-
-       ret = hd29l2_rd_regs(priv, 0x0b, buf, 2);
-       if (ret)
-               goto err;
-
-       tmp = (buf[0] << 8) | buf[1];
-
-       /* report SNR in dB * 10 */
-       #define LOG10_20736_24 72422627 /* log10(20736) << 24 */
-       if (tmp)
-               *snr = (LOG10_20736_24 - intlog10(tmp)) / ((1 << 24) / 100);
-       else
-               *snr = 0;
-
-       return 0;
-err:
-       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-       return ret;
-}
-
-static int hd29l2_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
-       int ret;
-       struct hd29l2_priv *priv = fe->demodulator_priv;
-       u8 buf[2];
-       u16 tmp;
-
-       *strength = 0;
-
-       ret = hd29l2_rd_regs(priv, 0xd5, buf, 2);
-       if (ret)
-               goto err;
-
-       tmp = buf[0] << 8 | buf[1];
-       tmp = ~tmp & 0x0fff;
-
-       /* scale value to 0x0000-0xffff from 0x0000-0x0fff */
-       *strength = tmp * 0xffff / 0x0fff;
-
-       return 0;
-err:
-       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-       return ret;
-}
-
-static int hd29l2_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
-       int ret;
-       struct hd29l2_priv *priv = fe->demodulator_priv;
-       u8 buf[2];
-
-       if (!(priv->fe_status & FE_HAS_SYNC)) {
-               *ber = 0;
-               ret = 0;
-               goto err;
-       }
-
-       ret = hd29l2_rd_regs(priv, 0xd9, buf, 2);
-       if (ret) {
-               *ber = 0;
-               goto err;
-       }
-
-       /* LDPC BER */
-       *ber = ((buf[0] & 0x0f) << 8) | buf[1];
-
-       return 0;
-err:
-       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-       return ret;
-}
-
-static int hd29l2_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-       /* no way to read? */
-       *ucblocks = 0;
-       return 0;
-}
-
-static enum dvbfe_search hd29l2_search(struct dvb_frontend *fe)
-{
-       int ret, i;
-       struct hd29l2_priv *priv = fe->demodulator_priv;
-       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-       u8 tmp, buf[3];
-       u8 modulation, carrier, guard_interval, interleave, code_rate;
-       u64 num64;
-       u32 if_freq, if_ctl;
-       bool auto_mode;
-
-       dev_dbg(&priv->i2c->dev, "%s: delivery_system=%d frequency=%d " \
-                       "bandwidth_hz=%d modulation=%d inversion=%d " \
-                       "fec_inner=%d guard_interval=%d\n", __func__,
-                       c->delivery_system, c->frequency, c->bandwidth_hz,
-                       c->modulation, c->inversion, c->fec_inner,
-                       c->guard_interval);
-
-       /* as for now we detect always params automatically */
-       auto_mode = true;
-
-       /* program tuner */
-       if (fe->ops.tuner_ops.set_params)
-               fe->ops.tuner_ops.set_params(fe);
-
-       /* get and program IF */
-       if (fe->ops.tuner_ops.get_if_frequency)
-               fe->ops.tuner_ops.get_if_frequency(fe, &if_freq);
-       else
-               if_freq = 0;
-
-       if (if_freq) {
-               /* normal IF */
-
-               /* calc IF control value */
-               num64 = if_freq;
-               num64 *= 0x800000;
-               num64 = div_u64(num64, HD29L2_XTAL);
-               num64 -= 0x800000;
-               if_ctl = num64;
-
-               tmp = 0xfc; /* tuner type normal */
-       } else {
-               /* zero IF */
-               if_ctl = 0;
-               tmp = 0xfe; /* tuner type Zero-IF */
-       }
-
-       buf[0] = ((if_ctl >>  0) & 0xff);
-       buf[1] = ((if_ctl >>  8) & 0xff);
-       buf[2] = ((if_ctl >> 16) & 0xff);
-
-       /* program IF control */
-       ret = hd29l2_wr_regs(priv, 0x14, buf, 3);
-       if (ret)
-               goto err;
-
-       /* program tuner type */
-       ret = hd29l2_wr_reg(priv, 0xab, tmp);
-       if (ret)
-               goto err;
-
-       dev_dbg(&priv->i2c->dev, "%s: if_freq=%d if_ctl=%x\n",
-                       __func__, if_freq, if_ctl);
-
-       if (auto_mode) {
-               /*
-                * use auto mode
-                */
-
-               /* disable quick mode */
-               ret = hd29l2_wr_reg_mask(priv, 0xac, 0 << 7, 0x80);
-               if (ret)
-                       goto err;
-
-               ret = hd29l2_wr_reg_mask(priv, 0x82, 1 << 1, 0x02);
-               if (ret)
-                       goto err;
-
-               /* enable auto mode */
-               ret = hd29l2_wr_reg_mask(priv, 0x7d, 1 << 6, 0x40);
-               if (ret)
-                       goto err;
-
-               ret = hd29l2_wr_reg_mask(priv, 0x81, 1 << 3, 0x08);
-               if (ret)
-                       goto err;
-
-               /* soft reset */
-               ret = hd29l2_soft_reset(priv);
-               if (ret)
-                       goto err;
-
-               /* detect modulation */
-               for (i = 30; i; i--) {
-                       msleep(100);
-
-                       ret = hd29l2_rd_reg(priv, 0x0d, &tmp);
-                       if (ret)
-                               goto err;
-
-                       if ((((tmp & 0xf0) >= 0x10) &&
-                               ((tmp & 0x0f) == 0x08)) || (tmp >= 0x2c))
-                               break;
-               }
-
-               dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i);
-
-               if (i == 0)
-                       /* detection failed */
-                       return DVBFE_ALGO_SEARCH_FAILED;
-
-               /* read modulation */
-               ret = hd29l2_rd_reg_mask(priv, 0x7d, &modulation, 0x07);
-               if (ret)
-                       goto err;
-       } else {
-               /*
-                * use manual mode
-                */
-
-               modulation = HD29L2_QAM64;
-               carrier = HD29L2_CARRIER_MULTI;
-               guard_interval = HD29L2_PN945;
-               interleave = HD29L2_INTERLEAVER_420;
-               code_rate = HD29L2_CODE_RATE_08;
-
-               tmp = (code_rate << 3) | modulation;
-               ret = hd29l2_wr_reg_mask(priv, 0x7d, tmp, 0x5f);
-               if (ret)
-                       goto err;
-
-               tmp = (carrier << 2) | guard_interval;
-               ret = hd29l2_wr_reg_mask(priv, 0x81, tmp, 0x0f);
-               if (ret)
-                       goto err;
-
-               tmp = interleave;
-               ret = hd29l2_wr_reg_mask(priv, 0x82, tmp, 0x03);
-               if (ret)
-                       goto err;
-       }
-
-       /* ensure modulation validy */
-       /* 0=QAM4_NR, 1=QAM4, 2=QAM16, 3=QAM32, 4=QAM64 */
-       if (modulation > (ARRAY_SIZE(reg_mod_vals_tab[0].val) - 1)) {
-               dev_dbg(&priv->i2c->dev, "%s: modulation=%d not valid\n",
-                               __func__, modulation);
-               goto err;
-       }
-
-       /* program registers according to modulation */
-       for (i = 0; i < ARRAY_SIZE(reg_mod_vals_tab); i++) {
-               ret = hd29l2_wr_reg(priv, reg_mod_vals_tab[i].reg,
-                       reg_mod_vals_tab[i].val[modulation]);
-               if (ret)
-                       goto err;
-       }
-
-       /* read guard interval */
-       ret = hd29l2_rd_reg_mask(priv, 0x81, &guard_interval, 0x03);
-       if (ret)
-               goto err;
-
-       /* read carrier mode */
-       ret = hd29l2_rd_reg_mask(priv, 0x81, &carrier, 0x04);
-       if (ret)
-               goto err;
-
-       dev_dbg(&priv->i2c->dev,
-                       "%s: modulation=%d guard_interval=%d carrier=%d\n",
-                       __func__, modulation, guard_interval, carrier);
-
-       if ((carrier == HD29L2_CARRIER_MULTI) && (modulation == HD29L2_QAM64) &&
-               (guard_interval == HD29L2_PN945)) {
-               dev_dbg(&priv->i2c->dev, "%s: C=3780 && QAM64 && PN945\n",
-                               __func__);
-
-               ret = hd29l2_wr_reg(priv, 0x42, 0x33);
-               if (ret)
-                       goto err;
-
-               ret = hd29l2_wr_reg(priv, 0xdd, 0x01);
-               if (ret)
-                       goto err;
-       }
-
-       usleep_range(10000, 20000);
-
-       /* soft reset */
-       ret = hd29l2_soft_reset(priv);
-       if (ret)
-               goto err;
-
-       /* wait demod lock */
-       for (i = 30; i; i--) {
-               msleep(100);
-
-               /* read lock bit */
-               ret = hd29l2_rd_reg_mask(priv, 0x05, &tmp, 0x01);
-               if (ret)
-                       goto err;
-
-               if (tmp)
-                       break;
-       }
-
-       dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i);
-
-       if (i == 0)
-               return DVBFE_ALGO_SEARCH_AGAIN;
-
-       return DVBFE_ALGO_SEARCH_SUCCESS;
-err:
-       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-       return DVBFE_ALGO_SEARCH_ERROR;
-}
-
-static int hd29l2_get_frontend_algo(struct dvb_frontend *fe)
-{
-       return DVBFE_ALGO_CUSTOM;
-}
-
-static int hd29l2_get_frontend(struct dvb_frontend *fe,
-                              struct dtv_frontend_properties *c)
-{
-       int ret;
-       struct hd29l2_priv *priv = fe->demodulator_priv;
-       u8 buf[3];
-       u32 if_ctl;
-       char *str_constellation, *str_code_rate, *str_constellation_code_rate,
-               *str_guard_interval, *str_carrier, *str_guard_interval_carrier,
-               *str_interleave, *str_interleave_;
-
-       ret = hd29l2_rd_reg(priv, 0x7d, &buf[0]);
-       if (ret)
-               goto err;
-
-       ret = hd29l2_rd_regs(priv, 0x81, &buf[1], 2);
-       if (ret)
-               goto err;
-
-       /* constellation, 0x7d[2:0] */
-       switch ((buf[0] >> 0) & 0x07) {
-       case 0: /* QAM4NR */
-               str_constellation = "QAM4NR";
-               c->modulation = QAM_AUTO; /* FIXME */
-               break;
-       case 1: /* QAM4 */
-               str_constellation = "QAM4";
-               c->modulation = QPSK; /* FIXME */
-               break;
-       case 2:
-               str_constellation = "QAM16";
-               c->modulation = QAM_16;
-               break;
-       case 3:
-               str_constellation = "QAM32";
-               c->modulation = QAM_32;
-               break;
-       case 4:
-               str_constellation = "QAM64";
-               c->modulation = QAM_64;
-               break;
-       default:
-               str_constellation = "?";
-       }
-
-       /* LDPC code rate, 0x7d[4:3] */
-       switch ((buf[0] >> 3) & 0x03) {
-       case 0: /* 0.4 */
-               str_code_rate = "0.4";
-               c->fec_inner = FEC_AUTO; /* FIXME */
-               break;
-       case 1: /* 0.6 */
-               str_code_rate = "0.6";
-               c->fec_inner = FEC_3_5;
-               break;
-       case 2: /* 0.8 */
-               str_code_rate = "0.8";
-               c->fec_inner = FEC_4_5;
-               break;
-       default:
-               str_code_rate = "?";
-       }
-
-       /* constellation & code rate set, 0x7d[6] */
-       switch ((buf[0] >> 6) & 0x01) {
-       case 0:
-               str_constellation_code_rate = "manual";
-               break;
-       case 1:
-               str_constellation_code_rate = "auto";
-               break;
-       default:
-               str_constellation_code_rate = "?";
-       }
-
-       /* frame header, 0x81[1:0] */
-       switch ((buf[1] >> 0) & 0x03) {
-       case 0: /* PN945 */
-               str_guard_interval = "PN945";
-               c->guard_interval = GUARD_INTERVAL_AUTO; /* FIXME */
-               break;
-       case 1: /* PN595 */
-               str_guard_interval = "PN595";
-               c->guard_interval = GUARD_INTERVAL_AUTO; /* FIXME */
-               break;
-       case 2: /* PN420 */
-               str_guard_interval = "PN420";
-               c->guard_interval = GUARD_INTERVAL_AUTO; /* FIXME */
-               break;
-       default:
-               str_guard_interval = "?";
-       }
-
-       /* carrier, 0x81[2] */
-       switch ((buf[1] >> 2) & 0x01) {
-       case 0:
-               str_carrier = "C=1";
-               break;
-       case 1:
-               str_carrier = "C=3780";
-               break;
-       default:
-               str_carrier = "?";
-       }
-
-       /* frame header & carrier set, 0x81[3] */
-       switch ((buf[1] >> 3) & 0x01) {
-       case 0:
-               str_guard_interval_carrier = "manual";
-               break;
-       case 1:
-               str_guard_interval_carrier = "auto";
-               break;
-       default:
-               str_guard_interval_carrier = "?";
-       }
-
-       /* interleave, 0x82[0] */
-       switch ((buf[2] >> 0) & 0x01) {
-       case 0:
-               str_interleave = "M=720";
-               break;
-       case 1:
-               str_interleave = "M=240";
-               break;
-       default:
-               str_interleave = "?";
-       }
-
-       /* interleave set, 0x82[1] */
-       switch ((buf[2] >> 1) & 0x01) {
-       case 0:
-               str_interleave_ = "manual";
-               break;
-       case 1:
-               str_interleave_ = "auto";
-               break;
-       default:
-               str_interleave_ = "?";
-       }
-
-       /*
-        * We can read out current detected NCO and use that value next
-        * time instead of calculating new value from targed IF.
-        * I think it will not effect receiver sensitivity but gaining lock
-        * after tune could be easier...
-        */
-       ret = hd29l2_rd_regs(priv, 0xb1, &buf[0], 3);
-       if (ret)
-               goto err;
-
-       if_ctl = (buf[0] << 16) | ((buf[1] - 7) << 8) | buf[2];
-
-       dev_dbg(&priv->i2c->dev, "%s: %s %s %s | %s %s %s | %s %s | NCO=%06x\n",
-                       __func__, str_constellation, str_code_rate,
-                       str_constellation_code_rate, str_guard_interval,
-                       str_carrier, str_guard_interval_carrier, str_interleave,
-                       str_interleave_, if_ctl);
-       return 0;
-err:
-       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-       return ret;
-}
-
-static int hd29l2_init(struct dvb_frontend *fe)
-{
-       int ret, i;
-       struct hd29l2_priv *priv = fe->demodulator_priv;
-       u8 tmp;
-       static const struct reg_val tab[] = {
-               { 0x3a, 0x06 },
-               { 0x3b, 0x03 },
-               { 0x3c, 0x04 },
-               { 0xaf, 0x06 },
-               { 0xb0, 0x1b },
-               { 0x80, 0x64 },
-               { 0x10, 0x38 },
-       };
-
-       dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
-
-       /* reset demod */
-       /* it is recommended to HW reset chip using RST_N pin */
-       if (fe->callback) {
-               ret = fe->callback(fe, DVB_FRONTEND_COMPONENT_DEMOD, 0, 0);
-               if (ret)
-                       goto err;
-
-               /* reprogramming needed because HW reset clears registers */
-               priv->tuner_i2c_addr_programmed = false;
-       }
-
-       /* init */
-       for (i = 0; i < ARRAY_SIZE(tab); i++) {
-               ret = hd29l2_wr_reg(priv, tab[i].reg, tab[i].val);
-               if (ret)
-                       goto err;
-       }
-
-       /* TS params */
-       ret = hd29l2_rd_reg(priv, 0x36, &tmp);
-       if (ret)
-               goto err;
-
-       tmp &= 0x1b;
-       tmp |= priv->cfg.ts_mode;
-       ret = hd29l2_wr_reg(priv, 0x36, tmp);
-       if (ret)
-               goto err;
-
-       ret = hd29l2_rd_reg(priv, 0x31, &tmp);
-       tmp &= 0xef;
-
-       if (!(priv->cfg.ts_mode >> 7))
-               /* set b4 for serial TS */
-               tmp |= 0x10;
-
-       ret = hd29l2_wr_reg(priv, 0x31, tmp);
-       if (ret)
-               goto err;
-
-       return ret;
-err:
-       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-       return ret;
-}
-
-static void hd29l2_release(struct dvb_frontend *fe)
-{
-       struct hd29l2_priv *priv = fe->demodulator_priv;
-       kfree(priv);
-}
-
-static const struct dvb_frontend_ops hd29l2_ops;
-
-struct dvb_frontend *hd29l2_attach(const struct hd29l2_config *config,
-       struct i2c_adapter *i2c)
-{
-       int ret;
-       struct hd29l2_priv *priv = NULL;
-       u8 tmp;
-
-       /* allocate memory for the internal state */
-       priv = kzalloc(sizeof(struct hd29l2_priv), GFP_KERNEL);
-       if (priv == NULL)
-               goto err;
-
-       /* setup the state */
-       priv->i2c = i2c;
-       memcpy(&priv->cfg, config, sizeof(struct hd29l2_config));
-
-
-       /* check if the demod is there */
-       ret = hd29l2_rd_reg(priv, 0x00, &tmp);
-       if (ret)
-               goto err;
-
-       /* create dvb_frontend */
-       memcpy(&priv->fe.ops, &hd29l2_ops, sizeof(struct dvb_frontend_ops));
-       priv->fe.demodulator_priv = priv;
-
-       return &priv->fe;
-err:
-       kfree(priv);
-       return NULL;
-}
-EXPORT_SYMBOL(hd29l2_attach);
-
-static const struct dvb_frontend_ops hd29l2_ops = {
-       .delsys = { SYS_DVBT },
-       .info = {
-               .name = "HDIC HD29L2 DMB-TH",
-               .frequency_min = 474000000,
-               .frequency_max = 858000000,
-               .frequency_stepsize = 10000,
-               .caps = FE_CAN_FEC_AUTO |
-                       FE_CAN_QPSK |
-                       FE_CAN_QAM_16 |
-                       FE_CAN_QAM_32 |
-                       FE_CAN_QAM_64 |
-                       FE_CAN_QAM_AUTO |
-                       FE_CAN_TRANSMISSION_MODE_AUTO |
-                       FE_CAN_BANDWIDTH_AUTO |
-                       FE_CAN_GUARD_INTERVAL_AUTO |
-                       FE_CAN_HIERARCHY_AUTO |
-                       FE_CAN_RECOVER
-       },
-
-       .release = hd29l2_release,
-
-       .init = hd29l2_init,
-
-       .get_frontend_algo = hd29l2_get_frontend_algo,
-       .search = hd29l2_search,
-       .get_frontend = hd29l2_get_frontend,
-
-       .read_status = hd29l2_read_status,
-       .read_snr = hd29l2_read_snr,
-       .read_signal_strength = hd29l2_read_signal_strength,
-       .read_ber = hd29l2_read_ber,
-       .read_ucblocks = hd29l2_read_ucblocks,
-
-       .i2c_gate_ctrl = hd29l2_i2c_gate_ctrl,
-};
-
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("HDIC HD29L2 DMB-TH demodulator driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/hd29l2.h b/drivers/media/dvb-frontends/hd29l2.h
deleted file mode 100644 (file)
index a14d6f3..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * HDIC HD29L2 DMB-TH demodulator driver
- *
- * Copyright (C) 2011 Metropolia University of Applied Sciences, Electria R&D
- *
- * Author: Antti Palosaari <crope@iki.fi>
- *
- *    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 HD29L2_H
-#define HD29L2_H
-
-#include <linux/dvb/frontend.h>
-
-struct hd29l2_config {
-       /*
-        * demodulator I2C address
-        */
-       u8 i2c_addr;
-
-       /*
-        * tuner I2C address
-        * only needed when tuner is behind demod I2C-gate
-        */
-       u8 tuner_i2c_addr;
-
-       /*
-        * TS settings
-        */
-#define HD29L2_TS_SERIAL            0x00
-#define HD29L2_TS_PARALLEL          0x80
-#define HD29L2_TS_CLK_NORMAL        0x40
-#define HD29L2_TS_CLK_INVERTED      0x00
-#define HD29L2_TS_CLK_GATED         0x20
-#define HD29L2_TS_CLK_FREE          0x00
-       u8 ts_mode;
-};
-
-
-#if IS_REACHABLE(CONFIG_DVB_HD29L2)
-extern struct dvb_frontend *hd29l2_attach(const struct hd29l2_config *config,
-       struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend *hd29l2_attach(
-const struct hd29l2_config *config, struct i2c_adapter *i2c)
-{
-       pr_warn("%s: driver disabled by Kconfig\n", __func__);
-       return NULL;
-}
-#endif
-
-#endif /* HD29L2_H */
diff --git a/drivers/media/dvb-frontends/hd29l2_priv.h b/drivers/media/dvb-frontends/hd29l2_priv.h
deleted file mode 100644 (file)
index 6dc225c..0000000
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * HDIC HD29L2 DMB-TH demodulator driver
- *
- * Copyright (C) 2011 Metropolia University of Applied Sciences, Electria R&D
- *
- * Author: Antti Palosaari <crope@iki.fi>
- *
- *    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 HD29L2_PRIV
-#define HD29L2_PRIV
-
-#include <linux/dvb/version.h>
-#include "dvb_frontend.h"
-#include "dvb_math.h"
-#include "hd29l2.h"
-
-#define HD29L2_XTAL 30400000 /* Hz */
-
-
-#define HD29L2_QAM4NR 0x00
-#define HD29L2_QAM4   0x01
-#define HD29L2_QAM16  0x02
-#define HD29L2_QAM32  0x03
-#define HD29L2_QAM64  0x04
-
-#define HD29L2_CODE_RATE_04 0x00
-#define HD29L2_CODE_RATE_06 0x08
-#define HD29L2_CODE_RATE_08 0x10
-
-#define HD29L2_PN945 0x00
-#define HD29L2_PN595 0x01
-#define HD29L2_PN420 0x02
-
-#define HD29L2_CARRIER_SINGLE 0x00
-#define HD29L2_CARRIER_MULTI  0x01
-
-#define HD29L2_INTERLEAVER_720 0x00
-#define HD29L2_INTERLEAVER_420 0x01
-
-struct reg_val {
-       u8 reg;
-       u8 val;
-};
-
-struct reg_mod_vals {
-       u8 reg;
-       u8 val[5];
-};
-
-struct hd29l2_priv {
-       struct i2c_adapter *i2c;
-       struct dvb_frontend fe;
-       struct hd29l2_config cfg;
-       u8 tuner_i2c_addr_programmed:1;
-
-       enum fe_status fe_status;
-};
-
-static const struct reg_mod_vals reg_mod_vals_tab[] = {
-       /* REG, QAM4NR, QAM4,QAM16,QAM32,QAM64 */
-       { 0x01, { 0x10, 0x10, 0x10, 0x10, 0x10 } },
-       { 0x02, { 0x07, 0x07, 0x07, 0x07, 0x07 } },
-       { 0x03, { 0x10, 0x10, 0x10, 0x10, 0x10 } },
-       { 0x04, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0x05, { 0x61, 0x60, 0x60, 0x61, 0x60 } },
-       { 0x06, { 0xff, 0xff, 0xff, 0xff, 0xff } },
-       { 0x07, { 0xff, 0xff, 0xff, 0xff, 0xff } },
-       { 0x08, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0x09, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0x0a, { 0x15, 0x15, 0x03, 0x03, 0x03 } },
-       { 0x0d, { 0x78, 0x78, 0x88, 0x78, 0x78 } },
-       { 0x0e, { 0xa0, 0x90, 0xa0, 0xa0, 0xa0 } },
-       { 0x0f, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0x10, { 0xa0, 0xa0, 0x58, 0x38, 0x38 } },
-       { 0x11, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0x12, { 0x5a, 0x5a, 0x5a, 0x5a, 0x5a } },
-       { 0x13, { 0xa2, 0xa2, 0xa2, 0xa2, 0xa2 } },
-       { 0x17, { 0x40, 0x40, 0x40, 0x40, 0x40 } },
-       { 0x18, { 0x21, 0x21, 0x42, 0x52, 0x42 } },
-       { 0x19, { 0x21, 0x21, 0x62, 0x72, 0x62 } },
-       { 0x1a, { 0x32, 0x43, 0xa9, 0xb9, 0xa9 } },
-       { 0x1b, { 0x32, 0x43, 0xb9, 0xd8, 0xb9 } },
-       { 0x1c, { 0x02, 0x02, 0x03, 0x02, 0x03 } },
-       { 0x1d, { 0x0c, 0x0c, 0x01, 0x02, 0x02 } },
-       { 0x1e, { 0x02, 0x02, 0x02, 0x01, 0x02 } },
-       { 0x1f, { 0x02, 0x02, 0x01, 0x02, 0x04 } },
-       { 0x20, { 0x01, 0x02, 0x01, 0x01, 0x01 } },
-       { 0x21, { 0x08, 0x08, 0x0a, 0x0a, 0x0a } },
-       { 0x22, { 0x06, 0x06, 0x04, 0x05, 0x05 } },
-       { 0x23, { 0x06, 0x06, 0x05, 0x03, 0x05 } },
-       { 0x24, { 0x08, 0x08, 0x05, 0x07, 0x07 } },
-       { 0x25, { 0x16, 0x10, 0x10, 0x0a, 0x10 } },
-       { 0x26, { 0x14, 0x14, 0x04, 0x04, 0x04 } },
-       { 0x27, { 0x58, 0x58, 0x58, 0x5c, 0x58 } },
-       { 0x28, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
-       { 0x29, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
-       { 0x2a, { 0x08, 0x0a, 0x08, 0x08, 0x08 } },
-       { 0x2b, { 0x08, 0x08, 0x08, 0x08, 0x08 } },
-       { 0x2c, { 0x06, 0x06, 0x06, 0x06, 0x06 } },
-       { 0x2d, { 0x05, 0x06, 0x06, 0x06, 0x06 } },
-       { 0x2e, { 0x21, 0x21, 0x21, 0x21, 0x21 } },
-       { 0x2f, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0x30, { 0x14, 0x14, 0x14, 0x14, 0x14 } },
-       { 0x33, { 0xb7, 0xb7, 0xb7, 0xb7, 0xb7 } },
-       { 0x34, { 0x81, 0x81, 0x81, 0x81, 0x81 } },
-       { 0x35, { 0x80, 0x80, 0x80, 0x80, 0x80 } },
-       { 0x37, { 0x70, 0x70, 0x70, 0x70, 0x70 } },
-       { 0x38, { 0x04, 0x04, 0x02, 0x02, 0x02 } },
-       { 0x39, { 0x07, 0x07, 0x05, 0x05, 0x05 } },
-       { 0x3a, { 0x06, 0x06, 0x06, 0x06, 0x06 } },
-       { 0x3b, { 0x03, 0x03, 0x03, 0x03, 0x03 } },
-       { 0x3c, { 0x07, 0x06, 0x04, 0x04, 0x04 } },
-       { 0x3d, { 0xf0, 0xf0, 0xf0, 0xf0, 0x80 } },
-       { 0x3e, { 0x60, 0x60, 0x60, 0x60, 0xff } },
-       { 0x3f, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0x40, { 0x5b, 0x5b, 0x5b, 0x57, 0x50 } },
-       { 0x41, { 0x30, 0x30, 0x30, 0x30, 0x18 } },
-       { 0x42, { 0x20, 0x20, 0x20, 0x00, 0x30 } },
-       { 0x43, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0x44, { 0x3f, 0x3f, 0x3f, 0x3f, 0x3f } },
-       { 0x45, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0x46, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
-       { 0x47, { 0x00, 0x00, 0x95, 0x00, 0x95 } },
-       { 0x48, { 0xc0, 0xc0, 0xc0, 0xc0, 0xc0 } },
-       { 0x49, { 0xc0, 0xc0, 0xc0, 0xc0, 0xc0 } },
-       { 0x4a, { 0x40, 0x40, 0x33, 0x11, 0x11 } },
-       { 0x4b, { 0x40, 0x40, 0x00, 0x00, 0x00 } },
-       { 0x4c, { 0x40, 0x40, 0x99, 0x11, 0x11 } },
-       { 0x4d, { 0x40, 0x40, 0x00, 0x00, 0x00 } },
-       { 0x4e, { 0x40, 0x40, 0x66, 0x77, 0x77 } },
-       { 0x4f, { 0x40, 0x40, 0x00, 0x00, 0x00 } },
-       { 0x50, { 0x40, 0x40, 0x88, 0x33, 0x11 } },
-       { 0x51, { 0x40, 0x40, 0x00, 0x00, 0x00 } },
-       { 0x52, { 0x40, 0x40, 0x88, 0x02, 0x02 } },
-       { 0x53, { 0x40, 0x40, 0x00, 0x02, 0x02 } },
-       { 0x54, { 0x00, 0x00, 0x88, 0x33, 0x33 } },
-       { 0x55, { 0x40, 0x40, 0x00, 0x00, 0x00 } },
-       { 0x56, { 0x00, 0x00, 0x00, 0x0b, 0x00 } },
-       { 0x57, { 0x40, 0x40, 0x0a, 0x0b, 0x0a } },
-       { 0x58, { 0xaa, 0x00, 0x00, 0x00, 0x00 } },
-       { 0x59, { 0x7a, 0x40, 0x02, 0x02, 0x02 } },
-       { 0x5a, { 0x18, 0x18, 0x01, 0x01, 0x01 } },
-       { 0x5b, { 0x18, 0x18, 0x01, 0x01, 0x01 } },
-       { 0x5c, { 0x18, 0x18, 0x01, 0x01, 0x01 } },
-       { 0x5d, { 0x18, 0x18, 0x01, 0x01, 0x01 } },
-       { 0x5e, { 0xc0, 0xc0, 0xc0, 0xff, 0xc0 } },
-       { 0x5f, { 0xc0, 0xc0, 0xc0, 0xff, 0xc0 } },
-       { 0x60, { 0x40, 0x40, 0x00, 0x30, 0x30 } },
-       { 0x61, { 0x40, 0x40, 0x10, 0x30, 0x30 } },
-       { 0x62, { 0x40, 0x40, 0x00, 0x30, 0x30 } },
-       { 0x63, { 0x40, 0x40, 0x05, 0x30, 0x30 } },
-       { 0x64, { 0x40, 0x40, 0x06, 0x00, 0x30 } },
-       { 0x65, { 0x40, 0x40, 0x06, 0x08, 0x30 } },
-       { 0x66, { 0x40, 0x40, 0x00, 0x00, 0x20 } },
-       { 0x67, { 0x40, 0x40, 0x01, 0x04, 0x20 } },
-       { 0x68, { 0x00, 0x00, 0x30, 0x00, 0x20 } },
-       { 0x69, { 0xa0, 0xa0, 0x00, 0x08, 0x20 } },
-       { 0x6a, { 0x00, 0x00, 0x30, 0x00, 0x25 } },
-       { 0x6b, { 0xa0, 0xa0, 0x00, 0x06, 0x25 } },
-       { 0x6c, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0x6d, { 0xa0, 0x60, 0x0c, 0x03, 0x0c } },
-       { 0x6e, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0x6f, { 0xa0, 0x60, 0x04, 0x01, 0x04 } },
-       { 0x70, { 0x58, 0x58, 0xaa, 0xaa, 0xaa } },
-       { 0x71, { 0x58, 0x58, 0xaa, 0xaa, 0xaa } },
-       { 0x72, { 0x58, 0x58, 0xff, 0xff, 0xff } },
-       { 0x73, { 0x58, 0x58, 0xff, 0xff, 0xff } },
-       { 0x74, { 0x06, 0x06, 0x09, 0x05, 0x05 } },
-       { 0x75, { 0x06, 0x06, 0x0a, 0x10, 0x10 } },
-       { 0x76, { 0x10, 0x10, 0x06, 0x0a, 0x0a } },
-       { 0x77, { 0x12, 0x18, 0x28, 0x10, 0x28 } },
-       { 0x78, { 0xf8, 0xf8, 0xf8, 0xf8, 0xf8 } },
-       { 0x79, { 0x15, 0x15, 0x03, 0x03, 0x03 } },
-       { 0x7a, { 0x02, 0x02, 0x01, 0x04, 0x03 } },
-       { 0x7b, { 0x01, 0x02, 0x03, 0x03, 0x03 } },
-       { 0x7c, { 0x28, 0x28, 0x28, 0x28, 0x28 } },
-       { 0x7f, { 0x25, 0x92, 0x5f, 0x17, 0x2d } },
-       { 0x80, { 0x64, 0x64, 0x64, 0x74, 0x64 } },
-       { 0x83, { 0x06, 0x03, 0x04, 0x04, 0x04 } },
-       { 0x84, { 0xff, 0xff, 0xff, 0xff, 0xff } },
-       { 0x85, { 0x05, 0x05, 0x05, 0x05, 0x05 } },
-       { 0x86, { 0x00, 0x00, 0x11, 0x11, 0x11 } },
-       { 0x87, { 0x03, 0x03, 0x03, 0x03, 0x03 } },
-       { 0x88, { 0x09, 0x09, 0x09, 0x09, 0x09 } },
-       { 0x89, { 0x20, 0x20, 0x30, 0x20, 0x20 } },
-       { 0x8a, { 0x03, 0x03, 0x02, 0x03, 0x02 } },
-       { 0x8b, { 0x00, 0x07, 0x09, 0x00, 0x09 } },
-       { 0x8c, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0x8d, { 0x4f, 0x4f, 0x4f, 0x3f, 0x4f } },
-       { 0x8e, { 0xf0, 0xf0, 0x60, 0xf0, 0xa0 } },
-       { 0x8f, { 0xe8, 0xe8, 0xe8, 0xe8, 0xe8 } },
-       { 0x90, { 0x10, 0x10, 0x10, 0x10, 0x10 } },
-       { 0x91, { 0x40, 0x40, 0x70, 0x70, 0x10 } },
-       { 0x92, { 0x00, 0x00, 0x00, 0x00, 0x04 } },
-       { 0x93, { 0x60, 0x60, 0x60, 0x60, 0x60 } },
-       { 0x94, { 0x00, 0x00, 0x00, 0x00, 0x03 } },
-       { 0x95, { 0x09, 0x09, 0x47, 0x47, 0x47 } },
-       { 0x96, { 0x80, 0xa0, 0xa0, 0x40, 0xa0 } },
-       { 0x97, { 0x60, 0x60, 0x60, 0x60, 0x60 } },
-       { 0x98, { 0x50, 0x50, 0x50, 0x30, 0x50 } },
-       { 0x99, { 0x10, 0x10, 0x10, 0x10, 0x10 } },
-       { 0x9a, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0x9b, { 0x40, 0x40, 0x40, 0x30, 0x40 } },
-       { 0x9c, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xa0, { 0xf0, 0xf0, 0xf0, 0xf0, 0xf0 } },
-       { 0xa1, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xa2, { 0x30, 0x30, 0x00, 0x30, 0x00 } },
-       { 0xa3, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xa4, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xa5, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xa6, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xa7, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xa8, { 0x77, 0x77, 0x77, 0x77, 0x77 } },
-       { 0xa9, { 0x02, 0x02, 0x02, 0x02, 0x02 } },
-       { 0xaa, { 0x40, 0x40, 0x40, 0x40, 0x40 } },
-       { 0xac, { 0x1f, 0x1f, 0x1f, 0x1f, 0x1f } },
-       { 0xad, { 0x14, 0x14, 0x14, 0x14, 0x14 } },
-       { 0xae, { 0x78, 0x78, 0x78, 0x78, 0x78 } },
-       { 0xaf, { 0x06, 0x06, 0x06, 0x06, 0x07 } },
-       { 0xb0, { 0x1b, 0x1b, 0x1b, 0x19, 0x1b } },
-       { 0xb1, { 0x18, 0x17, 0x17, 0x18, 0x17 } },
-       { 0xb2, { 0x35, 0x82, 0x82, 0x38, 0x82 } },
-       { 0xb3, { 0xb6, 0xce, 0xc7, 0x5c, 0xb0 } },
-       { 0xb4, { 0x3f, 0x3e, 0x3e, 0x3f, 0x3e } },
-       { 0xb5, { 0x70, 0x58, 0x50, 0x68, 0x50 } },
-       { 0xb6, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xb7, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xb8, { 0x03, 0x03, 0x01, 0x01, 0x01 } },
-       { 0xb9, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xba, { 0x06, 0x06, 0x0a, 0x05, 0x0a } },
-       { 0xbb, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xbc, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xbd, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xbe, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xbf, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xc0, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xc1, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xc2, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xc3, { 0x00, 0x00, 0x88, 0x66, 0x88 } },
-       { 0xc4, { 0x10, 0x10, 0x00, 0x00, 0x00 } },
-       { 0xc5, { 0x00, 0x00, 0x44, 0x60, 0x44 } },
-       { 0xc6, { 0x10, 0x0a, 0x00, 0x00, 0x00 } },
-       { 0xc7, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xc8, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xc9, { 0x90, 0x04, 0x00, 0x00, 0x00 } },
-       { 0xca, { 0x90, 0x08, 0x01, 0x01, 0x01 } },
-       { 0xcb, { 0xa0, 0x04, 0x00, 0x44, 0x00 } },
-       { 0xcc, { 0xa0, 0x10, 0x03, 0x00, 0x03 } },
-       { 0xcd, { 0x06, 0x06, 0x06, 0x05, 0x06 } },
-       { 0xce, { 0x05, 0x05, 0x01, 0x01, 0x01 } },
-       { 0xcf, { 0x40, 0x20, 0x18, 0x18, 0x18 } },
-       { 0xd0, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xd1, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xd2, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xd3, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xd4, { 0x05, 0x05, 0x05, 0x05, 0x05 } },
-       { 0xd5, { 0x05, 0x05, 0x05, 0x03, 0x05 } },
-       { 0xd6, { 0xac, 0x22, 0xca, 0x8f, 0xca } },
-       { 0xd7, { 0x20, 0x20, 0x20, 0x20, 0x20 } },
-       { 0xd8, { 0x01, 0x01, 0x01, 0x01, 0x01 } },
-       { 0xd9, { 0x00, 0x00, 0x0f, 0x00, 0x0f } },
-       { 0xda, { 0x00, 0xff, 0xff, 0x0e, 0xff } },
-       { 0xdb, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
-       { 0xdc, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
-       { 0xdd, { 0x05, 0x05, 0x05, 0x05, 0x05 } },
-       { 0xde, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
-       { 0xdf, { 0x42, 0x42, 0x44, 0x44, 0x04 } },
-       { 0xe0, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xe1, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xe2, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xe3, { 0x00, 0x00, 0x26, 0x06, 0x26 } },
-       { 0xe4, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xe5, { 0x01, 0x0a, 0x01, 0x01, 0x01 } },
-       { 0xe6, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xe7, { 0x08, 0x08, 0x08, 0x08, 0x08 } },
-       { 0xe8, { 0x63, 0x63, 0x63, 0x63, 0x63 } },
-       { 0xe9, { 0x59, 0x59, 0x59, 0x59, 0x59 } },
-       { 0xea, { 0x80, 0x80, 0x20, 0x80, 0x80 } },
-       { 0xeb, { 0x37, 0x37, 0x78, 0x37, 0x77 } },
-       { 0xec, { 0x1f, 0x1f, 0x25, 0x25, 0x25 } },
-       { 0xed, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } },
-       { 0xee, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-       { 0xef, { 0x70, 0x70, 0x58, 0x38, 0x58 } },
-       { 0xf0, { 0x00, 0x00, 0x00, 0x00, 0x00 } },
-};
-
-#endif /* HD29L2_PRIV */
index 6913cd687b4d514d8c8063c526492619fd823fda..2fc8d3c72c118ff2fdcd7e326cdfbb10c5e1487a 100644 (file)
  * 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.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  *
  *
  * the project's page is at https://linuxtv.org
index 4a23d3bdf3e6b6200fb60ded487aa963bcc96c7b..18fe714f9999b27dba6ad7d231b41a298dbcafee 100644 (file)
  * 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.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  *
  *
  * the project's page is at https://linuxtv.org
index 0b6d3837d5de52c0ecea33980a4c9f2afd3809ca..838b42771a05812c01e2d9f388e00512240030ca 100644 (file)
  * 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.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  *
  *
  * the project's page is at https://linuxtv.org
index 00f9874ca5a28b61f8e2942041066d3456a477d7..4deeddec51403b1458ff345596435ae9f1b8faf3 100644 (file)
  * 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.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  *
  *
  * the project's page is at https://linuxtv.org
index 4755251343278928c300e041c00229974d19cd5f..5bb1e73a10b4390c88a123b995e5181cbb04980a 100644 (file)
  *  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/module.h>
index a691bb6f26de7d89f6b582b77120231a4efc1412..f8a2256a0b36477ac87e47d03399159b49310cc7 100644 (file)
  *  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 ITD1000_H
index 08ca851223c9ed92f814b5b98514be3ade4cf4cf..6c99d95d1056b51a3be326b33b4a8f5fbfdfcdeb 100644 (file)
  *  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 ITD1000_PRIV_H
index ca371680a69fd9ac5fc2d799d59845e1b4c53088..534b24fa2b95ae021dd4989091c312b8d1f4081e 100644 (file)
  * 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/module.h>
index 5eab39744b23558f4754a9a46bda197007cbc224..0b0a431c74f61a404c7c3c38dce035bc90a826b6 100644 (file)
  * but WITHOUT 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 DVB_IX2505V_H
index 3b31e5f20f4668833ad7b7e878d16e5bedc842f0..5798079add1029f7ad4d751336537f06c3b84c2d 100644 (file)
  *    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/jiffies.h>
index 8c74ddc6b88a1a138f288d2509bef7cbf40445f2..ba99125deac0f41176da3a61b01d34ab525e8dd2 100644 (file)
  *    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 _LG2160_H_
index 9f5d9380bf5f1eeb3450982c4fa6c7992a8a476f..0af4d910476135a14be0e52532fbee8e3b8b9b45 100644 (file)
  *    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 <asm/div64.h>
index e7dceb60e5727a89934afd2fc58cb6a69dbb7e8b..2fb60d91f7b4e81cbda38e5d5b37c017e319765c 100644 (file)
  *    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 _LGDT3305_H_
index 19dca46b1171c516a6252b08d7153bd9e35e2616..c9b1eb38444e8cc199aeffa2c96244b141663b7d 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/dvb/frontend.h>
 #include "dvb_math.h"
 #include "lgdt3306a.h"
+#include <linux/i2c-mux.h>
 
 
 static int debug;
@@ -65,6 +66,8 @@ struct lgdt3306a_state {
        enum fe_modulation current_modulation;
        u32 current_frequency;
        u32 snr;
+
+       struct i2c_mux_core *muxc;
 };
 
 /*
@@ -2131,6 +2134,111 @@ static const struct dvb_frontend_ops lgdt3306a_ops = {
        .search               = lgdt3306a_search,
 };
 
+static int lgdt3306a_select(struct i2c_mux_core *muxc, u32 chan)
+{
+       struct i2c_client *client = i2c_mux_priv(muxc);
+       struct lgdt3306a_state *state = i2c_get_clientdata(client);
+
+       return lgdt3306a_i2c_gate_ctrl(&state->frontend, 1);
+}
+
+static int lgdt3306a_deselect(struct i2c_mux_core *muxc, u32 chan)
+{
+       struct i2c_client *client = i2c_mux_priv(muxc);
+       struct lgdt3306a_state *state = i2c_get_clientdata(client);
+
+       return lgdt3306a_i2c_gate_ctrl(&state->frontend, 0);
+}
+
+static int lgdt3306a_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       struct lgdt3306a_config *config;
+       struct lgdt3306a_state *state;
+       struct dvb_frontend *fe;
+       int ret;
+
+       config = kzalloc(sizeof(struct lgdt3306a_config), GFP_KERNEL);
+       if (config == NULL) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       memcpy(config, client->dev.platform_data,
+                       sizeof(struct lgdt3306a_config));
+
+       config->i2c_addr = client->addr;
+       fe = lgdt3306a_attach(config, client->adapter);
+       if (fe == NULL) {
+               ret = -ENODEV;
+               goto err_fe;
+       }
+
+       i2c_set_clientdata(client, fe->demodulator_priv);
+       state = fe->demodulator_priv;
+
+       /* create mux i2c adapter for tuner */
+       state->muxc = i2c_mux_alloc(client->adapter, &client->dev,
+                                 1, 0, I2C_MUX_LOCKED,
+                                 lgdt3306a_select, lgdt3306a_deselect);
+       if (!state->muxc) {
+               ret = -ENOMEM;
+               goto err_kfree;
+       }
+       state->muxc->priv = client;
+       ret = i2c_mux_add_adapter(state->muxc, 0, 0, 0);
+       if (ret)
+               goto err_kfree;
+
+       /* create dvb_frontend */
+       fe->ops.i2c_gate_ctrl = NULL;
+       *config->i2c_adapter = state->muxc->adapter[0];
+       *config->fe = fe;
+
+       return 0;
+
+err_kfree:
+       kfree(state);
+err_fe:
+       kfree(config);
+fail:
+       dev_dbg(&client->dev, "failed=%d\n", ret);
+       return ret;
+}
+
+static int lgdt3306a_remove(struct i2c_client *client)
+{
+       struct lgdt3306a_state *state = i2c_get_clientdata(client);
+
+       i2c_mux_del_adapters(state->muxc);
+
+       state->frontend.ops.release = NULL;
+       state->frontend.demodulator_priv = NULL;
+
+       kfree(state->cfg);
+       kfree(state);
+
+       return 0;
+}
+
+static const struct i2c_device_id lgdt3306a_id_table[] = {
+       {"lgdt3306a", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, lgdt3306a_id_table);
+
+static struct i2c_driver lgdt3306a_driver = {
+       .driver = {
+               .name                = "lgdt3306a",
+               .suppress_bind_attrs = true,
+       },
+       .probe          = lgdt3306a_probe,
+       .remove         = lgdt3306a_remove,
+       .id_table       = lgdt3306a_id_table,
+};
+
+module_i2c_driver(lgdt3306a_driver);
+
 MODULE_DESCRIPTION("LG Electronics LGDT3306A ATSC/QAM-B Demodulator Driver");
 MODULE_AUTHOR("Fred Richter <frichter@hauppauge.com>");
 MODULE_LICENSE("GPL");
index 9dbb2dced1fe49e08dc3b6b126d4ae16a38e2be0..6ce337ec5272138469cd2fd1de1713377873a265 100644 (file)
@@ -56,6 +56,10 @@ struct lgdt3306a_config {
 
        /* demod clock freq in MHz; 24 or 25 supported */
        int  xtalMHz;
+
+       /* returned by driver if using i2c bus multiplexing */
+       struct dvb_frontend **fe;
+       struct i2c_adapter **i2c_adapter;
 };
 
 #if IS_REACHABLE(CONFIG_DVB_LGDT3306A)
index 2f4a0316f89c4d6f274d5316994c26816ba4a134..06f47dc8cd3d014c34b026a89f227a7b62224951 100644 (file)
  *    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.
- *
  */
 
 /*
index c73eeb45e3305cf3ea043df4b119d8183549cc03..61434cbecd2c5519bb83c22b5be9d57df3b7d4d9 100644 (file)
  *    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 LGDT330X_H
index 1922f09a02d07d601db33a7241b51cde2a064781..dcb9a317eddc6f5bf6bd7319dce450855be91e15 100644 (file)
  *    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 _LGDT330X_PRIV_
index 6d2e62469d58fb21276dc2eb10f5ad32bfdac667..e6bf60e1138cc8ce757e4d76d887bbf5b6f64497 100644 (file)
  *    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 <asm/div64.h>
index 7519c02103995ea818ab542bc98abc70ad586579..aa83ea46807bee262559ef34b8d1e0427a032ad0 100644 (file)
  *    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 __LGS8GXX_H__
index 8ef376f1414de30c6d078a47e36d05717767b9ec..42ecbbd14c90a0665ee3006b8716dc6365369572 100644 (file)
  *    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 LGS8913_PRIV_H
index 24431dfdce1fa7273b63b1421d3dcadc5bb05fd1..332d639025ba085e8692c93dc4a456a004cc927a 100644 (file)
  * 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 _LNBH24_H
index 6261460d93a7f069e9b2e06a5e6972d413a5ef77..392d7be9377412bf83ad64a2c34ebcb4374e9c20 100644 (file)
  * 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.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  *
  *
  * the project's page is at https://linuxtv.org
index 4bb6439068ecca8b77263a21f79bcd94199c6da6..ee9d050ddc0415c450afcb4a6d14469bbff96216 100644 (file)
  * 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.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  *
  *
  * the project's page is at https://linuxtv.org
index 5c5fd04fd4a73dfacc3fb867eb32ee0f6a669bdd..39326a2ebab2746ef6df616f2b42e5d09375a80e 100644 (file)
  * 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.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  *
  *
  * the project's page is at https://linuxtv.org
index 0cb72126c498d9294e33d10d12ed7bd17ae776b7..f4c59ff7b7caa7d496a4c22bb09c7184a084aa09 100644 (file)
  * 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.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  *
  *
  * the project's page is at https://linuxtv.org
index c221c7d2ac3eabc268d91808cbf7e642560997af..15874244fd8b2054cc9a4697f7279b77a84b05b7 100644 (file)
@@ -223,6 +223,13 @@ static int mn88473_set_frontend(struct dvb_frontend *fe)
        if (ret)
                goto err;
 
+       /* PLP */
+       if (c->delivery_system == SYS_DVBT2) {
+               ret = regmap_write(dev->regmap[2], 0x36, c->stream_id);
+               if (ret)
+                       goto err;
+       }
+
        /* Reset FSM */
        ret = regmap_write(dev->regmap[2], 0xf8, 0x9f);
        if (ret)
@@ -592,7 +599,8 @@ static const struct dvb_frontend_ops mn88473_ops = {
                        FE_CAN_GUARD_INTERVAL_AUTO     |
                        FE_CAN_HIERARCHY_AUTO          |
                        FE_CAN_MUTE_TS                 |
-                       FE_CAN_2G_MODULATION
+                       FE_CAN_2G_MODULATION           |
+                       FE_CAN_MULTISTREAM
        },
 
        .get_tune_settings = mn88473_get_tune_settings,
index 48ea0408f02adb2397d76d44a3d7502cd967e7a8..e127090f2d228a0a86b4c16121df32bb047978c2 100644 (file)
  *  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/kernel.h>
index 5873263bd1af16fdaf5c6b9fd9638cc870ba9b82..b4c03b7405fb92a6e4fa0c0725e67de7b30d2770 100644 (file)
  *  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 MT352_H
index 44ad0d4c8f12b2a2057cc7fd2fa6e7e2da96e768..79bbb894b2876ab6fcdea06ecd6b909af354b036 100644 (file)
  *  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 _MT352_PRIV_
index 2fe40372ca07520ae43c1daf493d529daf54aa17..bf6e5cd572c55f831eb10fdaef0ad927a2688489 100644 (file)
  *    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.
- *
 */
 
 /*
index 825b928ef54235958e58020f9a4afc0cc4c6f613..36032064591356529613c577a839ed436b92d2b7 100644 (file)
  *    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 NXT200X_H
index 17bdadd7d0e1a53e2a31a4c8878acb7e242b937d..4b67d7e0116d615116d7e2ac736c09391ef6e793 100644 (file)
  *    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.
- *
 */
 
 /*
index 9acf8dc87413283be5a55a00f6dc1446d72bf73f..96b70e78e30a281d9311db759fb30bc9188ec14e 100644 (file)
  *    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 OR51132_H
index 27eb73aa4f6283a49fd1e190c49451836174e38d..d14fa9736ae526c848e785887742db2dac847ab4 100644 (file)
  *    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.
- *
 */
 
 #define pr_fmt(fmt)    KBUILD_MODNAME ": %s: " fmt, __func__
index cc6adab63249bbb9041a32ac2fd21d1fe21817a7..03b476982ad0860a7a1e5b8b63572003c6c29046 100644 (file)
  *    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 OR51211_H
index e038e886731b1326d584d2fcc767492f3d0e9f85..c6e78d870ccdc222ce20aac7d30f5a8c223f8988 100644 (file)
@@ -956,7 +956,7 @@ static void rtl2832_sdr_stop_streaming(struct vb2_queue *vq)
        mutex_unlock(&dev->v4l2_lock);
 }
 
-static struct vb2_ops rtl2832_sdr_vb2_ops = {
+static const struct vb2_ops rtl2832_sdr_vb2_ops = {
        .queue_setup            = rtl2832_sdr_queue_setup,
        .buf_prepare            = rtl2832_sdr_buf_prepare,
        .buf_queue              = rtl2832_sdr_buf_queue,
index f9a18fe94d88c5324ddd321e30912dbfb59210c5..cba9bff05b1245d4d02ddb53df4bfacdb4b7e679 100644 (file)
  * 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/kernel.h>
index 142d93e7d02bf27f257bfcea7b5497caba6050b9..43d0de6f3a55f81942e7fad1b4b9437c49bd7130 100644 (file)
  * 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 S5H1420_H
 #define S5H1420_H
index a32fd9bc51a93130474e0bde07e1a36e89100118..4de50fe0c638db2a0fb9fb9f6af6b097e53953e7 100644 (file)
  *  but WITHOUT 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/kernel.h>
index b81c9bd4e422388d3f8c3b94d31c31d37d88ef38..af3a157b5e77f1d81004359e456a330b17457920 100644 (file)
  *  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 __S5H1432_H__
index 20b4a659e2e459dd9f536566f60c8fdda300eaa4..680ba06c29fb57610b6804d9b233f7a4458ada23 100644 (file)
@@ -85,7 +85,8 @@ static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status)
        struct i2c_client *client = fe->demodulator_priv;
        struct si2168_dev *dev = i2c_get_clientdata(client);
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-       int ret;
+       int ret, i;
+       unsigned int utmp, utmp1, utmp2;
        struct si2168_cmd cmd;
 
        *status = 0;
@@ -144,6 +145,61 @@ static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status)
        dev_dbg(&client->dev, "status=%02x args=%*ph\n",
                        *status, cmd.rlen, cmd.args);
 
+       /* BER */
+       if (*status & FE_HAS_VITERBI) {
+               memcpy(cmd.args, "\x82\x00", 2);
+               cmd.wlen = 2;
+               cmd.rlen = 3;
+               ret = si2168_cmd_execute(client, &cmd);
+               if (ret)
+                       goto err;
+
+               /*
+                * Firmware returns [0, 255] mantissa and [0, 8] exponent.
+                * Convert to DVB API: mantissa * 10^(8 - exponent) / 10^8
+                */
+               utmp = clamp(8 - cmd.args[1], 0, 8);
+               for (i = 0, utmp1 = 1; i < utmp; i++)
+                       utmp1 = utmp1 * 10;
+
+               utmp1 = cmd.args[2] * utmp1;
+               utmp2 = 100000000; /* 10^8 */
+
+               dev_dbg(&client->dev,
+                       "post_bit_error=%u post_bit_count=%u ber=%u*10^-%u\n",
+                       utmp1, utmp2, cmd.args[2], cmd.args[1]);
+
+               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;
+       } else {
+               c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+               c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       }
+
+       /* UCB */
+       if (*status & FE_HAS_SYNC) {
+               memcpy(cmd.args, "\x84\x01", 2);
+               cmd.wlen = 2;
+               cmd.rlen = 3;
+               ret = si2168_cmd_execute(client, &cmd);
+               if (ret)
+                       goto err;
+
+               utmp1 = cmd.args[2] << 8 | cmd.args[1] << 0;
+               dev_dbg(&client->dev, "block_error=%u\n", utmp1);
+
+               /* Sometimes firmware returns bogus value */
+               if (utmp1 == 0xffff)
+                       utmp1 = 0;
+
+               c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+               c->block_error.stat[0].uvalue += utmp1;
+       } else {
+               c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       }
+
        return 0;
 err:
        dev_dbg(&client->dev, "failed=%d\n", ret);
@@ -355,6 +411,7 @@ static int si2168_init(struct dvb_frontend *fe)
 {
        struct i2c_client *client = fe->demodulator_priv;
        struct si2168_dev *dev = i2c_get_clientdata(client);
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int ret, len, remaining;
        const struct firmware *fw;
        struct si2168_cmd cmd;
@@ -493,10 +550,19 @@ static int si2168_init(struct dvb_frontend *fe)
 
        dev->warm = true;
 warm:
+       /* Init stats here to indicate which stats are supported */
+       c->cnr.len = 1;
+       c->cnr.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;
+
        dev->active = true;
 
        return 0;
-
 err_release_firmware:
        release_firmware(fw);
 err:
index 7843ccb448a088d097ea1fe95542dc4785a2e28a..2fecac6231ff47dce1cb6c71fd9147fe4d975f24 100644 (file)
@@ -21,6 +21,7 @@
 #include "dvb_frontend.h"
 #include <linux/firmware.h>
 #include <linux/i2c-mux.h>
+#include <linux/kernel.h>
 
 #define SI2168_A20_FIRMWARE "dvb-demod-si2168-a20-01.fw"
 #define SI2168_A30_FIRMWARE "dvb-demod-si2168-a30-01.fw"
index 4ac1ce2831bae9fd13341664a1ad38af6e6d93c9..fd49c436a36d16fc206e43d579414c4db3f817bb 100644 (file)
  * 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/kernel.h>
index b88166a9716faf40c1ffefd14ffc9dbc27209c5a..26c38a0503c8b5990367bf51f8392983e4acc252 100644 (file)
  * 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 STV0367_H
index 89bf6f64b078b7d7a6898ec77f5a183fe2f28bd3..8abc451dd5243e11950e47dc7bec81c35d78214e 100644 (file)
  * 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.
  */
 /* Common driver error constants */
 
index a96fbdc7e25e79794803784446be86215ba931c1..1d158622123953c7c531eb073ba4d9705498b940 100644 (file)
  * 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 STV0367_REGS_H
index 9ca2da90c7d7605f97d5c68537a43b742be1fe36..1571a465e05c4f93593c1dc1635b8940d406eaeb 100644 (file)
  * 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 STV0900_H
index 43a0f69b4b1449461a4983885fd49d561ac9f3fb..0b739725e3c0c06c9fb14f42ed09e5322a613968 100644 (file)
  * 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/kernel.h>
index b684df9995d82d5e4baf8574c5ffbc9110215319..411941442086e4d5abc806f6029328ec7ed11652 100644 (file)
  * 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 STV0900_INIT_H
index e0ea74c8e09327cf7813650f06144770325be971..7a95f955627b8fdc8882fc7ed6110ec17528227b 100644 (file)
  * 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 STV0900_PRIV_H
index 511ed2a2d987da24fef2035a88c813c8b0eb5a2b..59f264c2f8f5909325fd449926e104917b69bf93 100644 (file)
  * 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 STV0900_REG_H
index bded82774f4b5405ae1b27c47d6f4965019c49b4..c97a39120ea5eaa77cfe21a264dc915d49954bfd 100644 (file)
  * 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 "stv0900.h"
index 6a72d0be2ec50516b5603912f9198d40d4ef5877..e4fd9c1b05606dccdd5c32a68f90c27fcb92a69e 100644 (file)
  * 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/slab.h>
index 4604f793d954d7cdaf3fad52acd85fb0ce60db49..ab73124c0dec2a3eb51863af1eaec6d6318b907f 100644 (file)
  * 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 __DVB_STV6110_H__
index 6859fa5d5a85b799ad90344f532e0d0be3c2c869..2d2778be2d2fb905e3ab449961b099eed89537b2 100644 (file)
  * 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
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  */
 
 #include <linux/kernel.h>
index 2b9e8732c8024d30fe263bbe7e82ed1fb1f141cb..68358c0d869fe79c1fdf27fbba1b8ef19725ba6a 100644 (file)
  * but WITHOUT 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.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  *
  *
  * The project's page is at https://linuxtv.org
index 05ee16d29851fe1dcb4cadf42ff8976ed1b74cac..18e6d4c5be21ce75c0d6afbf714cf5d11406b67a 100644 (file)
  * but WITHOUT 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/slab.h>
index 52919e04e25852b35f7e85d6c86425d02dbfe12d..9f15cbdfdeca98b85ec4b28245ca13c1ed557a4c 100644 (file)
  * but WITHOUT 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 __DVB_TUA6100_H__
diff --git a/drivers/media/dvb-frontends/zd1301_demod.c b/drivers/media/dvb-frontends/zd1301_demod.c
new file mode 100644 (file)
index 0000000..fcf5f69
--- /dev/null
@@ -0,0 +1,551 @@
+/*
+ * ZyDAS ZD1301 driver (demodulator)
+ *
+ * Copyright (C) 2015 Antti Palosaari <crope@iki.fi>
+ *
+ *    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 "zd1301_demod.h"
+
+static u8 zd1301_demod_gain = 0x38;
+module_param_named(gain, zd1301_demod_gain, byte, 0644);
+MODULE_PARM_DESC(gain, "gain (value: 0x00 - 0x70, default: 0x38)");
+
+struct zd1301_demod_dev {
+       struct platform_device *pdev;
+       struct dvb_frontend frontend;
+       struct i2c_adapter adapter;
+       u8 gain;
+};
+
+static int zd1301_demod_wreg(struct zd1301_demod_dev *dev, u16 reg, u8 val)
+{
+       struct platform_device *pdev = dev->pdev;
+       struct zd1301_demod_platform_data *pdata = pdev->dev.platform_data;
+
+       return pdata->reg_write(pdata->reg_priv, reg, val);
+}
+
+static int zd1301_demod_rreg(struct zd1301_demod_dev *dev, u16 reg, u8 *val)
+{
+       struct platform_device *pdev = dev->pdev;
+       struct zd1301_demod_platform_data *pdata = pdev->dev.platform_data;
+
+       return pdata->reg_read(pdata->reg_priv, reg, val);
+}
+
+static int zd1301_demod_set_frontend(struct dvb_frontend *fe)
+{
+       struct zd1301_demod_dev *dev = fe->demodulator_priv;
+       struct platform_device *pdev = dev->pdev;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int ret;
+       u32 if_frequency;
+       u8 r6a50_val;
+
+       dev_dbg(&pdev->dev, "frequency=%u bandwidth_hz=%u\n",
+               c->frequency, c->bandwidth_hz);
+
+       /* Program tuner */
+       if (fe->ops.tuner_ops.set_params &&
+           fe->ops.tuner_ops.get_if_frequency) {
+               ret = fe->ops.tuner_ops.set_params(fe);
+               if (ret)
+                       goto err;
+               ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency);
+               if (ret)
+                       goto err;
+       } else {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       dev_dbg(&pdev->dev, "if_frequency=%u\n", if_frequency);
+       if (if_frequency != 36150000) {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       switch (c->bandwidth_hz) {
+       case 6000000:
+               r6a50_val = 0x78;
+               break;
+       case 7000000:
+               r6a50_val = 0x68;
+               break;
+       case 8000000:
+               r6a50_val = 0x58;
+               break;
+       default:
+               ret = -EINVAL;
+               goto err;
+       }
+
+       ret = zd1301_demod_wreg(dev, 0x6a60, 0x11);
+       if (ret)
+               goto err;
+       ret = zd1301_demod_wreg(dev, 0x6a47, 0x46);
+       if (ret)
+               goto err;
+       ret = zd1301_demod_wreg(dev, 0x6a48, 0x46);
+       if (ret)
+               goto err;
+       ret = zd1301_demod_wreg(dev, 0x6a4a, 0x15);
+       if (ret)
+               goto err;
+       ret = zd1301_demod_wreg(dev, 0x6a4b, 0x63);
+       if (ret)
+               goto err;
+       ret = zd1301_demod_wreg(dev, 0x6a5b, 0x99);
+       if (ret)
+               goto err;
+       ret = zd1301_demod_wreg(dev, 0x6a3b, 0x10);
+       if (ret)
+               goto err;
+       ret = zd1301_demod_wreg(dev, 0x6806, 0x01);
+       if (ret)
+               goto err;
+       ret = zd1301_demod_wreg(dev, 0x6a41, 0x08);
+       if (ret)
+               goto err;
+       ret = zd1301_demod_wreg(dev, 0x6a42, 0x46);
+       if (ret)
+               goto err;
+       ret = zd1301_demod_wreg(dev, 0x6a44, 0x14);
+       if (ret)
+               goto err;
+       ret = zd1301_demod_wreg(dev, 0x6a45, 0x67);
+       if (ret)
+               goto err;
+       ret = zd1301_demod_wreg(dev, 0x6a38, 0x00);
+       if (ret)
+               goto err;
+       ret = zd1301_demod_wreg(dev, 0x6a4c, 0x52);
+       if (ret)
+               goto err;
+       ret = zd1301_demod_wreg(dev, 0x6a49, 0x2a);
+       if (ret)
+               goto err;
+       ret = zd1301_demod_wreg(dev, 0x6840, 0x2e);
+       if (ret)
+               goto err;
+       ret = zd1301_demod_wreg(dev, 0x6a50, r6a50_val);
+       if (ret)
+               goto err;
+       ret = zd1301_demod_wreg(dev, 0x6a38, 0x07);
+       if (ret)
+               goto err;
+
+       return 0;
+err:
+       dev_dbg(&pdev->dev, "failed=%d\n", ret);
+       return ret;
+}
+
+static int zd1301_demod_sleep(struct dvb_frontend *fe)
+{
+       struct zd1301_demod_dev *dev = fe->demodulator_priv;
+       struct platform_device *pdev = dev->pdev;
+       int ret;
+
+       dev_dbg(&pdev->dev, "\n");
+
+       ret = zd1301_demod_wreg(dev, 0x6a43, 0x70);
+       if (ret)
+               goto err;
+       ret = zd1301_demod_wreg(dev, 0x684e, 0x00);
+       if (ret)
+               goto err;
+       ret = zd1301_demod_wreg(dev, 0x6849, 0x00);
+       if (ret)
+               goto err;
+       ret = zd1301_demod_wreg(dev, 0x68e2, 0xd7);
+       if (ret)
+               goto err;
+       ret = zd1301_demod_wreg(dev, 0x68e0, 0x39);
+       if (ret)
+               goto err;
+       ret = zd1301_demod_wreg(dev, 0x6840, 0x21);
+       if (ret)
+               goto err;
+
+       return 0;
+err:
+       dev_dbg(&pdev->dev, "failed=%d\n", ret);
+       return ret;
+}
+
+static int zd1301_demod_init(struct dvb_frontend *fe)
+{
+       struct zd1301_demod_dev *dev = fe->demodulator_priv;
+       struct platform_device *pdev = dev->pdev;
+       int ret;
+
+       dev_dbg(&pdev->dev, "\n");
+
+       ret = zd1301_demod_wreg(dev, 0x6840, 0x26);
+       if (ret)
+               goto err;
+       ret = zd1301_demod_wreg(dev, 0x68e0, 0xff);
+       if (ret)
+               goto err;
+       ret = zd1301_demod_wreg(dev, 0x68e2, 0xd8);
+       if (ret)
+               goto err;
+       ret = zd1301_demod_wreg(dev, 0x6849, 0x4e);
+       if (ret)
+               goto err;
+       ret = zd1301_demod_wreg(dev, 0x684e, 0x01);
+       if (ret)
+               goto err;
+       ret = zd1301_demod_wreg(dev, 0x6a43, zd1301_demod_gain);
+       if (ret)
+               goto err;
+
+       return 0;
+err:
+       dev_dbg(&pdev->dev, "failed=%d\n", ret);
+       return ret;
+}
+
+static int zd1301_demod_get_tune_settings(struct dvb_frontend *fe,
+                                         struct dvb_frontend_tune_settings *settings)
+{
+       struct zd1301_demod_dev *dev = fe->demodulator_priv;
+       struct platform_device *pdev = dev->pdev;
+
+       dev_dbg(&pdev->dev, "\n");
+
+       /* ~180ms seems to be enough */
+       settings->min_delay_ms = 400;
+
+       return 0;
+}
+
+static int zd1301_demod_read_status(struct dvb_frontend *fe,
+                                   enum fe_status *status)
+{
+       struct zd1301_demod_dev *dev = fe->demodulator_priv;
+       struct platform_device *pdev = dev->pdev;
+       int ret;
+       u8 u8tmp;
+
+       ret = zd1301_demod_rreg(dev, 0x6a24, &u8tmp);
+       if (ret)
+               goto err;
+       if (u8tmp > 0x00 && u8tmp < 0x20)
+               *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
+                         FE_HAS_SYNC | FE_HAS_LOCK;
+       else
+               *status = 0;
+
+       dev_dbg(&pdev->dev, "lock byte=%02x\n", u8tmp);
+
+       /*
+        * Interesting registers here are:
+        * 0x6a05: get some gain value
+        * 0x6a06: get about same gain value than set to 0x6a43
+        * 0x6a07: get some gain value
+        * 0x6a43: set gain value by driver
+        * 0x6a24: get demod lock bits (FSM stage?)
+        *
+        * Driver should implement some kind of algorithm to calculate suitable
+        * value for register 0x6a43, based likely values from register 0x6a05
+        * and 0x6a07. Looks like gain register 0x6a43 value could be from
+        * range 0x00 - 0x70.
+        */
+
+       if (dev->gain != zd1301_demod_gain) {
+               dev->gain = zd1301_demod_gain;
+
+               ret = zd1301_demod_wreg(dev, 0x6a43, dev->gain);
+               if (ret)
+                       goto err;
+       }
+
+       return 0;
+err:
+       dev_dbg(&pdev->dev, "failed=%d\n", ret);
+       return ret;
+}
+
+static const struct dvb_frontend_ops zd1301_demod_ops = {
+       .delsys = {SYS_DVBT},
+       .info = {
+               .name = "ZyDAS ZD1301",
+               .caps = FE_CAN_FEC_1_2 |
+                       FE_CAN_FEC_2_3 |
+                       FE_CAN_FEC_3_4 |
+                       FE_CAN_FEC_5_6 |
+                       FE_CAN_FEC_7_8 |
+                       FE_CAN_FEC_AUTO |
+                       FE_CAN_QPSK |
+                       FE_CAN_QAM_16 |
+                       FE_CAN_QAM_64 |
+                       FE_CAN_QAM_AUTO |
+                       FE_CAN_TRANSMISSION_MODE_AUTO |
+                       FE_CAN_GUARD_INTERVAL_AUTO |
+                       FE_CAN_HIERARCHY_AUTO |
+                       FE_CAN_MUTE_TS
+       },
+
+       .sleep = zd1301_demod_sleep,
+       .init = zd1301_demod_init,
+       .set_frontend = zd1301_demod_set_frontend,
+       .get_tune_settings = zd1301_demod_get_tune_settings,
+       .read_status = zd1301_demod_read_status,
+};
+
+struct dvb_frontend *zd1301_demod_get_dvb_frontend(struct platform_device *pdev)
+{
+       struct zd1301_demod_dev *dev = platform_get_drvdata(pdev);
+
+       dev_dbg(&pdev->dev, "\n");
+
+       return &dev->frontend;
+}
+EXPORT_SYMBOL(zd1301_demod_get_dvb_frontend);
+
+static int zd1301_demod_i2c_master_xfer(struct i2c_adapter *adapter,
+                                       struct i2c_msg msg[], int num)
+{
+       struct zd1301_demod_dev *dev = i2c_get_adapdata(adapter);
+       struct platform_device *pdev = dev->pdev;
+       int ret, i;
+       unsigned long timeout;
+       u8 u8tmp;
+
+       #define I2C_XFER_TIMEOUT 5
+       #define ZD1301_IS_I2C_XFER_WRITE_READ(_msg, _num) \
+               (_num == 2 && !(_msg[0].flags & I2C_M_RD) && (_msg[1].flags & I2C_M_RD))
+       #define ZD1301_IS_I2C_XFER_WRITE(_msg, _num) \
+               (_num == 1 && !(_msg[0].flags & I2C_M_RD))
+       #define ZD1301_IS_I2C_XFER_READ(_msg, _num) \
+               (_num == 1 && (_msg[0].flags & I2C_M_RD))
+       if (ZD1301_IS_I2C_XFER_WRITE_READ(msg, num)) {
+               dev_dbg(&pdev->dev, "write&read msg[0].len=%u msg[1].len=%u\n",
+                       msg[0].len, msg[1].len);
+               if (msg[0].len > 1 || msg[1].len > 8) {
+                       ret = -EOPNOTSUPP;
+                       goto err;
+               }
+
+               ret = zd1301_demod_wreg(dev, 0x6811, 0x80);
+               if (ret)
+                       goto err;
+               ret = zd1301_demod_wreg(dev, 0x6812, 0x05);
+               if (ret)
+                       goto err;
+               ret = zd1301_demod_wreg(dev, 0x6813, msg[1].addr << 1);
+               if (ret)
+                       goto err;
+               ret = zd1301_demod_wreg(dev, 0x6801, msg[0].buf[0]);
+               if (ret)
+                       goto err;
+               ret = zd1301_demod_wreg(dev, 0x6802, 0x00);
+               if (ret)
+                       goto err;
+               ret = zd1301_demod_wreg(dev, 0x6803, 0x06);
+               if (ret)
+                       goto err;
+               ret = zd1301_demod_wreg(dev, 0x6805, 0x00);
+               if (ret)
+                       goto err;
+               ret = zd1301_demod_wreg(dev, 0x6804, msg[1].len);
+               if (ret)
+                       goto err;
+
+               /* Poll xfer ready */
+               timeout = jiffies + msecs_to_jiffies(I2C_XFER_TIMEOUT);
+               for (u8tmp = 1; !time_after(jiffies, timeout) && u8tmp;) {
+                       usleep_range(500, 800);
+
+                       ret = zd1301_demod_rreg(dev, 0x6804, &u8tmp);
+                       if (ret)
+                               goto err;
+               }
+
+               for (i = 0; i < msg[1].len; i++) {
+                       ret = zd1301_demod_rreg(dev, 0x0600 + i, &msg[1].buf[i]);
+                       if (ret)
+                               goto err;
+               }
+       } else if (ZD1301_IS_I2C_XFER_WRITE(msg, num)) {
+               dev_dbg(&pdev->dev, "write msg[0].len=%u\n", msg[0].len);
+               if (msg[0].len > 1 + 8) {
+                       ret = -EOPNOTSUPP;
+                       goto err;
+               }
+
+               ret = zd1301_demod_wreg(dev, 0x6811, 0x80);
+               if (ret)
+                       goto err;
+               ret = zd1301_demod_wreg(dev, 0x6812, 0x01);
+               if (ret)
+                       goto err;
+               ret = zd1301_demod_wreg(dev, 0x6813, msg[0].addr << 1);
+               if (ret)
+                       goto err;
+               ret = zd1301_demod_wreg(dev, 0x6800, msg[0].buf[0]);
+               if (ret)
+                       goto err;
+               ret = zd1301_demod_wreg(dev, 0x6802, 0x00);
+               if (ret)
+                       goto err;
+               ret = zd1301_demod_wreg(dev, 0x6803, 0x06);
+               if (ret)
+                       goto err;
+
+               for (i = 0; i < msg[0].len - 1; i++) {
+                       ret = zd1301_demod_wreg(dev, 0x0600 + i, msg[0].buf[1 + i]);
+                       if (ret)
+                               goto err;
+               }
+
+               ret = zd1301_demod_wreg(dev, 0x6805, 0x80);
+               if (ret)
+                       goto err;
+               ret = zd1301_demod_wreg(dev, 0x6804, msg[0].len - 1);
+               if (ret)
+                       goto err;
+
+               /* Poll xfer ready */
+               timeout = jiffies + msecs_to_jiffies(I2C_XFER_TIMEOUT);
+               for (u8tmp = 1; !time_after(jiffies, timeout) && u8tmp;) {
+                       usleep_range(500, 800);
+
+                       ret = zd1301_demod_rreg(dev, 0x6804, &u8tmp);
+                       if (ret)
+                               goto err;
+               }
+       } else {
+               dev_dbg(&pdev->dev, "unknown msg[0].len=%u\n", msg[0].len);
+               ret = -EOPNOTSUPP;
+               if (ret)
+                       goto err;
+       }
+
+       return num;
+err:
+       dev_dbg(&pdev->dev, "failed=%d\n", ret);
+       return ret;
+}
+
+static u32 zd1301_demod_i2c_functionality(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm zd1301_demod_i2c_algorithm = {
+       .master_xfer   = zd1301_demod_i2c_master_xfer,
+       .functionality = zd1301_demod_i2c_functionality,
+};
+
+struct i2c_adapter *zd1301_demod_get_i2c_adapter(struct platform_device *pdev)
+{
+       struct zd1301_demod_dev *dev = platform_get_drvdata(pdev);
+
+       dev_dbg(&pdev->dev, "\n");
+
+       return &dev->adapter;
+}
+EXPORT_SYMBOL(zd1301_demod_get_i2c_adapter);
+
+/* Platform driver interface */
+static int zd1301_demod_probe(struct platform_device *pdev)
+{
+       struct zd1301_demod_dev *dev;
+       struct zd1301_demod_platform_data *pdata = pdev->dev.platform_data;
+       int ret;
+
+       dev_dbg(&pdev->dev, "\n");
+
+       if (!pdata) {
+               ret = -EINVAL;
+               dev_err(&pdev->dev, "cannot proceed without platform data\n");
+               goto err;
+       }
+       if (!pdev->dev.parent->driver) {
+               ret = -EINVAL;
+               dev_dbg(&pdev->dev, "no parent device\n");
+               goto err;
+       }
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       /* Setup the state */
+       dev->pdev = pdev;
+       dev->gain = zd1301_demod_gain;
+
+       /* Sleep */
+       ret = zd1301_demod_wreg(dev, 0x6840, 0x21);
+       if (ret)
+               goto err_kfree;
+       ret = zd1301_demod_wreg(dev, 0x6a38, 0x07);
+       if (ret)
+               goto err_kfree;
+
+       /* Create I2C adapter */
+       strlcpy(dev->adapter.name, "ZyDAS ZD1301 demod", sizeof(dev->adapter.name));
+       dev->adapter.algo = &zd1301_demod_i2c_algorithm;
+       dev->adapter.algo_data = NULL;
+       dev->adapter.dev.parent = pdev->dev.parent;
+       i2c_set_adapdata(&dev->adapter, dev);
+       ret = i2c_add_adapter(&dev->adapter);
+       if (ret) {
+               dev_err(&pdev->dev, "I2C adapter add failed %d\n", ret);
+               goto err_kfree;
+       }
+
+       /* Create dvb frontend */
+       memcpy(&dev->frontend.ops, &zd1301_demod_ops, sizeof(dev->frontend.ops));
+       dev->frontend.demodulator_priv = dev;
+       platform_set_drvdata(pdev, dev);
+       dev_info(&pdev->dev, "ZyDAS ZD1301 demod attached\n");
+
+       return 0;
+err_kfree:
+       kfree(dev);
+err:
+       dev_dbg(&pdev->dev, "failed=%d\n", ret);
+       return ret;
+}
+
+static int zd1301_demod_remove(struct platform_device *pdev)
+{
+       struct zd1301_demod_dev *dev = platform_get_drvdata(pdev);
+
+       dev_dbg(&pdev->dev, "\n");
+
+       i2c_del_adapter(&dev->adapter);
+       kfree(dev);
+
+       return 0;
+}
+
+static struct platform_driver zd1301_demod_driver = {
+       .driver = {
+               .name                = "zd1301_demod",
+               .suppress_bind_attrs = true,
+       },
+       .probe          = zd1301_demod_probe,
+       .remove         = zd1301_demod_remove,
+};
+module_platform_driver(zd1301_demod_driver);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("ZyDAS ZD1301 demodulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/zd1301_demod.h b/drivers/media/dvb-frontends/zd1301_demod.h
new file mode 100644 (file)
index 0000000..ceb2e05
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * ZyDAS ZD1301 driver (demodulator)
+ *
+ * Copyright (C) 2015 Antti Palosaari <crope@iki.fi>
+ *
+ *    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 ZD1301_DEMOD_H
+#define ZD1301_DEMOD_H
+
+#include <linux/platform_device.h>
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+/**
+ * struct zd1301_demod_platform_data - Platform data for the zd1301_demod driver
+ * @reg_priv: First argument of reg_read and reg_write callbacks.
+ * @reg_read: Register read callback.
+ * @reg_write: Register write callback.
+ */
+
+struct zd1301_demod_platform_data {
+       void *reg_priv;
+       int (*reg_read)(void *, u16, u8 *);
+       int (*reg_write)(void *, u16, u8);
+};
+
+#if IS_REACHABLE(CONFIG_DVB_ZD1301_DEMOD)
+/**
+ * zd1301_demod_get_dvb_frontend() - Get pointer to DVB frontend
+ * @pdev: Pointer to platform device
+ *
+ * Return: Pointer to DVB frontend which given platform device owns.
+ */
+
+struct dvb_frontend *zd1301_demod_get_dvb_frontend(struct platform_device *);
+
+/**
+ * zd1301_demod_get_i2c_adapter() - Get pointer to I2C adapter
+ * @pdev: Pointer to platform device
+ *
+ * Return: Pointer to I2C adapter which given platform device owns.
+ */
+
+struct i2c_adapter *zd1301_demod_get_i2c_adapter(struct platform_device *);
+
+#else
+
+static inline struct dvb_frontend *zd1301_demod_get_dvb_frontend(struct platform_device *dev)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+
+       return NULL;
+}
+static inline struct i2c_adapter *zd1301_demod_get_i2c_adapter(struct platform_device *dev)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+
+       return NULL;
+}
+
+#endif
+
+#endif /* ZD1301_DEMOD_H */
index a6d020fe9b8b801814d3a5a3c39b3fb80b7141f0..062282739ce56136f8abd0c2d30d8c4b0a94fcab 100644 (file)
  * 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.
- *
  **
  * The data sheet for this tuner can be found at:
  *    http://www.mcmilk.de/projects/dvb-card/datasheets/ZL10036.pdf
index c568d8d59de30c3f8f57a09e0282054740151dd0..88751adfecf7c6f5d8bf824f9f7ba1b2a7d4b4dc 100644 (file)
  * but WITHOUT 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 DVB_ZL10036_H
index 60a2954f8ff80cef04ed0fe78edec1eae67169a0..623355fc26661a2124133bb45d97f0e7a692d4b6 100644 (file)
  *  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/module.h>
index 4f3ff3e853ac65e19bb49d6521f0a54d237846a2..47c0549eb7b273d4901cff2045618b09f168d877 100644 (file)
  * 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/kernel.h>
index 37aa6e8f454a71977795fdb2e2f0b494052013fb..cb6248c00089c03a344e17bf744e5d22b1ffac7d 100644 (file)
  *  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 ZL10353_H
index e0dd1d3e09dd85665483afe9bf347d61ea738310..a1d902b2d47a75a09ab6406ea9ac8defd36cd82b 100644 (file)
  *  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 _ZL10353_PRIV_
index b979ea148251deab48fbfca7a0141aa408010f5e..cee1dae6e0143619d18f5c908bacd6f619afb319 100644 (file)
@@ -668,6 +668,7 @@ config VIDEO_S5K5BAF
          camera sensor with an embedded SoC image signal processor.
 
 source "drivers/media/i2c/smiapp/Kconfig"
+source "drivers/media/i2c/et8ek8/Kconfig"
 
 config VIDEO_S5C73M3
        tristate "Samsung S5C73M3 sensor support"
index 92773b2e62257db49ccced3af7503592492ec78d..5bc7bbeb5499345f28999b11622a0ebbe0920e09 100644 (file)
@@ -2,6 +2,7 @@ msp3400-objs    :=      msp3400-driver.o msp3400-kthreads.o
 obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
 
 obj-$(CONFIG_VIDEO_SMIAPP)     += smiapp/
+obj-$(CONFIG_VIDEO_ET8EK8)     += et8ek8/
 obj-$(CONFIG_VIDEO_CX25840) += cx25840/
 obj-$(CONFIG_VIDEO_M5MOLS)     += m5mols/
 obj-y                          += soc_camera/
index e191e295c95116e311fc226f64dc850b6a4ba196..ba1ec4ab9eba031bf74cd2b363aa8dfaad989a10 100644 (file)
  * 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 St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
  * TODO:
  * - fault interrupt handling
  * - hardware strobe
index fc9ec0f3679c57f675b9dddbde58ef5d2dd98db1..73933147342947387555c8eb35951262f6c7bc07 100644 (file)
  * but WITHOUT 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/module.h>
@@ -302,7 +298,6 @@ static int adv7170_set_fmt(struct v4l2_subdev *sd,
 {
        struct v4l2_mbus_framefmt *mf = &format->format;
        u8 val = adv7170_read(sd, 0x7);
-       int ret = 0;
 
        if (format->pad)
                return -EINVAL;
@@ -323,9 +318,9 @@ static int adv7170_set_fmt(struct v4l2_subdev *sd,
        }
 
        if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
-               ret = adv7170_write(sd, 0x7, val);
+               return adv7170_write(sd, 0x7, val);
 
-       return ret;
+       return 0;
 }
 
 /* ----------------------------------------------------------------------- */
index 72139bdae1ca3280848e96a3e0ed9439fb5de415..e31e8d909bb9958c765077369370376c96935486 100644 (file)
  * but WITHOUT 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/module.h>
index cbed2bc293255c58cb9c37f7ca0e2237346f6707..bdbbf8cf27e4bf93fffc3dc08507e563bda32a1f 100644 (file)
  * but WITHOUT 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/module.h>
index 04eecda74d66af63cb3d0bc2d894742182e2e224..8b00dc854cf87c119a4719258c46544a33f8b3ea 100644 (file)
  * but WITHOUT 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/delay.h>
index b253d400e8176a8baa3d1ba6928a1911d74bdb9d..843d4998435ef964b3ee806aebde007648459c19 100644 (file)
  * but WITHOUT 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 _ADV7183_REGS_H_
index d0375cac6a058c2d71720022ba283bd55e912bac..d8bf435db86db386a1f48b89c0f181bb505fe99e 100644 (file)
@@ -3133,6 +3133,9 @@ static int adv76xx_parse_dt(struct adv76xx_state *state)
        state->pdata.blank_data = 1;
        state->pdata.op_format_mode_sel = ADV7604_OP_FORMAT_MODE0;
        state->pdata.bus_order = ADV7604_BUS_ORDER_RGB;
+       state->pdata.dr_str_data = ADV76XX_DR_STR_MEDIUM_HIGH;
+       state->pdata.dr_str_clk = ADV76XX_DR_STR_MEDIUM_HIGH;
+       state->pdata.dr_str_sync = ADV76XX_DR_STR_MEDIUM_HIGH;
 
        return 0;
 }
index 3a795dcb7d8e07c76c16720850b6cb99c7d60369..16682c8477d14d378b761bf58e1b1be89912c1ff 100644 (file)
@@ -205,14 +205,14 @@ static int ak881x_s_stream(struct v4l2_subdev *sd, int enable)
        return 0;
 }
 
-static struct v4l2_subdev_core_ops ak881x_subdev_core_ops = {
+static const struct v4l2_subdev_core_ops ak881x_subdev_core_ops = {
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register     = ak881x_g_register,
        .s_register     = ak881x_s_register,
 #endif
 };
 
-static struct v4l2_subdev_video_ops ak881x_subdev_video_ops = {
+static const struct v4l2_subdev_video_ops ak881x_subdev_video_ops = {
        .s_std_output   = ak881x_s_std_output,
        .s_stream       = ak881x_s_stream,
 };
@@ -224,7 +224,7 @@ static const struct v4l2_subdev_pad_ops ak881x_subdev_pad_ops = {
        .get_fmt        = ak881x_fill_fmt,
 };
 
-static struct v4l2_subdev_ops ak881x_subdev_ops = {
+static const struct v4l2_subdev_ops ak881x_subdev_ops = {
        .core   = &ak881x_subdev_core_ops,
        .video  = &ak881x_subdev_video_ops,
        .pad    = &ak881x_subdev_pad_ops,
index 8153a449846b8f0248a8c9a63c4b5df838c350b3..224ae4e4cf8b16373790de6472c17943cb55d104 100644 (file)
  * WITHOUT 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 St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #include <linux/device.h>
index b370e341e75df67a28d02cf61207cf28a96a3a1d..1632f864c44f4aefc9799db9e9ceb03246a211b0 100644 (file)
  * WITHOUT 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 St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #ifndef __APTINA_PLL_H
index 2e90e4094b7960777296c0e24a4b3ed74706ac5a..b6aeceea985053163722f3b908e077c8e3df25d1 100644 (file)
  * 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 St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
  * TODO:
  * - Check hardware FSTROBE control when sensor driver add support for this
  *
index 7907bcfbaed33a020cddf349106b0aba6071a3a7..472e37637c8db54310ef7ca4053739887a91a1b6 100644 (file)
  * but WITHOUT 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/module.h>
index 54c627859c8ea5d24b15374db4896736ec174b20..2c039ae7d0b2446b00074fd1608d3c0368935693 100644 (file)
  * but WITHOUT 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/module.h>
index c7de9790d4f3fddf3e5bac5a3b6bc60ee337f910..03e80278dc10b03b776ed1334465e84142d74421 100644 (file)
  * but WITHOUT 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.
  */
 
 
index 59c1a98c5a90307edb117f255517a791ebf4dc9c..fd70fe2130a15c5aaea13d3e64defb60472c2b8a 100644 (file)
  * but WITHOUT 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.
  */
 
 
index baf3d9c8710e3066acc3b75ba4b2660b0b7ebd56..dfe94b84f1fb10be6759b8c169cd97e17bf6f9b9 100644 (file)
@@ -9,10 +9,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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
 
index 0dcf450052ac458a1d634e4dc51a32e45866f619..b8d3c070bfc1d10eb55b32b199a7b7cca4f09105 100644 (file)
  * but WITHOUT 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.
  */
 
 
index 254ef45ce41a8fb0138a1deafbabed0cd6fa1e7b..55432ed42714ac474483624f0b1bd1c14b42177f 100644 (file)
  * but WITHOUT 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.
  */
 
 #ifndef _CX25840_CORE_H_
index 37e052923a877d0097f23017acbc54824b58204f..a7819c4636740a1087965753a9dda006d4bed29c 100644 (file)
@@ -9,10 +9,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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
 #include <linux/module.h>
index 15fbd9607ceea889e6bb4d3c5543eabd01865a0c..9b65c7d2fa84a56d8f2d23ecc0458b62abe1b9bb 100644 (file)
  *  but WITHOUT 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.
  */
 
 #include <linux/slab.h>
index 0470bb6128e1f320be078dbc70e303c6f0148a25..8c99a79fb7261a4ec02065d6e3292d8aa28aa262 100644 (file)
@@ -9,10 +9,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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
 
diff --git a/drivers/media/i2c/et8ek8/Kconfig b/drivers/media/i2c/et8ek8/Kconfig
new file mode 100644 (file)
index 0000000..1439936
--- /dev/null
@@ -0,0 +1,6 @@
+config VIDEO_ET8EK8
+       tristate "ET8EK8 camera sensor support"
+       depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+       ---help---
+         This is a driver for the Toshiba ET8EK8 5 MP camera sensor.
+         It is used for example in Nokia N900 (RX-51).
diff --git a/drivers/media/i2c/et8ek8/Makefile b/drivers/media/i2c/et8ek8/Makefile
new file mode 100644 (file)
index 0000000..66d1b7d
--- /dev/null
@@ -0,0 +1,2 @@
+et8ek8-objs                    += et8ek8_mode.o et8ek8_driver.o
+obj-$(CONFIG_VIDEO_ET8EK8)     += et8ek8.o
diff --git a/drivers/media/i2c/et8ek8/et8ek8_driver.c b/drivers/media/i2c/et8ek8/et8ek8_driver.c
new file mode 100644 (file)
index 0000000..bec4a56
--- /dev/null
@@ -0,0 +1,1514 @@
+/*
+ * et8ek8_driver.c
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Contact: Sakari Ailus <sakari.ailus@iki.fi>
+ *          Tuukka Toivonen <tuukkat76@gmail.com>
+ *          Pavel Machek <pavel@ucw.cz>
+ *
+ * Based on code from Toni Leinonen <toni.leinonen@offcode.fi>.
+ *
+ * This driver is based on the Micron MT9T012 camera imager driver
+ * (C) Texas Instruments.
+ *
+ * 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/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/sort.h>
+#include <linux/v4l2-mediabus.h>
+
+#include <media/media-entity.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#include "et8ek8_reg.h"
+
+#define ET8EK8_NAME            "et8ek8"
+#define ET8EK8_PRIV_MEM_SIZE   128
+#define ET8EK8_MAX_MSG         48
+
+struct et8ek8_sensor {
+       struct v4l2_subdev subdev;
+       struct media_pad pad;
+       struct v4l2_mbus_framefmt format;
+       struct gpio_desc *reset;
+       struct regulator *vana;
+       struct clk *ext_clk;
+       u32 xclk_freq;
+
+       u16 version;
+
+       struct v4l2_ctrl_handler ctrl_handler;
+       struct v4l2_ctrl *exposure;
+       struct v4l2_ctrl *pixel_rate;
+       struct et8ek8_reglist *current_reglist;
+
+       u8 priv_mem[ET8EK8_PRIV_MEM_SIZE];
+
+       struct mutex power_lock;
+       int power_count;
+};
+
+#define to_et8ek8_sensor(sd)   container_of(sd, struct et8ek8_sensor, subdev)
+
+enum et8ek8_versions {
+       ET8EK8_REV_1 = 0x0001,
+       ET8EK8_REV_2,
+};
+
+/*
+ * This table describes what should be written to the sensor register
+ * for each gain value. The gain(index in the table) is in terms of
+ * 0.1EV, i.e. 10 indexes in the table give 2 time more gain [0] in
+ * the *analog gain, [1] in the digital gain
+ *
+ * Analog gain [dB] = 20*log10(regvalue/32); 0x20..0x100
+ */
+static struct et8ek8_gain {
+       u16 analog;
+       u16 digital;
+} const et8ek8_gain_table[] = {
+       { 32,    0},  /* x1 */
+       { 34,    0},
+       { 37,    0},
+       { 39,    0},
+       { 42,    0},
+       { 45,    0},
+       { 49,    0},
+       { 52,    0},
+       { 56,    0},
+       { 60,    0},
+       { 64,    0},  /* x2 */
+       { 69,    0},
+       { 74,    0},
+       { 79,    0},
+       { 84,    0},
+       { 91,    0},
+       { 97,    0},
+       {104,    0},
+       {111,    0},
+       {119,    0},
+       {128,    0},  /* x4 */
+       {137,    0},
+       {147,    0},
+       {158,    0},
+       {169,    0},
+       {181,    0},
+       {194,    0},
+       {208,    0},
+       {223,    0},
+       {239,    0},
+       {256,    0},  /* x8 */
+       {256,   73},
+       {256,  152},
+       {256,  236},
+       {256,  327},
+       {256,  424},
+       {256,  528},
+       {256,  639},
+       {256,  758},
+       {256,  886},
+       {256, 1023},  /* x16 */
+};
+
+/* Register definitions */
+#define REG_REVISION_NUMBER_L  0x1200
+#define REG_REVISION_NUMBER_H  0x1201
+
+#define PRIV_MEM_START_REG     0x0008
+#define PRIV_MEM_WIN_SIZE      8
+
+#define ET8EK8_I2C_DELAY       3       /* msec delay b/w accesses */
+
+#define USE_CRC                        1
+
+/*
+ * Register access helpers
+ *
+ * Read a 8/16/32-bit i2c register.  The value is returned in 'val'.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int et8ek8_i2c_read_reg(struct i2c_client *client, u16 data_length,
+                              u16 reg, u32 *val)
+{
+       int r;
+       struct i2c_msg msg;
+       unsigned char data[4];
+
+       if (!client->adapter)
+               return -ENODEV;
+       if (data_length != ET8EK8_REG_8BIT && data_length != ET8EK8_REG_16BIT)
+               return -EINVAL;
+
+       msg.addr = client->addr;
+       msg.flags = 0;
+       msg.len = 2;
+       msg.buf = data;
+
+       /* high byte goes out first */
+       data[0] = (u8) (reg >> 8);
+       data[1] = (u8) (reg & 0xff);
+       r = i2c_transfer(client->adapter, &msg, 1);
+       if (r < 0)
+               goto err;
+
+       msg.len = data_length;
+       msg.flags = I2C_M_RD;
+       r = i2c_transfer(client->adapter, &msg, 1);
+       if (r < 0)
+               goto err;
+
+       *val = 0;
+       /* high byte comes first */
+       if (data_length == ET8EK8_REG_8BIT)
+               *val = data[0];
+       else
+               *val = (data[1] << 8) + data[0];
+
+       return 0;
+
+err:
+       dev_err(&client->dev, "read from offset 0x%x error %d\n", reg, r);
+
+       return r;
+}
+
+static void et8ek8_i2c_create_msg(struct i2c_client *client, u16 len, u16 reg,
+                                 u32 val, struct i2c_msg *msg,
+                                 unsigned char *buf)
+{
+       msg->addr = client->addr;
+       msg->flags = 0; /* Write */
+       msg->len = 2 + len;
+       msg->buf = buf;
+
+       /* high byte goes out first */
+       buf[0] = (u8) (reg >> 8);
+       buf[1] = (u8) (reg & 0xff);
+
+       switch (len) {
+       case ET8EK8_REG_8BIT:
+               buf[2] = (u8) (val) & 0xff;
+               break;
+       case ET8EK8_REG_16BIT:
+               buf[2] = (u8) (val) & 0xff;
+               buf[3] = (u8) (val >> 8) & 0xff;
+               break;
+       default:
+               WARN_ONCE(1, ET8EK8_NAME ": %s: invalid message length.\n",
+                         __func__);
+       }
+}
+
+/*
+ * A buffered write method that puts the wanted register write
+ * commands in a message list and passes the list to the i2c framework
+ */
+static int et8ek8_i2c_buffered_write_regs(struct i2c_client *client,
+                                         const struct et8ek8_reg *wnext,
+                                         int cnt)
+{
+       struct i2c_msg msg[ET8EK8_MAX_MSG];
+       unsigned char data[ET8EK8_MAX_MSG][6];
+       int wcnt = 0;
+       u16 reg, data_length;
+       u32 val;
+
+       if (WARN_ONCE(cnt > ET8EK8_MAX_MSG,
+                     ET8EK8_NAME ": %s: too many messages.\n", __func__)) {
+               return -EINVAL;
+       }
+
+       /* Create new write messages for all writes */
+       while (wcnt < cnt) {
+               data_length = wnext->type;
+               reg = wnext->reg;
+               val = wnext->val;
+               wnext++;
+
+               et8ek8_i2c_create_msg(client, data_length, reg,
+                                   val, &msg[wcnt], &data[wcnt][0]);
+
+               /* Update write count */
+               wcnt++;
+       }
+
+       /* Now we send everything ... */
+       return i2c_transfer(client->adapter, msg, wcnt);
+}
+
+/*
+ * Write a list of registers to i2c device.
+ *
+ * The list of registers is terminated by ET8EK8_REG_TERM.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int et8ek8_i2c_write_regs(struct i2c_client *client,
+                                const struct et8ek8_reg *regs)
+{
+       int r, cnt = 0;
+       const struct et8ek8_reg *next;
+
+       if (!client->adapter)
+               return -ENODEV;
+
+       if (!regs)
+               return -EINVAL;
+
+       /* Initialize list pointers to the start of the list */
+       next = regs;
+
+       do {
+               /*
+                * We have to go through the list to figure out how
+                * many regular writes we have in a row
+                */
+               while (next->type != ET8EK8_REG_TERM &&
+                      next->type != ET8EK8_REG_DELAY) {
+                       /*
+                        * Here we check that the actual length fields
+                        * are valid
+                        */
+                       if (WARN(next->type != ET8EK8_REG_8BIT &&
+                                next->type != ET8EK8_REG_16BIT,
+                                "Invalid type = %d", next->type)) {
+                               return -EINVAL;
+                       }
+                       /*
+                        * Increment count of successive writes and
+                        * read pointer
+                        */
+                       cnt++;
+                       next++;
+               }
+
+               /* Now we start writing ... */
+               r = et8ek8_i2c_buffered_write_regs(client, regs, cnt);
+
+               /* ... and then check that everything was OK */
+               if (r < 0) {
+                       dev_err(&client->dev, "i2c transfer error!\n");
+                       return r;
+               }
+
+               /*
+                * If we ran into a sleep statement when going through
+                * the list, this is where we snooze for the required time
+                */
+               if (next->type == ET8EK8_REG_DELAY) {
+                       msleep(next->val);
+                       /*
+                        * ZZZ ...
+                        * Update list pointers and cnt and start over ...
+                        */
+                       next++;
+                       regs = next;
+                       cnt = 0;
+               }
+       } while (next->type != ET8EK8_REG_TERM);
+
+       return 0;
+}
+
+/*
+ * Write to a 8/16-bit register.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int et8ek8_i2c_write_reg(struct i2c_client *client, u16 data_length,
+                               u16 reg, u32 val)
+{
+       int r;
+       struct i2c_msg msg;
+       unsigned char data[6];
+
+       if (!client->adapter)
+               return -ENODEV;
+       if (data_length != ET8EK8_REG_8BIT && data_length != ET8EK8_REG_16BIT)
+               return -EINVAL;
+
+       et8ek8_i2c_create_msg(client, data_length, reg, val, &msg, data);
+
+       r = i2c_transfer(client->adapter, &msg, 1);
+       if (r < 0) {
+               dev_err(&client->dev,
+                       "wrote 0x%x to offset 0x%x error %d\n", val, reg, r);
+               return r;
+       }
+
+       return 0;
+}
+
+static struct et8ek8_reglist *et8ek8_reglist_find_type(
+               struct et8ek8_meta_reglist *meta,
+               u16 type)
+{
+       struct et8ek8_reglist **next = &meta->reglist[0].ptr;
+
+       while (*next) {
+               if ((*next)->type == type)
+                       return *next;
+
+               next++;
+       }
+
+       return NULL;
+}
+
+static int et8ek8_i2c_reglist_find_write(struct i2c_client *client,
+                                        struct et8ek8_meta_reglist *meta,
+                                        u16 type)
+{
+       struct et8ek8_reglist *reglist;
+
+       reglist = et8ek8_reglist_find_type(meta, type);
+       if (!reglist)
+               return -EINVAL;
+
+       return et8ek8_i2c_write_regs(client, reglist->regs);
+}
+
+static struct et8ek8_reglist **et8ek8_reglist_first(
+               struct et8ek8_meta_reglist *meta)
+{
+       return &meta->reglist[0].ptr;
+}
+
+static void et8ek8_reglist_to_mbus(const struct et8ek8_reglist *reglist,
+                                  struct v4l2_mbus_framefmt *fmt)
+{
+       fmt->width = reglist->mode.window_width;
+       fmt->height = reglist->mode.window_height;
+       fmt->code = reglist->mode.bus_format;
+}
+
+static struct et8ek8_reglist *et8ek8_reglist_find_mode_fmt(
+               struct et8ek8_meta_reglist *meta,
+               struct v4l2_mbus_framefmt *fmt)
+{
+       struct et8ek8_reglist **list = et8ek8_reglist_first(meta);
+       struct et8ek8_reglist *best_match = NULL;
+       struct et8ek8_reglist *best_other = NULL;
+       struct v4l2_mbus_framefmt format;
+       unsigned int max_dist_match = (unsigned int)-1;
+       unsigned int max_dist_other = (unsigned int)-1;
+
+       /*
+        * Find the mode with the closest image size. The distance between
+        * image sizes is the size in pixels of the non-overlapping regions
+        * between the requested size and the frame-specified size.
+        *
+        * Store both the closest mode that matches the requested format, and
+        * the closest mode for all other formats. The best match is returned
+        * if found, otherwise the best mode with a non-matching format is
+        * returned.
+        */
+       for (; *list; list++) {
+               unsigned int dist;
+
+               if ((*list)->type != ET8EK8_REGLIST_MODE)
+                       continue;
+
+               et8ek8_reglist_to_mbus(*list, &format);
+
+               dist = min(fmt->width, format.width)
+                    * min(fmt->height, format.height);
+               dist = format.width * format.height
+                    + fmt->width * fmt->height - 2 * dist;
+
+
+               if (fmt->code == format.code) {
+                       if (dist < max_dist_match || !best_match) {
+                               best_match = *list;
+                               max_dist_match = dist;
+                       }
+               } else {
+                       if (dist < max_dist_other || !best_other) {
+                               best_other = *list;
+                               max_dist_other = dist;
+                       }
+               }
+       }
+
+       return best_match ? best_match : best_other;
+}
+
+#define TIMEPERFRAME_AVG_FPS(t)                                                \
+       (((t).denominator + ((t).numerator >> 1)) / (t).numerator)
+
+static struct et8ek8_reglist *et8ek8_reglist_find_mode_ival(
+               struct et8ek8_meta_reglist *meta,
+               struct et8ek8_reglist *current_reglist,
+               struct v4l2_fract *timeperframe)
+{
+       int fps = TIMEPERFRAME_AVG_FPS(*timeperframe);
+       struct et8ek8_reglist **list = et8ek8_reglist_first(meta);
+       struct et8ek8_mode *current_mode = &current_reglist->mode;
+
+       for (; *list; list++) {
+               struct et8ek8_mode *mode = &(*list)->mode;
+
+               if ((*list)->type != ET8EK8_REGLIST_MODE)
+                       continue;
+
+               if (mode->window_width != current_mode->window_width ||
+                   mode->window_height != current_mode->window_height)
+                       continue;
+
+               if (TIMEPERFRAME_AVG_FPS(mode->timeperframe) == fps)
+                       return *list;
+       }
+
+       return NULL;
+}
+
+static int et8ek8_reglist_cmp(const void *a, const void *b)
+{
+       const struct et8ek8_reglist **list1 = (const struct et8ek8_reglist **)a,
+               **list2 = (const struct et8ek8_reglist **)b;
+
+       /* Put real modes in the beginning. */
+       if ((*list1)->type == ET8EK8_REGLIST_MODE &&
+           (*list2)->type != ET8EK8_REGLIST_MODE)
+               return -1;
+       if ((*list1)->type != ET8EK8_REGLIST_MODE &&
+           (*list2)->type == ET8EK8_REGLIST_MODE)
+               return 1;
+
+       /* Descending width. */
+       if ((*list1)->mode.window_width > (*list2)->mode.window_width)
+               return -1;
+       if ((*list1)->mode.window_width < (*list2)->mode.window_width)
+               return 1;
+
+       if ((*list1)->mode.window_height > (*list2)->mode.window_height)
+               return -1;
+       if ((*list1)->mode.window_height < (*list2)->mode.window_height)
+               return 1;
+
+       return 0;
+}
+
+static int et8ek8_reglist_import(struct i2c_client *client,
+                                struct et8ek8_meta_reglist *meta)
+{
+       int nlists = 0, i;
+
+       dev_info(&client->dev, "meta_reglist version %s\n", meta->version);
+
+       while (meta->reglist[nlists].ptr)
+               nlists++;
+
+       if (!nlists)
+               return -EINVAL;
+
+       sort(&meta->reglist[0].ptr, nlists, sizeof(meta->reglist[0].ptr),
+            et8ek8_reglist_cmp, NULL);
+
+       i = nlists;
+       nlists = 0;
+
+       while (i--) {
+               struct et8ek8_reglist *list;
+
+               list = meta->reglist[nlists].ptr;
+
+               dev_dbg(&client->dev,
+                      "%s: type %d\tw %d\th %d\tfmt %x\tival %d/%d\tptr %p\n",
+                      __func__,
+                      list->type,
+                      list->mode.window_width, list->mode.window_height,
+                      list->mode.bus_format,
+                      list->mode.timeperframe.numerator,
+                      list->mode.timeperframe.denominator,
+                      (void *)meta->reglist[nlists].ptr);
+
+               nlists++;
+       }
+
+       return 0;
+}
+
+/* Called to change the V4L2 gain control value. This function
+ * rounds and clamps the given value and updates the V4L2 control value.
+ * If power is on, also updates the sensor analog and digital gains.
+ * gain is in 0.1 EV (exposure value) units.
+ */
+static int et8ek8_set_gain(struct et8ek8_sensor *sensor, s32 gain)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+       struct et8ek8_gain new;
+       int r;
+
+       new = et8ek8_gain_table[gain];
+
+       /* FIXME: optimise I2C writes! */
+       r = et8ek8_i2c_write_reg(client, ET8EK8_REG_8BIT,
+                               0x124a, new.analog >> 8);
+       if (r)
+               return r;
+       r = et8ek8_i2c_write_reg(client, ET8EK8_REG_8BIT,
+                               0x1249, new.analog & 0xff);
+       if (r)
+               return r;
+
+       r = et8ek8_i2c_write_reg(client, ET8EK8_REG_8BIT,
+                               0x124d, new.digital >> 8);
+       if (r)
+               return r;
+       r = et8ek8_i2c_write_reg(client, ET8EK8_REG_8BIT,
+                               0x124c, new.digital & 0xff);
+
+       return r;
+}
+
+static int et8ek8_set_test_pattern(struct et8ek8_sensor *sensor, s32 mode)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+       int cbh_mode, cbv_mode, tp_mode, din_sw, r1420, rval;
+
+       /* Values for normal mode */
+       cbh_mode = 0;
+       cbv_mode = 0;
+       tp_mode  = 0;
+       din_sw   = 0x00;
+       r1420    = 0xF0;
+
+       if (mode) {
+               /* Test pattern mode */
+               if (mode < 5) {
+                       cbh_mode = 1;
+                       cbv_mode = 1;
+                       tp_mode  = mode + 3;
+               } else {
+                       cbh_mode = 0;
+                       cbv_mode = 0;
+                       tp_mode  = mode - 4 + 3;
+               }
+
+               din_sw   = 0x01;
+               r1420    = 0xE0;
+       }
+
+       rval = et8ek8_i2c_write_reg(client, ET8EK8_REG_8BIT, 0x111B,
+                                   tp_mode << 4);
+       if (rval)
+               return rval;
+
+       rval = et8ek8_i2c_write_reg(client, ET8EK8_REG_8BIT, 0x1121,
+                                   cbh_mode << 7);
+       if (rval)
+               return rval;
+
+       rval = et8ek8_i2c_write_reg(client, ET8EK8_REG_8BIT, 0x1124,
+                                   cbv_mode << 7);
+       if (rval)
+               return rval;
+
+       rval = et8ek8_i2c_write_reg(client, ET8EK8_REG_8BIT, 0x112C, din_sw);
+       if (rval)
+               return rval;
+
+       return et8ek8_i2c_write_reg(client, ET8EK8_REG_8BIT, 0x1420, r1420);
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 controls
+ */
+
+static int et8ek8_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct et8ek8_sensor *sensor =
+               container_of(ctrl->handler, struct et8ek8_sensor, ctrl_handler);
+
+       switch (ctrl->id) {
+       case V4L2_CID_GAIN:
+               return et8ek8_set_gain(sensor, ctrl->val);
+
+       case V4L2_CID_EXPOSURE:
+       {
+               struct i2c_client *client =
+                       v4l2_get_subdevdata(&sensor->subdev);
+
+               return et8ek8_i2c_write_reg(client, ET8EK8_REG_16BIT, 0x1243,
+                                           ctrl->val);
+       }
+
+       case V4L2_CID_TEST_PATTERN:
+               return et8ek8_set_test_pattern(sensor, ctrl->val);
+
+       case V4L2_CID_PIXEL_RATE:
+               return 0;
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static const struct v4l2_ctrl_ops et8ek8_ctrl_ops = {
+       .s_ctrl = et8ek8_set_ctrl,
+};
+
+static const char * const et8ek8_test_pattern_menu[] = {
+       "Normal",
+       "Vertical colorbar",
+       "Horizontal colorbar",
+       "Scale",
+       "Ramp",
+       "Small vertical colorbar",
+       "Small horizontal colorbar",
+       "Small scale",
+       "Small ramp",
+};
+
+static int et8ek8_init_controls(struct et8ek8_sensor *sensor)
+{
+       s32 max_rows;
+
+       v4l2_ctrl_handler_init(&sensor->ctrl_handler, 4);
+
+       /* V4L2_CID_GAIN */
+       v4l2_ctrl_new_std(&sensor->ctrl_handler, &et8ek8_ctrl_ops,
+                         V4L2_CID_GAIN, 0, ARRAY_SIZE(et8ek8_gain_table) - 1,
+                         1, 0);
+
+       max_rows = sensor->current_reglist->mode.max_exp;
+       {
+               u32 min = 1, max = max_rows;
+
+               sensor->exposure =
+                       v4l2_ctrl_new_std(&sensor->ctrl_handler,
+                                         &et8ek8_ctrl_ops, V4L2_CID_EXPOSURE,
+                                         min, max, min, max);
+       }
+
+       /* V4L2_CID_PIXEL_RATE */
+       sensor->pixel_rate =
+               v4l2_ctrl_new_std(&sensor->ctrl_handler, &et8ek8_ctrl_ops,
+               V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1);
+
+       /* V4L2_CID_TEST_PATTERN */
+       v4l2_ctrl_new_std_menu_items(&sensor->ctrl_handler,
+                                    &et8ek8_ctrl_ops, V4L2_CID_TEST_PATTERN,
+                                    ARRAY_SIZE(et8ek8_test_pattern_menu) - 1,
+                                    0, 0, et8ek8_test_pattern_menu);
+
+       if (sensor->ctrl_handler.error)
+               return sensor->ctrl_handler.error;
+
+       sensor->subdev.ctrl_handler = &sensor->ctrl_handler;
+
+       return 0;
+}
+
+static void et8ek8_update_controls(struct et8ek8_sensor *sensor)
+{
+       struct v4l2_ctrl *ctrl;
+       struct et8ek8_mode *mode = &sensor->current_reglist->mode;
+
+       u32 min, max, pixel_rate;
+       static const int S = 8;
+
+       ctrl = sensor->exposure;
+
+       min = 1;
+       max = mode->max_exp;
+
+       /*
+        * Calculate average pixel clock per line. Assume buffers can spread
+        * the data over horizontal blanking time. Rounding upwards.
+        * Formula taken from stock Nokia N900 kernel.
+        */
+       pixel_rate = ((mode->pixel_clock + (1 << S) - 1) >> S) + mode->width;
+       pixel_rate = mode->window_width * (pixel_rate - 1) / mode->width;
+
+       __v4l2_ctrl_modify_range(ctrl, min, max, min, max);
+       __v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate, pixel_rate << S);
+}
+
+static int et8ek8_configure(struct et8ek8_sensor *sensor)
+{
+       struct v4l2_subdev *subdev = &sensor->subdev;
+       struct i2c_client *client = v4l2_get_subdevdata(subdev);
+       int rval;
+
+       rval = et8ek8_i2c_write_regs(client, sensor->current_reglist->regs);
+       if (rval)
+               goto fail;
+
+       /* Controls set while the power to the sensor is turned off are saved
+        * but not applied to the hardware. Now that we're about to start
+        * streaming apply all the current values to the hardware.
+        */
+       rval = v4l2_ctrl_handler_setup(&sensor->ctrl_handler);
+       if (rval)
+               goto fail;
+
+       return 0;
+
+fail:
+       dev_err(&client->dev, "sensor configuration failed\n");
+
+       return rval;
+}
+
+static int et8ek8_stream_on(struct et8ek8_sensor *sensor)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+
+       return et8ek8_i2c_write_reg(client, ET8EK8_REG_8BIT, 0x1252, 0xb0);
+}
+
+static int et8ek8_stream_off(struct et8ek8_sensor *sensor)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+
+       return et8ek8_i2c_write_reg(client, ET8EK8_REG_8BIT, 0x1252, 0x30);
+}
+
+static int et8ek8_s_stream(struct v4l2_subdev *subdev, int streaming)
+{
+       struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev);
+       int ret;
+
+       if (!streaming)
+               return et8ek8_stream_off(sensor);
+
+       ret = et8ek8_configure(sensor);
+       if (ret < 0)
+               return ret;
+
+       return et8ek8_stream_on(sensor);
+}
+
+/* --------------------------------------------------------------------------
+ * V4L2 subdev operations
+ */
+
+static int et8ek8_power_off(struct et8ek8_sensor *sensor)
+{
+       gpiod_set_value(sensor->reset, 0);
+       udelay(1);
+
+       clk_disable_unprepare(sensor->ext_clk);
+
+       return regulator_disable(sensor->vana);
+}
+
+static int et8ek8_power_on(struct et8ek8_sensor *sensor)
+{
+       struct v4l2_subdev *subdev = &sensor->subdev;
+       struct i2c_client *client = v4l2_get_subdevdata(subdev);
+       unsigned int xclk_freq;
+       int val, rval;
+
+       rval = regulator_enable(sensor->vana);
+       if (rval) {
+               dev_err(&client->dev, "failed to enable vana regulator\n");
+               return rval;
+       }
+
+       if (sensor->current_reglist)
+               xclk_freq = sensor->current_reglist->mode.ext_clock;
+       else
+               xclk_freq = sensor->xclk_freq;
+
+       rval = clk_set_rate(sensor->ext_clk, xclk_freq);
+       if (rval < 0) {
+               dev_err(&client->dev, "unable to set extclk clock freq to %u\n",
+                       xclk_freq);
+               goto out;
+       }
+       rval = clk_prepare_enable(sensor->ext_clk);
+       if (rval < 0) {
+               dev_err(&client->dev, "failed to enable extclk\n");
+               goto out;
+       }
+
+       if (rval)
+               goto out;
+
+       udelay(10); /* I wish this is a good value */
+
+       gpiod_set_value(sensor->reset, 1);
+
+       msleep(5000 * 1000 / xclk_freq + 1); /* Wait 5000 cycles */
+
+       rval = et8ek8_i2c_reglist_find_write(client, &meta_reglist,
+                                            ET8EK8_REGLIST_POWERON);
+       if (rval)
+               goto out;
+
+#ifdef USE_CRC
+       rval = et8ek8_i2c_read_reg(client, ET8EK8_REG_8BIT, 0x1263, &val);
+       if (rval)
+               goto out;
+#if USE_CRC /* TODO get crc setting from DT */
+       val |= BIT(4);
+#else
+       val &= ~BIT(4);
+#endif
+       rval = et8ek8_i2c_write_reg(client, ET8EK8_REG_8BIT, 0x1263, val);
+       if (rval)
+               goto out;
+#endif
+
+out:
+       if (rval)
+               et8ek8_power_off(sensor);
+
+       return rval;
+}
+
+/* --------------------------------------------------------------------------
+ * V4L2 subdev video operations
+ */
+#define MAX_FMTS 4
+static int et8ek8_enum_mbus_code(struct v4l2_subdev *subdev,
+                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_mbus_code_enum *code)
+{
+       struct et8ek8_reglist **list =
+                       et8ek8_reglist_first(&meta_reglist);
+       u32 pixelformat[MAX_FMTS];
+       int npixelformat = 0;
+
+       if (code->index >= MAX_FMTS)
+               return -EINVAL;
+
+       for (; *list; list++) {
+               struct et8ek8_mode *mode = &(*list)->mode;
+               int i;
+
+               if ((*list)->type != ET8EK8_REGLIST_MODE)
+                       continue;
+
+               for (i = 0; i < npixelformat; i++) {
+                       if (pixelformat[i] == mode->bus_format)
+                               break;
+               }
+               if (i != npixelformat)
+                       continue;
+
+               if (code->index == npixelformat) {
+                       code->code = mode->bus_format;
+                       return 0;
+               }
+
+               pixelformat[npixelformat] = mode->bus_format;
+               npixelformat++;
+       }
+
+       return -EINVAL;
+}
+
+static int et8ek8_enum_frame_size(struct v4l2_subdev *subdev,
+                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_frame_size_enum *fse)
+{
+       struct et8ek8_reglist **list =
+                       et8ek8_reglist_first(&meta_reglist);
+       struct v4l2_mbus_framefmt format;
+       int cmp_width = INT_MAX;
+       int cmp_height = INT_MAX;
+       int index = fse->index;
+
+       for (; *list; list++) {
+               if ((*list)->type != ET8EK8_REGLIST_MODE)
+                       continue;
+
+               et8ek8_reglist_to_mbus(*list, &format);
+               if (fse->code != format.code)
+                       continue;
+
+               /* Assume that the modes are grouped by frame size. */
+               if (format.width == cmp_width && format.height == cmp_height)
+                       continue;
+
+               cmp_width = format.width;
+               cmp_height = format.height;
+
+               if (index-- == 0) {
+                       fse->min_width = format.width;
+                       fse->min_height = format.height;
+                       fse->max_width = format.width;
+                       fse->max_height = format.height;
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int et8ek8_enum_frame_ival(struct v4l2_subdev *subdev,
+                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_frame_interval_enum *fie)
+{
+       struct et8ek8_reglist **list =
+                       et8ek8_reglist_first(&meta_reglist);
+       struct v4l2_mbus_framefmt format;
+       int index = fie->index;
+
+       for (; *list; list++) {
+               struct et8ek8_mode *mode = &(*list)->mode;
+
+               if ((*list)->type != ET8EK8_REGLIST_MODE)
+                       continue;
+
+               et8ek8_reglist_to_mbus(*list, &format);
+               if (fie->code != format.code)
+                       continue;
+
+               if (fie->width != format.width || fie->height != format.height)
+                       continue;
+
+               if (index-- == 0) {
+                       fie->interval = mode->timeperframe;
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static struct v4l2_mbus_framefmt *
+__et8ek8_get_pad_format(struct et8ek8_sensor *sensor,
+                       struct v4l2_subdev_pad_config *cfg,
+                       unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+       switch (which) {
+       case V4L2_SUBDEV_FORMAT_TRY:
+               return v4l2_subdev_get_try_format(&sensor->subdev, cfg, pad);
+       case V4L2_SUBDEV_FORMAT_ACTIVE:
+               return &sensor->format;
+       default:
+               return NULL;
+       }
+}
+
+static int et8ek8_get_pad_format(struct v4l2_subdev *subdev,
+                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_format *fmt)
+{
+       struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev);
+       struct v4l2_mbus_framefmt *format;
+
+       format = __et8ek8_get_pad_format(sensor, cfg, fmt->pad, fmt->which);
+       if (!format)
+               return -EINVAL;
+
+       fmt->format = *format;
+
+       return 0;
+}
+
+static int et8ek8_set_pad_format(struct v4l2_subdev *subdev,
+                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_format *fmt)
+{
+       struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev);
+       struct v4l2_mbus_framefmt *format;
+       struct et8ek8_reglist *reglist;
+
+       format = __et8ek8_get_pad_format(sensor, cfg, fmt->pad, fmt->which);
+       if (!format)
+               return -EINVAL;
+
+       reglist = et8ek8_reglist_find_mode_fmt(&meta_reglist, &fmt->format);
+       et8ek8_reglist_to_mbus(reglist, &fmt->format);
+       *format = fmt->format;
+
+       if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+               sensor->current_reglist = reglist;
+               et8ek8_update_controls(sensor);
+       }
+
+       return 0;
+}
+
+static int et8ek8_get_frame_interval(struct v4l2_subdev *subdev,
+                                    struct v4l2_subdev_frame_interval *fi)
+{
+       struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev);
+
+       memset(fi, 0, sizeof(*fi));
+       fi->interval = sensor->current_reglist->mode.timeperframe;
+
+       return 0;
+}
+
+static int et8ek8_set_frame_interval(struct v4l2_subdev *subdev,
+                                    struct v4l2_subdev_frame_interval *fi)
+{
+       struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev);
+       struct et8ek8_reglist *reglist;
+
+       reglist = et8ek8_reglist_find_mode_ival(&meta_reglist,
+                                               sensor->current_reglist,
+                                               &fi->interval);
+
+       if (!reglist)
+               return -EINVAL;
+
+       if (sensor->current_reglist->mode.ext_clock != reglist->mode.ext_clock)
+               return -EINVAL;
+
+       sensor->current_reglist = reglist;
+       et8ek8_update_controls(sensor);
+
+       return 0;
+}
+
+static int et8ek8_g_priv_mem(struct v4l2_subdev *subdev)
+{
+       struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev);
+       struct i2c_client *client = v4l2_get_subdevdata(subdev);
+       unsigned int length = ET8EK8_PRIV_MEM_SIZE;
+       unsigned int offset = 0;
+       u8 *ptr  = sensor->priv_mem;
+       int rval = 0;
+
+       /* Read the EEPROM window-by-window, each window 8 bytes */
+       do {
+               u8 buffer[PRIV_MEM_WIN_SIZE];
+               struct i2c_msg msg;
+               int bytes, i;
+               int ofs;
+
+               /* Set the current window */
+               rval = et8ek8_i2c_write_reg(client, ET8EK8_REG_8BIT, 0x0001,
+                                           0xe0 | (offset >> 3));
+               if (rval < 0)
+                       return rval;
+
+               /* Wait for status bit */
+               for (i = 0; i < 1000; ++i) {
+                       u32 status;
+
+                       rval = et8ek8_i2c_read_reg(client, ET8EK8_REG_8BIT,
+                                                  0x0003, &status);
+                       if (rval < 0)
+                               return rval;
+                       if (!(status & 0x08))
+                               break;
+                       usleep_range(1000, 2000);
+               }
+
+               if (i == 1000)
+                       return -EIO;
+
+               /* Read window, 8 bytes at once, and copy to user space */
+               ofs = offset & 0x07;    /* Offset within this window */
+               bytes = length + ofs > 8 ? 8-ofs : length;
+               msg.addr = client->addr;
+               msg.flags = 0;
+               msg.len = 2;
+               msg.buf = buffer;
+               ofs += PRIV_MEM_START_REG;
+               buffer[0] = (u8)(ofs >> 8);
+               buffer[1] = (u8)(ofs & 0xFF);
+
+               rval = i2c_transfer(client->adapter, &msg, 1);
+               if (rval < 0)
+                       return rval;
+
+               mdelay(ET8EK8_I2C_DELAY);
+               msg.addr = client->addr;
+               msg.len = bytes;
+               msg.flags = I2C_M_RD;
+               msg.buf = buffer;
+               memset(buffer, 0, sizeof(buffer));
+
+               rval = i2c_transfer(client->adapter, &msg, 1);
+               if (rval < 0)
+                       return rval;
+
+               rval = 0;
+               memcpy(ptr, buffer, bytes);
+
+               length -= bytes;
+               offset += bytes;
+               ptr += bytes;
+       } while (length > 0);
+
+       return rval;
+}
+
+static int et8ek8_dev_init(struct v4l2_subdev *subdev)
+{
+       struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev);
+       struct i2c_client *client = v4l2_get_subdevdata(subdev);
+       int rval, rev_l, rev_h;
+
+       rval = et8ek8_power_on(sensor);
+       if (rval) {
+               dev_err(&client->dev, "could not power on\n");
+               return rval;
+       }
+
+       rval = et8ek8_i2c_read_reg(client, ET8EK8_REG_8BIT,
+                                  REG_REVISION_NUMBER_L, &rev_l);
+       if (!rval)
+               rval = et8ek8_i2c_read_reg(client, ET8EK8_REG_8BIT,
+                                          REG_REVISION_NUMBER_H, &rev_h);
+       if (rval) {
+               dev_err(&client->dev, "no et8ek8 sensor detected\n");
+               goto out_poweroff;
+       }
+
+       sensor->version = (rev_h << 8) + rev_l;
+       if (sensor->version != ET8EK8_REV_1 && sensor->version != ET8EK8_REV_2)
+               dev_info(&client->dev,
+                        "unknown version 0x%x detected, continuing anyway\n",
+                        sensor->version);
+
+       rval = et8ek8_reglist_import(client, &meta_reglist);
+       if (rval) {
+               dev_err(&client->dev,
+                       "invalid register list %s, import failed\n",
+                       ET8EK8_NAME);
+               goto out_poweroff;
+       }
+
+       sensor->current_reglist = et8ek8_reglist_find_type(&meta_reglist,
+                                                          ET8EK8_REGLIST_MODE);
+       if (!sensor->current_reglist) {
+               dev_err(&client->dev,
+                       "invalid register list %s, no mode found\n",
+                       ET8EK8_NAME);
+               rval = -ENODEV;
+               goto out_poweroff;
+       }
+
+       et8ek8_reglist_to_mbus(sensor->current_reglist, &sensor->format);
+
+       rval = et8ek8_i2c_reglist_find_write(client, &meta_reglist,
+                                            ET8EK8_REGLIST_POWERON);
+       if (rval) {
+               dev_err(&client->dev,
+                       "invalid register list %s, no POWERON mode found\n",
+                       ET8EK8_NAME);
+               goto out_poweroff;
+       }
+       rval = et8ek8_stream_on(sensor); /* Needed to be able to read EEPROM */
+       if (rval)
+               goto out_poweroff;
+       rval = et8ek8_g_priv_mem(subdev);
+       if (rval)
+               dev_warn(&client->dev,
+                       "can not read OTP (EEPROM) memory from sensor\n");
+       rval = et8ek8_stream_off(sensor);
+       if (rval)
+               goto out_poweroff;
+
+       rval = et8ek8_power_off(sensor);
+       if (rval)
+               goto out_poweroff;
+
+       return 0;
+
+out_poweroff:
+       et8ek8_power_off(sensor);
+
+       return rval;
+}
+
+/* --------------------------------------------------------------------------
+ * sysfs attributes
+ */
+static ssize_t
+et8ek8_priv_mem_read(struct device *dev, struct device_attribute *attr,
+                    char *buf)
+{
+       struct v4l2_subdev *subdev = i2c_get_clientdata(to_i2c_client(dev));
+       struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev);
+
+#if PAGE_SIZE < ET8EK8_PRIV_MEM_SIZE
+#error PAGE_SIZE too small!
+#endif
+
+       memcpy(buf, sensor->priv_mem, ET8EK8_PRIV_MEM_SIZE);
+
+       return ET8EK8_PRIV_MEM_SIZE;
+}
+static DEVICE_ATTR(priv_mem, 0444, et8ek8_priv_mem_read, NULL);
+
+/* --------------------------------------------------------------------------
+ * V4L2 subdev core operations
+ */
+
+static int
+et8ek8_registered(struct v4l2_subdev *subdev)
+{
+       struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev);
+       struct i2c_client *client = v4l2_get_subdevdata(subdev);
+       int rval;
+
+       dev_dbg(&client->dev, "registered!");
+
+       rval = device_create_file(&client->dev, &dev_attr_priv_mem);
+       if (rval) {
+               dev_err(&client->dev, "could not register sysfs entry\n");
+               return rval;
+       }
+
+       rval = et8ek8_dev_init(subdev);
+       if (rval)
+               goto err_file;
+
+       rval = et8ek8_init_controls(sensor);
+       if (rval) {
+               dev_err(&client->dev, "controls initialization failed\n");
+               goto err_file;
+       }
+
+       __et8ek8_get_pad_format(sensor, NULL, 0, V4L2_SUBDEV_FORMAT_ACTIVE);
+
+       return 0;
+
+err_file:
+       device_remove_file(&client->dev, &dev_attr_priv_mem);
+
+       return rval;
+}
+
+static int __et8ek8_set_power(struct et8ek8_sensor *sensor, bool on)
+{
+       return on ? et8ek8_power_on(sensor) : et8ek8_power_off(sensor);
+}
+
+static int et8ek8_set_power(struct v4l2_subdev *subdev, int on)
+{
+       struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev);
+       int ret = 0;
+
+       mutex_lock(&sensor->power_lock);
+
+       /* If the power count is modified from 0 to != 0 or from != 0 to 0,
+        * update the power state.
+        */
+       if (sensor->power_count == !on) {
+               ret = __et8ek8_set_power(sensor, !!on);
+               if (ret < 0)
+                       goto done;
+       }
+
+       /* Update the power count. */
+       sensor->power_count += on ? 1 : -1;
+       WARN_ON(sensor->power_count < 0);
+
+done:
+       mutex_unlock(&sensor->power_lock);
+
+       return ret;
+}
+
+static int et8ek8_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+       struct et8ek8_sensor *sensor = to_et8ek8_sensor(sd);
+       struct v4l2_mbus_framefmt *format;
+       struct et8ek8_reglist *reglist;
+
+       reglist = et8ek8_reglist_find_type(&meta_reglist, ET8EK8_REGLIST_MODE);
+       format = __et8ek8_get_pad_format(sensor, fh->pad, 0,
+                                        V4L2_SUBDEV_FORMAT_TRY);
+       et8ek8_reglist_to_mbus(reglist, format);
+
+       return et8ek8_set_power(sd, true);
+}
+
+static int et8ek8_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+       return et8ek8_set_power(sd, false);
+}
+
+static const struct v4l2_subdev_video_ops et8ek8_video_ops = {
+       .s_stream = et8ek8_s_stream,
+       .g_frame_interval = et8ek8_get_frame_interval,
+       .s_frame_interval = et8ek8_set_frame_interval,
+};
+
+static const struct v4l2_subdev_core_ops et8ek8_core_ops = {
+       .s_power = et8ek8_set_power,
+};
+
+static const struct v4l2_subdev_pad_ops et8ek8_pad_ops = {
+       .enum_mbus_code = et8ek8_enum_mbus_code,
+       .enum_frame_size = et8ek8_enum_frame_size,
+       .enum_frame_interval = et8ek8_enum_frame_ival,
+       .get_fmt = et8ek8_get_pad_format,
+       .set_fmt = et8ek8_set_pad_format,
+};
+
+static const struct v4l2_subdev_ops et8ek8_ops = {
+       .core = &et8ek8_core_ops,
+       .video = &et8ek8_video_ops,
+       .pad = &et8ek8_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops et8ek8_internal_ops = {
+       .registered = et8ek8_registered,
+       .open = et8ek8_open,
+       .close = et8ek8_close,
+};
+
+/* --------------------------------------------------------------------------
+ * I2C driver
+ */
+static int __maybe_unused et8ek8_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+       struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev);
+
+       if (!sensor->power_count)
+               return 0;
+
+       return __et8ek8_set_power(sensor, false);
+}
+
+static int __maybe_unused et8ek8_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+       struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev);
+
+       if (!sensor->power_count)
+               return 0;
+
+       return __et8ek8_set_power(sensor, true);
+}
+
+static int et8ek8_probe(struct i2c_client *client,
+                       const struct i2c_device_id *devid)
+{
+       struct et8ek8_sensor *sensor;
+       struct device *dev = &client->dev;
+       int ret;
+
+       sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL);
+       if (!sensor)
+               return -ENOMEM;
+
+       sensor->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+       if (IS_ERR(sensor->reset)) {
+               dev_dbg(&client->dev, "could not request reset gpio\n");
+               return PTR_ERR(sensor->reset);
+       }
+
+       sensor->vana = devm_regulator_get(dev, "vana");
+       if (IS_ERR(sensor->vana)) {
+               dev_err(&client->dev, "could not get regulator for vana\n");
+               return PTR_ERR(sensor->vana);
+       }
+
+       sensor->ext_clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(sensor->ext_clk)) {
+               dev_err(&client->dev, "could not get clock\n");
+               return PTR_ERR(sensor->ext_clk);
+       }
+
+       ret = of_property_read_u32(dev->of_node, "clock-frequency",
+                                  &sensor->xclk_freq);
+       if (ret) {
+               dev_warn(dev, "can't get clock-frequency\n");
+               return ret;
+       }
+
+       mutex_init(&sensor->power_lock);
+
+       v4l2_i2c_subdev_init(&sensor->subdev, client, &et8ek8_ops);
+       sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+       sensor->subdev.internal_ops = &et8ek8_internal_ops;
+
+       sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
+       ret = media_entity_pads_init(&sensor->subdev.entity, 1, &sensor->pad);
+       if (ret < 0) {
+               dev_err(&client->dev, "media entity init failed!\n");
+               goto err_mutex;
+       }
+
+       ret = v4l2_async_register_subdev(&sensor->subdev);
+       if (ret < 0)
+               goto err_entity;
+
+       dev_dbg(dev, "initialized!\n");
+
+       return 0;
+
+err_entity:
+       media_entity_cleanup(&sensor->subdev.entity);
+err_mutex:
+       mutex_destroy(&sensor->power_lock);
+       return ret;
+}
+
+static int __exit et8ek8_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+       struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev);
+
+       if (sensor->power_count) {
+               WARN_ON(1);
+               et8ek8_power_off(sensor);
+               sensor->power_count = 0;
+       }
+
+       v4l2_device_unregister_subdev(&sensor->subdev);
+       device_remove_file(&client->dev, &dev_attr_priv_mem);
+       v4l2_ctrl_handler_free(&sensor->ctrl_handler);
+       v4l2_async_unregister_subdev(&sensor->subdev);
+       media_entity_cleanup(&sensor->subdev.entity);
+       mutex_destroy(&sensor->power_lock);
+
+       return 0;
+}
+
+static const struct of_device_id et8ek8_of_table[] = {
+       { .compatible = "toshiba,et8ek8" },
+       { },
+};
+
+static const struct i2c_device_id et8ek8_id_table[] = {
+       { ET8EK8_NAME, 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, et8ek8_id_table);
+
+static const struct dev_pm_ops et8ek8_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(et8ek8_suspend, et8ek8_resume)
+};
+
+static struct i2c_driver et8ek8_i2c_driver = {
+       .driver         = {
+               .name   = ET8EK8_NAME,
+               .pm     = &et8ek8_pm_ops,
+               .of_match_table = et8ek8_of_table,
+       },
+       .probe          = et8ek8_probe,
+       .remove         = __exit_p(et8ek8_remove),
+       .id_table       = et8ek8_id_table,
+};
+
+module_i2c_driver(et8ek8_i2c_driver);
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@iki.fi>, Pavel Machek <pavel@ucw.cz");
+MODULE_DESCRIPTION("Toshiba ET8EK8 camera sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/et8ek8/et8ek8_mode.c b/drivers/media/i2c/et8ek8/et8ek8_mode.c
new file mode 100644 (file)
index 0000000..a79882a
--- /dev/null
@@ -0,0 +1,587 @@
+/*
+ * et8ek8_mode.c
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Contact: Sakari Ailus <sakari.ailus@iki.fi>
+ *          Tuukka Toivonen <tuukkat76@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 "et8ek8_reg.h"
+
+/*
+ * Stingray sensor mode settings for Scooby
+ */
+
+/* Mode1_poweron_Mode2_16VGA_2592x1968_12.07fps */
+static struct et8ek8_reglist mode1_poweron_mode2_16vga_2592x1968_12_07fps = {
+/* (without the +1)
+ * SPCK       = 80 MHz
+ * CCP2       = 640 MHz
+ * VCO        = 640 MHz
+ * VCOUNT     = 84 (2016)
+ * HCOUNT     = 137 (3288)
+ * CKREF_DIV  = 2
+ * CKVAR_DIV  = 200
+ * VCO_DIV    = 0
+ * SPCK_DIV   = 7
+ * MRCK_DIV   = 7
+ * LVDSCK_DIV = 0
+ */
+       .type = ET8EK8_REGLIST_POWERON,
+       .mode = {
+               .sensor_width = 2592,
+               .sensor_height = 1968,
+               .sensor_window_origin_x = 0,
+               .sensor_window_origin_y = 0,
+               .sensor_window_width = 2592,
+               .sensor_window_height = 1968,
+               .width = 3288,
+               .height = 2016,
+               .window_origin_x = 0,
+               .window_origin_y = 0,
+               .window_width = 2592,
+               .window_height = 1968,
+               .pixel_clock = 80000000,
+               .ext_clock = 9600000,
+               .timeperframe = {
+                       .numerator = 100,
+                       .denominator = 1207
+               },
+               .max_exp = 2012,
+               /* .max_gain = 0, */
+               .bus_format = MEDIA_BUS_FMT_SGRBG10_1X10,
+               .sensitivity = 65536
+       },
+       .regs = {
+               /* Need to set firstly */
+               { ET8EK8_REG_8BIT, 0x126C, 0xCC },
+               /* Strobe and Data of CCP2 delay are minimized. */
+               { ET8EK8_REG_8BIT, 0x1269, 0x00 },
+               /* Refined value of Min H_COUNT  */
+               { ET8EK8_REG_8BIT, 0x1220, 0x89 },
+               /* Frequency of SPCK setting (SPCK=MRCK) */
+               { ET8EK8_REG_8BIT, 0x123A, 0x07 },
+               { ET8EK8_REG_8BIT, 0x1241, 0x94 },
+               { ET8EK8_REG_8BIT, 0x1242, 0x02 },
+               { ET8EK8_REG_8BIT, 0x124B, 0x00 },
+               { ET8EK8_REG_8BIT, 0x1255, 0xFF },
+               { ET8EK8_REG_8BIT, 0x1256, 0x9F },
+               { ET8EK8_REG_8BIT, 0x1258, 0x00 },
+               /* From parallel out to serial out */
+               { ET8EK8_REG_8BIT, 0x125D, 0x88 },
+               /* From w/ embeded data to w/o embeded data */
+               { ET8EK8_REG_8BIT, 0x125E, 0xC0 },
+               /* CCP2 out is from STOP to ACTIVE */
+               { ET8EK8_REG_8BIT, 0x1263, 0x98 },
+               { ET8EK8_REG_8BIT, 0x1268, 0xC6 },
+               { ET8EK8_REG_8BIT, 0x1434, 0x00 },
+               { ET8EK8_REG_8BIT, 0x1163, 0x44 },
+               { ET8EK8_REG_8BIT, 0x1166, 0x29 },
+               { ET8EK8_REG_8BIT, 0x1140, 0x02 },
+               { ET8EK8_REG_8BIT, 0x1011, 0x24 },
+               { ET8EK8_REG_8BIT, 0x1151, 0x80 },
+               { ET8EK8_REG_8BIT, 0x1152, 0x23 },
+               /* Initial setting for improvement2 of lower frequency noise */
+               { ET8EK8_REG_8BIT, 0x1014, 0x05 },
+               { ET8EK8_REG_8BIT, 0x1033, 0x06 },
+               { ET8EK8_REG_8BIT, 0x1034, 0x79 },
+               { ET8EK8_REG_8BIT, 0x1423, 0x3F },
+               { ET8EK8_REG_8BIT, 0x1424, 0x3F },
+               { ET8EK8_REG_8BIT, 0x1426, 0x00 },
+               /* Switch of Preset-White-balance (0d:disable / 1d:enable) */
+               { ET8EK8_REG_8BIT, 0x1439, 0x00 },
+               /* Switch of blemish correction (0d:disable / 1d:enable) */
+               { ET8EK8_REG_8BIT, 0x161F, 0x60 },
+               /* Switch of auto noise correction (0d:disable / 1d:enable) */
+               { ET8EK8_REG_8BIT, 0x1634, 0x00 },
+               { ET8EK8_REG_8BIT, 0x1646, 0x00 },
+               { ET8EK8_REG_8BIT, 0x1648, 0x00 },
+               { ET8EK8_REG_8BIT, 0x113E, 0x01 },
+               { ET8EK8_REG_8BIT, 0x113F, 0x22 },
+               { ET8EK8_REG_8BIT, 0x1239, 0x64 },
+               { ET8EK8_REG_8BIT, 0x1238, 0x02 },
+               { ET8EK8_REG_8BIT, 0x123B, 0x70 },
+               { ET8EK8_REG_8BIT, 0x123A, 0x07 },
+               { ET8EK8_REG_8BIT, 0x121B, 0x64 },
+               { ET8EK8_REG_8BIT, 0x121D, 0x64 },
+               { ET8EK8_REG_8BIT, 0x1221, 0x00 },
+               { ET8EK8_REG_8BIT, 0x1220, 0x89 },
+               { ET8EK8_REG_8BIT, 0x1223, 0x00 },
+               { ET8EK8_REG_8BIT, 0x1222, 0x54 },
+               { ET8EK8_REG_8BIT, 0x125D, 0x88 }, /* CCP_LVDS_MODE/  */
+               { ET8EK8_REG_TERM, 0, 0}
+       }
+};
+
+/* Mode1_16VGA_2592x1968_13.12fps_DPCM10-8 */
+static struct et8ek8_reglist mode1_16vga_2592x1968_13_12fps_dpcm10_8 = {
+/* (without the +1)
+ * SPCK       = 80 MHz
+ * CCP2       = 560 MHz
+ * VCO        = 560 MHz
+ * VCOUNT     = 84 (2016)
+ * HCOUNT     = 128 (3072)
+ * CKREF_DIV  = 2
+ * CKVAR_DIV  = 175
+ * VCO_DIV    = 0
+ * SPCK_DIV   = 6
+ * MRCK_DIV   = 7
+ * LVDSCK_DIV = 0
+ */
+       .type = ET8EK8_REGLIST_MODE,
+       .mode = {
+               .sensor_width = 2592,
+               .sensor_height = 1968,
+               .sensor_window_origin_x = 0,
+               .sensor_window_origin_y = 0,
+               .sensor_window_width = 2592,
+               .sensor_window_height = 1968,
+               .width = 3072,
+               .height = 2016,
+               .window_origin_x = 0,
+               .window_origin_y = 0,
+               .window_width = 2592,
+               .window_height = 1968,
+               .pixel_clock = 80000000,
+               .ext_clock = 9600000,
+               .timeperframe = {
+                       .numerator = 100,
+                       .denominator = 1292
+               },
+               .max_exp = 2012,
+               /* .max_gain = 0, */
+               .bus_format = MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
+               .sensitivity = 65536
+       },
+       .regs = {
+               { ET8EK8_REG_8BIT, 0x1239, 0x57 },
+               { ET8EK8_REG_8BIT, 0x1238, 0x82 },
+               { ET8EK8_REG_8BIT, 0x123B, 0x70 },
+               { ET8EK8_REG_8BIT, 0x123A, 0x06 },
+               { ET8EK8_REG_8BIT, 0x121B, 0x64 },
+               { ET8EK8_REG_8BIT, 0x121D, 0x64 },
+               { ET8EK8_REG_8BIT, 0x1221, 0x00 },
+               { ET8EK8_REG_8BIT, 0x1220, 0x80 }, /* <-changed to v14 7E->80 */
+               { ET8EK8_REG_8BIT, 0x1223, 0x00 },
+               { ET8EK8_REG_8BIT, 0x1222, 0x54 },
+               { ET8EK8_REG_8BIT, 0x125D, 0x83 }, /* CCP_LVDS_MODE/  */
+               { ET8EK8_REG_TERM, 0, 0}
+       }
+};
+
+/* Mode3_4VGA_1296x984_29.99fps_DPCM10-8 */
+static struct et8ek8_reglist mode3_4vga_1296x984_29_99fps_dpcm10_8 = {
+/* (without the +1)
+ * SPCK       = 96.5333333333333 MHz
+ * CCP2       = 579.2 MHz
+ * VCO        = 579.2 MHz
+ * VCOUNT     = 84 (2016)
+ * HCOUNT     = 133 (3192)
+ * CKREF_DIV  = 2
+ * CKVAR_DIV  = 181
+ * VCO_DIV    = 0
+ * SPCK_DIV   = 5
+ * MRCK_DIV   = 7
+ * LVDSCK_DIV = 0
+ */
+       .type = ET8EK8_REGLIST_MODE,
+       .mode = {
+               .sensor_width = 2592,
+               .sensor_height = 1968,
+               .sensor_window_origin_x = 0,
+               .sensor_window_origin_y = 0,
+               .sensor_window_width = 2592,
+               .sensor_window_height = 1968,
+               .width = 3192,
+               .height = 1008,
+               .window_origin_x = 0,
+               .window_origin_y = 0,
+               .window_width = 1296,
+               .window_height = 984,
+               .pixel_clock = 96533333,
+               .ext_clock = 9600000,
+               .timeperframe = {
+                       .numerator = 100,
+                       .denominator = 3000
+               },
+               .max_exp = 1004,
+               /* .max_gain = 0, */
+               .bus_format = MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
+               .sensitivity = 65536
+       },
+       .regs = {
+               { ET8EK8_REG_8BIT, 0x1239, 0x5A },
+               { ET8EK8_REG_8BIT, 0x1238, 0x82 },
+               { ET8EK8_REG_8BIT, 0x123B, 0x70 },
+               { ET8EK8_REG_8BIT, 0x123A, 0x05 },
+               { ET8EK8_REG_8BIT, 0x121B, 0x63 },
+               { ET8EK8_REG_8BIT, 0x1220, 0x85 },
+               { ET8EK8_REG_8BIT, 0x1221, 0x00 },
+               { ET8EK8_REG_8BIT, 0x1222, 0x54 },
+               { ET8EK8_REG_8BIT, 0x1223, 0x00 },
+               { ET8EK8_REG_8BIT, 0x121D, 0x63 },
+               { ET8EK8_REG_8BIT, 0x125D, 0x83 }, /* CCP_LVDS_MODE/  */
+               { ET8EK8_REG_TERM, 0, 0}
+       }
+};
+
+/* Mode4_SVGA_864x656_29.88fps */
+static struct et8ek8_reglist mode4_svga_864x656_29_88fps = {
+/* (without the +1)
+ * SPCK       = 80 MHz
+ * CCP2       = 320 MHz
+ * VCO        = 640 MHz
+ * VCOUNT     = 84 (2016)
+ * HCOUNT     = 166 (3984)
+ * CKREF_DIV  = 2
+ * CKVAR_DIV  = 200
+ * VCO_DIV    = 0
+ * SPCK_DIV   = 7
+ * MRCK_DIV   = 7
+ * LVDSCK_DIV = 1
+ */
+       .type = ET8EK8_REGLIST_MODE,
+       .mode = {
+               .sensor_width = 2592,
+               .sensor_height = 1968,
+               .sensor_window_origin_x = 0,
+               .sensor_window_origin_y = 0,
+               .sensor_window_width = 2592,
+               .sensor_window_height = 1968,
+               .width = 3984,
+               .height = 672,
+               .window_origin_x = 0,
+               .window_origin_y = 0,
+               .window_width = 864,
+               .window_height = 656,
+               .pixel_clock = 80000000,
+               .ext_clock = 9600000,
+               .timeperframe = {
+                       .numerator = 100,
+                       .denominator = 2988
+               },
+               .max_exp = 668,
+               /* .max_gain = 0, */
+               .bus_format = MEDIA_BUS_FMT_SGRBG10_1X10,
+               .sensitivity = 65536
+       },
+       .regs = {
+               { ET8EK8_REG_8BIT, 0x1239, 0x64 },
+               { ET8EK8_REG_8BIT, 0x1238, 0x02 },
+               { ET8EK8_REG_8BIT, 0x123B, 0x71 },
+               { ET8EK8_REG_8BIT, 0x123A, 0x07 },
+               { ET8EK8_REG_8BIT, 0x121B, 0x62 },
+               { ET8EK8_REG_8BIT, 0x121D, 0x62 },
+               { ET8EK8_REG_8BIT, 0x1221, 0x00 },
+               { ET8EK8_REG_8BIT, 0x1220, 0xA6 },
+               { ET8EK8_REG_8BIT, 0x1223, 0x00 },
+               { ET8EK8_REG_8BIT, 0x1222, 0x54 },
+               { ET8EK8_REG_8BIT, 0x125D, 0x88 }, /* CCP_LVDS_MODE/  */
+               { ET8EK8_REG_TERM, 0, 0}
+       }
+};
+
+/* Mode5_VGA_648x492_29.93fps */
+static struct et8ek8_reglist mode5_vga_648x492_29_93fps = {
+/* (without the +1)
+ * SPCK       = 80 MHz
+ * CCP2       = 320 MHz
+ * VCO        = 640 MHz
+ * VCOUNT     = 84 (2016)
+ * HCOUNT     = 221 (5304)
+ * CKREF_DIV  = 2
+ * CKVAR_DIV  = 200
+ * VCO_DIV    = 0
+ * SPCK_DIV   = 7
+ * MRCK_DIV   = 7
+ * LVDSCK_DIV = 1
+ */
+       .type = ET8EK8_REGLIST_MODE,
+       .mode = {
+               .sensor_width = 2592,
+               .sensor_height = 1968,
+               .sensor_window_origin_x = 0,
+               .sensor_window_origin_y = 0,
+               .sensor_window_width = 2592,
+               .sensor_window_height = 1968,
+               .width = 5304,
+               .height = 504,
+               .window_origin_x = 0,
+               .window_origin_y = 0,
+               .window_width = 648,
+               .window_height = 492,
+               .pixel_clock = 80000000,
+               .ext_clock = 9600000,
+               .timeperframe = {
+                       .numerator = 100,
+                       .denominator = 2993
+               },
+               .max_exp = 500,
+               /* .max_gain = 0, */
+               .bus_format = MEDIA_BUS_FMT_SGRBG10_1X10,
+               .sensitivity = 65536
+       },
+       .regs = {
+               { ET8EK8_REG_8BIT, 0x1239, 0x64 },
+               { ET8EK8_REG_8BIT, 0x1238, 0x02 },
+               { ET8EK8_REG_8BIT, 0x123B, 0x71 },
+               { ET8EK8_REG_8BIT, 0x123A, 0x07 },
+               { ET8EK8_REG_8BIT, 0x121B, 0x61 },
+               { ET8EK8_REG_8BIT, 0x121D, 0x61 },
+               { ET8EK8_REG_8BIT, 0x1221, 0x00 },
+               { ET8EK8_REG_8BIT, 0x1220, 0xDD },
+               { ET8EK8_REG_8BIT, 0x1223, 0x00 },
+               { ET8EK8_REG_8BIT, 0x1222, 0x54 },
+               { ET8EK8_REG_8BIT, 0x125D, 0x88 }, /* CCP_LVDS_MODE/  */
+               { ET8EK8_REG_TERM, 0, 0}
+       }
+};
+
+/* Mode2_16VGA_2592x1968_3.99fps */
+static struct et8ek8_reglist mode2_16vga_2592x1968_3_99fps = {
+/* (without the +1)
+ * SPCK       = 80 MHz
+ * CCP2       = 640 MHz
+ * VCO        = 640 MHz
+ * VCOUNT     = 254 (6096)
+ * HCOUNT     = 137 (3288)
+ * CKREF_DIV  = 2
+ * CKVAR_DIV  = 200
+ * VCO_DIV    = 0
+ * SPCK_DIV   = 7
+ * MRCK_DIV   = 7
+ * LVDSCK_DIV = 0
+ */
+       .type = ET8EK8_REGLIST_MODE,
+       .mode = {
+               .sensor_width = 2592,
+               .sensor_height = 1968,
+               .sensor_window_origin_x = 0,
+               .sensor_window_origin_y = 0,
+               .sensor_window_width = 2592,
+               .sensor_window_height = 1968,
+               .width = 3288,
+               .height = 6096,
+               .window_origin_x = 0,
+               .window_origin_y = 0,
+               .window_width = 2592,
+               .window_height = 1968,
+               .pixel_clock = 80000000,
+               .ext_clock = 9600000,
+               .timeperframe = {
+                       .numerator = 100,
+                       .denominator = 399
+               },
+               .max_exp = 6092,
+               /* .max_gain = 0, */
+               .bus_format = MEDIA_BUS_FMT_SGRBG10_1X10,
+               .sensitivity = 65536
+       },
+       .regs = {
+               { ET8EK8_REG_8BIT, 0x1239, 0x64 },
+               { ET8EK8_REG_8BIT, 0x1238, 0x02 },
+               { ET8EK8_REG_8BIT, 0x123B, 0x70 },
+               { ET8EK8_REG_8BIT, 0x123A, 0x07 },
+               { ET8EK8_REG_8BIT, 0x121B, 0x64 },
+               { ET8EK8_REG_8BIT, 0x121D, 0x64 },
+               { ET8EK8_REG_8BIT, 0x1221, 0x00 },
+               { ET8EK8_REG_8BIT, 0x1220, 0x89 },
+               { ET8EK8_REG_8BIT, 0x1223, 0x00 },
+               { ET8EK8_REG_8BIT, 0x1222, 0xFE },
+               { ET8EK8_REG_TERM, 0, 0}
+       }
+};
+
+/* Mode_648x492_5fps */
+static struct et8ek8_reglist mode_648x492_5fps = {
+/* (without the +1)
+ * SPCK       = 13.3333333333333 MHz
+ * CCP2       = 53.3333333333333 MHz
+ * VCO        = 640 MHz
+ * VCOUNT     = 84 (2016)
+ * HCOUNT     = 221 (5304)
+ * CKREF_DIV  = 2
+ * CKVAR_DIV  = 200
+ * VCO_DIV    = 5
+ * SPCK_DIV   = 7
+ * MRCK_DIV   = 7
+ * LVDSCK_DIV = 1
+ */
+       .type = ET8EK8_REGLIST_MODE,
+       .mode = {
+               .sensor_width = 2592,
+               .sensor_height = 1968,
+               .sensor_window_origin_x = 0,
+               .sensor_window_origin_y = 0,
+               .sensor_window_width = 2592,
+               .sensor_window_height = 1968,
+               .width = 5304,
+               .height = 504,
+               .window_origin_x = 0,
+               .window_origin_y = 0,
+               .window_width = 648,
+               .window_height = 492,
+               .pixel_clock = 13333333,
+               .ext_clock = 9600000,
+               .timeperframe = {
+                       .numerator = 100,
+                       .denominator = 499
+               },
+               .max_exp = 500,
+               /* .max_gain = 0, */
+               .bus_format = MEDIA_BUS_FMT_SGRBG10_1X10,
+               .sensitivity = 65536
+       },
+       .regs = {
+               { ET8EK8_REG_8BIT, 0x1239, 0x64 },
+               { ET8EK8_REG_8BIT, 0x1238, 0x02 },
+               { ET8EK8_REG_8BIT, 0x123B, 0x71 },
+               { ET8EK8_REG_8BIT, 0x123A, 0x57 },
+               { ET8EK8_REG_8BIT, 0x121B, 0x61 },
+               { ET8EK8_REG_8BIT, 0x121D, 0x61 },
+               { ET8EK8_REG_8BIT, 0x1221, 0x00 },
+               { ET8EK8_REG_8BIT, 0x1220, 0xDD },
+               { ET8EK8_REG_8BIT, 0x1223, 0x00 },
+               { ET8EK8_REG_8BIT, 0x1222, 0x54 },
+               { ET8EK8_REG_8BIT, 0x125D, 0x88 }, /* CCP_LVDS_MODE/  */
+               { ET8EK8_REG_TERM, 0, 0}
+       }
+};
+
+/* Mode3_4VGA_1296x984_5fps */
+static struct et8ek8_reglist mode3_4vga_1296x984_5fps = {
+/* (without the +1)
+ * SPCK       = 49.4 MHz
+ * CCP2       = 395.2 MHz
+ * VCO        = 790.4 MHz
+ * VCOUNT     = 250 (6000)
+ * HCOUNT     = 137 (3288)
+ * CKREF_DIV  = 2
+ * CKVAR_DIV  = 247
+ * VCO_DIV    = 1
+ * SPCK_DIV   = 7
+ * MRCK_DIV   = 7
+ * LVDSCK_DIV = 0
+ */
+       .type = ET8EK8_REGLIST_MODE,
+       .mode = {
+               .sensor_width = 2592,
+               .sensor_height = 1968,
+               .sensor_window_origin_x = 0,
+               .sensor_window_origin_y = 0,
+               .sensor_window_width = 2592,
+               .sensor_window_height = 1968,
+               .width = 3288,
+               .height = 3000,
+               .window_origin_x = 0,
+               .window_origin_y = 0,
+               .window_width = 1296,
+               .window_height = 984,
+               .pixel_clock = 49400000,
+               .ext_clock = 9600000,
+               .timeperframe = {
+                       .numerator = 100,
+                       .denominator = 501
+               },
+               .max_exp = 2996,
+               /* .max_gain = 0, */
+               .bus_format = MEDIA_BUS_FMT_SGRBG10_1X10,
+               .sensitivity = 65536
+       },
+       .regs = {
+               { ET8EK8_REG_8BIT, 0x1239, 0x7B },
+               { ET8EK8_REG_8BIT, 0x1238, 0x82 },
+               { ET8EK8_REG_8BIT, 0x123B, 0x70 },
+               { ET8EK8_REG_8BIT, 0x123A, 0x17 },
+               { ET8EK8_REG_8BIT, 0x121B, 0x63 },
+               { ET8EK8_REG_8BIT, 0x121D, 0x63 },
+               { ET8EK8_REG_8BIT, 0x1221, 0x00 },
+               { ET8EK8_REG_8BIT, 0x1220, 0x89 },
+               { ET8EK8_REG_8BIT, 0x1223, 0x00 },
+               { ET8EK8_REG_8BIT, 0x1222, 0xFA },
+               { ET8EK8_REG_8BIT, 0x125D, 0x88 }, /* CCP_LVDS_MODE/  */
+               { ET8EK8_REG_TERM, 0, 0}
+       }
+};
+
+/* Mode_4VGA_1296x984_25fps_DPCM10-8 */
+static struct et8ek8_reglist mode_4vga_1296x984_25fps_dpcm10_8 = {
+/* (without the +1)
+ * SPCK       = 84.2666666666667 MHz
+ * CCP2       = 505.6 MHz
+ * VCO        = 505.6 MHz
+ * VCOUNT     = 88 (2112)
+ * HCOUNT     = 133 (3192)
+ * CKREF_DIV  = 2
+ * CKVAR_DIV  = 158
+ * VCO_DIV    = 0
+ * SPCK_DIV   = 5
+ * MRCK_DIV   = 7
+ * LVDSCK_DIV = 0
+ */
+       .type = ET8EK8_REGLIST_MODE,
+       .mode = {
+               .sensor_width = 2592,
+               .sensor_height = 1968,
+               .sensor_window_origin_x = 0,
+               .sensor_window_origin_y = 0,
+               .sensor_window_width = 2592,
+               .sensor_window_height = 1968,
+               .width = 3192,
+               .height = 1056,
+               .window_origin_x = 0,
+               .window_origin_y = 0,
+               .window_width = 1296,
+               .window_height = 984,
+               .pixel_clock = 84266667,
+               .ext_clock = 9600000,
+               .timeperframe = {
+                       .numerator = 100,
+                       .denominator = 2500
+               },
+               .max_exp = 1052,
+               /* .max_gain = 0, */
+               .bus_format = MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
+               .sensitivity = 65536
+       },
+       .regs = {
+               { ET8EK8_REG_8BIT, 0x1239, 0x4F },
+               { ET8EK8_REG_8BIT, 0x1238, 0x02 },
+               { ET8EK8_REG_8BIT, 0x123B, 0x70 },
+               { ET8EK8_REG_8BIT, 0x123A, 0x05 },
+               { ET8EK8_REG_8BIT, 0x121B, 0x63 },
+               { ET8EK8_REG_8BIT, 0x1220, 0x85 },
+               { ET8EK8_REG_8BIT, 0x1221, 0x00 },
+               { ET8EK8_REG_8BIT, 0x1222, 0x58 },
+               { ET8EK8_REG_8BIT, 0x1223, 0x00 },
+               { ET8EK8_REG_8BIT, 0x121D, 0x63 },
+               { ET8EK8_REG_8BIT, 0x125D, 0x83 },
+               { ET8EK8_REG_TERM, 0, 0}
+       }
+};
+
+struct et8ek8_meta_reglist meta_reglist = {
+       .version = "V14 03-June-2008",
+       .reglist = {
+               { .ptr = &mode1_poweron_mode2_16vga_2592x1968_12_07fps },
+               { .ptr = &mode1_16vga_2592x1968_13_12fps_dpcm10_8 },
+               { .ptr = &mode3_4vga_1296x984_29_99fps_dpcm10_8 },
+               { .ptr = &mode4_svga_864x656_29_88fps },
+               { .ptr = &mode5_vga_648x492_29_93fps },
+               { .ptr = &mode2_16vga_2592x1968_3_99fps },
+               { .ptr = &mode_648x492_5fps },
+               { .ptr = &mode3_4vga_1296x984_5fps },
+               { .ptr = &mode_4vga_1296x984_25fps_dpcm10_8 },
+               { .ptr = NULL }
+       }
+};
diff --git a/drivers/media/i2c/et8ek8/et8ek8_reg.h b/drivers/media/i2c/et8ek8/et8ek8_reg.h
new file mode 100644 (file)
index 0000000..07f1873
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * et8ek8_reg.h
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Contact: Sakari Ailus <sakari.ailus@iki.fi>
+ *          Tuukka Toivonen <tuukkat76@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 ET8EK8REGS_H
+#define ET8EK8REGS_H
+
+#include <linux/i2c.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-subdev.h>
+
+struct v4l2_mbus_framefmt;
+struct v4l2_subdev_pad_mbus_code_enum;
+
+struct et8ek8_mode {
+       /* Physical sensor resolution and current image window */
+       u16 sensor_width;
+       u16 sensor_height;
+       u16 sensor_window_origin_x;
+       u16 sensor_window_origin_y;
+       u16 sensor_window_width;
+       u16 sensor_window_height;
+
+       /* Image data coming from sensor (after scaling) */
+       u16 width;
+       u16 height;
+       u16 window_origin_x;
+       u16 window_origin_y;
+       u16 window_width;
+       u16 window_height;
+
+       u32 pixel_clock;                /* in Hz */
+       u32 ext_clock;                  /* in Hz */
+       struct v4l2_fract timeperframe;
+       u32 max_exp;                    /* Maximum exposure value */
+       u32 bus_format;                 /* MEDIA_BUS_FMT_ */
+       u32 sensitivity;                /* 16.16 fixed point */
+};
+
+#define ET8EK8_REG_8BIT                        1
+#define ET8EK8_REG_16BIT               2
+#define ET8EK8_REG_DELAY               100
+#define ET8EK8_REG_TERM                        0xff
+struct et8ek8_reg {
+       u16 type;
+       u16 reg;                        /* 16-bit offset */
+       u32 val;                        /* 8/16/32-bit value */
+};
+
+/* Possible struct smia_reglist types. */
+#define ET8EK8_REGLIST_STANDBY         0
+#define ET8EK8_REGLIST_POWERON         1
+#define ET8EK8_REGLIST_RESUME          2
+#define ET8EK8_REGLIST_STREAMON                3
+#define ET8EK8_REGLIST_STREAMOFF       4
+#define ET8EK8_REGLIST_DISABLED                5
+
+#define ET8EK8_REGLIST_MODE            10
+
+#define ET8EK8_REGLIST_LSC_ENABLE      100
+#define ET8EK8_REGLIST_LSC_DISABLE     101
+#define ET8EK8_REGLIST_ANR_ENABLE      102
+#define ET8EK8_REGLIST_ANR_DISABLE     103
+
+struct et8ek8_reglist {
+       u32 type;
+       struct et8ek8_mode mode;
+       struct et8ek8_reg regs[];
+};
+
+#define ET8EK8_MAX_LEN                 32
+struct et8ek8_meta_reglist {
+       char version[ET8EK8_MAX_LEN];
+       union {
+               struct et8ek8_reglist *ptr;
+       } reglist[];
+};
+
+extern struct et8ek8_meta_reglist meta_reglist;
+
+#endif /* ET8EK8REGS */
index cede3975d04bd90441abcb29e6f169857561f935..cee7fd9cf08b3fe1704902a9959392277d9c04ca 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
  */
 
 #include <asm/unaligned.h>
@@ -428,7 +424,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
                 * If platform_data doesn't specify rc_dev, initialize it
                 * internally
                 */
-               rc = rc_allocate_device();
+               rc = rc_allocate_device(RC_DRIVER_SCANCODE);
                if (!rc)
                        return -ENOMEM;
        }
index 77551baab068bd2358a5abfbbe9aa8b5dfeecca0..ab536c4a711558fb22cf5dd0ab22cb4b770a49f2 100644 (file)
  * 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.
- *
  *****************************************************************************
  *
  * Modified and extended by
index cb8abd5403b341f12a1243a6e39286a75a2a5d55..636b70a984f757531e6eafb2bc7241ceda4a8af4 100644 (file)
  * but WITHOUT 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 KS0127_H
index 89c28c36c5bf7e5b6e220da6e34c64c1c801dd51..a7a8f9a4e45cc52d79c321a2f79dca4d66c70a66 100644 (file)
  * but WITHOUT 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.
  */
 
 
index acb804bceccbc745b06da770ef7eb541d53118e6..9ccb5ee55fa9c845a076ee23bf46220339021df5 100644 (file)
@@ -168,7 +168,7 @@ static int m5mols_read(struct v4l2_subdev *sd, u32 size, u32 reg, u32 *val)
        msg[1].buf = rbuf;
 
        /* minimum stabilization time */
-       usleep_range(200, 200);
+       usleep_range(200, 300);
 
        ret = i2c_transfer(client->adapter, msg, 2);
 
@@ -268,7 +268,8 @@ int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val)
 
        *buf = m5mols_swap_byte((u8 *)&val, size);
 
-       usleep_range(200, 200);
+       /* minimum stabilization time */
+       usleep_range(200, 300);
 
        ret = i2c_transfer(client->adapter, msg, 1);
        if (ret == 1)
@@ -651,7 +652,7 @@ static int m5mols_enum_mbus_code(struct v4l2_subdev *sd,
        return 0;
 }
 
-static struct v4l2_subdev_pad_ops m5mols_pad_ops = {
+static const struct v4l2_subdev_pad_ops m5mols_pad_ops = {
        .enum_mbus_code = m5mols_enum_mbus_code,
        .get_fmt        = m5mols_get_fmt,
        .set_fmt        = m5mols_set_fmt,
index 38a20fe181eef9b09e73cdf266ce4642a074a6f3..57ef901edb06074a90c1f81cbca252d43c21f60f 100644 (file)
@@ -290,7 +290,7 @@ static const struct v4l2_ctrl_ops ml86v7667_ctrl_ops = {
        .s_ctrl = ml86v7667_s_ctrl,
 };
 
-static struct v4l2_subdev_video_ops ml86v7667_subdev_video_ops = {
+static const struct v4l2_subdev_video_ops ml86v7667_subdev_video_ops = {
        .g_std = ml86v7667_g_std,
        .s_std = ml86v7667_s_std,
        .querystd = ml86v7667_querystd,
@@ -304,14 +304,14 @@ static const struct v4l2_subdev_pad_ops ml86v7667_subdev_pad_ops = {
        .set_fmt = ml86v7667_fill_fmt,
 };
 
-static struct v4l2_subdev_core_ops ml86v7667_subdev_core_ops = {
+static const struct v4l2_subdev_core_ops ml86v7667_subdev_core_ops = {
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register = ml86v7667_g_register,
        .s_register = ml86v7667_s_register,
 #endif
 };
 
-static struct v4l2_subdev_ops ml86v7667_subdev_ops = {
+static const struct v4l2_subdev_ops ml86v7667_subdev_ops = {
        .core = &ml86v7667_subdev_core_ops,
        .video = &ml86v7667_subdev_video_ops,
        .pad = &ml86v7667_subdev_pad_ops,
index 201a9800ea52a8e8860acec804ac7a989e54b596..3db966db83eb50c6888549c062fefd05ae591da9 100644 (file)
  * but WITHOUT 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.
  */
 
 
index eec7aa4c6f98f6b6a48c36177df93dfc5825b585..11fc593ed908a25db615c5ecec979eb31f3e0ac5 100644 (file)
  * but WITHOUT 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.
  */
 
 
index da076796999ee6ee5e3ee9ae17d65856ce744629..6a9e068462fd9484be7a69135af9ed8510311d63 100644 (file)
  * WITHOUT 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 St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #include <linux/delay.h>
index 237737fec09c15fdc6b3148c10a602860d3b5bff..91d822fc4443a362d3ee8d2b6538deb84b8e2f91 100644 (file)
@@ -972,15 +972,15 @@ static int mt9p031_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
        return mt9p031_set_power(subdev, 0);
 }
 
-static struct v4l2_subdev_core_ops mt9p031_subdev_core_ops = {
+static const struct v4l2_subdev_core_ops mt9p031_subdev_core_ops = {
        .s_power        = mt9p031_set_power,
 };
 
-static struct v4l2_subdev_video_ops mt9p031_subdev_video_ops = {
+static const struct v4l2_subdev_video_ops mt9p031_subdev_video_ops = {
        .s_stream       = mt9p031_s_stream,
 };
 
-static struct v4l2_subdev_pad_ops mt9p031_subdev_pad_ops = {
+static const struct v4l2_subdev_pad_ops mt9p031_subdev_pad_ops = {
        .enum_mbus_code = mt9p031_enum_mbus_code,
        .enum_frame_size = mt9p031_enum_frame_size,
        .get_fmt = mt9p031_get_format,
@@ -989,7 +989,7 @@ static struct v4l2_subdev_pad_ops mt9p031_subdev_pad_ops = {
        .set_selection = mt9p031_set_selection,
 };
 
-static struct v4l2_subdev_ops mt9p031_subdev_ops = {
+static const struct v4l2_subdev_ops mt9p031_subdev_ops = {
        .core   = &mt9p031_subdev_core_ops,
        .video  = &mt9p031_subdev_video_ops,
        .pad    = &mt9p031_subdev_pad_ops,
index 58eb62f1ba214449d72a8f06b09e2f21c1eb47c4..2e7a6e62a358ab637342aafebd8ecc3882b942f9 100644 (file)
@@ -266,8 +266,7 @@ static int mt9v032_power_on(struct mt9v032 *mt9v032)
        struct regmap *map = mt9v032->regmap;
        int ret;
 
-       if (mt9v032->reset_gpio)
-               gpiod_set_value_cansleep(mt9v032->reset_gpio, 1);
+       gpiod_set_value_cansleep(mt9v032->reset_gpio, 1);
 
        ret = clk_set_rate(mt9v032->clk, mt9v032->sysclk);
        if (ret < 0)
@@ -936,15 +935,15 @@ static int mt9v032_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
        return mt9v032_set_power(subdev, 0);
 }
 
-static struct v4l2_subdev_core_ops mt9v032_subdev_core_ops = {
+static const struct v4l2_subdev_core_ops mt9v032_subdev_core_ops = {
        .s_power        = mt9v032_set_power,
 };
 
-static struct v4l2_subdev_video_ops mt9v032_subdev_video_ops = {
+static const struct v4l2_subdev_video_ops mt9v032_subdev_video_ops = {
        .s_stream       = mt9v032_s_stream,
 };
 
-static struct v4l2_subdev_pad_ops mt9v032_subdev_pad_ops = {
+static const struct v4l2_subdev_pad_ops mt9v032_subdev_pad_ops = {
        .enum_mbus_code = mt9v032_enum_mbus_code,
        .enum_frame_size = mt9v032_enum_frame_size,
        .get_fmt = mt9v032_get_format,
@@ -953,7 +952,7 @@ static struct v4l2_subdev_pad_ops mt9v032_subdev_pad_ops = {
        .set_selection = mt9v032_set_selection,
 };
 
-static struct v4l2_subdev_ops mt9v032_subdev_ops = {
+static const struct v4l2_subdev_ops mt9v032_subdev_ops = {
        .core   = &mt9v032_subdev_core_ops,
        .video  = &mt9v032_subdev_video_ops,
        .pad    = &mt9v032_subdev_pad_ops,
index 30cb90b88d7551515abb601dd578216ee60bc204..88c498ad45dfb01aa089090609307ed3ce29673c 100644 (file)
@@ -664,13 +664,13 @@ static const struct v4l2_subdev_core_ops noon010_core_ops = {
        .log_status     = noon010_log_status,
 };
 
-static struct v4l2_subdev_pad_ops noon010_pad_ops = {
+static const struct v4l2_subdev_pad_ops noon010_pad_ops = {
        .enum_mbus_code = noon010_enum_mbus_code,
        .get_fmt        = noon010_get_fmt,
        .set_fmt        = noon010_set_fmt,
 };
 
-static struct v4l2_subdev_video_ops noon010_video_ops = {
+static const struct v4l2_subdev_video_ops noon010_video_ops = {
        .s_stream       = noon010_s_stream,
 };
 
index 1f999e9c0118e358ac111c17084c21799a677db0..6e6367214d408081f36416a1d8249a75b16fb4fd 100644 (file)
@@ -1121,7 +1121,6 @@ static int ov2659_set_fmt(struct v4l2_subdev *sd,
                return -EINVAL;
 
        mf->colorspace = V4L2_COLORSPACE_SRGB;
-       mf->code = ov2659_formats[index].code;
        mf->field = V4L2_FIELD_NONE;
 
        mutex_lock(&ov2659->lock);
index b8961df5af3350d8497d66bc8cbd9e7f0e0c566c..a03b41a3639ec5a54145afa7bafe04a47a8508f7 100644 (file)
@@ -9,10 +9,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.
  */
 
 #include <linux/init.h>
index 502c72238a4a52440a2fa735686f88ffa00a88bf..2de2fbb13b857ec92cc2766fe06730ed4702ad56 100644 (file)
@@ -522,7 +522,7 @@ static void __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);
-               usleep_range(25000, 26000);
+               msleep(25);
        } else {
                ov965x_gpio_set(ov965x->gpios[GPIO_RST], 1);
                ov965x_gpio_set(ov965x->gpios[GPIO_PWDN], 1);
@@ -1438,7 +1438,7 @@ static int ov965x_detect_sensor(struct v4l2_subdev *sd)
 
        mutex_lock(&ov965x->lock);
        __ov965x_set_power(ov965x, 1);
-       usleep_range(25000, 26000);
+       msleep(25);
 
        /* Check sensor revision */
        ret = ov965x_read(client, REG_PID, &pid);
index 0a060339e51667b4ded02b180bc5d8fa7f0f877a..2e7185030741919095cdef356d7b049921190fac 100644 (file)
@@ -211,7 +211,7 @@ static int s5c73m3_3a_lock(struct s5c73m3 *state, struct v4l2_ctrl *ctrl)
        }
 
        if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_FOCUS)
-               ret = s5c73m3_af_run(state, ~af_lock);
+               ret = s5c73m3_af_run(state, !af_lock);
 
        return ret;
 }
index 769964057881cd1090c47fee5ac33e8b0fc5e818..67dcca76f981cc5a38a23f6a098cc71dc37622e9 100644 (file)
@@ -165,7 +165,7 @@ static int s5k6a3_get_fmt(struct v4l2_subdev *sd,
        return 0;
 }
 
-static struct v4l2_subdev_pad_ops s5k6a3_pad_ops = {
+static const struct v4l2_subdev_pad_ops s5k6a3_pad_ops = {
        .enum_mbus_code = s5k6a3_enum_mbus_code,
        .get_fmt        = s5k6a3_get_fmt,
        .set_fmt        = s5k6a3_set_fmt,
@@ -266,11 +266,11 @@ static int s5k6a3_s_power(struct v4l2_subdev *sd, int on)
        return ret;
 }
 
-static struct v4l2_subdev_core_ops s5k6a3_core_ops = {
+static const struct v4l2_subdev_core_ops s5k6a3_core_ops = {
        .s_power = s5k6a3_s_power,
 };
 
-static struct v4l2_subdev_ops s5k6a3_subdev_ops = {
+static const struct v4l2_subdev_ops s5k6a3_subdev_ops = {
        .core = &s5k6a3_core_ops,
        .pad = &s5k6a3_pad_ops,
 };
index ad456ce051f9f6e2e95a7a88c2214b662e965ec2..63fe521752a171c530548a46d2e0d3da0fd26a1a 100644 (file)
  * but WITHOUT 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/module.h>
index 58062b41c923e48e1c87fdc421cf195b9bdb3e07..d863b04aa2a891be150fc759a1ca881c32386161 100644 (file)
  * but WITHOUT 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.
  */
 
 #include "saa711x_regs.h"
index 8d94dcbf4366466c87067d61c16aa78be7f76470..99c303002e9049f80d0ab2285d2afd583aa876db 100644 (file)
  * but WITHOUT 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.
  */
 
 
index 1baca37f3eb6056e1d9de35c1b167c0ceda96353..e1f6bc219c6460ed0d905db277590c95679fede6 100644 (file)
  * but WITHOUT 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/module.h>
index 119050e1197a4966c4164868f6da1405391c891d..0e27fafaef2d9ceff5191c31a4f6268a876badb4 100644 (file)
  * but WITHOUT 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/module.h>
index 8c93c57af71cd2c7413b0bdd5564d1f070bf0f66..65085a235128ecd844199b292a549a7d2a8841e2 100644 (file)
@@ -233,7 +233,7 @@ static int ov9640_reg_rmw(struct i2c_client *client, u8 reg, u8 set, u8 unset)
        if (ret) {
                dev_err(&client->dev,
                        "[Read]-Modify-Write of register %02x failed!\n", reg);
-               return val;
+               return ret;
        }
 
        val |= set;
index 6b1a04ffad32e1ede62b95264ef77248383610da..a9c067bcc0acd6ed24ac392fb914a2929c4741e8 100644 (file)
@@ -9,10 +9,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.
  */
 
 #include <linux/module.h>
index 1e3a0dd2238cf4aa1c43705ca3493d3652d79967..f569a05fe10547e4ffc159bbce96d5765ae9e40b 100644 (file)
@@ -96,6 +96,7 @@ struct tc358743_state {
 
        struct v4l2_dv_timings timings;
        u32 mbus_fmt_code;
+       u8 csi_lanes_in_use;
 
        struct gpio_desc *reset_gpio;
 };
@@ -287,11 +288,6 @@ static int get_audio_sampling_rate(struct v4l2_subdev *sd)
        return code_to_rate[i2c_rd8(sd, FS_SET) & MASK_FS];
 }
 
-static unsigned tc358743_num_csi_lanes_in_use(struct v4l2_subdev *sd)
-{
-       return ((i2c_rd32(sd, CSI_CONTROL) & MASK_NOL) >> 1) + 1;
-}
-
 /* --------------- TIMINGS --------------- */
 
 static inline unsigned fps(const struct v4l2_bt_timings *t)
@@ -372,29 +368,21 @@ static void tc358743_set_hdmi_hdcp(struct v4l2_subdev *sd, bool enable)
        v4l2_dbg(2, debug, sd, "%s: %s\n", __func__, enable ?
                                "enable" : "disable");
 
-       i2c_wr8_and_or(sd, HDCP_REG1,
-                       ~(MASK_AUTH_UNAUTH_SEL | MASK_AUTH_UNAUTH),
-                       MASK_AUTH_UNAUTH_SEL_16_FRAMES | MASK_AUTH_UNAUTH_AUTO);
+       if (enable) {
+               i2c_wr8_and_or(sd, HDCP_REG3, ~KEY_RD_CMD, KEY_RD_CMD);
 
-       i2c_wr8_and_or(sd, HDCP_REG2, ~MASK_AUTO_P3_RESET,
-                       SET_AUTO_P3_RESET_FRAMES(0x0f));
+               i2c_wr8_and_or(sd, HDCP_MODE, ~MASK_MANUAL_AUTHENTICATION, 0);
 
-       /* HDCP is disabled by configuring the receiver as HDCP repeater. The
-        * repeater mode require software support to work, so HDCP
-        * authentication will fail.
-        */
-       i2c_wr8_and_or(sd, HDCP_REG3, ~KEY_RD_CMD, enable ? KEY_RD_CMD : 0);
-       i2c_wr8_and_or(sd, HDCP_MODE, ~(MASK_AUTO_CLR | MASK_MODE_RST_TN),
-                       enable ?  (MASK_AUTO_CLR | MASK_MODE_RST_TN) : 0);
+               i2c_wr8_and_or(sd, HDCP_REG1, 0xff,
+                               MASK_AUTH_UNAUTH_SEL_16_FRAMES |
+                               MASK_AUTH_UNAUTH_AUTO);
 
-       /* Apple MacBook Pro gen.8 has a bug that makes it freeze every fifth
-        * second when HDCP is disabled, but the MAX_EXCED bit is handled
-        * correctly and HDCP is disabled on the HDMI output.
-        */
-       i2c_wr8_and_or(sd, BSTATUS1, ~MASK_MAX_EXCED,
-                       enable ? 0 : MASK_MAX_EXCED);
-       i2c_wr8_and_or(sd, BCAPS, ~(MASK_REPEATER | MASK_READY),
-                       enable ? 0 : MASK_REPEATER | MASK_READY);
+               i2c_wr8_and_or(sd, HDCP_REG2, ~MASK_AUTO_P3_RESET,
+                               SET_AUTO_P3_RESET_FRAMES(0x0f));
+       } else {
+               i2c_wr8_and_or(sd, HDCP_MODE, ~MASK_MANUAL_AUTHENTICATION,
+                               MASK_MANUAL_AUTHENTICATION);
+       }
 }
 
 static void tc358743_disable_edid(struct v4l2_subdev *sd)
@@ -416,6 +404,7 @@ static void tc358743_enable_edid(struct v4l2_subdev *sd)
 
        if (state->edid_blocks_written == 0) {
                v4l2_dbg(2, debug, sd, "%s: no EDID -> no hotplug\n", __func__);
+               tc358743_s_ctrl_detect_tx_5v(sd);
                return;
        }
 
@@ -683,6 +672,8 @@ static void tc358743_set_csi(struct v4l2_subdev *sd)
 
        v4l2_dbg(3, debug, sd, "%s:\n", __func__);
 
+       state->csi_lanes_in_use = lanes;
+
        tc358743_reset(sd, MASK_CTXRST);
 
        if (lanes < 1)
@@ -1155,7 +1146,7 @@ static int tc358743_log_status(struct v4l2_subdev *sd)
        v4l2_info(sd, "Lanes needed: %d\n",
                        tc358743_num_csi_lanes_needed(sd));
        v4l2_info(sd, "Lanes in use: %d\n",
-                       tc358743_num_csi_lanes_in_use(sd));
+                       state->csi_lanes_in_use);
        v4l2_info(sd, "Waiting for particular sync signal: %s\n",
                        (i2c_rd16(sd, CSI_STATUS) & MASK_S_WSYNC) ?
                        "yes" : "no");
@@ -1438,12 +1429,14 @@ static int tc358743_dv_timings_cap(struct v4l2_subdev *sd,
 static int tc358743_g_mbus_config(struct v4l2_subdev *sd,
                             struct v4l2_mbus_config *cfg)
 {
+       struct tc358743_state *state = to_state(sd);
+
        cfg->type = V4L2_MBUS_CSI2;
 
        /* Support for non-continuous CSI-2 clock is missing in the driver */
        cfg->flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
 
-       switch (tc358743_num_csi_lanes_in_use(sd)) {
+       switch (state->csi_lanes_in_use) {
        case 1:
                cfg->flags |= V4L2_MBUS_CSI2_1_LANE;
                break;
index 81f1db558e7c79f4e0ca1787e8dae8ccd62ac0f2..657ef50f215f5f03ccebc2b734a38b51387be587 100644 (file)
 #define MASK_MODE_RST_TN                      0x20
 #define MASK_LINE_REKEY                       0x10
 #define MASK_AUTO_CLR                         0x04
+#define MASK_MANUAL_AUTHENTICATION            0x02 /* Not in REF_01 */
 
 #define HDCP_REG1                             0x8563 /* Not in REF_01 */
 #define MASK_AUTH_UNAUTH_SEL                  0x70
index cc6104da34ef6f3702b055915b473a4ef0506c0e..6ac26986f6a2194014d321edb0958efa43c9903e 100644 (file)
  * but WITHOUT 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/module.h>
index 0c62899c3667cb4b59a1cb12759dea7cb7a51b24..07853d2252aab2a64d3eb5df195e64a60f798f05 100644 (file)
  * 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/i2c.h>
index d23aa2fbb9b1e2f6f540ad7864298a28d4a3b3b4..1e6c0857590e89dbca603757960f7c15d2d9009a 100644 (file)
  * 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 _TVP514X_REGS_H
index 3dc3341c48961907f8c26fa5b2a21b58a014e339..4c1190127c85c90f8d5e88a936373b0d71b2ba02 100644 (file)
  * but WITHOUT 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/delay.h>
 #include <linux/i2c.h>
index 0e34ca9bccf3913e6524ba07175d5a45e25e3a6f..933673561fa25d095acc59797874ffd896462858 100644 (file)
  * but WITHOUT 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.
  */
 
 /* Naming conventions
index 7347480c0b0c48788e44e6fad150343ccc6941e7..bc8a3ecebffbe4cc24ceaabbbad5dcc7101254c5 100644 (file)
@@ -9,10 +9,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.
  */
 
 #include <linux/module.h>
index bef79cf74364fa2b816b54985886cf8b19c1806b..af32db3d74089a437ddcc7ce0dde46aa9e68e9ec 100644 (file)
@@ -9,10 +9,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.
  */
 
 #include <linux/module.h>
index 316a3113ef27b32befccbde8db222262d51f01fc..5081307b2cdbff6a007cd4359878394bc5111791 100644 (file)
@@ -9,10 +9,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.
  */
 
 #include <linux/module.h>
index 8e17a83920d4355038673410459af1011d69e00e..eb0084ebe35e8bf763ffa87ca6469903afaf3395 100644 (file)
@@ -9,10 +9,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.
  */
 
 #include <linux/module.h>
index c03567e993cd3c7645e010314211354ff170f511..7ad5d51dfbc3d31c2938c0090573f53ea8f00196 100644 (file)
  * but WITHOUT 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.
  */
 
 
index 77f122f2e3c99af0390a64c30a2cf7c14efa82dd..c7fdd7c163cb9ea8db2af76fedd573a2708e951e 100644 (file)
  * but WITHOUT 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.
  */
 
 #include <linux/module.h>
index ef0d8b8e3df79ccd4c84f26c95ac76c495ff9342..c6611a3f2b3d9e1782666a00289528a889ddd232 100644 (file)
  * but WITHOUT 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/module.h>
index ce9f09370e22171167c2ea9f1e31780f40268e77..67de79b2d55039704ef589949690d4b60502bcf1 100644 (file)
  * but WITHOUT 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/module.h>
index be4cb7a8bdebec1c1df3463dba4bd1aa7378f289..f0741ab338df2441180e4066cafe775a8e2c55c2 100644 (file)
  * but WITHOUT 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/delay.h>
index 6ba2ee25827ea9029b1c49ccfe8f21abbeaa4060..f78e7d1087a48a6d67b1146b0c0eeec3cb2c779c 100644 (file)
  * but WITHOUT 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 _VS6624_REGS_H_
index c885def54b15a0a65ec03d2f19621613e0dc4597..23464d0641febbd220d546fa9dd894cd712d7e9a 100644 (file)
  * but WITHOUT 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/module.h>
index 45039d7567535e6a3590cd59100a8741c29e5f51..704bccf0d4b23464735baadfa47d87d4e28d0e06 100644 (file)
  * but WITHOUT 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/module.h>
index 8756275e9fc4ee71d99d2b9d15eb592cc8e04e2a..760e3e424e23cc0357e5b316a0a66c01b9063dd7 100644 (file)
  * but WITHOUT 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
  */
 
 /* We need to access legacy defines from linux/media.h */
@@ -130,7 +126,7 @@ static long media_device_enum_entities(struct media_device *mdev,
         * old range.
         */
        if (ent->function < MEDIA_ENT_F_OLD_BASE ||
-           ent->function > MEDIA_ENT_T_DEVNODE_UNKNOWN) {
+           ent->function > MEDIA_ENT_F_TUNER) {
                if (is_media_entity_v4l2_subdev(ent))
                        entd->type = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
                else if (ent->function != MEDIA_ENT_F_IO_V4L)
@@ -601,19 +597,19 @@ int __must_check media_device_register_entity(struct media_device *mdev,
 
        if (mdev->entity_internal_idx_max
            >= mdev->pm_count_walk.ent_enum.idx_max) {
-               struct media_entity_graph new = { .top = 0 };
+               struct media_graph new = { .top = 0 };
 
                /*
                 * Initialise the new graph walk before cleaning up
                 * the old one in order not to spoil the graph walk
                 * object of the media device if graph walk init fails.
                 */
-               ret = media_entity_graph_walk_init(&new, mdev);
+               ret = media_graph_walk_init(&new, mdev);
                if (ret) {
                        mutex_unlock(&mdev->graph_mutex);
                        return ret;
                }
-               media_entity_graph_walk_cleanup(&mdev->pm_count_walk);
+               media_graph_walk_cleanup(&mdev->pm_count_walk);
                mdev->pm_count_walk = new;
        }
        mutex_unlock(&mdev->graph_mutex);
@@ -695,7 +691,7 @@ void media_device_cleanup(struct media_device *mdev)
 {
        ida_destroy(&mdev->entity_internal_idx);
        mdev->entity_internal_idx_max = 0;
-       media_entity_graph_walk_cleanup(&mdev->pm_count_walk);
+       media_graph_walk_cleanup(&mdev->pm_count_walk);
        mutex_destroy(&mdev->graph_mutex);
 }
 EXPORT_SYMBOL_GPL(media_device_cleanup);
index f2772ba6f61163f59d25c31b9b1b4cf16d824856..ae46753c90cbe96a2bb359eca45fa27d9f576284 100644 (file)
  * 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
- *
  * --
  *
  * Generic media device node infrastructure to register and unregister
index f9f723f5e4f06bdcb1c306e61c597bb187bcfb49..5640ca29da8c9bbc8ea63ce84077c087a0bb9557 100644 (file)
  * but WITHOUT 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
  */
 
 #include <linux/bitmap.h>
@@ -258,7 +254,7 @@ media_entity_other(struct media_entity *entity, struct media_link *link)
 }
 
 /* push an entity to traversal stack */
-static void stack_push(struct media_entity_graph *graph,
+static void stack_push(struct media_graph *graph,
                       struct media_entity *entity)
 {
        if (graph->top == MEDIA_ENTITY_ENUM_MAX_DEPTH - 1) {
@@ -270,7 +266,7 @@ static void stack_push(struct media_entity_graph *graph,
        graph->stack[graph->top].entity = entity;
 }
 
-static struct media_entity *stack_pop(struct media_entity_graph *graph)
+static struct media_entity *stack_pop(struct media_graph *graph)
 {
        struct media_entity *entity;
 
@@ -289,35 +285,35 @@ static struct media_entity *stack_pop(struct media_entity_graph *graph)
 #define MEDIA_ENTITY_MAX_PADS          512
 
 /**
- * media_entity_graph_walk_init - Allocate resources for graph walk
+ * media_graph_walk_init - Allocate resources for graph walk
  * @graph: Media graph structure that will be used to walk the graph
  * @mdev: Media device
  *
  * Reserve resources for graph walk in media device's current
  * state. The memory must be released using
- * media_entity_graph_walk_free().
+ * media_graph_walk_free().
  *
  * Returns error on failure, zero on success.
  */
-__must_check int media_entity_graph_walk_init(
-       struct media_entity_graph *graph, struct media_device *mdev)
+__must_check int media_graph_walk_init(
+       struct media_graph *graph, struct media_device *mdev)
 {
        return media_entity_enum_init(&graph->ent_enum, mdev);
 }
-EXPORT_SYMBOL_GPL(media_entity_graph_walk_init);
+EXPORT_SYMBOL_GPL(media_graph_walk_init);
 
 /**
- * media_entity_graph_walk_cleanup - Release resources related to graph walking
+ * media_graph_walk_cleanup - Release resources related to graph walking
  * @graph: Media graph structure that was used to walk the graph
  */
-void media_entity_graph_walk_cleanup(struct media_entity_graph *graph)
+void media_graph_walk_cleanup(struct media_graph *graph)
 {
        media_entity_enum_cleanup(&graph->ent_enum);
 }
-EXPORT_SYMBOL_GPL(media_entity_graph_walk_cleanup);
+EXPORT_SYMBOL_GPL(media_graph_walk_cleanup);
 
-void media_entity_graph_walk_start(struct media_entity_graph *graph,
-                                  struct media_entity *entity)
+void media_graph_walk_start(struct media_graph *graph,
+                           struct media_entity *entity)
 {
        media_entity_enum_zero(&graph->ent_enum);
        media_entity_enum_set(&graph->ent_enum, entity);
@@ -325,12 +321,52 @@ void media_entity_graph_walk_start(struct media_entity_graph *graph,
        graph->top = 0;
        graph->stack[graph->top].entity = NULL;
        stack_push(graph, entity);
+       dev_dbg(entity->graph_obj.mdev->dev,
+               "begin graph walk at '%s'\n", entity->name);
 }
-EXPORT_SYMBOL_GPL(media_entity_graph_walk_start);
+EXPORT_SYMBOL_GPL(media_graph_walk_start);
 
-struct media_entity *
-media_entity_graph_walk_next(struct media_entity_graph *graph)
+static void media_graph_walk_iter(struct media_graph *graph)
 {
+       struct media_entity *entity = stack_top(graph);
+       struct media_link *link;
+       struct media_entity *next;
+
+       link = list_entry(link_top(graph), typeof(*link), list);
+
+       /* The link is not enabled so we do not follow. */
+       if (!(link->flags & MEDIA_LNK_FL_ENABLED)) {
+               link_top(graph) = link_top(graph)->next;
+               dev_dbg(entity->graph_obj.mdev->dev,
+                       "walk: skipping disabled link '%s':%u -> '%s':%u\n",
+                       link->source->entity->name, link->source->index,
+                       link->sink->entity->name, link->sink->index);
+               return;
+       }
+
+       /* Get the entity in the other end of the link . */
+       next = media_entity_other(entity, link);
+
+       /* Has the entity already been visited? */
+       if (media_entity_enum_test_and_set(&graph->ent_enum, next)) {
+               link_top(graph) = link_top(graph)->next;
+               dev_dbg(entity->graph_obj.mdev->dev,
+                       "walk: skipping entity '%s' (already seen)\n",
+                       next->name);
+               return;
+       }
+
+       /* Push the new entity to stack and start over. */
+       link_top(graph) = link_top(graph)->next;
+       stack_push(graph, next);
+       dev_dbg(entity->graph_obj.mdev->dev, "walk: pushing '%s' on stack\n",
+               next->name);
+}
+
+struct media_entity *media_graph_walk_next(struct media_graph *graph)
+{
+       struct media_entity *entity;
+
        if (stack_top(graph) == NULL)
                return NULL;
 
@@ -339,59 +375,39 @@ media_entity_graph_walk_next(struct media_entity_graph *graph)
         * top of the stack until no more entities on the level can be
         * found.
         */
-       while (link_top(graph) != &stack_top(graph)->links) {
-               struct media_entity *entity = stack_top(graph);
-               struct media_link *link;
-               struct media_entity *next;
-
-               link = list_entry(link_top(graph), typeof(*link), list);
-
-               /* The link is not enabled so we do not follow. */
-               if (!(link->flags & MEDIA_LNK_FL_ENABLED)) {
-                       link_top(graph) = link_top(graph)->next;
-                       continue;
-               }
+       while (link_top(graph) != &stack_top(graph)->links)
+               media_graph_walk_iter(graph);
 
-               /* Get the entity in the other end of the link . */
-               next = media_entity_other(entity, link);
+       entity = stack_pop(graph);
+       dev_dbg(entity->graph_obj.mdev->dev,
+               "walk: returning entity '%s'\n", entity->name);
 
-               /* Has the entity already been visited? */
-               if (media_entity_enum_test_and_set(&graph->ent_enum, next)) {
-                       link_top(graph) = link_top(graph)->next;
-                       continue;
-               }
-
-               /* Push the new entity to stack and start over. */
-               link_top(graph) = link_top(graph)->next;
-               stack_push(graph, next);
-       }
-
-       return stack_pop(graph);
+       return entity;
 }
-EXPORT_SYMBOL_GPL(media_entity_graph_walk_next);
+EXPORT_SYMBOL_GPL(media_graph_walk_next);
 
 /* -----------------------------------------------------------------------------
  * Pipeline management
  */
 
-__must_check int __media_entity_pipeline_start(struct media_entity *entity,
-                                              struct media_pipeline *pipe)
+__must_check int __media_pipeline_start(struct media_entity *entity,
+                                       struct media_pipeline *pipe)
 {
        struct media_device *mdev = entity->graph_obj.mdev;
-       struct media_entity_graph *graph = &pipe->graph;
+       struct media_graph *graph = &pipe->graph;
        struct media_entity *entity_err = entity;
        struct media_link *link;
        int ret;
 
        if (!pipe->streaming_count++) {
-               ret = media_entity_graph_walk_init(&pipe->graph, mdev);
+               ret = media_graph_walk_init(&pipe->graph, mdev);
                if (ret)
                        goto error_graph_walk_start;
        }
 
-       media_entity_graph_walk_start(&pipe->graph, entity);
+       media_graph_walk_start(&pipe->graph, entity);
 
-       while ((entity = media_entity_graph_walk_next(graph))) {
+       while ((entity = media_graph_walk_next(graph))) {
                DECLARE_BITMAP(active, MEDIA_ENTITY_MAX_PADS);
                DECLARE_BITMAP(has_no_links, MEDIA_ENTITY_MAX_PADS);
 
@@ -441,7 +457,7 @@ __must_check int __media_entity_pipeline_start(struct media_entity *entity,
                        ret = entity->ops->link_validate(link);
                        if (ret < 0 && ret != -ENOIOCTLCMD) {
                                dev_dbg(entity->graph_obj.mdev->dev,
-                                       "link validation failed for \"%s\":%u -> \"%s\":%u, error %d\n",
+                                       "link validation failed for '%s':%u -> '%s':%u, error %d\n",
                                        link->source->entity->name,
                                        link->source->index,
                                        entity->name, link->sink->index, ret);
@@ -455,7 +471,7 @@ __must_check int __media_entity_pipeline_start(struct media_entity *entity,
                if (!bitmap_full(active, entity->num_pads)) {
                        ret = -ENOLINK;
                        dev_dbg(entity->graph_obj.mdev->dev,
-                               "\"%s\":%u must be connected by an enabled link\n",
+                               "'%s':%u must be connected by an enabled link\n",
                                entity->name,
                                (unsigned)find_first_zero_bit(
                                        active, entity->num_pads));
@@ -470,11 +486,11 @@ error:
         * Link validation on graph failed. We revert what we did and
         * return the error.
         */
-       media_entity_graph_walk_start(graph, entity_err);
+       media_graph_walk_start(graph, entity_err);
 
-       while ((entity_err = media_entity_graph_walk_next(graph))) {
-               /* don't let the stream_count go negative */
-               if (entity->stream_count > 0) {
+       while ((entity_err = media_graph_walk_next(graph))) {
+               /* Sanity check for negative stream_count */
+               if (!WARN_ON_ONCE(entity_err->stream_count <= 0)) {
                        entity_err->stream_count--;
                        if (entity_err->stream_count == 0)
                                entity_err->pipe = NULL;
@@ -490,37 +506,37 @@ error:
 
 error_graph_walk_start:
        if (!--pipe->streaming_count)
-               media_entity_graph_walk_cleanup(graph);
+               media_graph_walk_cleanup(graph);
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(__media_entity_pipeline_start);
+EXPORT_SYMBOL_GPL(__media_pipeline_start);
 
-__must_check int media_entity_pipeline_start(struct media_entity *entity,
-                                            struct media_pipeline *pipe)
+__must_check int media_pipeline_start(struct media_entity *entity,
+                                     struct media_pipeline *pipe)
 {
        struct media_device *mdev = entity->graph_obj.mdev;
        int ret;
 
        mutex_lock(&mdev->graph_mutex);
-       ret = __media_entity_pipeline_start(entity, pipe);
+       ret = __media_pipeline_start(entity, pipe);
        mutex_unlock(&mdev->graph_mutex);
        return ret;
 }
-EXPORT_SYMBOL_GPL(media_entity_pipeline_start);
+EXPORT_SYMBOL_GPL(media_pipeline_start);
 
-void __media_entity_pipeline_stop(struct media_entity *entity)
+void __media_pipeline_stop(struct media_entity *entity)
 {
-       struct media_entity_graph *graph = &entity->pipe->graph;
+       struct media_graph *graph = &entity->pipe->graph;
        struct media_pipeline *pipe = entity->pipe;
 
 
        WARN_ON(!pipe->streaming_count);
-       media_entity_graph_walk_start(graph, entity);
+       media_graph_walk_start(graph, entity);
 
-       while ((entity = media_entity_graph_walk_next(graph))) {
-               /* don't let the stream_count go negative */
-               if (entity->stream_count > 0) {
+       while ((entity = media_graph_walk_next(graph))) {
+               /* Sanity check for negative stream_count */
+               if (!WARN_ON_ONCE(entity->stream_count <= 0)) {
                        entity->stream_count--;
                        if (entity->stream_count == 0)
                                entity->pipe = NULL;
@@ -528,20 +544,20 @@ void __media_entity_pipeline_stop(struct media_entity *entity)
        }
 
        if (!--pipe->streaming_count)
-               media_entity_graph_walk_cleanup(graph);
+               media_graph_walk_cleanup(graph);
 
 }
-EXPORT_SYMBOL_GPL(__media_entity_pipeline_stop);
+EXPORT_SYMBOL_GPL(__media_pipeline_stop);
 
-void media_entity_pipeline_stop(struct media_entity *entity)
+void media_pipeline_stop(struct media_entity *entity)
 {
        struct media_device *mdev = entity->graph_obj.mdev;
 
        mutex_lock(&mdev->graph_mutex);
-       __media_entity_pipeline_stop(entity);
+       __media_pipeline_stop(entity);
        mutex_unlock(&mdev->graph_mutex);
 }
-EXPORT_SYMBOL_GPL(media_entity_pipeline_stop);
+EXPORT_SYMBOL_GPL(media_pipeline_stop);
 
 /* -----------------------------------------------------------------------------
  * Module use count
index 99ce28442a75b389956bc43b8407f5d71cff690d..6e60decb2198b407bd963fed4925b64f767b489f 100644 (file)
@@ -157,7 +157,7 @@ static irqreturn_t flexcop_pci_isr(int irq, void *dev_id)
        if (v.irq_20c.Data_receiver_error)
                deb_chk("data receiver error\n");
        if (v.irq_20c.Continuity_error_flag)
-               deb_chk("Contunuity error flag is set\n");
+               deb_chk("Continuity error flag is set\n");
        if (v.irq_20c.LLC_SNAP_FLAG_set)
                deb_chk("LLC_SNAP_FLAG_set is set\n");
        if (v.irq_20c.Transport_Error)
index 4da720e4867e8d195ca597f2d1b79f5147662ecf..2fd07a8afcd2500d641d72031075f5aebea151e2 100644 (file)
  * but WITHOUT 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
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -424,7 +420,7 @@ int bttv_input_init(struct bttv *btv)
                return -ENODEV;
 
        ir = kzalloc(sizeof(*ir),GFP_KERNEL);
-       rc = rc_allocate_device();
+       rc = rc_allocate_device(RC_DRIVER_SCANCODE);
        if (!ir || !rc)
                goto err_out_free;
 
index 8681b9143a3521fd0457095d8d66e6eab776c566..04d06c564602566e442cd427ec7878ed87a22d98 100644 (file)
@@ -475,16 +475,14 @@ static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message
 
 static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
 {
-       int i = 0;
-
-       u32 command = 0;
+       int i;
+       u32 command;
        struct ca_msg *hw_buffer;
        int result = 0;
 
-       if ((hw_buffer = kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
-               dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
+       hw_buffer = kmalloc(sizeof(*hw_buffer), GFP_KERNEL);
+       if (!hw_buffer)
                return -ENOMEM;
-       }
        dprintk(verbose, DST_CA_DEBUG, 1, " ");
 
        if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg))) {
@@ -567,7 +565,6 @@ static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioct
        p_ca_slot_info = kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL);
        p_ca_caps = kmalloc(sizeof (struct ca_caps), GFP_KERNEL);
        if (!p_ca_message || !p_ca_slot_info || !p_ca_caps) {
-               dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
                result = -ENOMEM;
                goto free_mem_and_exit;
        }
index 6100fa71ece818274964aabf2cf268ea6f8e72a7..ad617871ce9b003940b0e06a275fb2e31aed7ff9 100644 (file)
  * 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.
- *
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -683,6 +679,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
                /*      DST is not a frontend, attaching the ASIC       */
                if (dvb_attach(dst_attach, state, &card->dvb_adapter) == NULL) {
                        pr_err("%s: Could not find a Twinhan DST\n", __func__);
+                       kfree(state);
                        break;
                }
                /*      Attach other DST peripherals if any             */
index 4499ed2ac0ed7339384663dc1b2a5f8f77d82224..0ec538e23b4e18a096e80d45eec8930a4b89761a 100644 (file)
  * 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 DVB_BT8XX_H
index 23c875fc173efd04f372e9edd4d2e80afc9ce4d0..bfcecef659e3851be0247b1b4bc81230c798337e 100644 (file)
@@ -71,9 +71,9 @@ static void cpld_info_ver3(struct cobalt *cobalt)
        cobalt_info("\t\tMAXII program revision:  0x%04x\n",
                    cpld_read(cobalt, 0x30));
        cobalt_info("CPLD temp and voltage ADT7411 registers (read only)\n");
-       cobalt_info("\t\tBoard temperature:  %u Celcius\n",
+       cobalt_info("\t\tBoard temperature:  %u Celsius\n",
                    cpld_read(cobalt, 0x34) / 4);
-       cobalt_info("\t\tFPGA temperature:   %u Celcius\n",
+       cobalt_info("\t\tFPGA temperature:   %u Celsius\n",
                    cpld_read(cobalt, 0x38) / 4);
        rd = cpld_read(cobalt, 0x3c);
        tmp = (rd * 33 * 1000) / (483 * 10);
index 9fb7f5978c8b5b14bac5854a8d5d024c4933bd60..2531e4b81b60ad9718cd8934fb726926bc8921e4 100644 (file)
  *  but WITHOUT 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
  */
 
 #include <linux/init.h>
index 284275270f1bb18d2a7b05045ab0c33919c05142..06b066bc9301a8a730ef4efba411f952a075ad5c 100644 (file)
  *  but WITHOUT 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
  */
 
 #include <linux/init.h>
index ec9238793f6f415fbf660d4b592af1e4431942e7..3aed123955dd992a08e03d181239782dd326f82f 100644 (file)
  *  but WITHOUT 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
  */
 
 int __init snd_cx18_mixer_create(struct snd_cx18_card *cxsc);
index 5344510fbea30afb97cb99229b96e1eab67e1599..205a98da877caa9db99ae21f11cf6c0c86434265 100644 (file)
  *  but WITHOUT 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
  */
 
 #include <linux/init.h>
index e2b2c5b012157feff45ea99176fd8b79ec85fe47..b9e3afe14ee0b1697bcf7026694474e15642de7b 100644 (file)
  *  but WITHOUT 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
  */
 
 int snd_cx18_pcm_create(struct snd_cx18_card *cxsc);
index 2718be28bf5f541bec384b1dbd2fc629756fc2eb..d88e3bd7944e8f20bbbcd289fe5bf32dcb370c2f 100644 (file)
  *  but WITHOUT 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
  */
 
 struct snd_card;
index 35268923911c94b88bf527bc0734941cd3617b95..61fc485d3d8015af4aaaf5d36370f4446cb1a945 100644 (file)
  *  but WITHOUT 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
  */
 
 #include "cx18-driver.h"
index 2731d29b0ab95078cb856cac4c9fb4067fa9c6c6..f65d71a04c199948cf13221b0579f0ddd920e355 100644 (file)
  *  but WITHOUT 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
  */
 
 int cx18_audio_set_io(struct cx18 *cx);
index 4a24ffb17a7d85177d9792a7c5f4eebf51e65a32..8b95e9aae576c33e85b4c83680d9872b401dfba0 100644 (file)
  *  but WITHOUT 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.
  */
 
 #include "cx18-driver.h"
index 7f7306fd9a7f73adf5254fc41cdef9ccc2bd567c..cf8817e9c8b9b7f10905c7ad1201ac73269da8d7 100644 (file)
  *  but WITHOUT 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.
  */
 
 #include "cx18-driver.h"
index 4c559e86e340b39f2727794144ca4fd55b1ac2ac..c976ce6e7a78aa2f1bccb41393e0e6bdaaab13df 100644 (file)
  *  but WITHOUT 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.
  */
 
 #ifndef _CX18_AV_CORE_H_
index 160e2e53383ffa9715f0ee260f9fc72d58d265dc..543ace7a481a4a61661e28f065d542ee1a57f8de 100644 (file)
  *  but WITHOUT 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.
  */
 
 #include "cx18-driver.h"
index 246982841fece5ac75df67c9beb08604d56f3eba..a002537a387d79864ed05d7f9098e7a685ba90d4 100644 (file)
  *  but WITHOUT 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.
  */
 
 
index 5e01ea441dc4d59d77558087bddbce11e024a7d9..11e898e66ce907f2dae812e9f87d620f55bad3da 100644 (file)
  *  but WITHOUT 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
  */
 
 #include "cx18-driver.h"
index f6b921f3b0acdda222e294592854a1ffbe352915..667e2d7b1d037c5fad4a2012d22084c7e7c40a87 100644 (file)
  *  but WITHOUT 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
  */
 
 /* hardware flags */
index 812a2507945ae27fe931453d85f193ef9898e17a..f02df985def0777be920a1f356c26365628fa6ec 100644 (file)
  *  but WITHOUT 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
  */
 #include <linux/kernel.h>
 #include <linux/slab.h>
index b8eedbe51c8f65cbebca2cd56d71c72590b9bca6..206db81ef78eb7723192adc4abfe9f6b4d87bd67 100644 (file)
  *  but WITHOUT 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
  */
 
 #include "cx18-driver.h"
index ef308a10e870c45a73b968a6da3d9b0ea3b4d56f..fef3c736fcba68c21cbb63fc5ade2e646ea13c66 100644 (file)
  *  but WITHOUT 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 CX18_DRIVER_H
index 03d0478170a7522a5a77d7418ed6de8bc81c417c..d130d65828b0b6d305c529dbc1281bfe960769e8 100644 (file)
  *  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 "cx18-version.h"
index bf8d8f6f54558ab3264dd783ad13dc9246632b40..33dfc53e3b4f6cd064da3f999de09b6299b57c7e 100644 (file)
  *  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 "cx18-driver.h"
index 78b399b8613e8952d0b517747c85e0750a0d0505..98467b2089fa8e837134d8e73fd0ccc584de4a4e 100644 (file)
  *  but WITHOUT 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
  */
 
 #include "cx18-driver.h"
index b9e5110ad04368765fbe7be12fe4dd7ea869d6d0..58b00b43370809fa3ba1a2f78bf2bf7ddf5e2f33 100644 (file)
  *  but WITHOUT 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
  */
 
 /* Testing/Debugging */
index c6c83445f8bfb93605990d6726b9d2755d0d4f24..1b34ea1c3730561c5b24d6c6283072c3cb2dafbd 100644 (file)
  *  but WITHOUT 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
  */
 
 #include "cx18-driver.h"
index 38d4c05e8499749bfcb187ecf07c41a6bf65aa09..bdc4b11f74f7c97468a71c48c646d1d5808251ed 100644 (file)
  *  but WITHOUT 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
  */
 
 int cx18_firmware_init(struct cx18 *cx);
index 38dc6b8f82546ffdf275a192dba3ff6c38cad6b9..012859e6dc7bdb7ef011011e5984c254a3145592 100644 (file)
  *  but WITHOUT 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
  */
 
 #include "cx18-driver.h"
index 4aea2ef88e8d05794e6a07e3a7ba734dc9be1048..0274a17a88372491898f614e16b6b143a15144e2 100644 (file)
  *  but WITHOUT 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
  */
 
 void cx18_gpio_init(struct cx18 *cx);
index c9329371a3f8ed867b1c1beeb335789122971849..eabdd4c5520ad36e9ed617f56d9bde6614fcaa6c 100644 (file)
  *  but WITHOUT 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
  */
 
 #include "cx18-driver.h"
index 1180fdc8d983b1b861edc635a7e9ed53463d56ee..bf315ecbe5ddf25fbc5d3f990edd57fad66e0d5d 100644 (file)
  *  but WITHOUT 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
  */
 
 int cx18_i2c_register(struct cx18 *cx, unsigned idx);
index 49b9dbd06248c53e0e0388e23e1ceb0104a45ec1..7090fdbce28f537c6299f1077a1e709afe558dab 100644 (file)
  *  but WITHOUT 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
  */
 
 #include "cx18-driver.h"
index 18974d886cf729e01d777f10a3f2226a936b397d..a3c96fb5d28d9b94c6651edd1af66dcd923cf052 100644 (file)
  *  but WITHOUT 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 CX18_IO_H
index 0faeb979ceb94e1ce413fa1c431d6605a96d12bb..80b902b12a78a97880786c0afe3143fb1db62c46 100644 (file)
  *  but WITHOUT 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
  */
 
 #include "cx18-driver.h"
index 43433969d6331271969fc84477161eada3f540e2..413129004a89bbb3978c1cbe931b10232d54fe32 100644 (file)
  *  but WITHOUT 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
  */
 
 u16 cx18_service2vbi(int type);
index 361426485e98837fece026eb4e47a10939bd4c03..ff33ffda0126c21dbffceb89bf0249c7f799592b 100644 (file)
  *  but WITHOUT 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
  */
 
 #include "cx18-driver.h"
index 30e7eaf8cb5540007446cb79f0c923caf1d21867..64496746ea46fc6a5eb3198c270d907d5b1e1986 100644 (file)
  *  but WITHOUT 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
  */
 
 #define HW2_I2C1_INT                   (1 << 22)
index d3cf3588879f5740aa16fff3f04c487182a21b66..763f960fc918bbc22e230204fd1ffe752458c320 100644 (file)
  *  but WITHOUT 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
  */
 
 #include <stdarg.h>
index b63fdfaac49ea39c01ee999c6549c303c7f6b539..54b11322bd23fb0864b6b6ea023564e4a4191a85 100644 (file)
  *  but WITHOUT 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 _CX18_MAILBOX_H_
index 13e96d6055ebf6a4da65a774e901f5dad787d0a9..d212f79fd3aab1b472864f93d71087cf512ff5d6 100644 (file)
  *  but WITHOUT 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
  */
 
 #include "cx18-driver.h"
index 4201ddc16091518b553b0ce0e94282a5e025fb4d..093b04e0189c43dbbd79e3b49be9e0425e5ac43b 100644 (file)
  *  but WITHOUT 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
  */
 
 #define CX18_DMA_UNMAPPED      ((u32) -1)
index 85cc59637e54f67fa5ef0ad975adbeef4a958b76..83a92629519d74b4e7acf9a2e89fe06bf3cd38d5 100644 (file)
  *  but WITHOUT 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
  */
 
 #include "cx18-driver.h"
index 08877652e321f8579d350effa6b0531be12f2be1..7c3eaea3021fdb2ff3a69a6b068f6663c01bb3b9 100644 (file)
  *  but WITHOUT 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 CX18_SCB_H
index 7f699f0ee76cbadf3b58045fbeae9b5a30c1b59a..7c93814489667e621f881aa039fedf656939504e 100644 (file)
  *  but WITHOUT 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
  */
 
 #include "cx18-driver.h"
index 27f8af9b11cdbdea0536ecf63655e3ba09b7a441..75c86f1b2e260b151e5d744ffa11b60361b309d7 100644 (file)
  *  but WITHOUT 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
  */
 
 u32 cx18_find_handle(struct cx18 *cx);
index 43360cbcf24b443b2d6ec4d9a73bc2cdb4bc3a69..72c74d60c6fbf6f5b711e32be144d54b7a969aaa 100644 (file)
  *  but WITHOUT 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
  */
 
 #include "cx18-driver.h"
index b365cf4b46683d7e029eafc69dd7d1406b7a7a0c..8c514ea2d2ba36f1600997a255d8af95fc695236 100644 (file)
  *  but WITHOUT 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
  */
 
 void cx18_process_vbi_data(struct cx18 *cx, struct cx18_mdl *mdl,
index fed48b6bb67b622b981532be129a5834ecdd8547..50728c68b83551fe82a9562cea590c5e69ead6eb 100644 (file)
  *  but WITHOUT 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 CX18_VERSION_H
index 6dc84aac8f4421eda5b4c53ac01f3c7e11eb3743..697d01168b63c381e9590f0eb0ad23201746434d 100644 (file)
  *  but WITHOUT 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
  */
 
 #include "cx18-driver.h"
index 529006a06e5cf6d95625ac194e3c0c89d6497f6b..f6eca36e72717f13d3f3db8d5fb25589523995bd 100644 (file)
  *  but WITHOUT 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
  */
 
 void cx18_video_set_io(struct cx18 *cx);
index 67ffe65b56a35fdcb64776c417195d806a3603fc..901ed7fac10f00855ab214f80bfa3920561de56b 100644 (file)
  *  but WITHOUT 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 CX23418_H
index 589a168d1df4581c1481cb5d389d888e1de570b2..979b66627f60faeaef4683eaf2bddd825277d881 100644 (file)
@@ -920,19 +920,6 @@ static const struct m88ds3103_config dvbsky_s950c_m88ds3103_config = {
        .agc = 0x99,
 };
 
-static const struct m88ds3103_config dvbsky_s952_portc_m88ds3103_config = {
-       .i2c_addr = 0x68,
-       .clock = 27000000,
-       .i2c_wr_max = 33,
-       .clock_out = 0,
-       .ts_mode = M88DS3103_TS_SERIAL,
-       .ts_clk = 96000,
-       .ts_clk_pol = 0,
-       .lnb_en_pol = 1,
-       .lnb_hv_pol = 0,
-       .agc = 0x99,
-};
-
 static const struct m88ds3103_config hauppauge_hvr5525_m88ds3103_config = {
        .i2c_addr = 0x69,
        .clock = 27000000,
@@ -1206,11 +1193,11 @@ static int dvb_register(struct cx23885_tsport *port)
        struct si2165_platform_data si2165_pdata;
        struct si2157_config si2157_config;
        struct ts2020_config ts2020_config;
+       struct m88ds3103_platform_data m88ds3103_pdata;
        struct i2c_board_info info;
        struct i2c_adapter *adapter;
        struct i2c_client *client_demod = NULL, *client_tuner = NULL;
        struct i2c_client *client_sec = NULL;
-       const struct m88ds3103_config *p_m88ds3103_config = NULL;
        int (*p_set_voltage)(struct dvb_frontend *fe,
                             enum fe_sec_voltage voltage) = NULL;
        int mfe_shared = 0; /* bus not shared by default */
@@ -2103,27 +2090,50 @@ static int dvb_register(struct cx23885_tsport *port)
                port->i2c_client_tuner = client_tuner;
                break;
        case CX23885_BOARD_DVBSKY_S952:
+               /* attach frontend */
+               memset(&m88ds3103_pdata, 0, sizeof(m88ds3103_pdata));
+               m88ds3103_pdata.clk = 27000000;
+               m88ds3103_pdata.i2c_wr_max = 33;
+               m88ds3103_pdata.agc = 0x99;
+               m88ds3103_pdata.clk_out = M88DS3103_CLOCK_OUT_DISABLED;
+               m88ds3103_pdata.lnb_en_pol = 1;
+
                switch (port->nr) {
                /* port b */
                case 1:
                        i2c_bus = &dev->i2c_bus[1];
-                       p_m88ds3103_config = &dvbsky_t9580_m88ds3103_config;
+                       m88ds3103_pdata.ts_mode = M88DS3103_TS_PARALLEL;
+                       m88ds3103_pdata.ts_clk = 16000;
+                       m88ds3103_pdata.ts_clk_pol = 1;
                        p_set_voltage = dvbsky_t9580_set_voltage;
                        break;
                /* port c */
                case 2:
                        i2c_bus = &dev->i2c_bus[0];
-                       p_m88ds3103_config = &dvbsky_s952_portc_m88ds3103_config;
+                       m88ds3103_pdata.ts_mode = M88DS3103_TS_SERIAL;
+                       m88ds3103_pdata.ts_clk = 96000;
+                       m88ds3103_pdata.ts_clk_pol = 0;
                        p_set_voltage = dvbsky_s952_portc_set_voltage;
                        break;
+               default:
+                       return 0;
                }
 
-               /* attach frontend */
-               fe0->dvb.frontend = dvb_attach(m88ds3103_attach,
-                               p_m88ds3103_config,
-                               &i2c_bus->i2c_adap, &adapter);
-               if (fe0->dvb.frontend == NULL)
-                       break;
+               memset(&info, 0, sizeof(info));
+               strlcpy(info.type, "m88ds3103", I2C_NAME_SIZE);
+               info.addr = 0x68;
+               info.platform_data = &m88ds3103_pdata;
+               request_module(info.type);
+               client_demod = i2c_new_device(&i2c_bus->i2c_adap, &info);
+               if (client_demod == NULL || client_demod->dev.driver == NULL)
+                       goto frontend_detach;
+               if (!try_module_get(client_demod->dev.driver->owner)) {
+                       i2c_unregister_device(client_demod);
+                       goto frontend_detach;
+               }
+               port->i2c_client_demod = client_demod;
+               adapter = m88ds3103_pdata.get_i2c_adapter(client_demod);
+               fe0->dvb.frontend = m88ds3103_pdata.get_dvb_frontend(client_demod);
 
                /* attach tuner */
                memset(&ts2020_config, 0, sizeof(ts2020_config));
index 1f092febdbd18fead84f8569787c28d96750f6e3..4367cb3162b659e9018ece20c39ba51979a321d2 100644 (file)
@@ -267,7 +267,6 @@ int cx23885_input_init(struct cx23885_dev *dev)
        struct cx23885_kernel_ir *kernel_ir;
        struct rc_dev *rc;
        char *rc_map;
-       enum rc_driver_type driver_type;
        u64 allowed_protos;
 
        int ret;
@@ -285,37 +284,32 @@ int cx23885_input_init(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1290:
        case CX23885_BOARD_HAUPPAUGE_HVR1250:
                /* Integrated CX2388[58] IR controller */
-               driver_type = RC_DRIVER_IR_RAW;
-               allowed_protos = RC_BIT_ALL;
+               allowed_protos = RC_BIT_ALL_IR_DECODER;
                /* The grey Hauppauge RC-5 remote */
                rc_map = RC_MAP_HAUPPAUGE;
                break;
        case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
                /* Integrated CX23885 IR controller */
-               driver_type = RC_DRIVER_IR_RAW;
-               allowed_protos = RC_BIT_ALL;
+               allowed_protos = RC_BIT_ALL_IR_DECODER;
                /* The grey Terratec remote with orange buttons */
                rc_map = RC_MAP_NEC_TERRATEC_CINERGY_XS;
                break;
        case CX23885_BOARD_TEVII_S470:
                /* Integrated CX23885 IR controller */
-               driver_type = RC_DRIVER_IR_RAW;
-               allowed_protos = RC_BIT_ALL;
+               allowed_protos = RC_BIT_ALL_IR_DECODER;
                /* A guess at the remote */
                rc_map = RC_MAP_TEVII_NEC;
                break;
        case CX23885_BOARD_MYGICA_X8507:
                /* Integrated CX23885 IR controller */
-               driver_type = RC_DRIVER_IR_RAW;
-               allowed_protos = RC_BIT_ALL;
+               allowed_protos = RC_BIT_ALL_IR_DECODER;
                /* A guess at the remote */
                rc_map = RC_MAP_TOTAL_MEDIA_IN_HAND_02;
                break;
        case CX23885_BOARD_TBS_6980:
        case CX23885_BOARD_TBS_6981:
                /* Integrated CX23885 IR controller */
-               driver_type = RC_DRIVER_IR_RAW;
-               allowed_protos = RC_BIT_ALL;
+               allowed_protos = RC_BIT_ALL_IR_DECODER;
                /* A guess at the remote */
                rc_map = RC_MAP_TBS_NEC;
                break;
@@ -326,14 +320,12 @@ int cx23885_input_init(struct cx23885_dev *dev)
        case CX23885_BOARD_DVBSKY_S952:
        case CX23885_BOARD_DVBSKY_T982:
                /* Integrated CX23885 IR controller */
-               driver_type = RC_DRIVER_IR_RAW;
-               allowed_protos = RC_BIT_ALL;
+               allowed_protos = RC_BIT_ALL_IR_DECODER;
                rc_map = RC_MAP_DVBSKY;
                break;
        case CX23885_BOARD_TT_CT2_4500_CI:
                /* Integrated CX23885 IR controller */
-               driver_type = RC_DRIVER_IR_RAW;
-               allowed_protos = RC_BIT_ALL;
+               allowed_protos = RC_BIT_ALL_IR_DECODER;
                rc_map = RC_MAP_TT_1500;
                break;
        default:
@@ -352,7 +344,7 @@ int cx23885_input_init(struct cx23885_dev *dev)
                                    pci_name(dev->pci));
 
        /* input device */
-       rc = rc_allocate_device();
+       rc = rc_allocate_device(RC_DRIVER_IR_RAW);
        if (!rc) {
                ret = -ENOMEM;
                goto err_out_free;
@@ -371,7 +363,6 @@ int cx23885_input_init(struct cx23885_dev *dev)
                rc->input_id.product = dev->pci->device;
        }
        rc->dev.parent = &dev->pci->dev;
-       rc->driver_type = driver_type;
        rc->allowed_protocols = allowed_protos;
        rc->priv = kernel_ir;
        rc->open = cx23885_input_ir_open;
index 4711583de8fe5325312cfb757f7c624cc27b11e0..519b81c0c8378fd02733b7bd897a00f8a780148e 100644 (file)
  *   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
- *
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 7c8edb6181ec888d233faa96eb59187d832aa310..b94eb1c0023d810c9ed7fcb50b9c88d4b222b5fe 100644 (file)
  *  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.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index af2ae7c5815a68cba3c79fa9e1aebd22e98578bc..2bc875d1ec9fafe536f500b377512b2cac889c50 100644 (file)
  *  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/mutex.h>
index 1fc2d24f5110ac400e80f94ec5112ba4f0bc42c7..55df64091539367aaec3ba231aa8a4ae744e8ab9 100644 (file)
  *  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 __CX25821_AUDIO_H__
index 937f5a70fb7a8d8d032759a937ca889a45f11f64..7c0ada3e382dc6e99496bb9072f6ca5f8bab2c8e 100644 (file)
  *  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 _BITFUNCS_H
index f2ebc989b30338b943e1406780a61a219db7c7fc..f3b4d89d90c8543a7da081c34ae26d8d29aa1ae7 100644 (file)
  *  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.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 9a5f912ca859a6951fb78bb3cf125eeeea4dfa4b..fbc0229183bde435df926fb388a4541c6372935f 100644 (file)
  *  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.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 95e8ddf629472afe938177a1be93bebf297d886a..76b8f619e55a5b423d0e31b7ba832ac6f67d6741 100644 (file)
  *  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/module.h>
index 63ba25b826929ca9b91f7fab99fae849252f47a6..263a1cf36ef1c8370bd33a0b5332ea2f0f812c82 100644 (file)
  *  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.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 7a9e6470ba227db92d2a26fc89c83388fa6c3d89..36977090ec4c10ac0408208d234aea45f75a73b8 100644 (file)
  *  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 _MEDUSA_DEF_H_
index 2e10643a86b7fb218b97beb274377796915e912a..6ef63b86787962668f9adf5bbad199910cd887d3 100644 (file)
  *  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 __MEDUSA_REGISTERS__
index 43bdfa4dfba11c54ecfdffc98a0ce07c77b070b7..0a9db050b1756d5c0988e5297dbc01aaf1f66ab5 100644 (file)
  *  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.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 8bf602ff27b1049e9bee6f0495ce205a4d753822..176b35333f2b631fe132ac23ed0a0f5a467183e2 100644 (file)
  *  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 _MEDUSA_VIDEO_H
index a3fc25a4dc0bcfeb5699af9184bd12877851d882..061cdeb9b45b7cef50169e9a0452f2a0ffe7e5cb 100644 (file)
  *  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 __CX25821_REGISTERS__
index 5f05d153bc4d5dc49d57fb800b5ab5511e5ce164..b94e0d4df6645341126fc9cb9d9bfdaac667cf3b 100644 (file)
  *  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 __ATHENA_SRAM_H__
index a664997e1958dccdba7fbf6315d1d5b4606ca084..6c838c8a7924f7c067e986b98d264b801426eadc 100644 (file)
  *  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.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 268ec8aa6a6142844bedbb71aededb1be7a4f097..b6cf95f2d11bac6f089b4e1ce4a4fa4edec6404b 100644 (file)
  *  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/mutex.h>
index 7ce352a0f2d3af7dedee47239d792b669a986457..dbaf42ec26cd8efd4076a53419262fc0855f12fc 100644 (file)
  *  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.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index ab63b3858acf14b1853078903fc9af91e25444a0..246011c1ba084dd343c81d8424aa270e309a683c 100644 (file)
  *  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 CX25821_VIDEO_H_
index ef61dea982e8f864cde03d1ac114ea2879d8b032..0f20e89b0cdeda5aca1917cb6bce67f5aff9dc8a 100644 (file)
  *  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 CX25821_H_
index c7b3cb406499b0b7d0319f64cc0891e03bcd485a..01f2e472a2a09c9ba0bfd8b0d5bdb61f218c343f 100644 (file)
@@ -274,7 +274,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
                                 */
 
        ir = kzalloc(sizeof(*ir), GFP_KERNEL);
-       dev = rc_allocate_device();
+       dev = rc_allocate_device(RC_DRIVER_IR_RAW);
        if (!ir || !dev)
                goto err_out_free;
 
@@ -484,7 +484,6 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
        dev->scancode_mask = hardware_mask;
 
        if (ir->sampling) {
-               dev->driver_type = RC_DRIVER_IR_RAW;
                dev->timeout = 10 * 1000 * 1000; /* 10 ms */
        } else {
                dev->driver_type = RC_DRIVER_SCANCODE;
index a6c9fe235974a81dd9f761182a1948d09a95ad1e..340cff02dee250b8c565517f83e7262b4f433cfb 100644 (file)
  * 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
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  */
 
 #include <linux/module.h>
index a3ccb318b500055b4506707e5b19aed74a511e76..6ae810324b4e6df83d232c6ea29cda50704e3101 100644 (file)
  * 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
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  */
 
 /* DD-DVBBridgeV1.h 273 2010-09-17 05:03:16Z manfred */
index be87fbd9045646214f61aeda2f573ba1e62b1462..185b423818d38376028d9d0b79a5f6ebf6c21be2 100644 (file)
  * 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
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  */
 
 #ifndef _DDBRIDGE_H_
index 173daf0c084703419674b050c1872a077855a1b2..14fa7e40f2a62c744050901d6d8f98e900104d99 100644 (file)
@@ -1,6 +1,6 @@
 config DVB_DM1105
        tristate "SDMC DM1105 based PCI cards"
-       depends on DVB_CORE && PCI && I2C
+       depends on DVB_CORE && PCI && I2C && I2C_ALGOBIT
        select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
        select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
        select DVB_STV0288 if MEDIA_SUBDRV_AUTOSELECT
index a589aa78d1d98deed94e38b98deacb080d8b0e3a..a7724b78fbb463e9be1cef92eb55cd31f96eaba8 100644 (file)
  * 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/i2c.h>
@@ -743,7 +739,7 @@ static int dm1105_ir_init(struct dm1105_dev *dm1105)
        struct rc_dev *dev;
        int err = -ENOMEM;
 
-       dev = rc_allocate_device();
+       dev = rc_allocate_device(RC_DRIVER_SCANCODE);
        if (!dev)
                return -ENOMEM;
 
@@ -752,7 +748,6 @@ static int dm1105_ir_init(struct dm1105_dev *dm1105)
 
        dev->driver_name = MODULE_NAME;
        dev->map_name = RC_MAP_DM1105_NEC;
-       dev->driver_type = RC_DRIVER_SCANCODE;
        dev->input_name = "DVB on-card IR receiver";
        dev->input_phys = dm1105->ir.input_phys;
        dev->input_id.bustype = BUS_PCI;
index 6e5867c57305253227096b3e9715bc92b4c761bd..c72cbbd2d40c601024cbef73d5cf4031e968cf70 100644 (file)
@@ -28,6 +28,19 @@ config VIDEO_IVTV
          To compile this driver as a module, choose M here: the
          module will be called ivtv.
 
+config VIDEO_IVTV_DEPRECATED_IOCTLS
+       bool "enable the DVB ioctls abuse on ivtv driver"
+       depends on VIDEO_IVTV
+       default n
+       ---help---
+         Enable the usage of the a DVB set of ioctls that were abused by
+         IVTV driver for a while.
+
+         Those ioctls were not needed for a long time, as IVTV implements
+         the proper V4L2 ioctls since kernel 3.3.
+
+         If unsure, say N.
+
 config VIDEO_IVTV_ALSA
        tristate "Conexant cx23415/cx23416 ALSA interface for PCM audio capture"
        depends on VIDEO_IVTV && SND
index 374f45f81ab300cb9a4ec4bcaf5eb09fe992e515..029f52733f70330bd3316ec7885b789403498012 100644 (file)
  *  but WITHOUT 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
  */
 
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/spinlock.h>
-
-#include <media/v4l2-device.h>
-
-#include <sound/core.h>
-#include <sound/initval.h>
-
 #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>
+#include <sound/initval.h>
+
 int ivtv_alsa_debug;
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
 
-#define IVTV_DEBUG_ALSA_INFO(fmt, arg...) \
+#define IVTV_DEBUG_ALSA_INFO(__fmt, __arg...) \
        do { \
                if (ivtv_alsa_debug & 2) \
-                       pr_info("%s: " fmt, "ivtv-alsa", ## arg); \
+                       printk(KERN_INFO pr_fmt("%s: alsa:" __fmt),     \
+                              __func__, ##__arg);                      \
        } while (0)
 
 module_param_named(debug, ivtv_alsa_debug, int, 0644);
@@ -235,8 +222,7 @@ static int ivtv_alsa_load(struct ivtv *itv)
 
        s = &itv->streams[IVTV_ENC_STREAM_TYPE_PCM];
        if (s->vdev.v4l2_dev == NULL) {
-               IVTV_DEBUG_ALSA_INFO("%s: PCM stream for card is disabled - skipping\n",
-                                    __func__);
+               IVTV_DEBUG_ALSA_INFO("PCM stream for card is disabled - skipping\n");
                return 0;
        }
 
@@ -250,8 +236,7 @@ static int ivtv_alsa_load(struct ivtv *itv)
                IVTV_ALSA_ERR("%s: failed to create struct snd_ivtv_card\n",
                              __func__);
        } else {
-               IVTV_DEBUG_ALSA_INFO("%s: created ivtv ALSA interface instance \n",
-                                    __func__);
+               IVTV_DEBUG_ALSA_INFO("created ivtv ALSA interface instance\n");
        }
        return 0;
 }
index 79b24bde4a39a6527008ca414e8a26c02eebd5c4..ba372a23eb5c0538273a349ba8f75ec9c34e539b 100644 (file)
  *  but WITHOUT 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
  */
 
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/spinlock.h>
-#include <linux/videodev2.h>
+#include "ivtv-alsa.h"
+#include "ivtv-alsa-mixer.h"
+#include "ivtv-driver.h"
 
-#include <media/v4l2-device.h>
+#include <linux/videodev2.h>
 
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/tlv.h>
 
-#include "ivtv-alsa.h"
-#include "ivtv-driver.h"
-
 /*
  * Note the cx25840-core volume scale is funny, due to the alignment of the
  * scale with another chip's range:
index cdde36704d53e1822264caf0637cb15e699a63ab..382bc36bc529534064f9d2e4cb84f45da0868ca1 100644 (file)
  *  but WITHOUT 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
  */
 
 int __init snd_ivtv_mixer_create(struct snd_ivtv_card *itvsc);
index a26f9800eca34e55e88436edc0ea93a57e4b2cff..807ead20d212f559072e49673cdeb1c6492c8dcb 100644 (file)
  *  but WITHOUT 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
  */
 
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/vmalloc.h>
-
-#include <media/v4l2-device.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-
 #include "ivtv-driver.h"
 #include "ivtv-queue.h"
 #include "ivtv-streams.h"
 #include "ivtv-alsa.h"
 #include "ivtv-alsa-pcm.h"
 
+#include <linux/vmalloc.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+
+
 static unsigned int pcm_debug;
 module_param(pcm_debug, int, 0644);
 MODULE_PARM_DESC(pcm_debug, "enable debug messages for pcm");
@@ -174,6 +166,7 @@ static int snd_ivtv_pcm_capture_open(struct snd_pcm_substream *substream)
        /* See if the stream is available */
        if (ivtv_claim_stream(&item, item.type)) {
                /* No, it's already in use */
+               v4l2_fh_exit(&item.fh);
                snd_ivtv_unlock(itvsc);
                return -EBUSY;
        }
index 186814e0b2d4d1a19dcebdf0f42d79ca024bd5fb..147586a886fc988b140f87cdbb24a72075f48d16 100644 (file)
  *  but WITHOUT 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
  */
 
 int snd_ivtv_pcm_create(struct snd_ivtv_card *itvsc);
index 4a0d8f2c254deca6e740a599b6af19245bbd32d9..eae6462233674e481960a9fea31e251309860470 100644 (file)
  *  but WITHOUT 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
  */
 
 struct snd_card;
index 0a3b80a4bd69d69e0b967156d42d3148a2e22729..ab2ae53618e829e926a78162d146aa91766762ef 100644 (file)
@@ -1452,7 +1452,7 @@ static void ivtv_remove(struct pci_dev *pdev)
        for (i = 0; i < IVTV_VBI_FRAMES; i++)
                kfree(itv->vbi.sliced_mpeg_data[i]);
 
-       printk(KERN_INFO "ivtv: Removed %s\n", itv->card_name);
+       pr_info("Removed %s\n", itv->card_name);
 
        v4l2_device_unregister(&itv->v4l2_dev);
        kfree(itv);
@@ -1468,25 +1468,25 @@ static struct pci_driver ivtv_pci_driver = {
 
 static int __init module_start(void)
 {
-       printk(KERN_INFO "ivtv: Start initialization, version %s\n", IVTV_VERSION);
+       pr_info("Start initialization, version %s\n", IVTV_VERSION);
 
        /* Validate parameters */
        if (ivtv_first_minor < 0 || ivtv_first_minor >= IVTV_MAX_CARDS) {
-               printk(KERN_ERR "ivtv: Exiting, ivtv_first_minor must be between 0 and %d\n",
+               pr_err("Exiting, ivtv_first_minor must be between 0 and %d\n",
                     IVTV_MAX_CARDS - 1);
                return -1;
        }
 
        if (ivtv_debug < 0 || ivtv_debug > 2047) {
                ivtv_debug = 0;
-               printk(KERN_INFO "ivtv: Debug value must be >= 0 and <= 2047\n");
+               pr_info("Debug value must be >= 0 and <= 2047\n");
        }
 
        if (pci_register_driver(&ivtv_pci_driver)) {
-               printk(KERN_ERR "ivtv: Error detecting PCI card\n");
+               pr_err("Error detecting PCI card\n");
                return -ENODEV;
        }
-       printk(KERN_INFO "ivtv: End initialization\n");
+       pr_info("End initialization\n");
        return 0;
 }
 
index 6b09a9514d649925028ed6af3358532f109c5218..cde452e30746793dd781de9c392e42d6e2421973 100644 (file)
@@ -22,6 +22,8 @@
 #ifndef IVTV_DRIVER_H
 #define IVTV_DRIVER_H
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 /* Internal header for ivtv project:
  * Driver for the cx23415/6 chip.
  * Author: Kevin Thayer (nufan_wfk at yahoo.com)
  *                using information provided by Jiun-Kuei Jung @ AVerMedia.
  */
 
-#include <linux/module.h>
-#include <linux/init.h>
+#include <asm/byteorder.h>
 #include <linux/delay.h>
-#include <linux/sched.h>
+#include <linux/device.h>
 #include <linux/fs.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ivtv.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
 #include <linux/list.h>
-#include <linux/unistd.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/pagemap.h>
+#include <linux/pci.h>
 #include <linux/scatterlist.h>
-#include <linux/kthread.h>
-#include <linux/mutex.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/spinlock.h>
 #include <linux/uaccess.h>
-#include <asm/byteorder.h>
+#include <linux/unistd.h>
 
-#include <linux/dvb/video.h>
-#include <linux/dvb/audio.h>
+#include <media/drv-intf/cx2341x.h>
+#include <media/i2c/ir-kbd-i2c.h>
+#include <media/tuner.h>
 #include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-fh.h>
-#include <media/tuner.h>
-#include <media/drv-intf/cx2341x.h>
-#include <media/i2c/ir-kbd-i2c.h>
-
-#include <linux/ivtv.h>
+#include <media/v4l2-ioctl.h>
 
 /* Memory layout */
 #define IVTV_ENCODER_OFFSET    0x00000000
index 2dc4b20f3ac0a80773167a6a8ef52d5a042581c5..f956188f7f196699d4279a66a2a0c55b1a683e1b 100644 (file)
 #include <media/i2c/saa7127.h>
 #include <media/tveeprom.h>
 #include <media/v4l2-event.h>
+#ifdef CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS
 #include <linux/dvb/audio.h>
+#include <linux/dvb/video.h>
+#endif
 
 u16 ivtv_service2vbi(int type)
 {
@@ -1620,13 +1623,23 @@ static int ivtv_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder
        return ivtv_video_command(itv, id, dec, true);
 }
 
+#ifdef CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS
+static __inline__ void warn_deprecated_ioctl(const char *name)
+{
+       pr_warn_once("warning: the %s ioctl is deprecated. Don't use it, as it will be removed soon\n",
+                    name);
+}
+#endif
+
 static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
 {
        struct ivtv_open_id *id = fh2id(filp->private_data);
        struct ivtv *itv = id->itv;
-       int nonblocking = filp->f_flags & O_NONBLOCK;
        struct ivtv_stream *s = &itv->streams[id->type];
+#ifdef CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS
+       int nonblocking = filp->f_flags & O_NONBLOCK;
        unsigned long iarg = (unsigned long)arg;
+#endif
 
        switch (cmd) {
        case IVTV_IOC_DMA_FRAME: {
@@ -1658,12 +1671,12 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
                if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
                        return -EINVAL;
                return ivtv_passthrough_mode(itv, *(int *)arg != 0);
-
+#ifdef CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS
        case VIDEO_GET_PTS: {
                s64 *pts = arg;
                s64 frame;
 
-               IVTV_DEBUG_IOCTL("VIDEO_GET_PTS\n");
+               warn_deprecated_ioctl("VIDEO_GET_PTS");
                if (s->type < IVTV_DEC_STREAM_TYPE_MPG) {
                        *pts = s->dma_pts;
                        break;
@@ -1677,7 +1690,7 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
                s64 *frame = arg;
                s64 pts;
 
-               IVTV_DEBUG_IOCTL("VIDEO_GET_FRAME_COUNT\n");
+               warn_deprecated_ioctl("VIDEO_GET_FRAME_COUNT");
                if (s->type < IVTV_DEC_STREAM_TYPE_MPG) {
                        *frame = 0;
                        break;
@@ -1690,7 +1703,7 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
        case VIDEO_PLAY: {
                struct v4l2_decoder_cmd dc;
 
-               IVTV_DEBUG_IOCTL("VIDEO_PLAY\n");
+               warn_deprecated_ioctl("VIDEO_PLAY");
                memset(&dc, 0, sizeof(dc));
                dc.cmd = V4L2_DEC_CMD_START;
                return ivtv_video_command(itv, id, &dc, 0);
@@ -1699,7 +1712,7 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
        case VIDEO_STOP: {
                struct v4l2_decoder_cmd dc;
 
-               IVTV_DEBUG_IOCTL("VIDEO_STOP\n");
+               warn_deprecated_ioctl("VIDEO_STOP");
                memset(&dc, 0, sizeof(dc));
                dc.cmd = V4L2_DEC_CMD_STOP;
                dc.flags = V4L2_DEC_CMD_STOP_TO_BLACK | V4L2_DEC_CMD_STOP_IMMEDIATELY;
@@ -1709,7 +1722,7 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
        case VIDEO_FREEZE: {
                struct v4l2_decoder_cmd dc;
 
-               IVTV_DEBUG_IOCTL("VIDEO_FREEZE\n");
+               warn_deprecated_ioctl("VIDEO_FREEZE");
                memset(&dc, 0, sizeof(dc));
                dc.cmd = V4L2_DEC_CMD_PAUSE;
                return ivtv_video_command(itv, id, &dc, 0);
@@ -1718,7 +1731,7 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
        case VIDEO_CONTINUE: {
                struct v4l2_decoder_cmd dc;
 
-               IVTV_DEBUG_IOCTL("VIDEO_CONTINUE\n");
+               warn_deprecated_ioctl("VIDEO_CONTINUE");
                memset(&dc, 0, sizeof(dc));
                dc.cmd = V4L2_DEC_CMD_RESUME;
                return ivtv_video_command(itv, id, &dc, 0);
@@ -1732,9 +1745,9 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
                int try = (cmd == VIDEO_TRY_COMMAND);
 
                if (try)
-                       IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND %d\n", dc->cmd);
+                       warn_deprecated_ioctl("VIDEO_TRY_COMMAND");
                else
-                       IVTV_DEBUG_IOCTL("VIDEO_COMMAND %d\n", dc->cmd);
+                       warn_deprecated_ioctl("VIDEO_COMMAND");
                return ivtv_video_command(itv, id, dc, try);
        }
 
@@ -1742,7 +1755,7 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
                struct video_event *ev = arg;
                DEFINE_WAIT(wait);
 
-               IVTV_DEBUG_IOCTL("VIDEO_GET_EVENT\n");
+               warn_deprecated_ioctl("VIDEO_GET_EVENT");
                if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
                        return -EINVAL;
                memset(ev, 0, sizeof(*ev));
@@ -1785,28 +1798,28 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
        }
 
        case VIDEO_SELECT_SOURCE:
-               IVTV_DEBUG_IOCTL("VIDEO_SELECT_SOURCE\n");
+               warn_deprecated_ioctl("VIDEO_SELECT_SOURCE");
                if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
                        return -EINVAL;
                return ivtv_passthrough_mode(itv, iarg == VIDEO_SOURCE_DEMUX);
 
        case AUDIO_SET_MUTE:
-               IVTV_DEBUG_IOCTL("AUDIO_SET_MUTE\n");
+               warn_deprecated_ioctl("AUDIO_SET_MUTE");
                itv->speed_mute_audio = iarg;
                return 0;
 
        case AUDIO_CHANNEL_SELECT:
-               IVTV_DEBUG_IOCTL("AUDIO_CHANNEL_SELECT\n");
+               warn_deprecated_ioctl("AUDIO_CHANNEL_SELECT");
                if (iarg > AUDIO_STEREO_SWAPPED)
                        return -EINVAL;
                return v4l2_ctrl_s_ctrl(itv->ctrl_audio_playback, iarg + 1);
 
        case AUDIO_BILINGUAL_CHANNEL_SELECT:
-               IVTV_DEBUG_IOCTL("AUDIO_BILINGUAL_CHANNEL_SELECT\n");
+               warn_deprecated_ioctl("AUDIO_BILINGUAL_CHANNEL_SELECT");
                if (iarg > AUDIO_STEREO_SWAPPED)
                        return -EINVAL;
                return v4l2_ctrl_s_ctrl(itv->ctrl_audio_multilingual_playback, iarg + 1);
-
+#endif
        default:
                return -EINVAL;
        }
@@ -1821,6 +1834,7 @@ static long ivtv_default(struct file *file, void *fh, bool valid_prio,
        if (!valid_prio) {
                switch (cmd) {
                case IVTV_IOC_PASSTHROUGH_MODE:
+#ifdef CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS
                case VIDEO_PLAY:
                case VIDEO_STOP:
                case VIDEO_FREEZE:
@@ -1830,6 +1844,7 @@ static long ivtv_default(struct file *file, void *fh, bool valid_prio,
                case AUDIO_SET_MUTE:
                case AUDIO_CHANNEL_SELECT:
                case AUDIO_BILINGUAL_CHANNEL_SELECT:
+#endif
                        return -EBUSY;
                }
        }
@@ -1847,6 +1862,7 @@ static long ivtv_default(struct file *file, void *fh, bool valid_prio,
 
        case IVTV_IOC_DMA_FRAME:
        case IVTV_IOC_PASSTHROUGH_MODE:
+#ifdef CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS
        case VIDEO_GET_PTS:
        case VIDEO_GET_FRAME_COUNT:
        case VIDEO_GET_EVENT:
@@ -1860,6 +1876,7 @@ static long ivtv_default(struct file *file, void *fh, bool valid_prio,
        case AUDIO_SET_MUTE:
        case AUDIO_CHANNEL_SELECT:
        case AUDIO_BILINGUAL_CHANNEL_SELECT:
+#endif
                return ivtv_decoder_ioctls(file, cmd, (void *)arg);
 
        default:
index e3ce967637853d906756009cce321c930c2f82c9..9a2506a5edbebaaa58182ae345462121923ca92a 100644 (file)
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <stdarg.h>
-
 #include "ivtv-driver.h"
 #include "ivtv-mailbox.h"
 
+#include <stdarg.h>
+
 /* Firmware mailbox flags*/
 #define IVTV_MBOX_FIRMWARE_DONE 0x00000004
 #define IVTV_MBOX_DRIVER_DONE   0x00000002
index 612a8402cf4d66efe50e6a103a604abd64ad2f8e..621b2f613d818dbc7ae8f9ddf9fa3310010aaabb 100644 (file)
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include "ivtv-driver.h"
+#include "ivtv-cards.h"
+#include "ivtv-i2c.h"
+#include "ivtv-udma.h"
+#include "ivtv-mailbox.h"
+#include "ivtv-firmware.h"
 
-#include <linux/module.h>
-#include <linux/kernel.h>
 #include <linux/fb.h>
 #include <linux/ivtvfb.h>
-#include <linux/slab.h>
 
 #ifdef CONFIG_X86_64
 #include <asm/pat.h>
 #endif
 
-#include "ivtv-driver.h"
-#include "ivtv-cards.h"
-#include "ivtv-i2c.h"
-#include "ivtv-udma.h"
-#include "ivtv-mailbox.h"
-#include "ivtv-firmware.h"
-
 /* card parameters */
 static int ivtvfb_card_id = -1;
 static int ivtvfb_debug = 0;
@@ -1275,7 +1270,7 @@ static int __init ivtvfb_init(void)
 
 
        if (ivtvfb_card_id < -1 || ivtvfb_card_id >= IVTV_MAX_CARDS) {
-               printk(KERN_ERR "ivtvfb:  ivtvfb_card_id parameter is out of range (valid range: -1 - %d)\n",
+               pr_err("ivtvfb_card_id parameter is out of range (valid range: -1 - %d)\n",
                     IVTV_MAX_CARDS - 1);
                return -EINVAL;
        }
@@ -1284,7 +1279,7 @@ static int __init ivtvfb_init(void)
        err = driver_for_each_device(drv, NULL, &registered, ivtvfb_callback_init);
        (void)err;      /* suppress compiler warning */
        if (!registered) {
-               printk(KERN_ERR "ivtvfb:  no cards found\n");
+               pr_err("no cards found\n");
                return -ENODEV;
        }
        return 0;
@@ -1295,7 +1290,7 @@ static void ivtvfb_cleanup(void)
        struct device_driver *drv;
        int err;
 
-       printk(KERN_INFO "ivtvfb:  Unloading framebuffer module\n");
+       pr_info("Unloading framebuffer module\n");
 
        drv = driver_find("ivtv", &pci_bus_type);
        err = driver_for_each_device(drv, NULL, NULL, ivtvfb_callback_cleanup);
index 5a71e1791cf5a00ab1d198520c380cf7a44c1890..0db4de3a228522089de86ec2a5ce7314fde64b37 100644 (file)
@@ -226,11 +226,12 @@ int mantis_dvb_init(struct mantis_pci *mantis)
                        goto err5;
                } else {
                        if (mantis->fe == NULL) {
+                               result = -ENOMEM;
                                dprintk(MANTIS_ERROR, 1, "FE <NULL>");
                                goto err5;
                        }
-
-                       if (dvb_register_frontend(&mantis->dvb_adapter, mantis->fe)) {
+                       result = dvb_register_frontend(&mantis->dvb_adapter, mantis->fe);
+                       if (result) {
                                dprintk(MANTIS_ERROR, 1, "ERROR: Frontend registration failed");
 
                                if (mantis->fe->ops.release)
index 7f7f1d4d7bb1a98984ae03691a20c1d95445bc5e..50d10cb7d49de0fd5222fdf28d55fd3839440f09 100644 (file)
@@ -39,7 +39,7 @@ int mantis_input_init(struct mantis_pci *mantis)
        struct rc_dev *dev;
        int err;
 
-       dev = rc_allocate_device();
+       dev = rc_allocate_device(RC_DRIVER_SCANCODE);
        if (!dev) {
                dprintk(MANTIS_ERROR, 1, "Remote device allocation failed");
                err = -ENOMEM;
index 24fba633c21712fa7cc4eec56420dd809a3ea922..9c4a024745de055571c6696daa4f4caf6cdb0c0a 100644 (file)
  * but WITHOUT 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/module.h>
 #include <linux/pci.h>
@@ -1663,6 +1659,7 @@ static int meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
                goto outenabledev;
        }
 
+       ret = -EIO;
        mchip_adr = pci_resource_start(meye.mchip_dev,0);
        if (!mchip_adr) {
                v4l2_err(v4l2_dev, "meye: mchip has no device base address\n");
index 751be5e533c7e12eeff2ff40a78396223b4943b6..c4a8a5fe040c5dba757baf73528b5ab411a7adff 100644 (file)
  * but WITHOUT 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 _MEYE_PRIV_H_
index 423e8c8893109f45bda279a157a8e0f9c69a0b1a..bb49620540c5129f4a3ee05e2484a7e2a7694b12 100644 (file)
  * 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
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  */
 
 #include <linux/module.h>
@@ -781,12 +777,6 @@ static pci_ers_result_t ngene_error_detected(struct pci_dev *dev,
        return PCI_ERS_RESULT_CAN_RECOVER;
 }
 
-static pci_ers_result_t ngene_link_reset(struct pci_dev *dev)
-{
-       printk(KERN_INFO DEVICE_NAME ": link reset\n");
-       return 0;
-}
-
 static pci_ers_result_t ngene_slot_reset(struct pci_dev *dev)
 {
        printk(KERN_INFO DEVICE_NAME ": slot reset\n");
@@ -800,7 +790,6 @@ static void ngene_resume(struct pci_dev *dev)
 
 static const struct pci_error_handlers ngene_errors = {
        .error_detected = ngene_error_detected,
-       .link_reset = ngene_link_reset,
        .slot_reset = ngene_slot_reset,
        .resume = ngene_resume,
 };
index 4e924e2d1638fe2d98d034f90e0263070dab1982..ce69e648b663a934f5ace1c834e8c0b1642d044a 100644 (file)
  * 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
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  */
 
 #include <linux/module.h>
index 59bb2858c8d0127c8779f3323b8f1d1a25b832e2..03fc218a45e95e2e742eb1ba8a55a4bdf3e09f7e 100644 (file)
  * 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
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  */
 
 #include <linux/module.h>
index d28554f8ce9961f1102a9a22e8f28d71f057e7cd..cf39fcf54adfb812ca691caa68e09ddcbb434947 100644 (file)
  * 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
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  */
 
 /* FIXME - some of these can probably be removed */
index fa30930d70477cc7c0f48644e3a414ca1847504d..10d8f74c4f0a50a4f282b0211b8bb0b616919d5a 100644 (file)
  * 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
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  */
 
 #ifndef _NGENE_H_
index 65afb71ff79fef1bebb13e7ce29836047251d413..74838109afe554812354984363419243f2c7a5fb 100644 (file)
  * 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/i2c.h>
index d5ee82aee9e8518d983f17ac331f87a6f74d9f70..da1eebd2016f5c45ff0615d44b05b31a29f06b10 100644 (file)
  * but WITHOUT 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/kernel.h>
index 249273b2e0f22af7792b5a0b3b7eaf633b4d6ff8..f75f69556be7e2fc98dfb2314c9378f152accd99 100644 (file)
  * but WITHOUT 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/kernel.h>
index b7d6f05a0e02fc26e20e674081add247977ec082..efbe6ccae8b42ee3093c55c7fa9450b58a04c9e2 100644 (file)
  * but WITHOUT 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 VA1J5JF8007S_H
index e0766e69a37083e4ca21276b0e01c2072b399922..63fda79a75c0498517c0088fa132283f05ffb9ec 100644 (file)
  * but WITHOUT 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/kernel.h>
index 2903be519ef55039a29a308ce4e63b3cf32f99bf..6fb119c6e73ac303bd19afbf7fb74f40a2f7a9c2 100644 (file)
  * but WITHOUT 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 VA1J5JF8007T_H
index 8a35ecfb75e38d41f2a11d93831d3032cd17cafc..bf358ec7aca57167429de6843825811c15704e00 100644 (file)
  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *   GNU General Public License for more details.
  *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
  */
 
 #include "saa7134.h"
index 2b60af493de4330e5a99e9036a01cafd804dc4e6..321253827997a2c163893126e9ef444c355c50d6 100644 (file)
  *  but WITHOUT 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 "saa7134.h"
index 7d6bb5c9343f76d651c123429214aeb667e5d8b1..7976c5a12ca85af06235f458bea1e613bf571099 100644 (file)
  *  but WITHOUT 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 "saa7134.h"
index 598b8bbfe726413dde7c24b812a7ed2a2a37ec4c..efdece5ab11cb9f855225819af15626c84fe2e26 100644 (file)
  *  but WITHOUT 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 "saa7134.h"
index f0fe2524259f0799e1ba9b6986b8310fb02839c2..b1d3648dcba1898502bc84d1f05b11be17d02294 100644 (file)
  *  but WITHOUT 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 "saa7134.h"
index dca0592c5f47157bae6d1b85a751bb51f7aee6fe..9d0e69eae036fafe8e2001a330a7139174f8b1f9 100644 (file)
  *  but WITHOUT 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 "saa7134.h"
index 823b75ed47e152e00890ddf38a742df83ffb4d3d..78849c19f68a97232c3fb02d549196c77e3937e8 100644 (file)
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
  */
 
 #include "saa7134.h"
@@ -846,7 +842,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        }
 
        ir = kzalloc(sizeof(*ir), GFP_KERNEL);
-       rc = rc_allocate_device();
+       rc = rc_allocate_device(RC_DRIVER_SCANCODE);
        if (!ir || !rc) {
                err = -ENOMEM;
                goto err_out_free;
index 7eaf36a41db9ea05c415b3836935b0022f628b8d..578e03f8c04157bb24c1346bd1eb870c7292ef31 100644 (file)
  *  but WITHOUT 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 "saa7134.h"
index 38f94b742e28354b407f25a002f619685136813d..68d400e1e240e9c785c73256fa1595a419c9d8d8 100644 (file)
  *  but WITHOUT 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 "saa7134.h"
index cf9a31e0a390783fbe2b3431b950090ffdf81147..46193370e41a41c872c76de6f25a56c9c586757a 100644 (file)
  *  but WITHOUT 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 "saa7134.h"
index cbb173d990853840f7a364494613c0028cb97ede..4b1c4327f1127418ada7260d739070bca3dd3b24 100644 (file)
  *  but WITHOUT 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 "saa7134.h"
index 3849083526a7ac24f0a3b3976ae9d38131bd3b28..816b5282d6710639f2869e15e7fda9c4037b38b3 100644 (file)
  *  but WITHOUT 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.
  */
 
 #define SAA7134_VERSION "0, 2, 17"
index e7e586c1ba535af882a2159f5e33ae2f0286ef91..e318ccf81277d26dda436a3e057dd90c8ca0380f 100644 (file)
  *  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/wait.h>
index 62c34504199df6f8021bd5f1594688e560a140df..a0d2129c6ca97ff0c464eace88904523cba69ac1 100644 (file)
  *  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/slab.h>
index e305c02f9dc9d9a06a54e6bd2ef08664b96c61c5..b2ff82fa7116962b718aebd3213ab7036e8b02ba 100644 (file)
  *  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 "saa7164.h"
index 15a98c638c5563d48bdb75c6115c42081d507984..0e1cd7e153ca83ba08c13061eabd38f179a58d5c 100644 (file)
  *  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/init.h>
index 45951b3cc251c6ab21f670bd5d8d902f1f60fabf..f55c177fd1e4ac7155abe8eacdc8088d5eaa79f5 100644 (file)
  *  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/wait.h>
index 03a1511a92be2c870951f199ec60ba06b441b97a..75eed4cc4823062d1cd53debf9c5d395dbe428a9 100644 (file)
  *  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/init.h>
index cd3eeda5250bf8bf113b0fe82c1139599452b3dd..e76d3bafe2ce246ff8dceaf9c3db09054c0c7d3f 100644 (file)
  *  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 "saa7164.h"
index 68124ce7ebc39ab7ab158fa2fb26a19fe1fcd1c7..f21c245a54f7243603ec30fcbe7462cb7ffd410e 100644 (file)
  *  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 "saa7164.h"
index 8568adfd7ece9e1a48f2fa2f8a3ec12b2f9b0591..4ba5eade7ce29bc5863be57de7147e8f22c116d8 100644 (file)
  *  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/firmware.h>
@@ -309,7 +305,7 @@ int saa7164_downloadfirmware(struct saa7164_dev *dev)
                                        break;
                                }
                                if (err_flags & SAA_DEVICE_NO_IMAGE) {
-                                       printk(KERN_ERR "%s() no first image\n",
+                                       printk(KERN_ERR "%s() no second image\n",
                                                __func__);
                                        break;
                                }
index 024f4e29e8400d192b566966b9b291511907e1af..430f6789f222cc9573695177abd56e4bea99f7f9 100644 (file)
  *  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/module.h>
index 37521a2ee50453a924478123c7efa7f30532fb11..5cf842112e4345f6cd10439f17bcb2793dbc2462 100644 (file)
  *  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.
  */
 
 /* TODO: Retest the driver with errors expressed as negatives */
index 1efba6c64ebfad0c684f2fa20bcea2688c829003..ae241103b2611633dbeab11695c53c04609c886e 100644 (file)
  *  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.
  */
 
 /* TODO: Cleanup and shorten the namespace */
index e5dcb81029d3be2f74b2637ececf2fc3f5d62c4a..9255d7d23947252299c12a5bf041e1ea2eda4203 100644 (file)
  *  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 "saa7164.h"
index 97411b0384c15b32a7ada4f41e93fb06ecaa947e..81b3f0e1999370d527422d6890b49d1d387547b4 100644 (file)
  *  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.
  */
 
 /*
index 826c7c75e64d13cdcea14a8c5c35981fc2085041..d2730c3fdbae5b60ae22a7fc8ac6af1ceb4ecbbc 100644 (file)
@@ -183,7 +183,7 @@ int smi_ir_init(struct smi_dev *dev)
        struct rc_dev *rc_dev;
        struct smi_rc *ir = &dev->ir;
 
-       rc_dev = rc_allocate_device();
+       rc_dev = rc_allocate_device(RC_DRIVER_SCANCODE);
        if (!rc_dev)
                return -ENOMEM;
 
@@ -202,7 +202,6 @@ int smi_ir_init(struct smi_dev *dev)
        rc_dev->input_id.product = dev->pci_dev->subsystem_device;
        rc_dev->dev.parent = &dev->pci_dev->dev;
 
-       rc_dev->driver_type = RC_DRIVER_SCANCODE;
        rc_dev->map_name = dev->info->rc_map;
 
        ir->rc_dev = rc_dev;
index 6a35107aca255b88555297567feb44c8f6eb74bc..36e93540bb49b9384158c50487aeec6aa6295ee2 100644 (file)
@@ -350,7 +350,7 @@ static int solo_snd_pcm_init(struct solo_dev *solo_dev)
 
 int solo_g723_init(struct solo_dev *solo_dev)
 {
-       static struct snd_device_ops ops = { NULL };
+       static struct snd_device_ops ops = { };
        struct snd_card *card;
        struct snd_kcontrol_new kctl;
        char name[32];
index aeb2b4e2db35cf500535586ccc2562f83f557859..6343d24eb1d591510967f7f624430c39410d1f8a 100644 (file)
@@ -377,7 +377,7 @@ static void stop_streaming(struct vb2_queue *vq)
        spin_unlock(&vip->lock);
 }
 
-static struct vb2_ops vip_video_qops = {
+static const struct vb2_ops vip_video_qops = {
        .queue_setup            = queue_setup,
        .buf_init               = buffer_init,
        .buf_prepare            = buffer_prepare,
index 4f81a13666eb22fd37401ee1f8c6216bbe5649ab..61e5c4822b52b2bf26c0ce7b91aef91b6f346419 100644 (file)
  * 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
- *
  * Author:  Anders Wallin <anders.wallin@windriver.com>
  *
  */
index 6e63949d6ad0b7285d2fcc16e4640dfd54a4b063..df9395c87178c8941c1174a7e673448c4c631080 100644 (file)
  * 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.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  *
  *
  * the project's page is at https://linuxtv.org
index 26c5696c193bf244aa098e6c99e205dc4475710b..2aa4ba675194e2eb02e5825ce94147e19270a53d 100644 (file)
  * 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.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  *
  *
  * the project's page is at https://linuxtv.org
index 96a130fb4595729b880aab0aba9ab4ab75faddb8..f64723aea56be2c3dc8602eb9ade71ec70648aab 100644 (file)
  * 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.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  *
  *
  * the project's page is at https://linuxtv.org
index 520414cbe087b30ca2cb199eb2ba1cd06219eb0b..b2b79bb739176c019aae693cc63de96690d47aad 100644 (file)
  * but WITHOUT 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.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  *
  * the project's page is at https://linuxtv.org
  */
    by Nathan Laredo <laredo@gnu.org> */
 
 int av7110_debiwrite(struct av7110 *av7110, u32 config,
-                    int addr, u32 val, int count)
+                    int addr, u32 val, unsigned int count)
 {
        struct saa7146_dev *dev = av7110->dev;
 
-       if (count <= 0 || count > 32764) {
+       if (count > 32764) {
                printk("%s: invalid count %d\n", __func__, count);
                return -1;
        }
@@ -78,12 +75,12 @@ int av7110_debiwrite(struct av7110 *av7110, u32 config,
        return 0;
 }
 
-u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, int count)
+u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, unsigned int count)
 {
        struct saa7146_dev *dev = av7110->dev;
        u32 result = 0;
 
-       if (count > 32764 || count <= 0) {
+       if (count > 32764) {
                printk("%s: invalid count %d\n", __func__, count);
                return 0;
        }
index 1634aba5cb84693bfde178dba08f5dc32ab3ab91..ccb1480594068f4058ac8c774cbc888ea16818be 100644 (file)
@@ -377,14 +377,14 @@ extern int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
 
 /* DEBI (saa7146 data extension bus interface) access */
 extern int av7110_debiwrite(struct av7110 *av7110, u32 config,
-                           int addr, u32 val, int count);
+                           int addr, u32 val, unsigned int count);
 extern u32 av7110_debiread(struct av7110 *av7110, u32 config,
-                          int addr, int count);
+                          int addr, unsigned int count);
 
 
 /* DEBI during interrupt */
 /* single word writes */
-static inline void iwdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count)
+static inline void iwdebi(struct av7110 *av7110, u32 config, int addr, u32 val, unsigned int count)
 {
        av7110_debiwrite(av7110, config, addr, val, count);
 }
@@ -397,7 +397,7 @@ static inline void mwdebi(struct av7110 *av7110, u32 config, int addr,
        av7110_debiwrite(av7110, config, addr, 0, count);
 }
 
-static inline u32 irdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count)
+static inline u32 irdebi(struct av7110 *av7110, u32 config, int addr, u32 val, unsigned int count)
 {
        u32 res;
 
@@ -408,7 +408,7 @@ static inline u32 irdebi(struct av7110 *av7110, u32 config, int addr, u32 val, i
 }
 
 /* DEBI outside interrupts, only for count <= 4! */
-static inline void wdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count)
+static inline void wdebi(struct av7110 *av7110, u32 config, int addr, u32 val, unsigned int count)
 {
        unsigned long flags;
 
@@ -417,7 +417,7 @@ static inline void wdebi(struct av7110 *av7110, u32 config, int addr, u32 val, i
        spin_unlock_irqrestore(&av7110->debilock, flags);
 }
 
-static inline u32 rdebi(struct av7110 *av7110, u32 config, int addr, u32 val, int count)
+static inline u32 rdebi(struct av7110 *av7110, u32 config, int addr, u32 val, unsigned int count)
 {
        unsigned long flags;
        u32 res;
index 0e763a784e2b44d6d12c78d83cc2be5cbc7918ab..10e28f067b4551fd427c3bdc07a20742b481e2d1 100644 (file)
  * but WITHOUT 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.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  *
  */
 
index 479aff02db81b72e93fda83896b2b6c2be19b4d9..397fe146dedd12753aa92ea68e3ab5e1d116f315 100644 (file)
  * but WITHOUT 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.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  *
  * the project's page is at https://linuxtv.org
  */
index 896c66d4b3ae74207aebea6da7830e6a4c46614e..19f07d4aba6acc9388b25aa7d8ed1073281a6368 100644 (file)
  * 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.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  *
  *
  * the project's page is at https://linuxtv.org
index 20ad93bf0f544568ffe6aed0a3245564e67f699f..68355484ba7d5bd828cd3a8d9ec5f2e51574f90d 100644 (file)
  * 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.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  *
  *
  * the project's page is at https://linuxtv.org
@@ -177,7 +174,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
        struct rc_dev *dev;
        int error;
 
-       dev = rc_allocate_device();
+       dev = rc_allocate_device(RC_DRIVER_SCANCODE);
        if (!dev) {
                printk(KERN_ERR "budget_ci: IR interface initialisation failed\n");
                return -ENOMEM;
index 6d42dcfd4825bd85348260de5ea3b0a85cfec758..97499b2af71442ffd4db39151be5252df0710d63 100644 (file)
  * 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.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  *
  *
  * the project's page is at https://linuxtv.org
index f152eda0123a3bb34cd12acc2b1415ebfe52edbf..44299237200846c30b9ab6dae3316b6a95a9be04 100644 (file)
  * 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.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  *
  *
  * the project's page is at https://linuxtv.org
index 3091b480ce222c295c8985b4e75113b432cf0081..5f17e1c9a20745ce6322992ea023ad2360c86e84 100644 (file)
  * 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.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * To obtain the license, point your browser to
+ * http://www.gnu.org/copyleft/gpl.html
  *
  *
  * the project's page is at https://linuxtv.org
index 375e3be184b1afc54bacb55ad951948e819ed1c9..3d410d02a987f297524a2b7a1d72cc985831eae4 100644 (file)
  * but WITHOUT 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 Lesser 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 _DVB_FILTER_H_
index 71a0453b1af15dabea389e82fd22111d3f269dce..336e2f9bc1b6363045f4890c662299d8009f5e30 100644 (file)
@@ -74,7 +74,7 @@ static const char *dma_mode_name(unsigned int mode)
 
 static int tw686x_dma_mode_get(char *buffer, struct kernel_param *kp)
 {
-       return sprintf(buffer, dma_mode_name(dma_mode));
+       return sprintf(buffer, "%s", dma_mode_name(dma_mode));
 }
 
 static int tw686x_dma_mode_set(const char *val, struct kernel_param *kp)
index 3c3cbce0f9ccaa83d965e008126ebcc8ebe29403..303289a7fd3f614846ca4252c47c37de519df455 100644 (file)
  * 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.
- *
  * ------------------------------------------------------------------------
  */
 
index def55585ad2321901c19f4c709eb6caa924b6d4f..8ed5a0f7ac018df4d63ab066c53d32852bd960e5 100644 (file)
  * 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.
- *
  * ------------------------------------------------------------------------
  */
 
index 4e7db8939c2be89cf9a7f580f2df92f2b9bad23c..9bb3c21aa2757a8aa1f18ace1c25c4fbe898c9ae 100644 (file)
  * but WITHOUT 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 _BUZ_H_
index 9d2697f5b455d261b0bdc9447cf13e764a398e14..5266755add63de6e9f93876b8ff0e89a4d9416cb 100644 (file)
  * but WITHOUT 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/delay.h>
index 4936fead73e8693cfab4a2ad7ebb9111be92a1e7..81cba177cd9027a5c883d0e1f3d93cf4e329d405 100644 (file)
  * but WITHOUT 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 __ZORAN_CARD_H__
index 35b552c178dae86f3623024a36f81030c940781a..671907a6e6b631d780593fff55a3254ad00020e1 100644 (file)
  * but WITHOUT 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/types.h>
index 07f2c23ff7401a3b5e6653f0133477939c4ca2a3..a507aaad4ebbb579745682971670623aad8cb744 100644 (file)
  * but WITHOUT 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 __ZORAN_DEVICE_H__
index 94b9b616df989e29d24af197471fb921e3190c73..180f3d7af3e1d1426a9d8a9675e6e71304326679 100644 (file)
  * but WITHOUT 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/init.h>
@@ -975,6 +971,7 @@ static int zoran_open(struct file *file)
        return 0;
 
 fail_fh:
+       v4l2_fh_exit(&fh->fh);
        kfree(fh);
 fail_unlock:
        mutex_unlock(&zr->lock);
index 437652761093746e8536ef5ca04e9ca1a9e3df79..78ac8f853748e73e3bd6c7fb18ba86f14fb067c8 100644 (file)
  * but WITHOUT 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/types.h>
index f2d5b1ba448f4b8c8dc4baa9dbe14bcd56e52eeb..0ac7cb0011f281f27b7f3eda900a652960050633 100644 (file)
  * but WITHOUT 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 __ZORAN_PROCFS_H__
index c12ca9f96bac40a825ac3ce8bede2ffc3c32d6fc..8736b9d8d97eb7d7cfe47225c665c7d61c8d86d5 100644 (file)
  * 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.
- *
  * ------------------------------------------------------------------------
  */
 
index 8c79229f69d1a5e4e85eeb761073e35f5bda9435..784bcf5727b865e36d7852c195d2b9a71c2b6b4c 100644 (file)
  * 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.
- *
  * ------------------------------------------------------------------------
  */
 
index e1985609af4bc416a7ba7d6e42f7dd872461ad9e..5ebfc16672f378e6ae7ec12469e11e868ffd2ce8 100644 (file)
  * 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.
- *
  * ------------------------------------------------------------------------
  */
 
index ea083adda04579e8c8875bbec020da59a935a985..9236486d3c2b56a700e365202bfb306f79cec269 100644 (file)
  * 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.
- *
  * ------------------------------------------------------------------------
  */
 
index 54c9362aa98059879300ab6e7700b041176e688a..c9ffef15532db1f5107779bbc02979bb57632989 100644 (file)
  * but WITHOUT 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 _ZR36057_H_
index f08546fe22347718777c8b330b9ec4ce54bb91d5..2c2e8130fc96c1d8efa07ea8fa39f0ea3e88cc93 100644 (file)
  * 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.
- *
  * ------------------------------------------------------------------------
  */
 
index 914ffa4ad8d3bde7f6219c672ea4382048179f56..82911757ba782c3004a5455707e0a85df0e95597 100644 (file)
  * 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.
- *
  * ------------------------------------------------------------------------
  */
 
index d944421e392d7b0af9e1c93b6bd63ea902bc5e60..c9106e105baba8eba37a36e6e27e1e6a28feea17 100644 (file)
@@ -162,6 +162,9 @@ config VIDEO_CODA
           Coda is a range of video codec IPs that supports
           H.264, MPEG-4, and other video formats.
 
+config VIDEO_IMX_VDOA
+       def_tristate VIDEO_CODA if SOC_IMX6Q || COMPILE_TEST
+
 config VIDEO_MEDIATEK_VPU
        tristate "Mediatek Video Processor Unit"
        depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA
@@ -298,6 +301,56 @@ config VIDEO_STI_HVA
          To compile this driver as a module, choose M here:
          the module will be called st-hva.
 
+config VIDEO_STI_HVA_DEBUGFS
+       bool "Export STMicroelectronics HVA internals in debugfs"
+       depends on VIDEO_STI_HVA
+       depends on DEBUG_FS
+       help
+         Select this to see information about the internal state and the last
+          operation of STMicroelectronics HVA multi-format video encoder in
+          debugfs.
+
+          Choose N unless you know you need this.
+
+config VIDEO_STI_DELTA
+       tristate "STMicroelectronics DELTA multi-format video decoder V4L2 driver"
+       depends on VIDEO_DEV && VIDEO_V4L2
+       depends on ARCH_STI || COMPILE_TEST
+       depends on HAS_DMA
+       help
+               This V4L2 driver enables DELTA multi-format video decoder
+               of STMicroelectronics STiH4xx SoC series allowing hardware
+               decoding of various compressed video bitstream format in
+               raw uncompressed format.
+
+               Use this option to see the decoders available for such
+               hardware.
+
+               Please notice that the driver will only be built if
+               at least one of the DELTA decoder below is selected.
+
+if VIDEO_STI_DELTA
+
+config VIDEO_STI_DELTA_MJPEG
+       bool "STMicroelectronics DELTA MJPEG support"
+       default y
+       help
+               Enables DELTA MJPEG hardware support.
+
+               To compile this driver as a module, choose M here:
+               the module will be called st-delta.
+
+config VIDEO_STI_DELTA_DRIVER
+       tristate
+       depends on VIDEO_STI_DELTA
+       depends on VIDEO_STI_DELTA_MJPEG
+       default VIDEO_STI_DELTA_MJPEG
+       select VIDEOBUF2_DMA_CONTIG
+       select V4L2_MEM2MEM_DEV
+       select RPMSG
+
+endif # VIDEO_STI_DELTA
+
 config VIDEO_SH_VEU
        tristate "SuperH VEU mem2mem video processing driver"
        depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA
index 5b3cb271d2b8ccf3a2d47a00dcfe90bdb5a95e3c..349ddf6a69da2183b5e36d303add55aa79d68793 100644 (file)
@@ -39,6 +39,8 @@ obj-$(CONFIG_VIDEO_STI_BDISP)         += sti/bdisp/
 obj-$(CONFIG_VIDEO_STI_HVA)            += sti/hva/
 obj-$(CONFIG_DVB_C8SECTPFE)            += sti/c8sectpfe/
 
+obj-$(CONFIG_VIDEO_STI_DELTA)          += sti/delta/
+
 obj-$(CONFIG_BLACKFIN)                  += blackfin/
 
 obj-$(CONFIG_ARCH_DAVINCI)             += davinci/
index b33b9e35e60e4aac658fb370379ff8f11b062c28..05489a401c5c1506efbd7f742ac7ea81e3276ef7 100644 (file)
@@ -1576,7 +1576,7 @@ static int vpfe_s_fmt(struct file *file, void *priv,
                return -EBUSY;
        }
 
-       ret = vpfe_try_fmt(file, priv, &format);
+       ret = __vpfe_get_format(vpfe, &format, &bpp);
        if (ret)
                return ret;
 
index 2e6edc09b58fb0bb755a0bb75cfcc45b44ad84e8..1c5166df46f58dfd07a246672b907815643119db 100644 (file)
  * but WITHOUT 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/completion.h>
index b8f3d9fa66e907ca54c0e61972c5c2bbacfad2b5..37169054b82888be7923c0d1a83751245a30710b 100644 (file)
  * but WITHOUT 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/module.h>
index 9342ac57b23067823bba23901bb294969bc77219..858284328af9dae700a43b1db3b64fce5a99f398 100644 (file)
@@ -3,3 +3,4 @@ ccflags-y += -I$(src)
 coda-objs := coda-common.o coda-bit.o coda-gdi.o coda-h264.o coda-jpeg.o
 
 obj-$(CONFIG_VIDEO_CODA) += coda.o
+obj-$(CONFIG_VIDEO_IMX_VDOA) += imx-vdoa.o
index b6625047250d62c40ca153606aa0227ee4f4de86..466a44e4549e5e611d13a5b3d08f91571524301d 100644 (file)
@@ -30,6 +30,7 @@
 #include <media/videobuf2-vmalloc.h>
 
 #include "coda.h"
+#include "imx-vdoa.h"
 #define CREATE_TRACE_POINTS
 #include "trace.h"
 
@@ -758,7 +759,7 @@ static void coda9_set_frame_cache(struct coda_ctx *ctx, u32 fourcc)
                cache_config = 1 << CODA9_CACHE_PAGEMERGE_OFFSET;
        }
        coda_write(ctx->dev, cache_size, CODA9_CMD_SET_FRAME_CACHE_SIZE);
-       if (fourcc == V4L2_PIX_FMT_NV12) {
+       if (fourcc == V4L2_PIX_FMT_NV12 || fourcc == V4L2_PIX_FMT_YUYV) {
                cache_config |= 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET |
                                16 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET |
                                0 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET;
@@ -1517,6 +1518,10 @@ static int __coda_start_decoding(struct coda_ctx *ctx)
        u32 val;
        int ret;
 
+       v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+                "Video Data Order Adapter: %s\n",
+                ctx->use_vdoa ? "Enabled" : "Disabled");
+
        /* Start decoding */
        q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
        q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
@@ -1532,10 +1537,11 @@ static int __coda_start_decoding(struct coda_ctx *ctx)
 
        ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) |
                                 CODA9_FRAME_TILED2LINEAR);
-       if (dst_fourcc == V4L2_PIX_FMT_NV12)
+       if (dst_fourcc == V4L2_PIX_FMT_NV12 || dst_fourcc == V4L2_PIX_FMT_YUYV)
                ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE;
        if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP)
-               ctx->frame_mem_ctrl |= (0x3 << 9) | CODA9_FRAME_TILED2LINEAR;
+               ctx->frame_mem_ctrl |= (0x3 << 9) |
+                       ((ctx->use_vdoa) ? 0 : CODA9_FRAME_TILED2LINEAR);
        coda_write(dev, ctx->frame_mem_ctrl, CODA_REG_BIT_FRAME_MEM_CTRL);
 
        ctx->display_idx = -1;
@@ -1618,6 +1624,15 @@ static int __coda_start_decoding(struct coda_ctx *ctx)
                 __func__, ctx->idx, width, height);
 
        ctx->num_internal_frames = coda_read(dev, CODA_RET_DEC_SEQ_FRAME_NEED);
+       /*
+        * If the VDOA is used, the decoder needs one additional frame,
+        * because the frames are freed when the next frame is decoded.
+        * Otherwise there are visible errors in the decoded frames (green
+        * regions in displayed frames) and a broken order of frames (earlier
+        * frames are sporadically displayed after later frames).
+        */
+       if (ctx->use_vdoa)
+               ctx->num_internal_frames += 1;
        if (ctx->num_internal_frames > CODA_MAX_FRAMEBUFFERS) {
                v4l2_err(&dev->v4l2_dev,
                         "not enough framebuffers to decode (%d < %d)\n",
@@ -1724,6 +1739,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
        struct coda_q_data *q_data_dst;
        struct coda_buffer_meta *meta;
        unsigned long flags;
+       u32 rot_mode = 0;
        u32 reg_addr, reg_stride;
 
        dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
@@ -1759,27 +1775,40 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
        if (dev->devtype->product == CODA_960)
                coda_set_gdi_regs(ctx);
 
-       if (dev->devtype->product == CODA_960) {
-               /*
-                * The CODA960 seems to have an internal list of buffers with
-                * 64 entries that includes the registered frame buffers as
-                * well as the rotator buffer output.
-                * ROT_INDEX needs to be < 0x40, but > ctx->num_internal_frames.
-                */
-               coda_write(dev, CODA_MAX_FRAMEBUFFERS + dst_buf->vb2_buf.index,
-                               CODA9_CMD_DEC_PIC_ROT_INDEX);
-
-               reg_addr = CODA9_CMD_DEC_PIC_ROT_ADDR_Y;
-               reg_stride = CODA9_CMD_DEC_PIC_ROT_STRIDE;
+       if (ctx->use_vdoa &&
+           ctx->display_idx >= 0 &&
+           ctx->display_idx < ctx->num_internal_frames) {
+               vdoa_device_run(ctx->vdoa,
+                               vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0),
+                               ctx->internal_frames[ctx->display_idx].paddr);
        } else {
-               reg_addr = CODA_CMD_DEC_PIC_ROT_ADDR_Y;
-               reg_stride = CODA_CMD_DEC_PIC_ROT_STRIDE;
+               if (dev->devtype->product == CODA_960) {
+                       /*
+                        * The CODA960 seems to have an internal list of
+                        * buffers with 64 entries that includes the
+                        * registered frame buffers as well as the rotator
+                        * buffer output.
+                        *
+                        * ROT_INDEX needs to be < 0x40, but >
+                        * ctx->num_internal_frames.
+                        */
+                       coda_write(dev,
+                                  CODA_MAX_FRAMEBUFFERS + dst_buf->vb2_buf.index,
+                                  CODA9_CMD_DEC_PIC_ROT_INDEX);
+
+                       reg_addr = CODA9_CMD_DEC_PIC_ROT_ADDR_Y;
+                       reg_stride = CODA9_CMD_DEC_PIC_ROT_STRIDE;
+               } else {
+                       reg_addr = CODA_CMD_DEC_PIC_ROT_ADDR_Y;
+                       reg_stride = CODA_CMD_DEC_PIC_ROT_STRIDE;
+               }
+               coda_write_base(ctx, q_data_dst, dst_buf, reg_addr);
+               coda_write(dev, q_data_dst->bytesperline, reg_stride);
+
+               rot_mode = CODA_ROT_MIR_ENABLE | ctx->params.rot_mode;
        }
-       coda_write_base(ctx, q_data_dst, dst_buf, reg_addr);
-       coda_write(dev, q_data_dst->bytesperline, reg_stride);
 
-       coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode,
-                       CODA_CMD_DEC_PIC_ROT_MODE);
+       coda_write(dev, rot_mode, CODA_CMD_DEC_PIC_ROT_MODE);
 
        switch (dev->devtype->product) {
        case CODA_DX6:
@@ -1851,6 +1880,7 @@ static void coda_finish_decode(struct coda_ctx *ctx)
        u32 src_fourcc;
        int success;
        u32 err_mb;
+       int err_vdoa = 0;
        u32 val;
 
        /* Update kfifo out pointer from coda bitstream read pointer */
@@ -1934,13 +1964,17 @@ static void coda_finish_decode(struct coda_ctx *ctx)
                }
        }
 
+       /* Wait until the VDOA finished writing the previous display frame */
+       if (ctx->use_vdoa &&
+           ctx->display_idx >= 0 &&
+           ctx->display_idx < ctx->num_internal_frames) {
+               err_vdoa = vdoa_wait_for_completion(ctx->vdoa);
+       }
+
        ctx->frm_dis_flg = coda_read(dev,
                                     CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
 
-       /*
-        * The previous display frame was copied out by the rotator,
-        * now it can be overwritten again
-        */
+       /* The previous display frame was copied out and can be overwritten */
        if (ctx->display_idx >= 0 &&
            ctx->display_idx < ctx->num_internal_frames) {
                ctx->frm_dis_flg &= ~(1 << ctx->display_idx);
@@ -2045,6 +2079,9 @@ static void coda_finish_decode(struct coda_ctx *ctx)
                trace_coda_dec_rot_done(ctx, dst_buf, meta);
 
                switch (q_data_dst->fourcc) {
+               case V4L2_PIX_FMT_YUYV:
+                       payload = width * height * 2;
+                       break;
                case V4L2_PIX_FMT_YUV420:
                case V4L2_PIX_FMT_YVU420:
                case V4L2_PIX_FMT_NV12:
@@ -2057,8 +2094,10 @@ static void coda_finish_decode(struct coda_ctx *ctx)
                }
                vb2_set_plane_payload(&dst_buf->vb2_buf, 0, payload);
 
-               coda_m2m_buf_done(ctx, dst_buf, ctx->frame_errors[display_idx] ?
-                                 VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+               if (ctx->frame_errors[ctx->display_idx] || err_vdoa)
+                       coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_ERROR);
+               else
+                       coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_DONE);
 
                v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
                        "job finished: decoding frame (%d) (%s)\n",
index 9e6bdafa16f583fc657940824cf9d1236bd9a249..eb6548f46cbac1978056f78d8a5d101a7fbe8a0a 100644 (file)
@@ -41,6 +41,7 @@
 #include <media/videobuf2-vmalloc.h>
 
 #include "coda.h"
+#include "imx-vdoa.h"
 
 #define CODA_NAME              "coda"
 
@@ -66,6 +67,10 @@ static int disable_tiling;
 module_param(disable_tiling, int, 0644);
 MODULE_PARM_DESC(disable_tiling, "Disable tiled frame buffers");
 
+static int disable_vdoa;
+module_param(disable_vdoa, int, 0644);
+MODULE_PARM_DESC(disable_vdoa, "Disable Video Data Order Adapter tiled to raster-scan conversion");
+
 void coda_write(struct coda_dev *dev, u32 data, u32 reg)
 {
        v4l2_dbg(2, coda_debug, &dev->v4l2_dev,
@@ -90,6 +95,8 @@ void coda_write_base(struct coda_ctx *ctx, struct coda_q_data *q_data,
        u32 base_cb, base_cr;
 
        switch (q_data->fourcc) {
+       case V4L2_PIX_FMT_YUYV:
+               /* Fallthrough: IN -H264-> CODA -NV12 MB-> VDOA -YUYV-> OUT */
        case V4L2_PIX_FMT_NV12:
        case V4L2_PIX_FMT_YUV420:
        default:
@@ -196,6 +203,11 @@ static const struct coda_video_device coda_bit_decoder = {
                V4L2_PIX_FMT_NV12,
                V4L2_PIX_FMT_YUV420,
                V4L2_PIX_FMT_YVU420,
+               /*
+                * If V4L2_PIX_FMT_YUYV should be default,
+                * set_default_params() must be adjusted.
+                */
+               V4L2_PIX_FMT_YUYV,
        },
 };
 
@@ -241,6 +253,7 @@ static u32 coda_format_normalize_yuv(u32 fourcc)
        case V4L2_PIX_FMT_YUV420:
        case V4L2_PIX_FMT_YVU420:
        case V4L2_PIX_FMT_YUV422P:
+       case V4L2_PIX_FMT_YUYV:
                return V4L2_PIX_FMT_YUV420;
        default:
                return fourcc;
@@ -325,6 +338,31 @@ const char *coda_product_name(int product)
        }
 }
 
+static struct vdoa_data *coda_get_vdoa_data(void)
+{
+       struct device_node *vdoa_node;
+       struct platform_device *vdoa_pdev;
+       struct vdoa_data *vdoa_data = NULL;
+
+       vdoa_node = of_find_compatible_node(NULL, NULL, "fsl,imx6q-vdoa");
+       if (!vdoa_node)
+               return NULL;
+
+       vdoa_pdev = of_find_device_by_node(vdoa_node);
+       if (!vdoa_pdev)
+               goto out;
+
+       vdoa_data = platform_get_drvdata(vdoa_pdev);
+       if (!vdoa_data)
+               vdoa_data = ERR_PTR(-EPROBE_DEFER);
+
+out:
+       if (vdoa_node)
+               of_node_put(vdoa_node);
+
+       return vdoa_data;
+}
+
 /*
  * V4L2 ioctl() operations.
  */
@@ -404,6 +442,11 @@ static int coda_try_pixelformat(struct coda_ctx *ctx, struct v4l2_format *f)
                return -EINVAL;
 
        for (i = 0; i < CODA_MAX_FORMATS; i++) {
+               /* Skip YUYV if the vdoa is not available */
+               if (!ctx->vdoa && f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+                   formats[i] == V4L2_PIX_FMT_YUYV)
+                       continue;
+
                if (formats[i] == f->fmt.pix.pixelformat) {
                        f->fmt.pix.pixelformat = formats[i];
                        return 0;
@@ -417,6 +460,33 @@ static int coda_try_pixelformat(struct coda_ctx *ctx, struct v4l2_format *f)
        return 0;
 }
 
+static int coda_try_fmt_vdoa(struct coda_ctx *ctx, struct v4l2_format *f,
+                            bool *use_vdoa)
+{
+       int err;
+
+       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       if (!use_vdoa)
+               return -EINVAL;
+
+       if (!ctx->vdoa) {
+               *use_vdoa = false;
+               return 0;
+       }
+
+       err = vdoa_context_configure(NULL, f->fmt.pix.width, f->fmt.pix.height,
+                                    f->fmt.pix.pixelformat);
+       if (err) {
+               *use_vdoa = false;
+               return 0;
+       }
+
+       *use_vdoa = true;
+       return 0;
+}
+
 static unsigned int coda_estimate_sizeimage(struct coda_ctx *ctx, u32 sizeimage,
                                            u32 width, u32 height)
 {
@@ -463,6 +533,11 @@ static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec,
                f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
                                        f->fmt.pix.height * 3 / 2;
                break;
+       case V4L2_PIX_FMT_YUYV:
+               f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16) * 2;
+               f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
+                                       f->fmt.pix.height;
+               break;
        case V4L2_PIX_FMT_YUV422P:
                f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16);
                f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
@@ -495,6 +570,7 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv,
        const struct coda_codec *codec;
        struct vb2_queue *src_vq;
        int ret;
+       bool use_vdoa;
 
        ret = coda_try_pixelformat(ctx, f);
        if (ret < 0)
@@ -531,6 +607,19 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv,
                f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16);
                f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
                                       f->fmt.pix.height * 3 / 2;
+
+               ret = coda_try_fmt_vdoa(ctx, f, &use_vdoa);
+               if (ret < 0)
+                       return ret;
+
+               if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) {
+                       if (!use_vdoa)
+                               return -EINVAL;
+
+                       f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16) * 2;
+                       f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
+                               f->fmt.pix.height;
+               }
        }
 
        return 0;
@@ -566,7 +655,8 @@ static int coda_try_fmt_vid_out(struct file *file, void *priv,
        return coda_try_fmt(ctx, codec, f);
 }
 
-static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f)
+static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f,
+                     struct v4l2_rect *r)
 {
        struct coda_q_data *q_data;
        struct vb2_queue *vq;
@@ -589,18 +679,23 @@ static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f)
        q_data->height = f->fmt.pix.height;
        q_data->bytesperline = f->fmt.pix.bytesperline;
        q_data->sizeimage = f->fmt.pix.sizeimage;
-       q_data->rect.left = 0;
-       q_data->rect.top = 0;
-       q_data->rect.width = f->fmt.pix.width;
-       q_data->rect.height = f->fmt.pix.height;
+       if (r) {
+               q_data->rect = *r;
+       } else {
+               q_data->rect.left = 0;
+               q_data->rect.top = 0;
+               q_data->rect.width = f->fmt.pix.width;
+               q_data->rect.height = f->fmt.pix.height;
+       }
 
        switch (f->fmt.pix.pixelformat) {
+       case V4L2_PIX_FMT_YUYV:
+               ctx->tiled_map_type = GDI_TILED_FRAME_MB_RASTER_MAP;
+               break;
        case V4L2_PIX_FMT_NV12:
-               if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
-                       ctx->tiled_map_type = GDI_TILED_FRAME_MB_RASTER_MAP;
-                       if (!disable_tiling)
-                               break;
-               }
+               ctx->tiled_map_type = GDI_TILED_FRAME_MB_RASTER_MAP;
+               if (!disable_tiling)
+                       break;
                /* else fall through */
        case V4L2_PIX_FMT_YUV420:
        case V4L2_PIX_FMT_YVU420:
@@ -610,9 +705,20 @@ static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f)
                break;
        }
 
+       if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP &&
+           !coda_try_fmt_vdoa(ctx, f, &ctx->use_vdoa) &&
+           ctx->use_vdoa)
+               vdoa_context_configure(ctx->vdoa, f->fmt.pix.width,
+                                      f->fmt.pix.height,
+                                      f->fmt.pix.pixelformat);
+       else
+               ctx->use_vdoa = false;
+
        v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
-               "Setting format for type %d, wxh: %dx%d, fmt: %d\n",
-               f->type, q_data->width, q_data->height, q_data->fourcc);
+               "Setting format for type %d, wxh: %dx%d, fmt: %4.4s %c\n",
+               f->type, q_data->width, q_data->height,
+               (char *)&q_data->fourcc,
+               (ctx->tiled_map_type == GDI_LINEAR_FRAME_MAP) ? 'L' : 'T');
 
        return 0;
 }
@@ -621,27 +727,37 @@ static int coda_s_fmt_vid_cap(struct file *file, void *priv,
                              struct v4l2_format *f)
 {
        struct coda_ctx *ctx = fh_to_ctx(priv);
+       struct coda_q_data *q_data_src;
+       struct v4l2_rect r;
        int ret;
 
        ret = coda_try_fmt_vid_cap(file, priv, f);
        if (ret)
                return ret;
 
-       return coda_s_fmt(ctx, f);
+       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       r.left = 0;
+       r.top = 0;
+       r.width = q_data_src->width;
+       r.height = q_data_src->height;
+
+       return coda_s_fmt(ctx, f, &r);
 }
 
 static int coda_s_fmt_vid_out(struct file *file, void *priv,
                              struct v4l2_format *f)
 {
        struct coda_ctx *ctx = fh_to_ctx(priv);
+       struct coda_q_data *q_data_src;
        struct v4l2_format f_cap;
+       struct v4l2_rect r;
        int ret;
 
        ret = coda_try_fmt_vid_out(file, priv, f);
        if (ret)
                return ret;
 
-       ret = coda_s_fmt(ctx, f);
+       ret = coda_s_fmt(ctx, f, NULL);
        if (ret)
                return ret;
 
@@ -657,7 +773,13 @@ static int coda_s_fmt_vid_out(struct file *file, void *priv,
        if (ret)
                return ret;
 
-       return coda_s_fmt(ctx, &f_cap);
+       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       r.left = 0;
+       r.top = 0;
+       r.width = q_data_src->width;
+       r.height = q_data_src->height;
+
+       return coda_s_fmt(ctx, &f_cap, &r);
 }
 
 static int coda_reqbufs(struct file *file, void *priv,
@@ -1018,6 +1140,16 @@ static int coda_job_ready(void *m2m_priv)
                bool stream_end = ctx->bit_stream_param &
                                  CODA_BIT_STREAM_END_FLAG;
                int num_metas = ctx->num_metas;
+               unsigned int count;
+
+               count = hweight32(ctx->frm_dis_flg);
+               if (ctx->use_vdoa && count >= (ctx->num_internal_frames - 1)) {
+                       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                                "%d: not ready: all internal buffers in use: %d/%d (0x%x)",
+                                ctx->idx, count, ctx->num_internal_frames,
+                                ctx->frm_dis_flg);
+                       return 0;
+               }
 
                if (ctx->hold && !src_bufs) {
                        v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
@@ -1708,6 +1840,13 @@ static int coda_open(struct file *file)
        default:
                ctx->reg_idx = idx;
        }
+       if (ctx->dev->vdoa && !disable_vdoa) {
+               ctx->vdoa = vdoa_context_create(dev->vdoa);
+               if (!ctx->vdoa)
+                       v4l2_warn(&dev->v4l2_dev,
+                                 "Failed to create vdoa context: not using vdoa");
+       }
+       ctx->use_vdoa = false;
 
        /* Power up and upload firmware if necessary */
        ret = pm_runtime_get_sync(&dev->plat_dev->dev);
@@ -1789,6 +1928,9 @@ static int coda_release(struct file *file)
        /* If this instance is running, call .job_abort and wait for it to end */
        v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
 
+       if (ctx->vdoa)
+               vdoa_context_destroy(ctx->vdoa);
+
        /* In case the instance was not running, we still need to call SEQ_END */
        if (ctx->ops->seq_end_work) {
                queue_work(dev->workqueue, &ctx->seq_end_work);
@@ -2079,6 +2221,7 @@ static const struct coda_devtype coda_devdata[] = {
        [CODA_IMX27] = {
                .firmware     = {
                        "vpu_fw_imx27_TO2.bin",
+                       "vpu/vpu_fw_imx27_TO2.bin",
                        "v4l-codadx6-imx27.bin"
                },
                .product      = CODA_DX6,
@@ -2092,6 +2235,7 @@ static const struct coda_devtype coda_devdata[] = {
        [CODA_IMX53] = {
                .firmware     = {
                        "vpu_fw_imx53.bin",
+                       "vpu/vpu_fw_imx53.bin",
                        "v4l-coda7541-imx53.bin"
                },
                .product      = CODA_7541,
@@ -2106,6 +2250,7 @@ static const struct coda_devtype coda_devdata[] = {
        [CODA_IMX6Q] = {
                .firmware     = {
                        "vpu_fw_imx6q.bin",
+                       "vpu/vpu_fw_imx6q.bin",
                        "v4l-coda960-imx6q.bin"
                },
                .product      = CODA_960,
@@ -2120,6 +2265,7 @@ static const struct coda_devtype coda_devdata[] = {
        [CODA_IMX6DL] = {
                .firmware     = {
                        "vpu_fw_imx6d.bin",
+                       "vpu/vpu_fw_imx6d.bin",
                        "v4l-coda960-imx6dl.bin"
                },
                .product      = CODA_960,
@@ -2235,6 +2381,11 @@ static int coda_probe(struct platform_device *pdev)
        }
        dev->iram_pool = pool;
 
+       /* Get vdoa_data if supported by the platform */
+       dev->vdoa = coda_get_vdoa_data();
+       if (PTR_ERR(dev->vdoa) == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+
        ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
        if (ret)
                return ret;
index 53f96661683c63c7865967467d96585e48264252..4b831c91ae4aff81f59574811f67ae82f1508eee 100644 (file)
@@ -50,7 +50,7 @@ enum coda_product {
 struct coda_video_device;
 
 struct coda_devtype {
-       char                    *firmware[2];
+       char                    *firmware[3];
        enum coda_product       product;
        const struct coda_codec *codecs;
        unsigned int            num_codecs;
@@ -75,6 +75,7 @@ struct coda_dev {
        struct platform_device  *plat_dev;
        const struct coda_devtype *devtype;
        int                     firmware;
+       struct vdoa_data        *vdoa;
 
        void __iomem            *regs_base;
        struct clk              *clk_per;
@@ -236,6 +237,8 @@ struct coda_ctx {
        int                             display_idx;
        struct dentry                   *debugfs_entry;
        bool                            use_bit;
+       bool                            use_vdoa;
+       struct vdoa_ctx                 *vdoa;
 };
 
 extern int coda_debug;
diff --git a/drivers/media/platform/coda/imx-vdoa.c b/drivers/media/platform/coda/imx-vdoa.c
new file mode 100644 (file)
index 0000000..67fd8ff
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+ * i.MX6 Video Data Order Adapter (VDOA)
+ *
+ * Copyright (C) 2014 Philipp Zabel
+ * Copyright (C) 2016 Pengutronix, Michael Tretter <kernel@pengutronix.de>
+ *
+ * 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/clk.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+
+#include "imx-vdoa.h"
+
+#define VDOA_NAME "imx-vdoa"
+
+#define VDOAC          0x00
+#define VDOASRR                0x04
+#define VDOAIE         0x08
+#define VDOAIST                0x0c
+#define VDOAFP         0x10
+#define VDOAIEBA00     0x14
+#define VDOAIEBA01     0x18
+#define VDOAIEBA02     0x1c
+#define VDOAIEBA10     0x20
+#define VDOAIEBA11     0x24
+#define VDOAIEBA12     0x28
+#define VDOASL         0x2c
+#define VDOAIUBO       0x30
+#define VDOAVEBA0      0x34
+#define VDOAVEBA1      0x38
+#define VDOAVEBA2      0x3c
+#define VDOAVUBO       0x40
+#define VDOASR         0x44
+
+#define VDOAC_ISEL             BIT(6)
+#define VDOAC_PFS              BIT(5)
+#define VDOAC_SO               BIT(4)
+#define VDOAC_SYNC             BIT(3)
+#define VDOAC_NF               BIT(2)
+#define VDOAC_BNDM_MASK                0x3
+#define VDOAC_BAND_HEIGHT_8    0x0
+#define VDOAC_BAND_HEIGHT_16   0x1
+#define VDOAC_BAND_HEIGHT_32   0x2
+
+#define VDOASRR_START          BIT(1)
+#define VDOASRR_SWRST          BIT(0)
+
+#define VDOAIE_EITERR          BIT(1)
+#define VDOAIE_EIEOT           BIT(0)
+
+#define VDOAIST_TERR           BIT(1)
+#define VDOAIST_EOT            BIT(0)
+
+#define VDOAFP_FH_MASK         (0x1fff << 16)
+#define VDOAFP_FW_MASK         (0x3fff)
+
+#define VDOASL_VSLY_MASK       (0x3fff << 16)
+#define VDOASL_ISLY_MASK       (0x7fff)
+
+#define VDOASR_ERRW            BIT(4)
+#define VDOASR_EOB             BIT(3)
+#define VDOASR_CURRENT_FRAME   (0x3 << 1)
+#define VDOASR_CURRENT_BUFFER  BIT(1)
+
+enum {
+       V4L2_M2M_SRC = 0,
+       V4L2_M2M_DST = 1,
+};
+
+struct vdoa_data {
+       struct vdoa_ctx         *curr_ctx;
+       struct device           *dev;
+       struct clk              *vdoa_clk;
+       void __iomem            *regs;
+       int                     irq;
+};
+
+struct vdoa_q_data {
+       unsigned int    width;
+       unsigned int    height;
+       unsigned int    bytesperline;
+       unsigned int    sizeimage;
+       u32             pixelformat;
+};
+
+struct vdoa_ctx {
+       struct vdoa_data        *vdoa;
+       struct completion       completion;
+       struct vdoa_q_data      q_data[2];
+};
+
+static irqreturn_t vdoa_irq_handler(int irq, void *data)
+{
+       struct vdoa_data *vdoa = data;
+       struct vdoa_ctx *curr_ctx;
+       u32 val;
+
+       /* Disable interrupts */
+       writel(0, vdoa->regs + VDOAIE);
+
+       curr_ctx = vdoa->curr_ctx;
+       if (!curr_ctx) {
+               dev_dbg(vdoa->dev,
+                       "Instance released before the end of transaction\n");
+               return IRQ_HANDLED;
+       }
+
+       val = readl(vdoa->regs + VDOAIST);
+       writel(val, vdoa->regs + VDOAIST);
+       if (val & VDOAIST_TERR) {
+               val = readl(vdoa->regs + VDOASR) & VDOASR_ERRW;
+               dev_err(vdoa->dev, "AXI %s error\n", val ? "write" : "read");
+       } else if (!(val & VDOAIST_EOT)) {
+               dev_warn(vdoa->dev, "Spurious interrupt\n");
+       }
+       complete(&curr_ctx->completion);
+
+       return IRQ_HANDLED;
+}
+
+void vdoa_device_run(struct vdoa_ctx *ctx, dma_addr_t dst, dma_addr_t src)
+{
+       struct vdoa_q_data *src_q_data, *dst_q_data;
+       struct vdoa_data *vdoa = ctx->vdoa;
+       u32 val;
+
+       vdoa->curr_ctx = ctx;
+
+       src_q_data = &ctx->q_data[V4L2_M2M_SRC];
+       dst_q_data = &ctx->q_data[V4L2_M2M_DST];
+
+       /* Progressive, no sync, 1 frame per run */
+       if (dst_q_data->pixelformat == V4L2_PIX_FMT_YUYV)
+               val = VDOAC_PFS;
+       else
+               val = 0;
+       writel(val, vdoa->regs + VDOAC);
+
+       writel(dst_q_data->height << 16 | dst_q_data->width,
+              vdoa->regs + VDOAFP);
+
+       val = dst;
+       writel(val, vdoa->regs + VDOAIEBA00);
+
+       writel(src_q_data->bytesperline << 16 | dst_q_data->bytesperline,
+              vdoa->regs + VDOASL);
+
+       if (dst_q_data->pixelformat == V4L2_PIX_FMT_NV12 ||
+           dst_q_data->pixelformat == V4L2_PIX_FMT_NV21)
+               val = dst_q_data->bytesperline * dst_q_data->height;
+       else
+               val = 0;
+       writel(val, vdoa->regs + VDOAIUBO);
+
+       val = src;
+       writel(val, vdoa->regs + VDOAVEBA0);
+       val = round_up(src_q_data->bytesperline * src_q_data->height, 4096);
+       writel(val, vdoa->regs + VDOAVUBO);
+
+       /* Enable interrupts and start transfer */
+       writel(VDOAIE_EITERR | VDOAIE_EIEOT, vdoa->regs + VDOAIE);
+       writel(VDOASRR_START, vdoa->regs + VDOASRR);
+}
+EXPORT_SYMBOL(vdoa_device_run);
+
+int vdoa_wait_for_completion(struct vdoa_ctx *ctx)
+{
+       struct vdoa_data *vdoa = ctx->vdoa;
+
+       if (!wait_for_completion_timeout(&ctx->completion,
+                                        msecs_to_jiffies(300))) {
+               dev_err(vdoa->dev,
+                       "Timeout waiting for transfer result\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(vdoa_wait_for_completion);
+
+struct vdoa_ctx *vdoa_context_create(struct vdoa_data *vdoa)
+{
+       struct vdoa_ctx *ctx;
+       int err;
+
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return NULL;
+
+       err = clk_prepare_enable(vdoa->vdoa_clk);
+       if (err) {
+               kfree(ctx);
+               return NULL;
+       }
+
+       init_completion(&ctx->completion);
+       ctx->vdoa = vdoa;
+
+       return ctx;
+}
+EXPORT_SYMBOL(vdoa_context_create);
+
+void vdoa_context_destroy(struct vdoa_ctx *ctx)
+{
+       struct vdoa_data *vdoa = ctx->vdoa;
+
+       clk_disable_unprepare(vdoa->vdoa_clk);
+       kfree(ctx);
+}
+EXPORT_SYMBOL(vdoa_context_destroy);
+
+int vdoa_context_configure(struct vdoa_ctx *ctx,
+                          unsigned int width, unsigned int height,
+                          u32 pixelformat)
+{
+       struct vdoa_q_data *src_q_data;
+       struct vdoa_q_data *dst_q_data;
+
+       if (width < 16 || width  > 8192 || width % 16 != 0 ||
+           height < 16 || height > 4096 || height % 16 != 0)
+               return -EINVAL;
+
+       if (pixelformat != V4L2_PIX_FMT_YUYV &&
+           pixelformat != V4L2_PIX_FMT_NV12)
+               return -EINVAL;
+
+       /* If no context is passed, only check if the format is valid */
+       if (!ctx)
+               return 0;
+
+       src_q_data = &ctx->q_data[V4L2_M2M_SRC];
+       dst_q_data = &ctx->q_data[V4L2_M2M_DST];
+
+       src_q_data->width = width;
+       src_q_data->height = height;
+       src_q_data->bytesperline = width;
+       src_q_data->sizeimage =
+               round_up(src_q_data->bytesperline * height, 4096) +
+               src_q_data->bytesperline * height / 2;
+
+       dst_q_data->width = width;
+       dst_q_data->height = height;
+       dst_q_data->pixelformat = pixelformat;
+       switch (pixelformat) {
+       case V4L2_PIX_FMT_YUYV:
+               dst_q_data->bytesperline = width * 2;
+               dst_q_data->sizeimage = dst_q_data->bytesperline * height;
+               break;
+       case V4L2_PIX_FMT_NV12:
+       default:
+               dst_q_data->bytesperline = width;
+               dst_q_data->sizeimage =
+                       dst_q_data->bytesperline * height * 3 / 2;
+               break;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(vdoa_context_configure);
+
+static int vdoa_probe(struct platform_device *pdev)
+{
+       struct vdoa_data *vdoa;
+       struct resource *res;
+
+       dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+
+       vdoa = devm_kzalloc(&pdev->dev, sizeof(*vdoa), GFP_KERNEL);
+       if (!vdoa)
+               return -ENOMEM;
+
+       vdoa->dev = &pdev->dev;
+
+       vdoa->vdoa_clk = devm_clk_get(vdoa->dev, NULL);
+       if (IS_ERR(vdoa->vdoa_clk)) {
+               dev_err(vdoa->dev, "Failed to get clock\n");
+               return PTR_ERR(vdoa->vdoa_clk);
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       vdoa->regs = devm_ioremap_resource(vdoa->dev, res);
+       if (IS_ERR(vdoa->regs))
+               return PTR_ERR(vdoa->regs);
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       vdoa->irq = devm_request_threaded_irq(&pdev->dev, res->start, NULL,
+                                       vdoa_irq_handler, IRQF_ONESHOT,
+                                       "vdoa", vdoa);
+       if (vdoa->irq < 0) {
+               dev_err(vdoa->dev, "Failed to get irq\n");
+               return vdoa->irq;
+       }
+
+       platform_set_drvdata(pdev, vdoa);
+
+       return 0;
+}
+
+static int vdoa_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static const struct of_device_id vdoa_dt_ids[] = {
+       { .compatible = "fsl,imx6q-vdoa" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, vdoa_dt_ids);
+
+static const struct platform_driver vdoa_driver = {
+       .probe          = vdoa_probe,
+       .remove         = vdoa_remove,
+       .driver         = {
+               .name   = VDOA_NAME,
+               .of_match_table = vdoa_dt_ids,
+       },
+};
+
+module_platform_driver(vdoa_driver);
+
+MODULE_DESCRIPTION("Video Data Order Adapter");
+MODULE_AUTHOR("Philipp Zabel <philipp.zabel@gmail.com>");
+MODULE_ALIAS("platform:imx-vdoa");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/coda/imx-vdoa.h b/drivers/media/platform/coda/imx-vdoa.h
new file mode 100644 (file)
index 0000000..967576b
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016 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.
+ * 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 IMX_VDOA_H
+#define IMX_VDOA_H
+
+struct vdoa_data;
+struct vdoa_ctx;
+
+#if (defined CONFIG_VIDEO_IMX_VDOA || defined CONFIG_VIDEO_IMX_VDOA_MODULE)
+
+struct vdoa_ctx *vdoa_context_create(struct vdoa_data *vdoa);
+int vdoa_context_configure(struct vdoa_ctx *ctx,
+                          unsigned int width, unsigned int height,
+                          u32 pixelformat);
+void vdoa_context_destroy(struct vdoa_ctx *ctx);
+
+void vdoa_device_run(struct vdoa_ctx *ctx, dma_addr_t dst, dma_addr_t src);
+int vdoa_wait_for_completion(struct vdoa_ctx *ctx);
+
+#else
+
+static inline struct vdoa_ctx *vdoa_context_create(struct vdoa_data *vdoa)
+{
+       return NULL;
+}
+
+static inline int vdoa_context_configure(struct vdoa_ctx *ctx,
+                                        unsigned int width,
+                                        unsigned int height,
+                                        u32 pixelformat)
+{
+       return 0;
+}
+
+static inline void vdoa_context_destroy(struct vdoa_ctx *ctx) { };
+
+static inline void vdoa_device_run(struct vdoa_ctx *ctx,
+                                  dma_addr_t dst, dma_addr_t src) { };
+
+static inline int vdoa_wait_for_completion(struct vdoa_ctx *ctx)
+{
+       return 0;
+};
+
+#endif
+
+#endif /* IMX_VDOA_H */
index ae5605de7679565013098282e2e89c837b4e4db2..8f6688a7a111cd0a5dbf9cf7370f9b97a1fcde52 100644 (file)
  * 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
- *
  * ccdc device API
  */
 #ifndef _CCDC_HW_DEVICE_H
index 65c2973167c678b7a1201118d07375b806dedfd4..73db166dc338e5b352e9718950fe1739e42115e7 100644 (file)
  * 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
- *
  * CCDC hardware module for DM355
  * ------------------------------
  *
index 2e1946e0b99f0b2fbc8c15be396cf9ef2715597a..a753ce2625832a65880205e68273e5818334ee60 100644 (file)
  * but WITHOUT 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 _DM355_CCDC_REGS_H
 #define _DM355_CCDC_REGS_H
index c7523a7e05940a59187bf205520abf4ab3f2a4d9..740fbc7a8c149172202c082576fdf159b6ba5bc7 100644 (file)
  * 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
- *
  * CCDC hardware module for DM6446
  * ------------------------------
  *
index 2b0aca5383f0d1fef320b88d2d8b4991fd6ff0fd..bece0bd9c9de6772099949f5f760aad53983c95d 100644 (file)
  * but WITHOUT 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 _DM644X_CCDC_REGS_H
 #define _DM644X_CCDC_REGS_H
index 99faea2e84c6b38d78ae9ee5b6337e765f2daf9f..5813b49391edb086b572d05e34bbd608eccf17ab 100644 (file)
  * 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
- *
  * Image Sensor Interface (ISIF) driver
  *
  * This driver is for configuring the ISIF IP available on DM365 or any other
index 3993aece821b92c8498a20f2021f9b7d6381d561..a3564abe08ae27f5c6746f8e10055c5e330ece47 100644 (file)
  * but WITHOUT 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 _ISIF_REGS_H
 #define _ISIF_REGS_H
index 8c8cbeb7d90f0c68312d950bea7be2467d7fc328..3679b1e7b39effe7c5c06ee733f3eabfdc8d2a51 100644 (file)
@@ -9,10 +9,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
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
index 7d96a4b13b3235031bb05efdfb5619606a746f23..df042e84a67830d476f0ee4bc2ebc2b197588c70 100644 (file)
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
  */
 #include <linux/module.h>
 #include <linux/kernel.h>
index 584520f3af608165d86c6bff4ecc32ac06d23f77..3db265f87c650bf368b1b71133d679fdf5b7e8de 100644 (file)
@@ -9,10 +9,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 _VPBE_OSD_REGS_H
 #define _VPBE_OSD_REGS_H
index 36ed1466b290ff7b86037439d7aca21a2db96e4f..8bfe90a246812185e32270230ef3b42ac8d5d174 100644 (file)
@@ -9,10 +9,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
  */
 #include <linux/module.h>
 #include <linux/kernel.h>
index 947cb1510776a03de18c360735bd0cb68095101d..6ad38f7ab0fe97725c2dc4aca013aa136a91ceb6 100644 (file)
@@ -9,10 +9,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 _VPBE_VENC_REGS_H
 #define _VPBE_VENC_REGS_H
index ee1cd79739c8caf6d9ef999738628dc85523078c..e3fe3e0635aa87806abf4b15e4ba83264ec8b557 100644 (file)
  * 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
- *
  * Driver name : VPFE Capture driver
  *    VPFE Capture driver allows applications to capture and stream video
  *    frames on DaVinci SoCs (DM6446, DM355 etc) from a YUV source such as
@@ -523,6 +519,8 @@ static int vpfe_open(struct file *file)
        if (!vpfe_dev->initialized) {
                if (vpfe_initialize_device(vpfe_dev)) {
                        mutex_unlock(&vpfe_dev->lock);
+                       v4l2_fh_exit(&fh->fh);
+                       kfree(fh);
                        return -ENODEV;
                }
        }
index 0380cf2e5775dda31fe7cefa0059c547390bef8d..1b02a6363f7779b664a217ae420a30973b9ac661 100644 (file)
@@ -32,6 +32,9 @@
 MODULE_DESCRIPTION("TI DaVinci Video Port Interface driver");
 MODULE_LICENSE("GPL");
 
+#define VPIF_DRIVER_NAME       "vpif"
+MODULE_ALIAS("platform:" VPIF_DRIVER_NAME);
+
 #define VPIF_CH0_MAX_MODES     22
 #define VPIF_CH1_MAX_MODES     2
 #define VPIF_CH2_MAX_MODES     15
@@ -464,9 +467,18 @@ static const struct dev_pm_ops vpif_pm = {
 #define vpif_pm_ops NULL
 #endif
 
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id vpif_of_match[] = {
+       { .compatible = "ti,da850-vpif", },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, vpif_of_match);
+#endif
+
 static struct platform_driver vpif_driver = {
        .driver = {
-               .name   = "vpif",
+               .of_match_table = of_match_ptr(vpif_of_match),
+               .name   = VPIF_DRIVER_NAME,
                .pm     = vpif_pm_ops,
        },
        .remove = vpif_remove,
index f791f5c402bf1dc72ed630f0f1a817505ac1e0b9..44f702752d3aae4add9bf85339607c0f6d317de3 100644 (file)
  * 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
- *
  * TODO : add support for VBI & HBI data service
  *       add static buffer allocation
  */
@@ -45,6 +41,7 @@ module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Debug level 0-1");
 
 #define VPIF_DRIVER_NAME       "vpif_capture"
+MODULE_ALIAS("platform:" VPIF_DRIVER_NAME);
 
 /* global variables */
 static struct vpif_device vpif_obj = { {NULL} };
@@ -178,8 +175,6 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)
        unsigned long addr, flags;
        int ret;
 
-       spin_lock_irqsave(&common->irqlock, flags);
-
        /* Initialize field_id */
        ch->field_id = 0;
 
@@ -210,6 +205,7 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)
        vpif_config_addr(ch, ret);
 
        /* Get the next frame from the buffer queue */
+       spin_lock_irqsave(&common->irqlock, flags);
        common->cur_frm = common->next_frm = list_entry(common->dma_queue.next,
                                    struct vpif_cap_buffer, list);
        /* Remove buffer from the buffer queue */
@@ -243,6 +239,7 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)
        return 0;
 
 err:
+       spin_lock_irqsave(&common->irqlock, flags);
        list_for_each_entry_safe(buf, tmp, &common->dma_queue, list) {
                list_del(&buf->list);
                vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED);
@@ -286,7 +283,6 @@ static void vpif_stop_streaming(struct vb2_queue *vq)
                vpif_dbg(1, debug, "stream off failed in subdev\n");
 
        /* release all active buffers */
-       spin_lock_irqsave(&common->irqlock, flags);
        if (common->cur_frm == common->next_frm) {
                vb2_buffer_done(&common->cur_frm->vb.vb2_buf,
                                VB2_BUF_STATE_ERROR);
@@ -299,6 +295,7 @@ static void vpif_stop_streaming(struct vb2_queue *vq)
                                        VB2_BUF_STATE_ERROR);
        }
 
+       spin_lock_irqsave(&common->irqlock, flags);
        while (!list_empty(&common->dma_queue)) {
                common->next_frm = list_entry(common->dma_queue.next,
                                                struct vpif_cap_buffer, list);
@@ -647,6 +644,10 @@ static int vpif_input_to_subdev(
 
        vpif_dbg(2, debug, "vpif_input_to_subdev\n");
 
+       if (!chan_cfg)
+               return -1;
+       if (input_index >= chan_cfg->input_count)
+               return -1;
        subdev_name = chan_cfg->inputs[input_index].subdev_name;
        if (!subdev_name)
                return -1;
@@ -685,6 +686,9 @@ static int vpif_set_input(
        if (sd_index >= 0) {
                sd = vpif_obj.sd[sd_index];
                subdev_info = &vpif_cfg->subdev_info[sd_index];
+       } else {
+               /* no subdevice, no input to setup */
+               return 0;
        }
 
        /* first setup input path from sub device to vpif */
@@ -1430,6 +1434,11 @@ static __init int vpif_probe(struct platform_device *pdev)
        int res_idx = 0;
        int i, err;
 
+       if (!pdev->dev.platform_data) {
+               dev_warn(&pdev->dev, "Missing platform data.  Giving up.\n");
+               return -EINVAL;
+       }
+
        vpif_dev = &pdev->dev;
 
        err = initialize_vpif();
@@ -1466,7 +1475,10 @@ static __init int vpif_probe(struct platform_device *pdev)
        }
 
        if (!vpif_obj.config->asd_sizes) {
-               i2c_adap = i2c_get_adapter(1);
+               int i2c_id = vpif_obj.config->i2c_adapter_id;
+
+               i2c_adap = i2c_get_adapter(i2c_id);
+               WARN_ON(!i2c_adap);
                for (i = 0; i < subdev_count; i++) {
                        subdevdata = &vpif_obj.config->subdev_info[i];
                        vpif_obj.sd[i] =
index 9e35b6771d22a04cc333938be45eb0dafa49b21f..cf494a596a440d03c44b2042a0e4376a609e2403 100644 (file)
  * but WITHOUT 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 VPIF_CAPTURE_H
@@ -67,7 +63,7 @@ struct common_obj {
        struct vb2_queue buffer_queue;
        /* Queue of filled frames */
        struct list_head dma_queue;
-       /* Used in video-buf */
+       /* Protects the dma_queue field */
        spinlock_t irqlock;
        /* lock used to access this structure */
        struct mutex lock;
index e5f18448dbf73e6cc73c9e573f6fa537a8edf60e..50c30731bb78e2ac4029874c0b2bb3ec8352ddbf 100644 (file)
@@ -42,6 +42,7 @@ module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Debug level 0-1");
 
 #define VPIF_DRIVER_NAME       "vpif_display"
+MODULE_ALIAS("platform:" VPIF_DRIVER_NAME);
 
 /* Is set to 1 in case of SDTV formats, 2 in case of HDTV formats. */
 static int ycmux_mode;
@@ -1244,6 +1245,11 @@ static __init int vpif_probe(struct platform_device *pdev)
        int res_idx = 0;
        int i, err;
 
+       if (!pdev->dev.platform_data) {
+               dev_warn(&pdev->dev, "Missing platform data.  Giving up.\n");
+               return -EINVAL;
+       }
+
        vpif_dev = &pdev->dev;
        err = initialize_vpif();
 
index 373b796132f20b96a337ba4a5f9213b2bdf416e9..f2d27b9329990a9cfbbaf315448210b0c9dc4ea4 100644 (file)
  * 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.
- *
  * common vpss system module platform driver for all video drivers.
  */
 #include <linux/module.h>
index cbf75b6194b431934a45b877617de3e6bb504501..cbb03768f5d73574b4d95939a08d7605e94dd6d7 100644 (file)
@@ -408,7 +408,7 @@ int gsc_try_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f)
        if (pix_mp->field == V4L2_FIELD_ANY)
                pix_mp->field = V4L2_FIELD_NONE;
        else if (pix_mp->field != V4L2_FIELD_NONE) {
-               pr_err("Not supported field order(%d)\n", pix_mp->field);
+               pr_debug("Not supported field order(%d)\n", pix_mp->field);
                return -EINVAL;
        }
 
@@ -1118,6 +1118,7 @@ static int gsc_remove(struct platform_device *pdev)
                clk_disable_unprepare(gsc->clock[i]);
 
        pm_runtime_put_noidle(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
 
        dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name);
        return 0;
index f49f24b4462abe62992837f95a1ab1724a6fd695..82505025d96c422d3b66ba82a70c70454740bef3 100644 (file)
@@ -675,8 +675,8 @@ static int gsc_m2m_open(struct file *file)
 
 error_ctrls:
        gsc_ctrls_delete(ctx);
-error_fh:
        v4l2_fh_del(&ctx->fh);
+error_fh:
        v4l2_fh_exit(&ctx->fh);
        kfree(ctx);
 unlock:
index 964f4a6819343a4fe1fc375ddde45a052cab3747..8a7cd07dbe281e757904fabe423296751e861012 100644 (file)
@@ -536,7 +536,7 @@ static int fimc_capture_release(struct file *file)
        mutex_lock(&fimc->lock);
 
        if (close && vc->streaming) {
-               media_entity_pipeline_stop(&vc->ve.vdev.entity);
+               media_pipeline_stop(&vc->ve.vdev.entity);
                vc->streaming = false;
        }
 
@@ -1195,7 +1195,7 @@ static int fimc_cap_streamon(struct file *file, void *priv,
        if (fimc_capture_active(fimc))
                return -EBUSY;
 
-       ret = media_entity_pipeline_start(entity, &vc->ve.pipe->mp);
+       ret = media_pipeline_start(entity, &vc->ve.pipe->mp);
        if (ret < 0)
                return ret;
 
@@ -1229,7 +1229,7 @@ static int fimc_cap_streamon(struct file *file, void *priv,
        }
 
 err_p_stop:
-       media_entity_pipeline_stop(entity);
+       media_pipeline_stop(entity);
        return ret;
 }
 
@@ -1244,7 +1244,7 @@ static int fimc_cap_streamoff(struct file *file, void *priv,
        if (ret < 0)
                return ret;
 
-       media_entity_pipeline_stop(&vc->ve.vdev.entity);
+       media_pipeline_stop(&vc->ve.vdev.entity);
        vc->streaming = false;
        return 0;
 }
@@ -1695,7 +1695,7 @@ static int fimc_subdev_set_selection(struct v4l2_subdev *sd,
        return 0;
 }
 
-static struct v4l2_subdev_pad_ops fimc_subdev_pad_ops = {
+static const struct v4l2_subdev_pad_ops fimc_subdev_pad_ops = {
        .enum_mbus_code = fimc_subdev_enum_mbus_code,
        .get_selection = fimc_subdev_get_selection,
        .set_selection = fimc_subdev_set_selection,
@@ -1703,7 +1703,7 @@ static struct v4l2_subdev_pad_ops fimc_subdev_pad_ops = {
        .set_fmt = fimc_subdev_set_fmt,
 };
 
-static struct v4l2_subdev_ops fimc_subdev_ops = {
+static const struct v4l2_subdev_ops fimc_subdev_ops = {
        .pad = &fimc_subdev_pad_ops,
 };
 
index 6bba4ca022be542e478b32c76286f0a2f11927d3..2f559663e51e5046e58a7be15e95242848d98cf6 100644 (file)
@@ -28,7 +28,14 @@ struct fimc_is_i2c {
  * is implemented in the FIMC-IS subsystem firmware and the host CPU
  * doesn't access the I2C bus controller.
  */
-static const struct i2c_algorithm fimc_is_i2c_algorithm;
+static u32 is_i2c_func(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C;
+}
+
+static const struct i2c_algorithm fimc_is_i2c_algorithm = {
+       .functionality  = is_i2c_func,
+};
 
 static int fimc_is_i2c_probe(struct platform_device *pdev)
 {
index 518ad34f80d7c4e1d29d7313568d8f4087f7cc5d..7f92144a1de3acd812dde54c70b32bd901a8959c 100644 (file)
@@ -825,12 +825,13 @@ static int fimc_is_probe(struct platform_device *pdev)
        is->irq = irq_of_parse_and_map(dev->of_node, 0);
        if (!is->irq) {
                dev_err(dev, "no irq found\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto err_iounmap;
        }
 
        ret = fimc_is_get_clocks(is);
        if (ret < 0)
-               return ret;
+               goto err_iounmap;
 
        platform_set_drvdata(pdev, is);
 
@@ -891,6 +892,8 @@ err_irq:
        free_irq(is->irq, is);
 err_clk:
        fimc_is_put_clocks(is);
+err_iounmap:
+       iounmap(is->pmu_regs);
        return ret;
 }
 
@@ -947,6 +950,7 @@ static int fimc_is_remove(struct platform_device *pdev)
        fimc_is_unregister_subdevs(is);
        vb2_dma_contig_clear_max_seg_size(dev);
        fimc_is_put_clocks(is);
+       iounmap(is->pmu_regs);
        fimc_is_debugfs_remove(is);
        release_firmware(is->fw.f_w);
        fimc_is_free_cpu_memory(is);
index 400ce0cb0c0dc97900226d0060c57cb0b3f71711..55ba696b8cf40e13339e42234bfd352e8df90520 100644 (file)
@@ -312,7 +312,7 @@ static int isp_video_release(struct file *file)
        mutex_lock(&isp->video_lock);
 
        if (v4l2_fh_is_singular_file(file) && ivc->streaming) {
-               media_entity_pipeline_stop(entity);
+               media_pipeline_stop(entity);
                ivc->streaming = 0;
        }
 
@@ -489,7 +489,7 @@ static int isp_video_streamon(struct file *file, void *priv,
        struct media_entity *me = &ve->vdev.entity;
        int ret;
 
-       ret = media_entity_pipeline_start(me, &ve->pipe->mp);
+       ret = media_pipeline_start(me, &ve->pipe->mp);
        if (ret < 0)
                return ret;
 
@@ -504,7 +504,7 @@ static int isp_video_streamon(struct file *file, void *priv,
        isp->video_capture.streaming = 1;
        return 0;
 p_stop:
-       media_entity_pipeline_stop(me);
+       media_pipeline_stop(me);
        return ret;
 }
 
@@ -519,7 +519,7 @@ static int isp_video_streamoff(struct file *file, void *priv,
        if (ret < 0)
                return ret;
 
-       media_entity_pipeline_stop(&video->ve.vdev.entity);
+       media_pipeline_stop(&video->ve.vdev.entity);
        video->streaming = 0;
        return 0;
 }
index b91abf1c4d43b6330ae8ff9daa307affdf25d03e..b4c4a33784c4fde9b9a523b1776d9ece24f40afb 100644 (file)
@@ -524,7 +524,7 @@ static int fimc_lite_release(struct file *file)
        if (v4l2_fh_is_singular_file(file) &&
            atomic_read(&fimc->out_path) == FIMC_IO_DMA) {
                if (fimc->streaming) {
-                       media_entity_pipeline_stop(entity);
+                       media_pipeline_stop(entity);
                        fimc->streaming = false;
                }
                fimc_lite_stop_capture(fimc, false);
@@ -832,7 +832,7 @@ static int fimc_lite_streamon(struct file *file, void *priv,
        if (fimc_lite_active(fimc))
                return -EBUSY;
 
-       ret = media_entity_pipeline_start(entity, &fimc->ve.pipe->mp);
+       ret = media_pipeline_start(entity, &fimc->ve.pipe->mp);
        if (ret < 0)
                return ret;
 
@@ -849,7 +849,7 @@ static int fimc_lite_streamon(struct file *file, void *priv,
        }
 
 err_p_stop:
-       media_entity_pipeline_stop(entity);
+       media_pipeline_stop(entity);
        return 0;
 }
 
@@ -863,7 +863,7 @@ static int fimc_lite_streamoff(struct file *file, void *priv,
        if (ret < 0)
                return ret;
 
-       media_entity_pipeline_stop(&fimc->ve.vdev.entity);
+       media_pipeline_stop(&fimc->ve.vdev.entity);
        fimc->streaming = false;
        return 0;
 }
index 6028e4fbaed35f3a7cf49e151ad9145fcaba9def..d8724fe9e9dae7ca7173c31610b62b04e92141ca 100644 (file)
@@ -663,8 +663,8 @@ error_m2m_ctx:
        v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
 error_c:
        fimc_ctrls_delete(ctx);
-error_fh:
        v4l2_fh_del(&ctx->fh);
+error_fh:
        v4l2_fh_exit(&ctx->fh);
        kfree(ctx);
 unlock:
index e3a8709138fa05bb26da493c23cc74ec2a937189..e82450e90a676db9ba1dafd410d0840d8f209c81 100644 (file)
@@ -402,8 +402,10 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd,
                return ret;
        }
 
-       if (WARN_ON(endpoint.base.port == 0) || index >= FIMC_MAX_SENSORS)
+       if (WARN_ON(endpoint.base.port == 0) || index >= FIMC_MAX_SENSORS) {
+               of_node_put(ep);
                return -EINVAL;
+       }
 
        pd->mux_id = (endpoint.base.port - 1) & 0x1;
 
@@ -1117,7 +1119,7 @@ static int __fimc_md_modify_pipeline(struct media_entity *entity, bool enable)
 
 /* Locking: called with entity->graph_obj.mdev->graph_mutex mutex held. */
 static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable,
-                                     struct media_entity_graph *graph)
+                                     struct media_graph *graph)
 {
        struct media_entity *entity_err = entity;
        int ret;
@@ -1128,9 +1130,9 @@ static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable,
         * through active links. This is needed as we cannot power on/off the
         * subdevs in random order.
         */
-       media_entity_graph_walk_start(graph, entity);
+       media_graph_walk_start(graph, entity);
 
-       while ((entity = media_entity_graph_walk_next(graph))) {
+       while ((entity = media_graph_walk_next(graph))) {
                if (!is_media_entity_v4l2_video_device(entity))
                        continue;
 
@@ -1143,9 +1145,9 @@ static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable,
        return 0;
 
 err:
-       media_entity_graph_walk_start(graph, entity_err);
+       media_graph_walk_start(graph, entity_err);
 
-       while ((entity_err = media_entity_graph_walk_next(graph))) {
+       while ((entity_err = media_graph_walk_next(graph))) {
                if (!is_media_entity_v4l2_video_device(entity_err))
                        continue;
 
@@ -1161,7 +1163,7 @@ err:
 static int fimc_md_link_notify(struct media_link *link, unsigned int flags,
                                unsigned int notification)
 {
-       struct media_entity_graph *graph =
+       struct media_graph *graph =
                &container_of(link->graph_obj.mdev, struct fimc_md,
                              media_dev)->link_setup_graph;
        struct media_entity *sink = link->sink->entity;
@@ -1169,7 +1171,7 @@ static int fimc_md_link_notify(struct media_link *link, unsigned int flags,
 
        /* Before link disconnection */
        if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH) {
-               ret = media_entity_graph_walk_init(graph,
+               ret = media_graph_walk_init(graph,
                                                   link->graph_obj.mdev);
                if (ret)
                        return ret;
@@ -1183,7 +1185,7 @@ static int fimc_md_link_notify(struct media_link *link, unsigned int flags,
        } else if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH) {
                if (link->flags & MEDIA_LNK_FL_ENABLED)
                        ret = __fimc_md_modify_pipelines(sink, true, graph);
-               media_entity_graph_walk_cleanup(graph);
+               media_graph_walk_cleanup(graph);
        }
 
        return ret ? -EPIPE : 0;
index ed122cb2dd7416bbc8fd3a6dbda4e7b2e0341b17..957787a2f48002379639ee362e0ba59935ab7062 100644 (file)
@@ -154,7 +154,7 @@ struct fimc_md {
        bool user_subdev_api;
        spinlock_t slock;
        struct list_head pipelines;
-       struct media_entity_graph link_setup_graph;
+       struct media_graph link_setup_graph;
 };
 
 static inline
index befd9fc0adc4aa26c74deee6a9e6ba39d50251c2..f819b29efc384bc573bd3070fda60472ef792ab6 100644 (file)
@@ -649,23 +649,23 @@ static int s5pcsis_log_status(struct v4l2_subdev *sd)
        return 0;
 }
 
-static struct v4l2_subdev_core_ops s5pcsis_core_ops = {
+static const struct v4l2_subdev_core_ops s5pcsis_core_ops = {
        .s_power = s5pcsis_s_power,
        .log_status = s5pcsis_log_status,
 };
 
-static struct v4l2_subdev_pad_ops s5pcsis_pad_ops = {
+static const struct v4l2_subdev_pad_ops s5pcsis_pad_ops = {
        .enum_mbus_code = s5pcsis_enum_mbus_code,
        .get_fmt = s5pcsis_get_fmt,
        .set_fmt = s5pcsis_set_fmt,
 };
 
-static struct v4l2_subdev_video_ops s5pcsis_video_ops = {
+static const struct v4l2_subdev_video_ops s5pcsis_video_ops = {
        .s_rx_buffer = s5pcsis_s_rx_buffer,
        .s_stream = s5pcsis_s_stream,
 };
 
-static struct v4l2_subdev_ops s5pcsis_subdev_ops = {
+static const struct v4l2_subdev_ops s5pcsis_subdev_ops = {
        .core = &s5pcsis_core_ops,
        .pad = &s5pcsis_pad_ops,
        .video = &s5pcsis_video_ops,
index 0746592278645d0a8794bfd4e3286a2bd7396a33..502877a4b1df34a502145d22e57af23889643fd8 100644 (file)
@@ -351,16 +351,6 @@ static void mtk_vdec_worker(struct work_struct *work)
        dst_vb2_v4l2 = container_of(dst_buf, struct vb2_v4l2_buffer, vb2_buf);
        dst_buf_info = container_of(dst_vb2_v4l2, struct mtk_video_dec_buf, vb);
 
-       buf.va = vb2_plane_vaddr(src_buf, 0);
-       buf.dma_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
-       buf.size = (size_t)src_buf->planes[0].bytesused;
-       if (!buf.va) {
-               v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
-               mtk_v4l2_err("[%d] id=%d src_addr is NULL!!",
-                               ctx->id, src_buf->index);
-               return;
-       }
-
        pfb = &dst_buf_info->frame_buffer;
        pfb->base_y.va = vb2_plane_vaddr(dst_buf, 0);
        pfb->base_y.dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
@@ -371,8 +361,6 @@ static void mtk_vdec_worker(struct work_struct *work)
        pfb->base_c.size = ctx->picinfo.c_bs_sz + ctx->picinfo.c_len_sz;
        pfb->status = 0;
        mtk_v4l2_debug(3, "===>[%d] vdec_if_decode() ===>", ctx->id);
-       mtk_v4l2_debug(3, "[%d] Bitstream VA=%p DMA=%pad Size=%zx vb=%p",
-                       ctx->id, buf.va, &buf.dma_addr, buf.size, src_buf);
 
        mtk_v4l2_debug(3,
                        "id=%d Framebuf  pfb=%p VA=%p Y_DMA=%pad C_DMA=%pad Size=%zx",
@@ -381,24 +369,36 @@ static void mtk_vdec_worker(struct work_struct *work)
                        &pfb->base_c.dma_addr, pfb->base_y.size);
 
        if (src_buf_info->lastframe) {
-               /* update src buf status */
+               mtk_v4l2_debug(1, "Got empty flush input buffer.");
                src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
-               src_buf_info->lastframe = false;
-               v4l2_m2m_buf_done(&src_buf_info->vb, VB2_BUF_STATE_DONE);
 
                /* update dst buf status */
                dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+               mutex_lock(&ctx->lock);
                dst_buf_info->used = false;
+               mutex_unlock(&ctx->lock);
 
                vdec_if_decode(ctx, NULL, NULL, &res_chg);
                clean_display_buffer(ctx);
                vb2_set_plane_payload(&dst_buf_info->vb.vb2_buf, 0, 0);
                vb2_set_plane_payload(&dst_buf_info->vb.vb2_buf, 1, 0);
+               dst_vb2_v4l2->flags |= V4L2_BUF_FLAG_LAST;
                v4l2_m2m_buf_done(&dst_buf_info->vb, VB2_BUF_STATE_DONE);
                clean_free_buffer(ctx);
                v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
                return;
        }
+       buf.va = vb2_plane_vaddr(src_buf, 0);
+       buf.dma_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+       buf.size = (size_t)src_buf->planes[0].bytesused;
+       if (!buf.va) {
+               v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
+               mtk_v4l2_err("[%d] id=%d src_addr is NULL!!",
+                               ctx->id, src_buf->index);
+               return;
+       }
+       mtk_v4l2_debug(3, "[%d] Bitstream VA=%p DMA=%pad Size=%zx vb=%p",
+                       ctx->id, buf.va, &buf.dma_addr, buf.size, src_buf);
        dst_buf_info->vb.vb2_buf.timestamp
                        = src_buf_info->vb.vb2_buf.timestamp;
        dst_buf_info->vb.timecode
@@ -412,10 +412,9 @@ static void mtk_vdec_worker(struct work_struct *work)
 
        if (ret) {
                mtk_v4l2_err(
-                       " <===[%d], src_buf[%d]%d sz=0x%zx pts=%llu dst_buf[%d] vdec_if_decode() ret=%d res_chg=%d===>",
+                       " <===[%d], src_buf[%d] sz=0x%zx pts=%llu dst_buf[%d] vdec_if_decode() ret=%d res_chg=%d===>",
                        ctx->id,
                        src_buf->index,
-                       src_buf_info->lastframe,
                        buf.size,
                        src_buf_info->vb.vb2_buf.timestamp,
                        dst_buf->index,
@@ -456,6 +455,65 @@ static void mtk_vdec_worker(struct work_struct *work)
        v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
 }
 
+static int vidioc_try_decoder_cmd(struct file *file, void *priv,
+                               struct v4l2_decoder_cmd *cmd)
+{
+       switch (cmd->cmd) {
+       case V4L2_DEC_CMD_STOP:
+       case V4L2_DEC_CMD_START:
+               if (cmd->flags != 0) {
+                       mtk_v4l2_err("cmd->flags=%u", cmd->flags);
+                       return -EINVAL;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+
+static int vidioc_decoder_cmd(struct file *file, void *priv,
+                               struct v4l2_decoder_cmd *cmd)
+{
+       struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+       struct vb2_queue *src_vq, *dst_vq;
+       int ret;
+
+       ret = vidioc_try_decoder_cmd(file, priv, cmd);
+       if (ret)
+               return ret;
+
+       mtk_v4l2_debug(1, "decoder cmd=%u", cmd->cmd);
+       dst_vq = v4l2_m2m_get_vq(ctx->m2m_ctx,
+                               V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+       switch (cmd->cmd) {
+       case V4L2_DEC_CMD_STOP:
+               src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx,
+                               V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+               if (!vb2_is_streaming(src_vq)) {
+                       mtk_v4l2_debug(1, "Output stream is off. No need to flush.");
+                       return 0;
+               }
+               if (!vb2_is_streaming(dst_vq)) {
+                       mtk_v4l2_debug(1, "Capture stream is off. No need to flush.");
+                       return 0;
+               }
+               v4l2_m2m_buf_queue(ctx->m2m_ctx, &ctx->empty_flush_buf->vb);
+               v4l2_m2m_try_schedule(ctx->m2m_ctx);
+               break;
+
+       case V4L2_DEC_CMD_START:
+               vb2_clear_last_buffer_dequeued(dst_vq);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 void mtk_vdec_unlock(struct mtk_vcodec_ctx *ctx)
 {
        mutex_unlock(&ctx->dev->dec_mutex);
@@ -521,10 +579,6 @@ static int vidioc_vdec_qbuf(struct file *file, void *priv,
                            struct v4l2_buffer *buf)
 {
        struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
-       struct vb2_queue *vq;
-       struct vb2_buffer *vb;
-       struct mtk_video_dec_buf *mtkbuf;
-       struct vb2_v4l2_buffer  *vb2_v4l2;
 
        if (ctx->state == MTK_STATE_ABORT) {
                mtk_v4l2_err("[%d] Call on QBUF after unrecoverable error",
@@ -532,25 +586,6 @@ static int vidioc_vdec_qbuf(struct file *file, void *priv,
                return -EIO;
        }
 
-       vq = v4l2_m2m_get_vq(ctx->m2m_ctx, buf->type);
-       if (buf->index >= vq->num_buffers) {
-               mtk_v4l2_debug(1, "buffer index %d out of range", buf->index);
-               return -EINVAL;
-       }
-       vb = vq->bufs[buf->index];
-       vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf);
-       mtkbuf = container_of(vb2_v4l2, struct mtk_video_dec_buf, vb);
-
-       if ((buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) &&
-           (buf->m.planes[0].bytesused == 0)) {
-               mtkbuf->lastframe = true;
-               mtk_v4l2_debug(1, "[%d] (%d) id=%d lastframe=%d (%d,%d, %d) vb=%p",
-                        ctx->id, buf->type, buf->index,
-                        mtkbuf->lastframe, buf->bytesused,
-                        buf->m.planes[0].bytesused, buf->length,
-                        vb);
-       }
-
        return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
 }
 
@@ -1067,10 +1102,8 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb)
        int ret = 0;
        unsigned int dpbsize = 1;
        struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-       struct vb2_v4l2_buffer *vb2_v4l2 = container_of(vb,
-                               struct vb2_v4l2_buffer, vb2_buf);
-       struct mtk_video_dec_buf *buf = container_of(vb2_v4l2,
-                               struct mtk_video_dec_buf, vb);
+       struct vb2_v4l2_buffer *vb2_v4l2 = NULL;
+       struct mtk_video_dec_buf *buf = NULL;
 
        mtk_v4l2_debug(3, "[%d] (%d) id=%d, vb=%p",
                        ctx->id, vb->vb2_queue->type,
@@ -1079,10 +1112,11 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb)
         * check if this buffer is ready to be used after decode
         */
        if (vb->vb2_queue->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               vb2_v4l2 = to_vb2_v4l2_buffer(vb);
+               buf = container_of(vb2_v4l2, struct mtk_video_dec_buf, vb);
                mutex_lock(&ctx->lock);
                if (buf->used == false) {
-                       v4l2_m2m_buf_queue(ctx->m2m_ctx,
-                                       to_vb2_v4l2_buffer(vb));
+                       v4l2_m2m_buf_queue(ctx->m2m_ctx, vb2_v4l2);
                        buf->queued_in_vb2 = true;
                        buf->queued_in_v4l2 = true;
                        buf->ready_to_display = false;
@@ -1095,7 +1129,7 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb)
                return;
        }
 
-       v4l2_m2m_buf_queue(ctx->m2m_ctx, vb2_v4l2);
+       v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb));
 
        if (ctx->state != MTK_STATE_INIT) {
                mtk_v4l2_debug(3, "[%d] already init driver %d",
@@ -1108,6 +1142,14 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb)
                mtk_v4l2_err("No src buffer");
                return;
        }
+       vb2_v4l2 = to_vb2_v4l2_buffer(src_buf);
+       buf = container_of(vb2_v4l2, struct mtk_video_dec_buf, vb);
+       if (buf->lastframe) {
+               /* This shouldn't happen. Just in case. */
+               mtk_v4l2_err("Invalid flush buffer.");
+               v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+               return;
+       }
 
        src_mem.va = vb2_plane_vaddr(src_buf, 0);
        src_mem.dma_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
@@ -1126,15 +1168,14 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb)
                 * if there is no SPS header or picture info
                 * in bs
                 */
-               int log_level = ret ? 0 : 1;
 
                src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
                v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf),
                                        VB2_BUF_STATE_DONE);
-               mtk_v4l2_debug(log_level,
-                               "[%d] vdec_if_decode() src_buf=%d, size=%zu, fail=%d, res_chg=%d",
-                               ctx->id, src_buf->index,
-                               src_mem.size, ret, res_chg);
+               mtk_v4l2_debug(ret ? 0 : 1,
+                              "[%d] vdec_if_decode() src_buf=%d, size=%zu, fail=%d, res_chg=%d",
+                              ctx->id, src_buf->index,
+                              src_mem.size, ret, res_chg);
                return;
        }
 
@@ -1224,9 +1265,15 @@ static void vb2ops_vdec_stop_streaming(struct vb2_queue *q)
                        ctx->id, q->type, ctx->state, ctx->decoded_frame_cnt);
 
        if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-               while ((src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx)))
-                       v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf),
-                                       VB2_BUF_STATE_ERROR);
+               while ((src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx))) {
+                       struct vb2_v4l2_buffer *vb2_v4l2 =
+                                       to_vb2_v4l2_buffer(src_buf);
+                       struct mtk_video_dec_buf *buf_info = container_of(
+                                       vb2_v4l2, struct mtk_video_dec_buf, vb);
+                       if (!buf_info->lastframe)
+                               v4l2_m2m_buf_done(vb2_v4l2,
+                                               VB2_BUF_STATE_ERROR);
+               }
                return;
        }
 
@@ -1406,6 +1453,9 @@ const struct v4l2_ioctl_ops mtk_vdec_ioctl_ops = {
        .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
        .vidioc_g_selection             = vidioc_vdec_g_selection,
        .vidioc_s_selection             = vidioc_vdec_s_selection,
+
+       .vidioc_decoder_cmd = vidioc_decoder_cmd,
+       .vidioc_try_decoder_cmd = vidioc_try_decoder_cmd,
 };
 
 int mtk_vcodec_dec_queue_init(void *priv, struct vb2_queue *src_vq,
index d48287c727f4f7e418f935bdad91c2f03a7daf73..4334b73948612911f508e7bf6ca29a41d53982f5 100644 (file)
@@ -105,13 +105,21 @@ static int fops_vcodec_open(struct file *file)
 {
        struct mtk_vcodec_dev *dev = video_drvdata(file);
        struct mtk_vcodec_ctx *ctx = NULL;
+       struct mtk_video_dec_buf *mtk_buf = NULL;
        int ret = 0;
+       struct vb2_queue *src_vq;
 
        ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
        if (!ctx)
                return -ENOMEM;
+       mtk_buf = kzalloc(sizeof(*mtk_buf), GFP_KERNEL);
+       if (!mtk_buf) {
+               kfree(ctx);
+               return -ENOMEM;
+       }
 
        mutex_lock(&dev->dev_mutex);
+       ctx->empty_flush_buf = mtk_buf;
        ctx->id = dev->id_counter++;
        v4l2_fh_init(&ctx->fh, video_devdata(file));
        file->private_data = &ctx->fh;
@@ -135,6 +143,10 @@ static int fops_vcodec_open(struct file *file)
                        ret);
                goto err_m2m_ctx_init;
        }
+       src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx,
+                               V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+       ctx->empty_flush_buf->vb.vb2_buf.vb2_queue = src_vq;
+       ctx->empty_flush_buf->lastframe = true;
        mtk_vcodec_dec_set_default_params(ctx);
 
        if (v4l2_fh_is_singular(&ctx->fh)) {
@@ -173,6 +185,7 @@ err_m2m_ctx_init:
 err_ctrls_setup:
        v4l2_fh_del(&ctx->fh);
        v4l2_fh_exit(&ctx->fh);
+       kfree(ctx->empty_flush_buf);
        kfree(ctx);
        mutex_unlock(&dev->dev_mutex);
 
@@ -203,6 +216,7 @@ static int fops_vcodec_release(struct file *file)
        v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
 
        list_del_init(&ctx->list);
+       kfree(ctx->empty_flush_buf);
        kfree(ctx);
        mutex_unlock(&dev->dev_mutex);
        return 0;
index d7eb8ef855d25e59d9de3871f42275d271beba0c..3cffb381ac8e280ba9c8fa14d75681e2d4bf8f3d 100644 (file)
@@ -254,6 +254,7 @@ struct vdec_pic_info {
  * @decode_work: worker for the decoding
  * @encode_work: worker for the encoding
  * @last_decoded_picinfo: pic information get from latest decode
+ * @empty_flush_buf: a fake size-0 capture buffer that indicates flush
  *
  * @colorspace: enum v4l2_colorspace; supplemental to pixelformat
  * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding
@@ -291,6 +292,7 @@ struct mtk_vcodec_ctx {
        struct work_struct decode_work;
        struct work_struct encode_work;
        struct vdec_pic_info last_decoded_picinfo;
+       struct mtk_video_dec_buf *empty_flush_buf;
 
        enum v4l2_colorspace colorspace;
        enum v4l2_ycbcr_encoding ycbcr_enc;
index 5a24c51aebb7dc13f2d4876bccc2bd67f1ff9203..1abd14e79565f4105b9bdbed425f6fe3d2464a30 100644 (file)
@@ -70,9 +70,8 @@ void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv)
 static int vcodec_vpu_send_msg(struct vdec_vpu_inst *vpu, void *msg, int len)
 {
        int err;
-       uint32_t msg_id = *(uint32_t *)msg;
 
-       mtk_vcodec_debug(vpu, "id=%X", msg_id);
+       mtk_vcodec_debug(vpu, "id=%X", *(uint32_t *)msg);
 
        vpu->failure = 0;
        vpu->signaled = 0;
@@ -80,7 +79,7 @@ static int vcodec_vpu_send_msg(struct vdec_vpu_inst *vpu, void *msg, int len)
        err = vpu_ipi_send(vpu->dev, vpu->id, msg, len);
        if (err) {
                mtk_vcodec_err(vpu, "send fail vpu_id=%d msg_id=%X status=%d",
-                              vpu->id, msg_id, err);
+                              vpu->id, *(uint32_t *)msg, err);
                return err;
        }
 
index b76c80bdf30b82f8c90aaf5aa3c9ad069261e282..4eb3be37ba143980291f33e0de40835a352f42ad 100644 (file)
@@ -665,10 +665,10 @@ static int h264_enc_deinit(unsigned long handle)
 }
 
 static const struct venc_common_if venc_h264_if = {
-       h264_enc_init,
-       h264_enc_encode,
-       h264_enc_set_param,
-       h264_enc_deinit,
+       .init = h264_enc_init,
+       .encode = h264_enc_encode,
+       .set_param = h264_enc_set_param,
+       .deinit = h264_enc_deinit,
 };
 
 const struct venc_common_if *get_h264_enc_comm_if(void);
index 544f57186243673e76063f82e58a54f6f05651e3..a6fa145f2c54e201937b3bab5e76197294b786cc 100644 (file)
@@ -470,10 +470,10 @@ static int vp8_enc_deinit(unsigned long handle)
 }
 
 static const struct venc_common_if venc_vp8_if = {
-       vp8_enc_init,
-       vp8_enc_encode,
-       vp8_enc_set_param,
-       vp8_enc_deinit,
+       .init = vp8_enc_init,
+       .encode = vp8_enc_encode,
+       .set_param = vp8_enc_set_param,
+       .deinit = vp8_enc_deinit,
 };
 
 const struct venc_common_if *get_vp8_enc_comm_if(void);
index a01c7599b5105704eb8b6d82b98de2e977b21bd4..0d882acf88305c03371ad72595155e8411d0a04a 100644 (file)
@@ -79,10 +79,8 @@ static int vpu_enc_send_msg(struct venc_vpu_inst *vpu, void *msg,
 
        status = vpu_ipi_send(vpu->dev, vpu->id, msg, len);
        if (status) {
-               uint32_t msg_id = *(uint32_t *)msg;
-
                mtk_vcodec_err(vpu, "vpu_ipi_send msg_id %x len %d fail %d",
-                              msg_id, len, status);
+                              *(uint32_t *)msg, len, status);
                return -EINVAL;
        }
        if (vpu->failure)
index 7354469670b79a0e71298411c7b6791a314815d4..218e6d7ae93ae003c7600ea9b1c268cf2305b7ed 100644 (file)
@@ -225,22 +225,22 @@ isp_video_remote_subdev(struct isp_video *video, u32 *pad)
 static int isp_video_get_graph_data(struct isp_video *video,
                                    struct isp_pipeline *pipe)
 {
-       struct media_entity_graph graph;
+       struct media_graph graph;
        struct media_entity *entity = &video->video.entity;
        struct media_device *mdev = entity->graph_obj.mdev;
        struct isp_video *far_end = NULL;
        int ret;
 
        mutex_lock(&mdev->graph_mutex);
-       ret = media_entity_graph_walk_init(&graph, entity->graph_obj.mdev);
+       ret = media_graph_walk_init(&graph, mdev);
        if (ret) {
                mutex_unlock(&mdev->graph_mutex);
                return ret;
        }
 
-       media_entity_graph_walk_start(&graph, entity);
+       media_graph_walk_start(&graph, entity);
 
-       while ((entity = media_entity_graph_walk_next(&graph))) {
+       while ((entity = media_graph_walk_next(&graph))) {
                struct isp_video *__video;
 
                media_entity_enum_set(&pipe->ent_enum, entity);
@@ -261,7 +261,7 @@ static int isp_video_get_graph_data(struct isp_video *video,
 
        mutex_unlock(&mdev->graph_mutex);
 
-       media_entity_graph_walk_cleanup(&graph);
+       media_graph_walk_cleanup(&graph);
 
        if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
                pipe->input = far_end;
@@ -1112,7 +1112,7 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
        pipe->l3_ick = clk_get_rate(video->isp->clock[ISP_CLK_L3_ICK]);
        pipe->max_rate = pipe->l3_ick;
 
-       ret = media_entity_pipeline_start(&video->video.entity, &pipe->pipe);
+       ret = media_pipeline_start(&video->video.entity, &pipe->pipe);
        if (ret < 0)
                goto err_pipeline_start;
 
@@ -1169,7 +1169,7 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
        return 0;
 
 err_check_format:
-       media_entity_pipeline_stop(&video->video.entity);
+       media_pipeline_stop(&video->video.entity);
 err_pipeline_start:
        /* TODO: Implement PM QoS */
        /* The DMA queue must be emptied here, otherwise CCDC interrupts that
@@ -1236,7 +1236,7 @@ isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
        video->error = false;
 
        /* TODO: Implement PM QoS */
-       media_entity_pipeline_stop(&video->video.entity);
+       media_pipeline_stop(&video->video.entity);
 
        media_entity_enum_cleanup(&pipe->ent_enum);
 
@@ -1350,6 +1350,7 @@ static int isp_video_open(struct file *file)
 done:
        if (ret < 0) {
                v4l2_fh_del(&handle->vfh);
+               v4l2_fh_exit(&handle->vfh);
                kfree(handle);
        }
 
@@ -1373,6 +1374,7 @@ static int isp_video_release(struct file *file)
 
        /* Release the file handle. */
        v4l2_fh_del(vfh);
+       v4l2_fh_exit(vfh);
        kfree(handle);
        file->private_data = NULL;
 
index 674cc1309b436b963b313e7102e789a4be966316..42f25d241edd7c40548842a2e2fb940002030b68 100644 (file)
@@ -1596,7 +1596,7 @@ static int fdp1_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
        else
                fdp1_try_fmt_capture(ctx, NULL, &f->fmt.pix_mp);
 
-       dprintk(ctx->fdp1, "Try %s format: %4s (0x%08x) %ux%u field %u\n",
+       dprintk(ctx->fdp1, "Try %s format: %4.4s (0x%08x) %ux%u field %u\n",
                V4L2_TYPE_IS_OUTPUT(f->type) ? "output" : "capture",
                (char *)&f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.pixelformat,
                f->fmt.pix_mp.width, f->fmt.pix_mp.height, f->fmt.pix_mp.field);
@@ -1671,7 +1671,7 @@ static int fdp1_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
 
        fdp1_set_format(ctx, &f->fmt.pix_mp, f->type);
 
-       dprintk(ctx->fdp1, "Set %s format: %4s (0x%08x) %ux%u field %u\n",
+       dprintk(ctx->fdp1, "Set %s format: %4.4s (0x%08x) %ux%u field %u\n",
                V4L2_TYPE_IS_OUTPUT(f->type) ? "output" : "capture",
                (char *)&f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.pixelformat,
                f->fmt.pix_mp.width, f->fmt.pix_mp.height, f->fmt.pix_mp.field);
index 0413a861a59a48e4ff76522892905b9e6f97e07d..1b30be72f4f9f1e664fee96b34dbb4b6d150401a 100644 (file)
@@ -856,13 +856,13 @@ static int s3c_camif_streamon(struct file *file, void *priv,
        if (s3c_vp_active(vp))
                return 0;
 
-       ret = media_entity_pipeline_start(sensor, camif->m_pipeline);
+       ret = media_pipeline_start(sensor, camif->m_pipeline);
        if (ret < 0)
                return ret;
 
        ret = camif_pipeline_validate(camif);
        if (ret < 0) {
-               media_entity_pipeline_stop(sensor);
+               media_pipeline_stop(sensor);
                return ret;
        }
 
@@ -886,7 +886,7 @@ static int s3c_camif_streamoff(struct file *file, void *priv,
 
        ret = vb2_streamoff(&vp->vb_queue, type);
        if (ret == 0)
-               media_entity_pipeline_stop(&camif->sensor.sd->entity);
+               media_pipeline_stop(&camif->sensor.sd->entity);
        return ret;
 }
 
@@ -1488,7 +1488,7 @@ static const struct v4l2_subdev_pad_ops s3c_camif_subdev_pad_ops = {
        .set_fmt = s3c_camif_subdev_set_fmt,
 };
 
-static struct v4l2_subdev_ops s3c_camif_subdev_ops = {
+static const struct v4l2_subdev_ops s3c_camif_subdev_ops = {
        .pad = &s3c_camif_subdev_pad_ops,
 };
 
index 534d6c3c6d608865aa7afe0135c31dcdb4b61cfe..cb4986b8f798296ff89851cc0615541c1e688b1e 100644 (file)
@@ -59,7 +59,7 @@ static int soc_camera_platform_s_power(struct v4l2_subdev *sd, int on)
        return soc_camera_set_power(p->icd->control, &p->icd->sdesc->subdev_desc, NULL, on);
 }
 
-static struct v4l2_subdev_core_ops platform_subdev_core_ops = {
+static const struct v4l2_subdev_core_ops platform_subdev_core_ops = {
        .s_power = soc_camera_platform_s_power,
 };
 
@@ -110,7 +110,7 @@ static int soc_camera_platform_g_mbus_config(struct v4l2_subdev *sd,
        return 0;
 }
 
-static struct v4l2_subdev_video_ops platform_subdev_video_ops = {
+static const struct v4l2_subdev_video_ops platform_subdev_video_ops = {
        .s_stream       = soc_camera_platform_s_stream,
        .g_mbus_config  = soc_camera_platform_g_mbus_config,
 };
@@ -122,7 +122,7 @@ static const struct v4l2_subdev_pad_ops platform_subdev_pad_ops = {
        .set_fmt        = soc_camera_platform_fill_fmt,
 };
 
-static struct v4l2_subdev_ops platform_subdev_ops = {
+static const struct v4l2_subdev_ops platform_subdev_ops = {
        .core   = &platform_subdev_core_ops,
        .video  = &platform_subdev_video_ops,
        .pad    = &platform_subdev_pad_ops,
index 79c56356a7c7aad03ccd4d8fbda5feb126d8be94..7af66860d6240cca3cf44e9b8a2ea8724920481e 100644 (file)
@@ -677,7 +677,7 @@ int bdisp_debugfs_create(struct bdisp_dev *bdisp)
 
 err:
        bdisp_debugfs_remove(bdisp);
-       return 0;
+       return -ENOMEM;
 }
 
 void bdisp_debugfs_remove(struct bdisp_dev *bdisp)
diff --git a/drivers/media/platform/sti/delta/Makefile b/drivers/media/platform/sti/delta/Makefile
new file mode 100644 (file)
index 0000000..8d03250
--- /dev/null
@@ -0,0 +1,6 @@
+obj-$(CONFIG_VIDEO_STI_DELTA_DRIVER) := st-delta.o
+st-delta-y := delta-v4l2.o delta-mem.o delta-ipc.o delta-debug.o
+
+# MJPEG support
+st-delta-$(CONFIG_VIDEO_STI_DELTA_MJPEG) += delta-mjpeg-hdr.o
+st-delta-$(CONFIG_VIDEO_STI_DELTA_MJPEG) += delta-mjpeg-dec.o
diff --git a/drivers/media/platform/sti/delta/delta-cfg.h b/drivers/media/platform/sti/delta/delta-cfg.h
new file mode 100644 (file)
index 0000000..c6388f5
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2015
+ * Author: Hugues Fruchet <hugues.fruchet@st.com> for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef DELTA_CFG_H
+#define DELTA_CFG_H
+
+#define DELTA_FW_VERSION "21.1-3"
+
+#define DELTA_MIN_WIDTH  32
+#define DELTA_MAX_WIDTH  4096
+#define DELTA_MIN_HEIGHT 32
+#define DELTA_MAX_HEIGHT 2400
+
+/* DELTA requires a 32x32 pixels alignment for frames */
+#define DELTA_WIDTH_ALIGNMENT    32
+#define DELTA_HEIGHT_ALIGNMENT   32
+
+#define DELTA_DEFAULT_WIDTH  DELTA_MIN_WIDTH
+#define DELTA_DEFAULT_HEIGHT DELTA_MIN_HEIGHT
+#define DELTA_DEFAULT_FRAMEFORMAT  V4L2_PIX_FMT_NV12
+#define DELTA_DEFAULT_STREAMFORMAT V4L2_PIX_FMT_MJPEG
+
+#define DELTA_MAX_RESO (DELTA_MAX_WIDTH * DELTA_MAX_HEIGHT)
+
+/* guard value for number of access units */
+#define DELTA_MAX_AUS 10
+
+/* IP perf dependent, can be tuned */
+#define DELTA_PEAK_FRAME_SMOOTHING 2
+
+/*
+ * guard output frame count:
+ * - at least 1 frame needed for display
+ * - at worst 21
+ *   ( max h264 dpb (16) +
+ *     decoding peak smoothing (2) +
+ *     user display pipeline (3) )
+ */
+#define DELTA_MIN_FRAME_USER    1
+#define DELTA_MAX_DPB           16
+#define DELTA_MAX_FRAME_USER    3 /* platform/use-case dependent */
+#define DELTA_MAX_FRAMES (DELTA_MAX_DPB + DELTA_PEAK_FRAME_SMOOTHING +\
+                         DELTA_MAX_FRAME_USER)
+
+#if DELTA_MAX_FRAMES > VIDEO_MAX_FRAME
+#undef DELTA_MAX_FRAMES
+#define DELTA_MAX_FRAMES (VIDEO_MAX_FRAME)
+#endif
+
+/* extra space to be allocated to store codec specific data per frame */
+#define DELTA_MAX_FRAME_PRIV_SIZE 100
+
+/* PM runtime auto power-off after 5ms of inactivity */
+#define DELTA_HW_AUTOSUSPEND_DELAY_MS 5
+
+#define DELTA_MAX_DECODERS 10
+#ifdef CONFIG_VIDEO_STI_DELTA_MJPEG
+extern const struct delta_dec mjpegdec;
+#endif
+
+#endif /* DELTA_CFG_H */
diff --git a/drivers/media/platform/sti/delta/delta-debug.c b/drivers/media/platform/sti/delta/delta-debug.c
new file mode 100644 (file)
index 0000000..a7ebf2c
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2015
+ * Authors: Hugues Fruchet <hugues.fruchet@st.com>
+ *          Fabrice Lecoultre <fabrice.lecoultre@st.com>
+ *          for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include "delta.h"
+#include "delta-debug.h"
+
+char *delta_streaminfo_str(struct delta_streaminfo *s, char *str,
+                          unsigned int len)
+{
+       if (!s)
+               return NULL;
+
+       snprintf(str, len,
+                "%4.4s %dx%d %s %s dpb=%d %s %s %s%dx%d@(%d,%d) %s%d/%d",
+                (char *)&s->streamformat, s->width, s->height,
+                s->profile, s->level, s->dpb,
+                (s->field == V4L2_FIELD_NONE) ? "progressive" : "interlaced",
+                s->other,
+                s->flags & DELTA_STREAMINFO_FLAG_CROP ? "crop=" : "",
+                s->crop.width, s->crop.height,
+                s->crop.left, s->crop.top,
+                s->flags & DELTA_STREAMINFO_FLAG_PIXELASPECT ? "par=" : "",
+                s->pixelaspect.numerator,
+                s->pixelaspect.denominator);
+
+       return str;
+}
+
+char *delta_frameinfo_str(struct delta_frameinfo *f, char *str,
+                         unsigned int len)
+{
+       if (!f)
+               return NULL;
+
+       snprintf(str, len,
+                "%4.4s %dx%d aligned %dx%d %s %s%dx%d@(%d,%d) %s%d/%d",
+                (char *)&f->pixelformat, f->width, f->height,
+                f->aligned_width, f->aligned_height,
+                (f->field == V4L2_FIELD_NONE) ? "progressive" : "interlaced",
+                f->flags & DELTA_STREAMINFO_FLAG_CROP ? "crop=" : "",
+                f->crop.width, f->crop.height,
+                f->crop.left, f->crop.top,
+                f->flags & DELTA_STREAMINFO_FLAG_PIXELASPECT ? "par=" : "",
+                f->pixelaspect.numerator,
+                f->pixelaspect.denominator);
+
+       return str;
+}
+
+void delta_trace_summary(struct delta_ctx *ctx)
+{
+       struct delta_dev *delta = ctx->dev;
+       struct delta_streaminfo *s = &ctx->streaminfo;
+       unsigned char str[100] = "";
+
+       if (!(ctx->flags & DELTA_FLAG_STREAMINFO))
+               return;
+
+       dev_dbg(delta->dev, "%s %s, %d frames decoded, %d frames output, %d frames dropped, %d stream errors, %d decode errors",
+               ctx->name,
+               delta_streaminfo_str(s, str, sizeof(str)),
+               ctx->decoded_frames,
+               ctx->output_frames,
+               ctx->dropped_frames,
+               ctx->stream_errors,
+               ctx->decode_errors);
+}
diff --git a/drivers/media/platform/sti/delta/delta-debug.h b/drivers/media/platform/sti/delta/delta-debug.h
new file mode 100644 (file)
index 0000000..955c158
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2015
+ * Authors: Hugues Fruchet <hugues.fruchet@st.com>
+ *          Fabrice Lecoultre <fabrice.lecoultre@st.com>
+ *          for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef DELTA_DEBUG_H
+#define DELTA_DEBUG_H
+
+char *delta_streaminfo_str(struct delta_streaminfo *s, char *str,
+                          unsigned int len);
+char *delta_frameinfo_str(struct delta_frameinfo *f, char *str,
+                         unsigned int len);
+void delta_trace_summary(struct delta_ctx *ctx);
+
+#endif /* DELTA_DEBUG_H */
diff --git a/drivers/media/platform/sti/delta/delta-ipc.c b/drivers/media/platform/sti/delta/delta-ipc.c
new file mode 100644 (file)
index 0000000..41e4a4c
--- /dev/null
@@ -0,0 +1,594 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2015
+ * Author: Hugues Fruchet <hugues.fruchet@st.com> for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/rpmsg.h>
+
+#include "delta.h"
+#include "delta-ipc.h"
+#include "delta-mem.h"
+
+#define IPC_TIMEOUT 100
+#define IPC_SANITY_TAG 0xDEADBEEF
+
+enum delta_ipc_fw_command {
+       DELTA_IPC_OPEN,
+       DELTA_IPC_SET_STREAM,
+       DELTA_IPC_DECODE,
+       DELTA_IPC_CLOSE
+};
+
+#define to_rpmsg_driver(__drv) container_of(__drv, struct rpmsg_driver, drv)
+#define to_delta(__d) container_of(__d, struct delta_dev, rpmsg_driver)
+
+#define to_ctx(hdl) ((struct delta_ipc_ctx *)hdl)
+#define to_pctx(ctx) container_of(ctx, struct delta_ctx, ipc_ctx)
+
+struct delta_ipc_header_msg {
+       u32 tag;
+       void *host_hdl;
+       u32 copro_hdl;
+       u32 command;
+};
+
+#define to_host_hdl(ctx) ((void *)ctx)
+
+#define msg_to_ctx(msg) ((struct delta_ipc_ctx *)(msg)->header.host_hdl)
+#define msg_to_copro_hdl(msg) ((msg)->header.copro_hdl)
+
+static inline dma_addr_t to_paddr(struct delta_ipc_ctx *ctx, void *vaddr)
+{
+       return (ctx->ipc_buf->paddr + (vaddr - ctx->ipc_buf->vaddr));
+}
+
+static inline bool is_valid_data(struct delta_ipc_ctx *ctx,
+                                void *data, u32 size)
+{
+       return ((data >= ctx->ipc_buf->vaddr) &&
+               ((data + size) <= (ctx->ipc_buf->vaddr + ctx->ipc_buf->size)));
+}
+
+/*
+ * IPC shared memory (@ipc_buf_size, @ipc_buf_paddr) is sent to copro
+ * at each instance opening. This memory is allocated by IPC client
+ * and given through delta_ipc_open(). All messages parameters
+ * (open, set_stream, decode) will have their phy address within
+ * this IPC shared memory, avoiding de-facto recopies inside delta-ipc.
+ * All the below messages structures are used on both host and firmware
+ * side and are packed (use only of 32 bits size fields in messages
+ * structures to ensure packing):
+ * - struct delta_ipc_open_msg
+ * - struct delta_ipc_set_stream_msg
+ * - struct delta_ipc_decode_msg
+ * - struct delta_ipc_close_msg
+ * - struct delta_ipc_cb_msg
+ */
+struct delta_ipc_open_msg {
+       struct delta_ipc_header_msg header;
+       u32 ipc_buf_size;
+       dma_addr_t ipc_buf_paddr;
+       char name[32];
+       u32 param_size;
+       dma_addr_t param_paddr;
+};
+
+struct delta_ipc_set_stream_msg {
+       struct delta_ipc_header_msg header;
+       u32 param_size;
+       dma_addr_t param_paddr;
+};
+
+struct delta_ipc_decode_msg {
+       struct delta_ipc_header_msg header;
+       u32 param_size;
+       dma_addr_t param_paddr;
+       u32 status_size;
+       dma_addr_t status_paddr;
+};
+
+struct delta_ipc_close_msg {
+       struct delta_ipc_header_msg header;
+};
+
+struct delta_ipc_cb_msg {
+       struct delta_ipc_header_msg header;
+       int err;
+};
+
+static void build_msg_header(struct delta_ipc_ctx *ctx,
+                            enum delta_ipc_fw_command command,
+                            struct delta_ipc_header_msg *header)
+{
+       header->tag = IPC_SANITY_TAG;
+       header->host_hdl = to_host_hdl(ctx);
+       header->copro_hdl = ctx->copro_hdl;
+       header->command = command;
+}
+
+int delta_ipc_open(struct delta_ctx *pctx, const char *name,
+                  struct delta_ipc_param *param, u32 ipc_buf_size,
+                  struct delta_buf **ipc_buf, void **hdl)
+{
+       struct delta_dev *delta = pctx->dev;
+       struct rpmsg_device *rpmsg_device = delta->rpmsg_device;
+       struct delta_ipc_ctx *ctx = &pctx->ipc_ctx;
+       struct delta_ipc_open_msg msg;
+       struct delta_buf *buf = &ctx->ipc_buf_struct;
+       int ret;
+
+       if (!rpmsg_device) {
+               dev_err(delta->dev,
+                       "%s   ipc: failed to open, rpmsg is not initialized\n",
+                       pctx->name);
+               pctx->sys_errors++;
+               return -EINVAL;
+       }
+
+       if (!name) {
+               dev_err(delta->dev,
+                       "%s   ipc: failed to open, no name given\n",
+                       pctx->name);
+               return -EINVAL;
+       }
+
+       if (!param || !param->data || !param->size) {
+               dev_err(delta->dev,
+                       "%s  ipc: failed to open, empty parameter\n",
+                       pctx->name);
+               return -EINVAL;
+       }
+
+       if (!ipc_buf_size) {
+               dev_err(delta->dev,
+                       "%s   ipc: failed to open, no size given for ipc buffer\n",
+                       pctx->name);
+               return -EINVAL;
+       }
+
+       if (param->size > ipc_buf_size) {
+               dev_err(delta->dev,
+                       "%s   ipc: failed to open, too large ipc parameter (%d bytes while max %d expected)\n",
+                       pctx->name,
+                       param->size, ctx->ipc_buf->size);
+               return -EINVAL;
+       }
+
+       /* init */
+       init_completion(&ctx->done);
+
+       /*
+        * allocation of contiguous buffer for
+        * data of commands exchanged between
+        * host and firmware coprocessor
+        */
+       ret = hw_alloc(pctx, ipc_buf_size,
+                      "ipc data buffer", buf);
+       if (ret)
+               return ret;
+       ctx->ipc_buf = buf;
+
+       /* build rpmsg message */
+       build_msg_header(ctx, DELTA_IPC_OPEN, &msg.header);
+
+       msg.ipc_buf_size = ipc_buf_size;
+       msg.ipc_buf_paddr = ctx->ipc_buf->paddr;
+
+       memcpy(msg.name, name, sizeof(msg.name));
+       msg.name[sizeof(msg.name) - 1] = 0;
+
+       msg.param_size = param->size;
+       memcpy(ctx->ipc_buf->vaddr, param->data, msg.param_size);
+       msg.param_paddr = ctx->ipc_buf->paddr;
+
+       /* send it */
+       ret = rpmsg_send(rpmsg_device->ept, &msg, sizeof(msg));
+       if (ret) {
+               dev_err(delta->dev,
+                       "%s   ipc: failed to open, rpmsg_send failed (%d) for DELTA_IPC_OPEN (name=%s, size=%d, data=%p)\n",
+                       pctx->name,
+                       ret, name, param->size, param->data);
+               goto err;
+       }
+
+       /* wait for acknowledge */
+       if (!wait_for_completion_timeout
+           (&ctx->done, msecs_to_jiffies(IPC_TIMEOUT))) {
+               dev_err(delta->dev,
+                       "%s   ipc: failed to open, timeout waiting for DELTA_IPC_OPEN callback (name=%s, size=%d, data=%p)\n",
+                       pctx->name,
+                       name, param->size, param->data);
+               ret = -ETIMEDOUT;
+               goto err;
+       }
+
+       /* command completed, check error */
+       if (ctx->cb_err) {
+               dev_err(delta->dev,
+                       "%s   ipc: failed to open, DELTA_IPC_OPEN completed but with error (%d) (name=%s, size=%d, data=%p)\n",
+                       pctx->name,
+                       ctx->cb_err, name, param->size, param->data);
+               ret = -EIO;
+               goto err;
+       }
+
+       *ipc_buf = ctx->ipc_buf;
+       *hdl = (void *)ctx;
+
+       return 0;
+
+err:
+       pctx->sys_errors++;
+       if (ctx->ipc_buf) {
+               hw_free(pctx, ctx->ipc_buf);
+               ctx->ipc_buf = NULL;
+       }
+
+       return ret;
+};
+
+int delta_ipc_set_stream(void *hdl, struct delta_ipc_param *param)
+{
+       struct delta_ipc_ctx *ctx = to_ctx(hdl);
+       struct delta_ctx *pctx = to_pctx(ctx);
+       struct delta_dev *delta = pctx->dev;
+       struct rpmsg_device *rpmsg_device = delta->rpmsg_device;
+       struct delta_ipc_set_stream_msg msg;
+       int ret;
+
+       if (!hdl) {
+               dev_err(delta->dev,
+                       "%s   ipc: failed to set stream, invalid ipc handle\n",
+                       pctx->name);
+               return -EINVAL;
+       }
+
+       if (!rpmsg_device) {
+               dev_err(delta->dev,
+                       "%s   ipc: failed to set stream, rpmsg is not initialized\n",
+                       pctx->name);
+               return -EINVAL;
+       }
+
+       if (!param || !param->data || !param->size) {
+               dev_err(delta->dev,
+                       "%s  ipc: failed to set stream, empty parameter\n",
+                       pctx->name);
+               return -EINVAL;
+       }
+
+       if (param->size > ctx->ipc_buf->size) {
+               dev_err(delta->dev,
+                       "%s   ipc: failed to set stream, too large ipc parameter(%d bytes while max %d expected)\n",
+                       pctx->name,
+                       param->size, ctx->ipc_buf->size);
+               return -EINVAL;
+       }
+
+       if (!is_valid_data(ctx, param->data, param->size)) {
+               dev_err(delta->dev,
+                       "%s   ipc: failed to set stream, parameter is not in expected address range (size=%d, data=%p not in %p..%p)\n",
+                       pctx->name,
+                       param->size,
+                       param->data,
+                       ctx->ipc_buf->vaddr,
+                       ctx->ipc_buf->vaddr + ctx->ipc_buf->size - 1);
+               return -EINVAL;
+       }
+
+       /* build rpmsg message */
+       build_msg_header(ctx, DELTA_IPC_SET_STREAM, &msg.header);
+
+       msg.param_size = param->size;
+       msg.param_paddr = to_paddr(ctx, param->data);
+
+       /* send it */
+       ret = rpmsg_send(rpmsg_device->ept, &msg, sizeof(msg));
+       if (ret) {
+               dev_err(delta->dev,
+                       "%s   ipc: failed to set stream, rpmsg_send failed (%d) for DELTA_IPC_SET_STREAM (size=%d, data=%p)\n",
+                       pctx->name,
+                       ret, param->size, param->data);
+               pctx->sys_errors++;
+               return ret;
+       }
+
+       /* wait for acknowledge */
+       if (!wait_for_completion_timeout
+           (&ctx->done, msecs_to_jiffies(IPC_TIMEOUT))) {
+               dev_err(delta->dev,
+                       "%s   ipc: failed to set stream, timeout waiting for DELTA_IPC_SET_STREAM callback (size=%d, data=%p)\n",
+                       pctx->name,
+                       param->size, param->data);
+               pctx->sys_errors++;
+               return -ETIMEDOUT;
+       }
+
+       /* command completed, check status */
+       if (ctx->cb_err) {
+               dev_err(delta->dev,
+                       "%s   ipc: failed to set stream, DELTA_IPC_SET_STREAM completed but with error (%d) (size=%d, data=%p)\n",
+                       pctx->name,
+                       ctx->cb_err, param->size, param->data);
+               pctx->sys_errors++;
+               return -EIO;
+       }
+
+       return 0;
+}
+
+int delta_ipc_decode(void *hdl, struct delta_ipc_param *param,
+                    struct delta_ipc_param *status)
+{
+       struct delta_ipc_ctx *ctx = to_ctx(hdl);
+       struct delta_ctx *pctx = to_pctx(ctx);
+       struct delta_dev *delta = pctx->dev;
+       struct rpmsg_device *rpmsg_device = delta->rpmsg_device;
+       struct delta_ipc_decode_msg msg;
+       int ret;
+
+       if (!hdl) {
+               dev_err(delta->dev,
+                       "%s   ipc: failed to decode, invalid ipc handle\n",
+                       pctx->name);
+               return -EINVAL;
+       }
+
+       if (!rpmsg_device) {
+               dev_err(delta->dev,
+                       "%s   ipc: failed to decode, rpmsg is not initialized\n",
+                       pctx->name);
+               return -EINVAL;
+       }
+
+       if (!param || !param->data || !param->size) {
+               dev_err(delta->dev,
+                       "%s  ipc: failed to decode, empty parameter\n",
+                       pctx->name);
+               return -EINVAL;
+       }
+
+       if (!status || !status->data || !status->size) {
+               dev_err(delta->dev,
+                       "%s  ipc: failed to decode, empty status\n",
+                       pctx->name);
+               return -EINVAL;
+       }
+
+       if (param->size + status->size > ctx->ipc_buf->size) {
+               dev_err(delta->dev,
+                       "%s   ipc: failed to decode, too large ipc parameter (%d bytes (param) + %d bytes (status) while max %d expected)\n",
+                       pctx->name,
+                       param->size,
+                       status->size,
+                       ctx->ipc_buf->size);
+               return -EINVAL;
+       }
+
+       if (!is_valid_data(ctx, param->data, param->size)) {
+               dev_err(delta->dev,
+                       "%s   ipc: failed to decode, parameter is not in expected address range (size=%d, data=%p not in %p..%p)\n",
+                       pctx->name,
+                       param->size,
+                       param->data,
+                       ctx->ipc_buf->vaddr,
+                       ctx->ipc_buf->vaddr + ctx->ipc_buf->size - 1);
+               return -EINVAL;
+       }
+
+       if (!is_valid_data(ctx, status->data, status->size)) {
+               dev_err(delta->dev,
+                       "%s   ipc: failed to decode, status is not in expected address range (size=%d, data=%p not in %p..%p)\n",
+                       pctx->name,
+                       status->size,
+                       status->data,
+                       ctx->ipc_buf->vaddr,
+                       ctx->ipc_buf->vaddr + ctx->ipc_buf->size - 1);
+               return -EINVAL;
+       }
+
+       /* build rpmsg message */
+       build_msg_header(ctx, DELTA_IPC_DECODE, &msg.header);
+
+       msg.param_size = param->size;
+       msg.param_paddr = to_paddr(ctx, param->data);
+
+       msg.status_size = status->size;
+       msg.status_paddr = to_paddr(ctx, status->data);
+
+       /* send it */
+       ret = rpmsg_send(rpmsg_device->ept, &msg, sizeof(msg));
+       if (ret) {
+               dev_err(delta->dev,
+                       "%s   ipc: failed to decode, rpmsg_send failed (%d) for DELTA_IPC_DECODE (size=%d, data=%p)\n",
+                       pctx->name,
+                       ret, param->size, param->data);
+               pctx->sys_errors++;
+               return ret;
+       }
+
+       /* wait for acknowledge */
+       if (!wait_for_completion_timeout
+           (&ctx->done, msecs_to_jiffies(IPC_TIMEOUT))) {
+               dev_err(delta->dev,
+                       "%s   ipc: failed to decode, timeout waiting for DELTA_IPC_DECODE callback (size=%d, data=%p)\n",
+                       pctx->name,
+                       param->size, param->data);
+               pctx->sys_errors++;
+               return -ETIMEDOUT;
+       }
+
+       /* command completed, check status */
+       if (ctx->cb_err) {
+               dev_err(delta->dev,
+                       "%s   ipc: failed to decode, DELTA_IPC_DECODE completed but with error (%d) (size=%d, data=%p)\n",
+                       pctx->name,
+                       ctx->cb_err, param->size, param->data);
+               pctx->sys_errors++;
+               return -EIO;
+       }
+
+       return 0;
+};
+
+void delta_ipc_close(void *hdl)
+{
+       struct delta_ipc_ctx *ctx = to_ctx(hdl);
+       struct delta_ctx *pctx = to_pctx(ctx);
+       struct delta_dev *delta = pctx->dev;
+       struct rpmsg_device *rpmsg_device = delta->rpmsg_device;
+       struct delta_ipc_close_msg msg;
+       int ret;
+
+       if (!hdl) {
+               dev_err(delta->dev,
+                       "%s   ipc: failed to close, invalid ipc handle\n",
+                       pctx->name);
+               return;
+       }
+
+       if (ctx->ipc_buf) {
+               hw_free(pctx, ctx->ipc_buf);
+               ctx->ipc_buf = NULL;
+       }
+
+       if (!rpmsg_device) {
+               dev_err(delta->dev,
+                       "%s   ipc: failed to close, rpmsg is not initialized\n",
+                       pctx->name);
+               return;
+       }
+
+       /* build rpmsg message */
+       build_msg_header(ctx, DELTA_IPC_CLOSE, &msg.header);
+
+       /* send it */
+       ret = rpmsg_send(rpmsg_device->ept, &msg, sizeof(msg));
+       if (ret) {
+               dev_err(delta->dev,
+                       "%s   ipc: failed to close, rpmsg_send failed (%d) for DELTA_IPC_CLOSE\n",
+                       pctx->name, ret);
+               pctx->sys_errors++;
+               return;
+       }
+
+       /* wait for acknowledge */
+       if (!wait_for_completion_timeout
+           (&ctx->done, msecs_to_jiffies(IPC_TIMEOUT))) {
+               dev_err(delta->dev,
+                       "%s   ipc: failed to close, timeout waiting for DELTA_IPC_CLOSE callback\n",
+                       pctx->name);
+               pctx->sys_errors++;
+               return;
+       }
+
+       /* command completed, check status */
+       if (ctx->cb_err) {
+               dev_err(delta->dev,
+                       "%s   ipc: failed to close, DELTA_IPC_CLOSE completed but with error (%d)\n",
+                       pctx->name, ctx->cb_err);
+               pctx->sys_errors++;
+       }
+};
+
+static int delta_ipc_cb(struct rpmsg_device *rpdev, void *data,
+                       int len, void *priv, u32 src)
+{
+       struct delta_ipc_ctx *ctx;
+       struct delta_ipc_cb_msg *msg;
+
+       /* sanity check */
+       if (!rpdev) {
+               dev_err(NULL, "rpdev is NULL\n");
+               return -EINVAL;
+       }
+
+       if (!data || !len) {
+               dev_err(&rpdev->dev,
+                       "unexpected empty message received from src=%d\n", src);
+               return -EINVAL;
+       }
+
+       if (len != sizeof(*msg)) {
+               dev_err(&rpdev->dev,
+                       "unexpected message length received from src=%d (received %d bytes while %zu bytes expected)\n",
+                       len, src, sizeof(*msg));
+               return -EINVAL;
+       }
+
+       msg = (struct delta_ipc_cb_msg *)data;
+       if (msg->header.tag != IPC_SANITY_TAG) {
+               dev_err(&rpdev->dev,
+                       "unexpected message tag received from src=%d (received %x tag while %x expected)\n",
+                       src, msg->header.tag, IPC_SANITY_TAG);
+               return -EINVAL;
+       }
+
+       ctx = msg_to_ctx(msg);
+       if (!ctx) {
+               dev_err(&rpdev->dev,
+                       "unexpected message with NULL host_hdl received from src=%d\n",
+                       src);
+               return -EINVAL;
+       }
+
+       /*
+        * if not already known, save copro instance context
+        * to ensure re-entrance on copro side
+        */
+       if (!ctx->copro_hdl)
+               ctx->copro_hdl = msg_to_copro_hdl(msg);
+
+       /*
+        * all is fine,
+        * update status & complete command
+        */
+       ctx->cb_err = msg->err;
+       complete(&ctx->done);
+
+       return 0;
+}
+
+static int delta_ipc_probe(struct rpmsg_device *rpmsg_device)
+{
+       struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpmsg_device->dev.driver);
+       struct delta_dev *delta = to_delta(rpdrv);
+
+       delta->rpmsg_device = rpmsg_device;
+
+       return 0;
+}
+
+static void delta_ipc_remove(struct rpmsg_device *rpmsg_device)
+{
+       struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpmsg_device->dev.driver);
+       struct delta_dev *delta = to_delta(rpdrv);
+
+       delta->rpmsg_device = NULL;
+}
+
+static struct rpmsg_device_id delta_ipc_device_id_table[] = {
+       {.name = "rpmsg-delta"},
+       {},
+};
+
+static struct rpmsg_driver delta_rpmsg_driver = {
+       .drv = {.name = KBUILD_MODNAME},
+       .id_table = delta_ipc_device_id_table,
+       .probe = delta_ipc_probe,
+       .callback = delta_ipc_cb,
+       .remove = delta_ipc_remove,
+};
+
+int delta_ipc_init(struct delta_dev *delta)
+{
+       delta->rpmsg_driver = delta_rpmsg_driver;
+
+       return register_rpmsg_driver(&delta->rpmsg_driver);
+}
+
+void delta_ipc_exit(struct delta_dev *delta)
+{
+       unregister_rpmsg_driver(&delta->rpmsg_driver);
+}
diff --git a/drivers/media/platform/sti/delta/delta-ipc.h b/drivers/media/platform/sti/delta/delta-ipc.h
new file mode 100644 (file)
index 0000000..cef2019
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2015
+ * Author: Hugues Fruchet <hugues.fruchet@st.com> for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef DELTA_IPC_H
+#define DELTA_IPC_H
+
+int delta_ipc_init(struct delta_dev *delta);
+void delta_ipc_exit(struct delta_dev *delta);
+
+/*
+ * delta_ipc_open - open a decoding instance on firmware side
+ * @ctx:               (in) delta context
+ * @name:              (in) name of decoder to be used
+ * @param:             (in) open command parameters specific to decoder
+ *  @param.size:               (in) size of parameter
+ *  @param.data:               (in) virtual address of parameter
+ * @ipc_buf_size:      (in) size of IPC shared buffer between host
+ *                          and copro used to share command data.
+ *                          Client have to set here the size of the biggest
+ *                          command parameters (+ status if any).
+ *                          Allocation will be done in this function which
+ *                          will give back to client in @ipc_buf the virtual
+ *                          & physical addresses & size of shared IPC buffer.
+ *                          All the further command data (parameters + status)
+ *                          have to be written in this shared IPC buffer
+ *                          virtual memory. This is done to avoid
+ *                          unnecessary copies of command data.
+ * @ipc_buf:           (out) allocated IPC shared buffer
+ *  @ipc_buf.size:             (out) allocated size
+ *  @ipc_buf.vaddr:            (out) virtual address where to copy
+ *                                   further command data
+ * @hdl:               (out) handle of decoding instance.
+ */
+
+int delta_ipc_open(struct delta_ctx *ctx, const char *name,
+                  struct delta_ipc_param *param, u32 ipc_buf_size,
+                  struct delta_buf **ipc_buf, void **hdl);
+
+/*
+ * delta_ipc_set_stream - set information about stream to decoder
+ * @hdl:               (in) handle of decoding instance.
+ * @param:             (in) set stream command parameters specific to decoder
+ *  @param.size:               (in) size of parameter
+ *  @param.data:               (in) virtual address of parameter. Must be
+ *                                  within IPC shared buffer range
+ */
+int delta_ipc_set_stream(void *hdl, struct delta_ipc_param *param);
+
+/*
+ * delta_ipc_decode - frame decoding synchronous request, returns only
+ *                   after decoding completion on firmware side.
+ * @hdl:               (in) handle of decoding instance.
+ * @param:             (in) decode command parameters specific to decoder
+ *  @param.size:               (in) size of parameter
+ *  @param.data:               (in) virtual address of parameter. Must be
+ *                                  within IPC shared buffer range
+ * @status:            (in/out) decode command status specific to decoder
+ *  @status.size:              (in) size of status
+ *  @status.data:              (in/out) virtual address of status. Must be
+ *                                      within IPC shared buffer range.
+ *                                      Status is filled by decoding instance
+ *                                      after decoding completion.
+ */
+int delta_ipc_decode(void *hdl, struct delta_ipc_param *param,
+                    struct delta_ipc_param *status);
+
+/*
+ * delta_ipc_close - close decoding instance
+ * @hdl:               (in) handle of decoding instance to close.
+ */
+void delta_ipc_close(void *hdl);
+
+#endif /* DELTA_IPC_H */
diff --git a/drivers/media/platform/sti/delta/delta-mem.c b/drivers/media/platform/sti/delta/delta-mem.c
new file mode 100644 (file)
index 0000000..d7b53d3
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2015
+ * Author: Hugues Fruchet <hugues.fruchet@st.com> for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include "delta.h"
+#include "delta-mem.h"
+
+int hw_alloc(struct delta_ctx *ctx, u32 size, const char *name,
+            struct delta_buf *buf)
+{
+       struct delta_dev *delta = ctx->dev;
+       dma_addr_t dma_addr;
+       void *addr;
+       unsigned long attrs = DMA_ATTR_WRITE_COMBINE;
+
+       addr = dma_alloc_attrs(delta->dev, size, &dma_addr,
+                              GFP_KERNEL | __GFP_NOWARN, attrs);
+       if (!addr) {
+               dev_err(delta->dev,
+                       "%s hw_alloc:dma_alloc_coherent failed for %s (size=%d)\n",
+                       ctx->name, name, size);
+               ctx->sys_errors++;
+               return -ENOMEM;
+       }
+
+       buf->size = size;
+       buf->paddr = dma_addr;
+       buf->vaddr = addr;
+       buf->name = name;
+       buf->attrs = attrs;
+
+       dev_dbg(delta->dev,
+               "%s allocate %d bytes of HW memory @(virt=0x%p, phy=0x%pad): %s\n",
+               ctx->name, size, buf->vaddr, &buf->paddr, buf->name);
+
+       return 0;
+}
+
+void hw_free(struct delta_ctx *ctx, struct delta_buf *buf)
+{
+       struct delta_dev *delta = ctx->dev;
+
+       dev_dbg(delta->dev,
+               "%s     free %d bytes of HW memory @(virt=0x%p, phy=0x%pad): %s\n",
+               ctx->name, buf->size, buf->vaddr, &buf->paddr, buf->name);
+
+       dma_free_attrs(delta->dev, buf->size,
+                      buf->vaddr, buf->paddr, buf->attrs);
+}
diff --git a/drivers/media/platform/sti/delta/delta-mem.h b/drivers/media/platform/sti/delta/delta-mem.h
new file mode 100644 (file)
index 0000000..f8ca109
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2015
+ * Author: Hugues Fruchet <hugues.fruchet@st.com> for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef DELTA_MEM_H
+#define DELTA_MEM_H
+
+int hw_alloc(struct delta_ctx *ctx, u32 size, const char *name,
+            struct delta_buf *buf);
+void hw_free(struct delta_ctx *ctx, struct delta_buf *buf);
+
+#endif /* DELTA_MEM_H */
diff --git a/drivers/media/platform/sti/delta/delta-mjpeg-dec.c b/drivers/media/platform/sti/delta/delta-mjpeg-dec.c
new file mode 100644 (file)
index 0000000..e79bdc6
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2013
+ * Author: Hugues Fruchet <hugues.fruchet@st.com> for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/slab.h>
+
+#include "delta.h"
+#include "delta-ipc.h"
+#include "delta-mjpeg.h"
+#include "delta-mjpeg-fw.h"
+
+#define DELTA_MJPEG_MAX_RESO DELTA_MAX_RESO
+
+struct delta_mjpeg_ctx {
+       /* jpeg header */
+       struct mjpeg_header header_struct;
+       struct mjpeg_header *header;
+
+       /* ipc */
+       void *ipc_hdl;
+       struct delta_buf *ipc_buf;
+
+       /* decoded output frame */
+       struct delta_frame *out_frame;
+
+       unsigned char str[3000];
+};
+
+#define to_ctx(ctx) ((struct delta_mjpeg_ctx *)(ctx)->priv)
+
+static char *ipc_open_param_str(struct jpeg_video_decode_init_params_t *p,
+                               char *str, unsigned int len)
+{
+       char *b = str;
+
+       if (!p)
+               return "";
+
+       b += snprintf(b, len,
+                     "jpeg_video_decode_init_params_t\n"
+                     "circular_buffer_begin_addr_p 0x%x\n"
+                     "circular_buffer_end_addr_p   0x%x\n",
+                     p->circular_buffer_begin_addr_p,
+                     p->circular_buffer_end_addr_p);
+
+       return str;
+}
+
+static char *ipc_decode_param_str(struct jpeg_decode_params_t *p,
+                                 char *str, unsigned int len)
+{
+       char *b = str;
+
+       if (!p)
+               return "";
+
+       b += snprintf(b, len,
+                     "jpeg_decode_params_t\n"
+                     "picture_start_addr_p                  0x%x\n"
+                     "picture_end_addr_p                    0x%x\n"
+                     "decoding_mode                        %d\n"
+                     "display_buffer_addr.display_decimated_luma_p   0x%x\n"
+                     "display_buffer_addr.display_decimated_chroma_p 0x%x\n"
+                     "main_aux_enable                       %d\n"
+                     "additional_flags                     0x%x\n"
+                     "field_flag                           %x\n"
+                     "is_jpeg_image                        %x\n",
+                     p->picture_start_addr_p,
+                     p->picture_end_addr_p,
+                     p->decoding_mode,
+                     p->display_buffer_addr.display_decimated_luma_p,
+                     p->display_buffer_addr.display_decimated_chroma_p,
+                     p->main_aux_enable, p->additional_flags,
+                     p->field_flag,
+                     p->is_jpeg_image);
+
+       return str;
+}
+
+static inline bool is_stream_error(enum jpeg_decoding_error_t err)
+{
+       switch (err) {
+       case JPEG_DECODER_UNDEFINED_HUFF_TABLE:
+       case JPEG_DECODER_BAD_RESTART_MARKER:
+       case JPEG_DECODER_BAD_SOS_SPECTRAL:
+       case JPEG_DECODER_BAD_SOS_SUCCESSIVE:
+       case JPEG_DECODER_BAD_HEADER_LENGTH:
+       case JPEG_DECODER_BAD_COUNT_VALUE:
+       case JPEG_DECODER_BAD_DHT_MARKER:
+       case JPEG_DECODER_BAD_INDEX_VALUE:
+       case JPEG_DECODER_BAD_NUMBER_HUFFMAN_TABLES:
+       case JPEG_DECODER_BAD_QUANT_TABLE_LENGTH:
+       case JPEG_DECODER_BAD_NUMBER_QUANT_TABLES:
+       case JPEG_DECODER_BAD_COMPONENT_COUNT:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static inline const char *err_str(enum jpeg_decoding_error_t err)
+{
+       switch (err) {
+       case JPEG_DECODER_NO_ERROR:
+               return "JPEG_DECODER_NO_ERROR";
+       case JPEG_DECODER_UNDEFINED_HUFF_TABLE:
+               return "JPEG_DECODER_UNDEFINED_HUFF_TABLE";
+       case JPEG_DECODER_UNSUPPORTED_MARKER:
+               return "JPEG_DECODER_UNSUPPORTED_MARKER";
+       case JPEG_DECODER_UNABLE_ALLOCATE_MEMORY:
+               return "JPEG_DECODER_UNABLE_ALLOCATE_MEMORY";
+       case JPEG_DECODER_NON_SUPPORTED_SAMP_FACTORS:
+               return "JPEG_DECODER_NON_SUPPORTED_SAMP_FACTORS";
+       case JPEG_DECODER_BAD_PARAMETER:
+               return "JPEG_DECODER_BAD_PARAMETER";
+       case JPEG_DECODER_DECODE_ERROR:
+               return "JPEG_DECODER_DECODE_ERROR";
+       case JPEG_DECODER_BAD_RESTART_MARKER:
+               return "JPEG_DECODER_BAD_RESTART_MARKER";
+       case JPEG_DECODER_UNSUPPORTED_COLORSPACE:
+               return "JPEG_DECODER_UNSUPPORTED_COLORSPACE";
+       case JPEG_DECODER_BAD_SOS_SPECTRAL:
+               return "JPEG_DECODER_BAD_SOS_SPECTRAL";
+       case JPEG_DECODER_BAD_SOS_SUCCESSIVE:
+               return "JPEG_DECODER_BAD_SOS_SUCCESSIVE";
+       case JPEG_DECODER_BAD_HEADER_LENGTH:
+               return "JPEG_DECODER_BAD_HEADER_LENGTH";
+       case JPEG_DECODER_BAD_COUNT_VALUE:
+               return "JPEG_DECODER_BAD_COUNT_VALUE";
+       case JPEG_DECODER_BAD_DHT_MARKER:
+               return "JPEG_DECODER_BAD_DHT_MARKER";
+       case JPEG_DECODER_BAD_INDEX_VALUE:
+               return "JPEG_DECODER_BAD_INDEX_VALUE";
+       case JPEG_DECODER_BAD_NUMBER_HUFFMAN_TABLES:
+               return "JPEG_DECODER_BAD_NUMBER_HUFFMAN_TABLES";
+       case JPEG_DECODER_BAD_QUANT_TABLE_LENGTH:
+               return "JPEG_DECODER_BAD_QUANT_TABLE_LENGTH";
+       case JPEG_DECODER_BAD_NUMBER_QUANT_TABLES:
+               return "JPEG_DECODER_BAD_NUMBER_QUANT_TABLES";
+       case JPEG_DECODER_BAD_COMPONENT_COUNT:
+               return "JPEG_DECODER_BAD_COMPONENT_COUNT";
+       case JPEG_DECODER_DIVIDE_BY_ZERO_ERROR:
+               return "JPEG_DECODER_DIVIDE_BY_ZERO_ERROR";
+       case JPEG_DECODER_NOT_JPG_IMAGE:
+               return "JPEG_DECODER_NOT_JPG_IMAGE";
+       case JPEG_DECODER_UNSUPPORTED_ROTATION_ANGLE:
+               return "JPEG_DECODER_UNSUPPORTED_ROTATION_ANGLE";
+       case JPEG_DECODER_UNSUPPORTED_SCALING:
+               return "JPEG_DECODER_UNSUPPORTED_SCALING";
+       case JPEG_DECODER_INSUFFICIENT_OUTPUTBUFFER_SIZE:
+               return "JPEG_DECODER_INSUFFICIENT_OUTPUTBUFFER_SIZE";
+       case JPEG_DECODER_BAD_HWCFG_GP_VERSION_VALUE:
+               return "JPEG_DECODER_BAD_HWCFG_GP_VERSION_VALUE";
+       case JPEG_DECODER_BAD_VALUE_FROM_RED:
+               return "JPEG_DECODER_BAD_VALUE_FROM_RED";
+       case JPEG_DECODER_BAD_SUBREGION_PARAMETERS:
+               return "JPEG_DECODER_BAD_SUBREGION_PARAMETERS";
+       case JPEG_DECODER_PROGRESSIVE_DECODE_NOT_SUPPORTED:
+               return "JPEG_DECODER_PROGRESSIVE_DECODE_NOT_SUPPORTED";
+       case JPEG_DECODER_ERROR_TASK_TIMEOUT:
+               return "JPEG_DECODER_ERROR_TASK_TIMEOUT";
+       case JPEG_DECODER_ERROR_FEATURE_NOT_SUPPORTED:
+               return "JPEG_DECODER_ERROR_FEATURE_NOT_SUPPORTED";
+       default:
+               return "!unknown MJPEG error!";
+       }
+}
+
+static bool delta_mjpeg_check_status(struct delta_ctx *pctx,
+                                    struct jpeg_decode_return_params_t *status)
+{
+       struct delta_dev *delta = pctx->dev;
+       bool dump = false;
+
+       if (status->error_code == JPEG_DECODER_NO_ERROR)
+               goto out;
+
+       if (is_stream_error(status->error_code)) {
+               dev_warn_ratelimited(delta->dev,
+                                    "%s  firmware: stream error @ frame %d (%s)\n",
+                                    pctx->name, pctx->decoded_frames,
+                                    err_str(status->error_code));
+               pctx->stream_errors++;
+       } else {
+               dev_warn_ratelimited(delta->dev,
+                                    "%s  firmware: decode error @ frame %d (%s)\n",
+                                    pctx->name, pctx->decoded_frames,
+                                    err_str(status->error_code));
+               pctx->decode_errors++;
+               dump = true;
+       }
+
+out:
+       dev_dbg(delta->dev,
+               "%s  firmware: decoding time(us)=%d\n", pctx->name,
+               status->decode_time_in_us);
+
+       return dump;
+}
+
+static int delta_mjpeg_ipc_open(struct delta_ctx *pctx)
+{
+       struct delta_dev *delta = pctx->dev;
+       struct delta_mjpeg_ctx *ctx = to_ctx(pctx);
+       int ret = 0;
+       struct jpeg_video_decode_init_params_t params_struct;
+       struct jpeg_video_decode_init_params_t *params = &params_struct;
+       struct delta_buf *ipc_buf;
+       u32 ipc_buf_size;
+       struct delta_ipc_param ipc_param;
+       void *hdl;
+
+       memset(params, 0, sizeof(*params));
+       params->circular_buffer_begin_addr_p = 0x00000000;
+       params->circular_buffer_end_addr_p = 0xffffffff;
+
+       dev_vdbg(delta->dev,
+                "%s  %s\n", pctx->name,
+                ipc_open_param_str(params, ctx->str, sizeof(ctx->str)));
+
+       ipc_param.size = sizeof(*params);
+       ipc_param.data = params;
+       ipc_buf_size = sizeof(struct jpeg_decode_params_t) +
+           sizeof(struct jpeg_decode_return_params_t);
+       ret = delta_ipc_open(pctx, "JPEG_DECODER_HW0", &ipc_param,
+                            ipc_buf_size, &ipc_buf, &hdl);
+       if (ret) {
+               dev_err(delta->dev,
+                       "%s  dumping command %s\n", pctx->name,
+                       ipc_open_param_str(params, ctx->str, sizeof(ctx->str)));
+               return ret;
+       }
+
+       ctx->ipc_buf = ipc_buf;
+       ctx->ipc_hdl = hdl;
+
+       return 0;
+}
+
+static int delta_mjpeg_ipc_decode(struct delta_ctx *pctx, struct delta_au *au)
+{
+       struct delta_dev *delta = pctx->dev;
+       struct delta_mjpeg_ctx *ctx = to_ctx(pctx);
+       int ret = 0;
+       struct jpeg_decode_params_t *params = ctx->ipc_buf->vaddr;
+       struct jpeg_decode_return_params_t *status =
+           ctx->ipc_buf->vaddr + sizeof(*params);
+       struct delta_frame *frame;
+       struct delta_ipc_param ipc_param, ipc_status;
+
+       ret = delta_get_free_frame(pctx, &frame);
+       if (ret)
+               return ret;
+
+       memset(params, 0, sizeof(*params));
+
+       params->picture_start_addr_p = (u32)(au->paddr);
+       params->picture_end_addr_p = (u32)(au->paddr + au->size - 1);
+
+       /*
+        * !WARNING!
+        * the NV12 decoded frame is only available
+        * on decimated output when enabling flag
+        * "JPEG_ADDITIONAL_FLAG_420MB"...
+        * the non decimated output gives YUV422SP
+        */
+       params->main_aux_enable = JPEG_DISP_AUX_EN;
+       params->additional_flags = JPEG_ADDITIONAL_FLAG_420MB;
+       params->horizontal_decimation_factor = JPEG_HDEC_1;
+       params->vertical_decimation_factor = JPEG_VDEC_1;
+       params->decoding_mode = JPEG_NORMAL_DECODE;
+
+       params->display_buffer_addr.struct_size =
+           sizeof(struct jpeg_display_buffer_address_t);
+       params->display_buffer_addr.display_decimated_luma_p =
+           (u32)frame->paddr;
+       params->display_buffer_addr.display_decimated_chroma_p =
+           (u32)(frame->paddr
+                 + frame->info.aligned_width * frame->info.aligned_height);
+
+       dev_vdbg(delta->dev,
+                "%s  %s\n", pctx->name,
+                ipc_decode_param_str(params, ctx->str, sizeof(ctx->str)));
+
+       /* status */
+       memset(status, 0, sizeof(*status));
+       status->error_code = JPEG_DECODER_NO_ERROR;
+
+       ipc_param.size = sizeof(*params);
+       ipc_param.data = params;
+       ipc_status.size = sizeof(*status);
+       ipc_status.data = status;
+       ret = delta_ipc_decode(ctx->ipc_hdl, &ipc_param, &ipc_status);
+       if (ret) {
+               dev_err(delta->dev,
+                       "%s  dumping command %s\n", pctx->name,
+                       ipc_decode_param_str(params, ctx->str,
+                                            sizeof(ctx->str)));
+               return ret;
+       }
+
+       pctx->decoded_frames++;
+
+       /* check firmware decoding status */
+       if (delta_mjpeg_check_status(pctx, status)) {
+               dev_err(delta->dev,
+                       "%s  dumping command %s\n", pctx->name,
+                       ipc_decode_param_str(params, ctx->str,
+                                            sizeof(ctx->str)));
+       }
+
+       frame->field = V4L2_FIELD_NONE;
+       frame->flags = V4L2_BUF_FLAG_KEYFRAME;
+       frame->state |= DELTA_FRAME_DEC;
+
+       ctx->out_frame = frame;
+
+       return 0;
+}
+
+static int delta_mjpeg_open(struct delta_ctx *pctx)
+{
+       struct delta_mjpeg_ctx *ctx;
+
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+       pctx->priv = ctx;
+
+       return 0;
+}
+
+static int delta_mjpeg_close(struct delta_ctx *pctx)
+{
+       struct delta_mjpeg_ctx *ctx = to_ctx(pctx);
+
+       if (ctx->ipc_hdl) {
+               delta_ipc_close(ctx->ipc_hdl);
+               ctx->ipc_hdl = NULL;
+       }
+
+       kfree(ctx);
+
+       return 0;
+}
+
+static int delta_mjpeg_get_streaminfo(struct delta_ctx *pctx,
+                                     struct delta_streaminfo *streaminfo)
+{
+       struct delta_mjpeg_ctx *ctx = to_ctx(pctx);
+
+       if (!ctx->header)
+               goto nodata;
+
+       streaminfo->streamformat = V4L2_PIX_FMT_MJPEG;
+       streaminfo->width = ctx->header->frame_width;
+       streaminfo->height = ctx->header->frame_height;
+
+       /* progressive stream */
+       streaminfo->field = V4L2_FIELD_NONE;
+
+       streaminfo->dpb = 1;
+
+       return 0;
+
+nodata:
+       return -ENODATA;
+}
+
+static int delta_mjpeg_decode(struct delta_ctx *pctx, struct delta_au *pau)
+{
+       struct delta_dev *delta = pctx->dev;
+       struct delta_mjpeg_ctx *ctx = to_ctx(pctx);
+       int ret;
+       struct delta_au au = *pau;
+       unsigned int data_offset;
+       struct mjpeg_header *header = &ctx->header_struct;
+
+       if (!ctx->header) {
+               ret = delta_mjpeg_read_header(pctx, au.vaddr, au.size,
+                                             header, &data_offset);
+               if (ret) {
+                       pctx->stream_errors++;
+                       goto err;
+               }
+               if (header->frame_width * header->frame_height >
+                   DELTA_MJPEG_MAX_RESO) {
+                       dev_err(delta->dev,
+                               "%s  stream resolution too large: %dx%d > %d pixels budget\n",
+                               pctx->name,
+                               header->frame_width,
+                               header->frame_height, DELTA_MJPEG_MAX_RESO);
+                       ret = -EINVAL;
+                       goto err;
+               }
+               ctx->header = header;
+               goto out;
+       }
+
+       if (!ctx->ipc_hdl) {
+               ret = delta_mjpeg_ipc_open(pctx);
+               if (ret)
+                       goto err;
+       }
+
+       ret = delta_mjpeg_read_header(pctx, au.vaddr, au.size,
+                                     ctx->header, &data_offset);
+       if (ret) {
+               pctx->stream_errors++;
+               goto err;
+       }
+
+       au.paddr += data_offset;
+       au.vaddr += data_offset;
+
+       ret = delta_mjpeg_ipc_decode(pctx, &au);
+       if (ret)
+               goto err;
+
+out:
+       return 0;
+
+err:
+       return ret;
+}
+
+static int delta_mjpeg_get_frame(struct delta_ctx *pctx,
+                                struct delta_frame **frame)
+{
+       struct delta_mjpeg_ctx *ctx = to_ctx(pctx);
+
+       if (!ctx->out_frame)
+               return -ENODATA;
+
+       *frame = ctx->out_frame;
+
+       ctx->out_frame = NULL;
+
+       return 0;
+}
+
+const struct delta_dec mjpegdec = {
+       .name = "MJPEG",
+       .streamformat = V4L2_PIX_FMT_MJPEG,
+       .pixelformat = V4L2_PIX_FMT_NV12,
+       .open = delta_mjpeg_open,
+       .close = delta_mjpeg_close,
+       .get_streaminfo = delta_mjpeg_get_streaminfo,
+       .get_frameinfo = delta_get_frameinfo_default,
+       .decode = delta_mjpeg_decode,
+       .get_frame = delta_mjpeg_get_frame,
+       .recycle = delta_recycle_default,
+};
diff --git a/drivers/media/platform/sti/delta/delta-mjpeg-fw.h b/drivers/media/platform/sti/delta/delta-mjpeg-fw.h
new file mode 100644 (file)
index 0000000..de803d0
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2015
+ * Author: Hugues Fruchet <hugues.fruchet@st.com> for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef DELTA_MJPEG_FW_H
+#define DELTA_MJPEG_FW_H
+
+/*
+ * struct jpeg_decoded_buffer_address_t
+ *
+ * defines the addresses where the decoded picture/additional
+ * info related to the block structures will be stored
+ *
+ * @display_luma_p:            address of the luma buffer
+ * @display_chroma_p:          address of the chroma buffer
+ */
+struct jpeg_decoded_buffer_address_t {
+       u32 luma_p;
+       u32 chroma_p;
+};
+
+/*
+ * struct jpeg_display_buffer_address_t
+ *
+ * defines the addresses (used by the Display Reconstruction block)
+ * where the pictures to be displayed will be stored
+ *
+ * @struct_size:               size of the structure in bytes
+ * @display_luma_p:            address of the luma buffer
+ * @display_chroma_p:          address of the chroma buffer
+ * @display_decimated_luma_p:  address of the decimated luma buffer
+ * @display_decimated_chroma_p:        address of the decimated chroma buffer
+ */
+struct jpeg_display_buffer_address_t {
+       u32 struct_size;
+       u32 display_luma_p;
+       u32 display_chroma_p;
+       u32 display_decimated_luma_p;
+       u32 display_decimated_chroma_p;
+};
+
+/*
+ * used for enabling main/aux outputs for both display &
+ * reference reconstruction blocks
+ */
+enum jpeg_rcn_ref_disp_enable_t {
+       /* enable decimated (for display) reconstruction */
+       JPEG_DISP_AUX_EN = 0x00000010,
+       /* enable main (for display) reconstruction */
+       JPEG_DISP_MAIN_EN = 0x00000020,
+       /* enable both main & decimated (for display) reconstruction */
+       JPEG_DISP_AUX_MAIN_EN = 0x00000030,
+       /* enable only reference output(ex. for trick modes) */
+       JPEG_REF_MAIN_EN = 0x00000100,
+       /*
+        * enable reference output with decimated
+        * (for display) reconstruction
+        */
+       JPEG_REF_MAIN_DISP_AUX_EN = 0x00000110,
+       /*
+        * enable reference output with main
+        * (for display) reconstruction
+        */
+       JPEG_REF_MAIN_DISP_MAIN_EN = 0x00000120,
+       /*
+        * enable reference output with main & decimated
+        * (for display) reconstruction
+        */
+       JPEG_REF_MAIN_DISP_MAIN_AUX_EN = 0x00000130
+};
+
+/* identifies the horizontal decimation factor */
+enum jpeg_horizontal_deci_factor_t {
+       /* no resize */
+       JPEG_HDEC_1 = 0x00000000,
+       /* Advanced H/2 resize using improved 8-tap filters */
+       JPEG_HDEC_ADVANCED_2 = 0x00000101,
+       /* Advanced H/4 resize using improved 8-tap filters */
+       JPEG_HDEC_ADVANCED_4 = 0x00000102
+};
+
+/* identifies the vertical decimation factor */
+enum jpeg_vertical_deci_factor_t {
+       /* no resize */
+       JPEG_VDEC_1 = 0x00000000,
+       /* V/2 , progressive resize */
+       JPEG_VDEC_ADVANCED_2_PROG = 0x00000204,
+       /* V/2 , interlaced resize */
+       JPEG_VDEC_ADVANCED_2_INT = 0x000000208
+};
+
+/* status of the decoding process */
+enum jpeg_decoding_error_t {
+       JPEG_DECODER_NO_ERROR = 0,
+       JPEG_DECODER_UNDEFINED_HUFF_TABLE = 1,
+       JPEG_DECODER_UNSUPPORTED_MARKER = 2,
+       JPEG_DECODER_UNABLE_ALLOCATE_MEMORY = 3,
+       JPEG_DECODER_NON_SUPPORTED_SAMP_FACTORS = 4,
+       JPEG_DECODER_BAD_PARAMETER = 5,
+       JPEG_DECODER_DECODE_ERROR = 6,
+       JPEG_DECODER_BAD_RESTART_MARKER = 7,
+       JPEG_DECODER_UNSUPPORTED_COLORSPACE = 8,
+       JPEG_DECODER_BAD_SOS_SPECTRAL = 9,
+       JPEG_DECODER_BAD_SOS_SUCCESSIVE = 10,
+       JPEG_DECODER_BAD_HEADER_LENGTH = 11,
+       JPEG_DECODER_BAD_COUNT_VALUE = 12,
+       JPEG_DECODER_BAD_DHT_MARKER = 13,
+       JPEG_DECODER_BAD_INDEX_VALUE = 14,
+       JPEG_DECODER_BAD_NUMBER_HUFFMAN_TABLES = 15,
+       JPEG_DECODER_BAD_QUANT_TABLE_LENGTH = 16,
+       JPEG_DECODER_BAD_NUMBER_QUANT_TABLES = 17,
+       JPEG_DECODER_BAD_COMPONENT_COUNT = 18,
+       JPEG_DECODER_DIVIDE_BY_ZERO_ERROR = 19,
+       JPEG_DECODER_NOT_JPG_IMAGE = 20,
+       JPEG_DECODER_UNSUPPORTED_ROTATION_ANGLE = 21,
+       JPEG_DECODER_UNSUPPORTED_SCALING = 22,
+       JPEG_DECODER_INSUFFICIENT_OUTPUTBUFFER_SIZE = 23,
+       JPEG_DECODER_BAD_HWCFG_GP_VERSION_VALUE = 24,
+       JPEG_DECODER_BAD_VALUE_FROM_RED = 25,
+       JPEG_DECODER_BAD_SUBREGION_PARAMETERS = 26,
+       JPEG_DECODER_PROGRESSIVE_DECODE_NOT_SUPPORTED = 27,
+       JPEG_DECODER_ERROR_TASK_TIMEOUT = 28,
+       JPEG_DECODER_ERROR_FEATURE_NOT_SUPPORTED = 29
+};
+
+/* identifies the decoding mode */
+enum jpeg_decoding_mode_t {
+       JPEG_NORMAL_DECODE = 0,
+};
+
+enum jpeg_additional_flags_t {
+       JPEG_ADDITIONAL_FLAG_NONE = 0,
+       /* request firmware to return values of the CEH registers */
+       JPEG_ADDITIONAL_FLAG_CEH = 1,
+       /* output storage of auxiliary reconstruction in Raster format. */
+       JPEG_ADDITIONAL_FLAG_RASTER = 64,
+       /* output storage of auxiliary reconstruction in 420MB format. */
+       JPEG_ADDITIONAL_FLAG_420MB = 128
+};
+
+/*
+ * struct jpeg_video_decode_init_params_t - initialization command parameters
+ *
+ * @circular_buffer_begin_addr_p:      start address of fw circular buffer
+ * @circular_buffer_end_addr_p:                end address of fw circular buffer
+ */
+struct jpeg_video_decode_init_params_t {
+       u32 circular_buffer_begin_addr_p;
+       u32 circular_buffer_end_addr_p;
+       u32 reserved;
+};
+
+/*
+ * struct jpeg_decode_params_t - decode command parameters
+ *
+ * @picture_start_addr_p:      start address of jpeg picture
+ * @picture_end_addr_p:                end address of jpeg picture
+ * @decoded_buffer_addr:       decoded picture buffer
+ * @display_buffer_addr:       display picture buffer
+ * @main_aux_enable:           enable main and/or aux outputs
+ * @horizontal_decimation_factor:horizontal decimation factor
+ * @vertical_decimation_factor:        vertical decimation factor
+ * @xvalue0:                   the x(0) coordinate for subregion decoding
+ * @xvalue1:                   the x(1) coordinate for subregion decoding
+ * @yvalue0:                   the y(0) coordinate for subregion decoding
+ * @yvalue1:                   the y(1) coordinate for subregion decoding
+ * @decoding_mode:             decoding mode
+ * @additional_flags:          additional flags
+ * @field_flag:                        determines frame/field scan
+ * @is_jpeg_image:             1 = still jpeg, 0 = motion jpeg
+ */
+struct jpeg_decode_params_t {
+       u32 picture_start_addr_p;
+       u32 picture_end_addr_p;
+       struct jpeg_decoded_buffer_address_t decoded_buffer_addr;
+       struct jpeg_display_buffer_address_t display_buffer_addr;
+       enum jpeg_rcn_ref_disp_enable_t main_aux_enable;
+       enum jpeg_horizontal_deci_factor_t horizontal_decimation_factor;
+       enum jpeg_vertical_deci_factor_t vertical_decimation_factor;
+       u32 xvalue0;
+       u32 xvalue1;
+       u32 yvalue0;
+       u32 yvalue1;
+       enum jpeg_decoding_mode_t decoding_mode;
+       u32 additional_flags;
+       u32 field_flag;
+       u32 reserved;
+       u32 is_jpeg_image;
+};
+
+/*
+ * struct jpeg_decode_return_params_t
+ *
+ * status returned by firmware after decoding
+ *
+ * @decode_time_in_us: decoding time in microseconds
+ * @pm_cycles:         profiling information
+ * @pm_dmiss:          profiling information
+ * @pm_imiss:          profiling information
+ * @pm_bundles:                profiling information
+ * @pm_pft:            profiling information
+ * @error_code:                status of the decoding process
+ * @ceh_registers:     array where values of the Contrast Enhancement
+ *                     Histogram (CEH) registers will be stored.
+ *                     ceh_registers[0] correspond to register MBE_CEH_0_7,
+ *                     ceh_registers[1] correspond to register MBE_CEH_8_15
+ *                     ceh_registers[2] correspond to register MBE_CEH_16_23
+ *                     Note that elements of this array will be updated only
+ *                     if additional_flags has JPEG_ADDITIONAL_FLAG_CEH set.
+ */
+struct jpeg_decode_return_params_t {
+       /* profiling info */
+       u32 decode_time_in_us;
+       u32 pm_cycles;
+       u32 pm_dmiss;
+       u32 pm_imiss;
+       u32 pm_bundles;
+       u32 pm_pft;
+       enum jpeg_decoding_error_t error_code;
+       u32 ceh_registers[32];
+};
+
+#endif /* DELTA_MJPEG_FW_H */
diff --git a/drivers/media/platform/sti/delta/delta-mjpeg-hdr.c b/drivers/media/platform/sti/delta/delta-mjpeg-hdr.c
new file mode 100644 (file)
index 0000000..a8fd8fa
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2013
+ * Author: Hugues Fruchet <hugues.fruchet@st.com> for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include "delta.h"
+#include "delta-mjpeg.h"
+
+#define MJPEG_SOF_0  0xc0
+#define MJPEG_SOF_1  0xc1
+#define MJPEG_SOI    0xd8
+#define MJPEG_MARKER 0xff
+
+static char *header_str(struct mjpeg_header *header,
+                       char *str,
+                       unsigned int len)
+{
+       char *cur = str;
+       unsigned int left = len;
+
+       if (!header)
+               return "";
+
+       snprintf(cur, left, "[MJPEG header]\n"
+                       "|- length     = %d\n"
+                       "|- precision  = %d\n"
+                       "|- width      = %d\n"
+                       "|- height     = %d\n"
+                       "|- components = %d\n",
+                       header->length,
+                       header->sample_precision,
+                       header->frame_width,
+                       header->frame_height,
+                       header->nb_of_components);
+
+       return str;
+}
+
+static int delta_mjpeg_read_sof(struct delta_ctx *pctx,
+                               unsigned char *data, unsigned int size,
+                               struct mjpeg_header *header)
+{
+       struct delta_dev *delta = pctx->dev;
+       unsigned int offset = 0;
+
+       if (size < 64)
+               goto err_no_more;
+
+       memset(header, 0, sizeof(*header));
+       header->length           = be16_to_cpu(*(__be16 *)(data + offset));
+       offset += sizeof(u16);
+       header->sample_precision = *(u8 *)(data + offset);
+       offset += sizeof(u8);
+       header->frame_height     = be16_to_cpu(*(__be16 *)(data + offset));
+       offset += sizeof(u16);
+       header->frame_width      = be16_to_cpu(*(__be16 *)(data + offset));
+       offset += sizeof(u16);
+       header->nb_of_components = *(u8 *)(data + offset);
+       offset += sizeof(u8);
+
+       if (header->nb_of_components >= MJPEG_MAX_COMPONENTS) {
+               dev_err(delta->dev,
+                       "%s   unsupported number of components (%d > %d)\n",
+                       pctx->name, header->nb_of_components,
+                       MJPEG_MAX_COMPONENTS);
+               return -EINVAL;
+       }
+
+       if ((offset + header->nb_of_components *
+            sizeof(header->components[0])) > size)
+               goto err_no_more;
+
+       return 0;
+
+err_no_more:
+       dev_err(delta->dev,
+               "%s   sof: reached end of %d size input stream\n",
+               pctx->name, size);
+       return -ENODATA;
+}
+
+int delta_mjpeg_read_header(struct delta_ctx *pctx,
+                           unsigned char *data, unsigned int size,
+                           struct mjpeg_header *header,
+                           unsigned int *data_offset)
+{
+       struct delta_dev *delta = pctx->dev;
+       unsigned char str[200];
+
+       unsigned int ret = 0;
+       unsigned int offset = 0;
+       unsigned int soi = 0;
+
+       if (size < 2)
+               goto err_no_more;
+
+       offset = 0;
+       while (1) {
+               if (data[offset] == MJPEG_MARKER)
+                       switch (data[offset + 1]) {
+                       case MJPEG_SOI:
+                               soi = 1;
+                               *data_offset = offset;
+                               break;
+
+                       case MJPEG_SOF_0:
+                       case MJPEG_SOF_1:
+                               if (!soi) {
+                                       dev_err(delta->dev,
+                                               "%s   wrong sequence, got SOF while SOI not seen\n",
+                                               pctx->name);
+                                       return -EINVAL;
+                               }
+
+                               ret = delta_mjpeg_read_sof(pctx,
+                                                          &data[offset + 2],
+                                                          size - (offset + 2),
+                                                          header);
+                               if (ret)
+                                       goto err;
+
+                               goto done;
+
+                       default:
+                               break;
+                       }
+
+               offset++;
+               if ((offset + 2) >= size)
+                       goto err_no_more;
+       }
+
+done:
+       dev_dbg(delta->dev,
+               "%s   found header @ offset %d:\n%s", pctx->name,
+               *data_offset,
+               header_str(header, str, sizeof(str)));
+       return 0;
+
+err_no_more:
+       dev_err(delta->dev,
+               "%s   no header found within %d bytes input stream\n",
+               pctx->name, size);
+       return -ENODATA;
+
+err:
+       return ret;
+}
diff --git a/drivers/media/platform/sti/delta/delta-mjpeg.h b/drivers/media/platform/sti/delta/delta-mjpeg.h
new file mode 100644 (file)
index 0000000..18e6b37
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2013
+ * Author: Hugues Fruchet <hugues.fruchet@st.com> for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef DELTA_MJPEG_H
+#define DELTA_MJPEG_H
+
+#include "delta.h"
+
+struct mjpeg_component {
+       unsigned int id;/* 1=Y, 2=Cb, 3=Cr, 4=L, 5=Q */
+       unsigned int h_sampling_factor;
+       unsigned int v_sampling_factor;
+       unsigned int quant_table_index;
+};
+
+#define MJPEG_MAX_COMPONENTS 5
+
+struct mjpeg_header {
+       unsigned int length;
+       unsigned int sample_precision;
+       unsigned int frame_width;
+       unsigned int frame_height;
+       unsigned int nb_of_components;
+       struct mjpeg_component components[MJPEG_MAX_COMPONENTS];
+};
+
+int delta_mjpeg_read_header(struct delta_ctx *pctx,
+                           unsigned char *data, unsigned int size,
+                           struct mjpeg_header *header,
+                           unsigned int *data_offset);
+
+#endif /* DELTA_MJPEG_H */
diff --git a/drivers/media/platform/sti/delta/delta-v4l2.c b/drivers/media/platform/sti/delta/delta-v4l2.c
new file mode 100644 (file)
index 0000000..c6f2e24
--- /dev/null
@@ -0,0 +1,1993 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2015
+ * Authors: Hugues Fruchet <hugues.fruchet@st.com>
+ *          Jean-Christophe Trotin <jean-christophe.trotin@st.com>
+ *          for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "delta.h"
+#include "delta-debug.h"
+#include "delta-ipc.h"
+
+#define DELTA_NAME     "st-delta"
+
+#define DELTA_PREFIX "[---:----]"
+
+#define to_ctx(__fh) container_of(__fh, struct delta_ctx, fh)
+#define to_au(__vbuf) container_of(__vbuf, struct delta_au, vbuf)
+#define to_frame(__vbuf) container_of(__vbuf, struct delta_frame, vbuf)
+
+#define call_dec_op(dec, op, args...)\
+               ((dec && (dec)->op) ? (dec)->op(args) : 0)
+
+/* registry of available decoders */
+static const struct delta_dec *delta_decoders[] = {
+#ifdef CONFIG_VIDEO_STI_DELTA_MJPEG
+       &mjpegdec,
+#endif
+};
+
+static inline int frame_size(u32 w, u32 h, u32 fmt)
+{
+       switch (fmt) {
+       case V4L2_PIX_FMT_NV12:
+               return (w * h * 3) / 2;
+       default:
+               return 0;
+       }
+}
+
+static inline int frame_stride(u32 w, u32 fmt)
+{
+       switch (fmt) {
+       case V4L2_PIX_FMT_NV12:
+               return w;
+       default:
+               return 0;
+       }
+}
+
+static void dump_au(struct delta_ctx *ctx, struct delta_au *au)
+{
+       struct delta_dev *delta = ctx->dev;
+       u32 size = 10;  /* dump first & last 10 bytes */
+       u8 *data = (u8 *)(au->vaddr);
+
+       if (au->size <= (size * 2))
+               dev_dbg(delta->dev, "%s dump au[%d] dts=%lld size=%d data=%*ph\n",
+                       ctx->name, au->vbuf.vb2_buf.index, au->dts, au->size,
+                       au->size, data);
+       else
+               dev_dbg(delta->dev, "%s dump au[%d] dts=%lld size=%d data=%*ph..%*ph\n",
+                       ctx->name, au->vbuf.vb2_buf.index, au->dts, au->size,
+                       size, data, size, data + au->size - size);
+}
+
+static void dump_frame(struct delta_ctx *ctx, struct delta_frame *frame)
+{
+       struct delta_dev *delta = ctx->dev;
+       u32 size = 10;  /* dump first 10 bytes */
+       u8 *data = (u8 *)(frame->vaddr);
+
+       dev_dbg(delta->dev, "%s dump frame[%d] dts=%lld type=%s field=%s data=%*ph\n",
+               ctx->name, frame->index, frame->dts,
+               frame_type_str(frame->flags),
+               frame_field_str(frame->field),
+               size, data);
+}
+
+static void delta_au_done(struct delta_ctx *ctx, struct delta_au *au, int err)
+{
+       struct vb2_v4l2_buffer *vbuf;
+
+       vbuf = &au->vbuf;
+       vbuf->sequence = ctx->au_num++;
+       v4l2_m2m_buf_done(vbuf, err ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+}
+
+static void delta_frame_done(struct delta_ctx *ctx, struct delta_frame *frame,
+                            int err)
+{
+       struct vb2_v4l2_buffer *vbuf;
+
+       dump_frame(ctx, frame);
+
+       /* decoded frame is now output to user */
+       frame->state |= DELTA_FRAME_OUT;
+
+       vbuf = &frame->vbuf;
+       vbuf->sequence = ctx->frame_num++;
+       v4l2_m2m_buf_done(vbuf, err ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+
+       if (frame->info.size) /* ignore EOS */
+               ctx->output_frames++;
+}
+
+static void requeue_free_frames(struct delta_ctx *ctx)
+{
+       struct vb2_v4l2_buffer *vbuf;
+       struct delta_frame *frame;
+       unsigned int i;
+
+       /* requeue all free frames */
+       for (i = 0; i < ctx->nb_of_frames; i++) {
+               frame = ctx->frames[i];
+               if (frame->state == DELTA_FRAME_FREE) {
+                       vbuf = &frame->vbuf;
+                       v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
+                       frame->state = DELTA_FRAME_M2M;
+               }
+       }
+}
+
+static int delta_recycle(struct delta_ctx *ctx, struct delta_frame *frame)
+{
+       const struct delta_dec *dec = ctx->dec;
+
+       /* recycle frame on decoder side */
+       call_dec_op(dec, recycle, ctx, frame);
+
+       /* this frame is no more output */
+       frame->state &= ~DELTA_FRAME_OUT;
+
+       /* requeue free frame */
+       if (frame->state == DELTA_FRAME_FREE) {
+               struct vb2_v4l2_buffer *vbuf = &frame->vbuf;
+
+               v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
+               frame->state = DELTA_FRAME_M2M;
+       }
+
+       /* reset other frame fields */
+       frame->flags = 0;
+       frame->dts = 0;
+
+       return 0;
+}
+
+static void delta_push_dts(struct delta_ctx *ctx, u64 val)
+{
+       struct delta_dts *dts;
+
+       dts = kzalloc(sizeof(*dts), GFP_KERNEL);
+       if (!dts)
+               return;
+
+       INIT_LIST_HEAD(&dts->list);
+
+       /*
+        * protected by global lock acquired
+        * by V4L2 when calling delta_vb2_au_queue
+        */
+       dts->val = val;
+       list_add_tail(&dts->list, &ctx->dts);
+}
+
+static void delta_pop_dts(struct delta_ctx *ctx, u64 *val)
+{
+       struct delta_dev *delta = ctx->dev;
+       struct delta_dts *dts;
+
+       /*
+        * protected by global lock acquired
+        * by V4L2 when calling delta_vb2_au_queue
+        */
+       if (list_empty(&ctx->dts)) {
+               dev_warn(delta->dev, "%s no dts to pop ... output dts = 0\n",
+                        ctx->name);
+               *val = 0;
+               return;
+       }
+
+       dts = list_first_entry(&ctx->dts, struct delta_dts, list);
+       list_del(&dts->list);
+
+       *val = dts->val;
+
+       kfree(dts);
+}
+
+static void delta_flush_dts(struct delta_ctx *ctx)
+{
+       struct delta_dts *dts;
+       struct delta_dts *next;
+
+       /*
+        * protected by global lock acquired
+        * by V4L2 when calling delta_vb2_au_queue
+        */
+
+       /* free all pending dts */
+       list_for_each_entry_safe(dts, next, &ctx->dts, list)
+               kfree(dts);
+
+       /* reset list */
+       INIT_LIST_HEAD(&ctx->dts);
+}
+
+static inline int frame_alignment(u32 fmt)
+{
+       switch (fmt) {
+       case V4L2_PIX_FMT_NV12:
+       case V4L2_PIX_FMT_NV21:
+               /* multiple of 2 */
+               return 2;
+       default:
+               return 1;
+       }
+}
+
+static inline int estimated_au_size(u32 w, u32 h)
+{
+       /*
+        * for a MJPEG stream encoded from YUV422 pixel format,
+        * assuming a compression ratio of 2, the maximum size
+        * of an access unit is (width x height x 2) / 2,
+        * so (width x height)
+        */
+       return (w * h);
+}
+
+static void set_default_params(struct delta_ctx *ctx)
+{
+       struct delta_frameinfo *frameinfo = &ctx->frameinfo;
+       struct delta_streaminfo *streaminfo = &ctx->streaminfo;
+
+       memset(frameinfo, 0, sizeof(*frameinfo));
+       frameinfo->pixelformat = V4L2_PIX_FMT_NV12;
+       frameinfo->width = DELTA_DEFAULT_WIDTH;
+       frameinfo->height = DELTA_DEFAULT_HEIGHT;
+       frameinfo->aligned_width = ALIGN(frameinfo->width,
+                                        DELTA_WIDTH_ALIGNMENT);
+       frameinfo->aligned_height = ALIGN(frameinfo->height,
+                                         DELTA_HEIGHT_ALIGNMENT);
+       frameinfo->size = frame_size(frameinfo->aligned_width,
+                                    frameinfo->aligned_height,
+                                    frameinfo->pixelformat);
+       frameinfo->field = V4L2_FIELD_NONE;
+       frameinfo->colorspace = V4L2_COLORSPACE_REC709;
+       frameinfo->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+       frameinfo->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+       frameinfo->quantization = V4L2_QUANTIZATION_DEFAULT;
+
+       memset(streaminfo, 0, sizeof(*streaminfo));
+       streaminfo->streamformat = DELTA_DEFAULT_STREAMFORMAT;
+       streaminfo->width = DELTA_DEFAULT_WIDTH;
+       streaminfo->height = DELTA_DEFAULT_HEIGHT;
+       streaminfo->field = V4L2_FIELD_NONE;
+       streaminfo->colorspace = V4L2_COLORSPACE_REC709;
+       streaminfo->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+       streaminfo->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+       streaminfo->quantization = V4L2_QUANTIZATION_DEFAULT;
+
+       ctx->max_au_size = estimated_au_size(streaminfo->width,
+                                            streaminfo->height);
+}
+
+static const struct delta_dec *delta_find_decoder(struct delta_ctx *ctx,
+                                                 u32 streamformat,
+                                                 u32 pixelformat)
+{
+       struct delta_dev *delta = ctx->dev;
+       const struct delta_dec *dec;
+       unsigned int i;
+
+       for (i = 0; i < delta->nb_of_decoders; i++) {
+               dec = delta->decoders[i];
+               if ((dec->pixelformat == pixelformat) &&
+                   (dec->streamformat == streamformat))
+                       return dec;
+       }
+
+       return NULL;
+}
+
+static void register_format(u32 format, u32 formats[], u32 *nb_of_formats)
+{
+       u32 i;
+
+       for (i = 0; i < *nb_of_formats; i++) {
+               if (format == formats[i])
+                       return;
+       }
+
+       formats[(*nb_of_formats)++] = format;
+}
+
+static void register_formats(struct delta_dev *delta)
+{
+       unsigned int i;
+
+       for (i = 0; i < delta->nb_of_decoders; i++) {
+               register_format(delta->decoders[i]->pixelformat,
+                               delta->pixelformats,
+                               &delta->nb_of_pixelformats);
+
+               register_format(delta->decoders[i]->streamformat,
+                               delta->streamformats,
+                               &delta->nb_of_streamformats);
+       }
+}
+
+static void register_decoders(struct delta_dev *delta)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(delta_decoders); i++) {
+               if (delta->nb_of_decoders >= DELTA_MAX_DECODERS) {
+                       dev_dbg(delta->dev,
+                               "%s failed to register %s decoder (%d maximum reached)\n",
+                               DELTA_PREFIX, delta_decoders[i]->name,
+                               DELTA_MAX_DECODERS);
+                       return;
+               }
+
+               delta->decoders[delta->nb_of_decoders++] = delta_decoders[i];
+               dev_info(delta->dev, "%s %s decoder registered\n",
+                        DELTA_PREFIX, delta_decoders[i]->name);
+       }
+}
+
+static void delta_lock(void *priv)
+{
+       struct delta_ctx *ctx = priv;
+       struct delta_dev *delta = ctx->dev;
+
+       mutex_lock(&delta->lock);
+}
+
+static void delta_unlock(void *priv)
+{
+       struct delta_ctx *ctx = priv;
+       struct delta_dev *delta = ctx->dev;
+
+       mutex_unlock(&delta->lock);
+}
+
+static int delta_open_decoder(struct delta_ctx *ctx, u32 streamformat,
+                             u32 pixelformat, const struct delta_dec **pdec)
+{
+       struct delta_dev *delta = ctx->dev;
+       const struct delta_dec *dec;
+       int ret;
+
+       dec = delta_find_decoder(ctx, streamformat, ctx->frameinfo.pixelformat);
+       if (!dec) {
+               dev_err(delta->dev, "%s no decoder found matching %4.4s => %4.4s\n",
+                       ctx->name, (char *)&streamformat, (char *)&pixelformat);
+               return -EINVAL;
+       }
+
+       dev_dbg(delta->dev, "%s one decoder matching %4.4s => %4.4s\n",
+               ctx->name, (char *)&streamformat, (char *)&pixelformat);
+
+       /* update instance name */
+       snprintf(ctx->name, sizeof(ctx->name), "[%3d:%4.4s]",
+                delta->instance_id, (char *)&streamformat);
+
+       /* open decoder instance */
+       ret = call_dec_op(dec, open, ctx);
+       if (ret) {
+               dev_err(delta->dev, "%s failed to open decoder instance (%d)\n",
+                       ctx->name, ret);
+               return ret;
+       }
+
+       dev_dbg(delta->dev, "%s %s decoder opened\n", ctx->name, dec->name);
+
+       *pdec = dec;
+
+       return ret;
+}
+
+/*
+ * V4L2 ioctl operations
+ */
+
+static int delta_querycap(struct file *file, void *priv,
+                         struct v4l2_capability *cap)
+{
+       struct delta_ctx *ctx = to_ctx(file->private_data);
+       struct delta_dev *delta = ctx->dev;
+
+       strlcpy(cap->driver, DELTA_NAME, sizeof(cap->driver));
+       strlcpy(cap->card, delta->vdev->name, sizeof(cap->card));
+       snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+                delta->pdev->name);
+
+       return 0;
+}
+
+static int delta_enum_fmt_stream(struct file *file, void *priv,
+                                struct v4l2_fmtdesc *f)
+{
+       struct delta_ctx *ctx = to_ctx(file->private_data);
+       struct delta_dev *delta = ctx->dev;
+
+       if (unlikely(f->index >= delta->nb_of_streamformats))
+               return -EINVAL;
+
+       f->pixelformat = delta->streamformats[f->index];
+
+       return 0;
+}
+
+static int delta_enum_fmt_frame(struct file *file, void *priv,
+                               struct v4l2_fmtdesc *f)
+{
+       struct delta_ctx *ctx = to_ctx(file->private_data);
+       struct delta_dev *delta = ctx->dev;
+
+       if (unlikely(f->index >= delta->nb_of_pixelformats))
+               return -EINVAL;
+
+       f->pixelformat = delta->pixelformats[f->index];
+
+       return 0;
+}
+
+static int delta_g_fmt_stream(struct file *file, void *fh,
+                             struct v4l2_format *f)
+{
+       struct delta_ctx *ctx = to_ctx(file->private_data);
+       struct delta_dev *delta = ctx->dev;
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       struct delta_streaminfo *streaminfo = &ctx->streaminfo;
+       unsigned char str[100] = "";
+
+       if (!(ctx->flags & DELTA_FLAG_STREAMINFO))
+               dev_dbg(delta->dev,
+                       "%s V4L2 GET_FMT (OUTPUT): no stream information available, default to %s\n",
+                       ctx->name,
+                       delta_streaminfo_str(streaminfo, str, sizeof(str)));
+
+       pix->pixelformat = streaminfo->streamformat;
+       pix->width = streaminfo->width;
+       pix->height = streaminfo->height;
+       pix->field = streaminfo->field;
+       pix->bytesperline = 0;
+       pix->sizeimage = ctx->max_au_size;
+       pix->colorspace = streaminfo->colorspace;
+       pix->xfer_func = streaminfo->xfer_func;
+       pix->ycbcr_enc = streaminfo->ycbcr_enc;
+       pix->quantization = streaminfo->quantization;
+
+       return 0;
+}
+
+static int delta_g_fmt_frame(struct file *file, void *fh, struct v4l2_format *f)
+{
+       struct delta_ctx *ctx = to_ctx(file->private_data);
+       struct delta_dev *delta = ctx->dev;
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       struct delta_frameinfo *frameinfo = &ctx->frameinfo;
+       struct delta_streaminfo *streaminfo = &ctx->streaminfo;
+       unsigned char str[100] = "";
+
+       if (!(ctx->flags & DELTA_FLAG_FRAMEINFO))
+               dev_dbg(delta->dev,
+                       "%s V4L2 GET_FMT (CAPTURE): no frame information available, default to %s\n",
+                       ctx->name,
+                       delta_frameinfo_str(frameinfo, str, sizeof(str)));
+
+       pix->pixelformat = frameinfo->pixelformat;
+       pix->width = frameinfo->aligned_width;
+       pix->height = frameinfo->aligned_height;
+       pix->field = frameinfo->field;
+       pix->bytesperline = frame_stride(frameinfo->aligned_width,
+                                              frameinfo->pixelformat);
+       pix->sizeimage = frameinfo->size;
+
+       if (ctx->flags & DELTA_FLAG_STREAMINFO) {
+               /* align colorspace & friends on stream ones if any set */
+               frameinfo->colorspace = streaminfo->colorspace;
+               frameinfo->xfer_func = streaminfo->xfer_func;
+               frameinfo->ycbcr_enc = streaminfo->ycbcr_enc;
+               frameinfo->quantization = streaminfo->quantization;
+       }
+       pix->colorspace = frameinfo->colorspace;
+       pix->xfer_func = frameinfo->xfer_func;
+       pix->ycbcr_enc = frameinfo->ycbcr_enc;
+       pix->quantization = frameinfo->quantization;
+
+       return 0;
+}
+
+static int delta_try_fmt_stream(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct delta_ctx *ctx = to_ctx(file->private_data);
+       struct delta_dev *delta = ctx->dev;
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       u32 streamformat = pix->pixelformat;
+       const struct delta_dec *dec;
+       u32 width, height;
+       u32 au_size;
+
+       dec = delta_find_decoder(ctx, streamformat, ctx->frameinfo.pixelformat);
+       if (!dec) {
+               dev_dbg(delta->dev,
+                       "%s V4L2 TRY_FMT (OUTPUT): unsupported format %4.4s\n",
+                       ctx->name, (char *)&pix->pixelformat);
+               return -EINVAL;
+       }
+
+       /* adjust width & height */
+       width = pix->width;
+       height = pix->height;
+       v4l_bound_align_image
+               (&pix->width,
+                DELTA_MIN_WIDTH,
+                dec->max_width ? dec->max_width : DELTA_MAX_WIDTH,
+                0,
+                &pix->height,
+                DELTA_MIN_HEIGHT,
+                dec->max_height ? dec->max_height : DELTA_MAX_HEIGHT,
+                0, 0);
+
+       if ((pix->width != width) || (pix->height != height))
+               dev_dbg(delta->dev,
+                       "%s V4L2 TRY_FMT (OUTPUT): resolution updated %dx%d -> %dx%d to fit min/max/alignment\n",
+                       ctx->name, width, height,
+                       pix->width, pix->height);
+
+       au_size = estimated_au_size(pix->width, pix->height);
+       if (pix->sizeimage < au_size) {
+               dev_dbg(delta->dev,
+                       "%s V4L2 TRY_FMT (OUTPUT): size updated %d -> %d to fit estimated size\n",
+                       ctx->name, pix->sizeimage, au_size);
+               pix->sizeimage = au_size;
+       }
+
+       pix->bytesperline = 0;
+
+       if (pix->field == V4L2_FIELD_ANY)
+               pix->field = V4L2_FIELD_NONE;
+
+       return 0;
+}
+
+static int delta_try_fmt_frame(struct file *file, void *priv,
+                              struct v4l2_format *f)
+{
+       struct delta_ctx *ctx = to_ctx(file->private_data);
+       struct delta_dev *delta = ctx->dev;
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       u32 pixelformat = pix->pixelformat;
+       const struct delta_dec *dec;
+       u32 width, height;
+
+       dec = delta_find_decoder(ctx, ctx->streaminfo.streamformat,
+                                pixelformat);
+       if (!dec) {
+               dev_dbg(delta->dev,
+                       "%s V4L2 TRY_FMT (CAPTURE): unsupported format %4.4s\n",
+                       ctx->name, (char *)&pixelformat);
+               return -EINVAL;
+       }
+
+       /* adjust width & height */
+       width = pix->width;
+       height = pix->height;
+       v4l_bound_align_image(&pix->width,
+                             DELTA_MIN_WIDTH, DELTA_MAX_WIDTH,
+                             frame_alignment(pixelformat) - 1,
+                             &pix->height,
+                             DELTA_MIN_HEIGHT, DELTA_MAX_HEIGHT,
+                             frame_alignment(pixelformat) - 1, 0);
+
+       if ((pix->width != width) || (pix->height != height))
+               dev_dbg(delta->dev,
+                       "%s V4L2 TRY_FMT (CAPTURE): resolution updated %dx%d -> %dx%d to fit min/max/alignment\n",
+                       ctx->name, width, height, pix->width, pix->height);
+
+       /* default decoder alignment constraint */
+       width = ALIGN(pix->width, DELTA_WIDTH_ALIGNMENT);
+       height = ALIGN(pix->height, DELTA_HEIGHT_ALIGNMENT);
+       if ((pix->width != width) || (pix->height != height))
+               dev_dbg(delta->dev,
+                       "%s V4L2 TRY_FMT (CAPTURE): resolution updated %dx%d -> %dx%d to fit decoder alignment\n",
+                       ctx->name, width, height, pix->width, pix->height);
+
+       if (!pix->colorspace) {
+               pix->colorspace = V4L2_COLORSPACE_REC709;
+               pix->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+               pix->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+               pix->quantization = V4L2_QUANTIZATION_DEFAULT;
+       }
+
+       pix->width = width;
+       pix->height = height;
+       pix->bytesperline = frame_stride(pix->width, pixelformat);
+       pix->sizeimage = frame_size(pix->width, pix->height, pixelformat);
+
+       if (pix->field == V4L2_FIELD_ANY)
+               pix->field = V4L2_FIELD_NONE;
+
+       return 0;
+}
+
+static int delta_s_fmt_stream(struct file *file, void *fh,
+                             struct v4l2_format *f)
+{
+       struct delta_ctx *ctx = to_ctx(file->private_data);
+       struct delta_dev *delta = ctx->dev;
+       struct vb2_queue *vq;
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       int ret;
+
+       ret = delta_try_fmt_stream(file, fh, f);
+       if (ret) {
+               dev_dbg(delta->dev,
+                       "%s V4L2 S_FMT (OUTPUT): unsupported format %4.4s\n",
+                       ctx->name, (char *)&pix->pixelformat);
+               return ret;
+       }
+
+       vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+       if (vb2_is_streaming(vq)) {
+               dev_dbg(delta->dev, "%s V4L2 S_FMT (OUTPUT): queue busy\n",
+                       ctx->name);
+               return -EBUSY;
+       }
+
+       ctx->max_au_size = pix->sizeimage;
+       ctx->streaminfo.width = pix->width;
+       ctx->streaminfo.height = pix->height;
+       ctx->streaminfo.streamformat = pix->pixelformat;
+       ctx->streaminfo.colorspace = pix->colorspace;
+       ctx->streaminfo.xfer_func = pix->xfer_func;
+       ctx->streaminfo.ycbcr_enc = pix->ycbcr_enc;
+       ctx->streaminfo.quantization = pix->quantization;
+       ctx->flags |= DELTA_FLAG_STREAMINFO;
+
+       return 0;
+}
+
+static int delta_s_fmt_frame(struct file *file, void *fh, struct v4l2_format *f)
+{
+       struct delta_ctx *ctx = to_ctx(file->private_data);
+       struct delta_dev *delta = ctx->dev;
+       const struct delta_dec *dec = ctx->dec;
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       struct delta_frameinfo frameinfo;
+       unsigned char str[100] = "";
+       struct vb2_queue *vq;
+       int ret;
+
+       vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+       if (vb2_is_streaming(vq)) {
+               dev_dbg(delta->dev, "%s V4L2 S_FMT (CAPTURE): queue busy\n",
+                       ctx->name);
+               return -EBUSY;
+       }
+
+       if (ctx->state < DELTA_STATE_READY) {
+               /*
+                * decoder not yet opened and valid stream header not found,
+                * could not negotiate format with decoder, check at least
+                * pixel format & negotiate resolution boundaries
+                * and alignment...
+                */
+               ret = delta_try_fmt_frame(file, fh, f);
+               if (ret) {
+                       dev_dbg(delta->dev,
+                               "%s V4L2 S_FMT (CAPTURE): unsupported format %4.4s\n",
+                               ctx->name, (char *)&pix->pixelformat);
+                       return ret;
+               }
+
+               return 0;
+       }
+
+       /* set frame information to decoder */
+       memset(&frameinfo, 0, sizeof(frameinfo));
+       frameinfo.pixelformat = pix->pixelformat;
+       frameinfo.width = pix->width;
+       frameinfo.height = pix->height;
+       frameinfo.aligned_width = pix->width;
+       frameinfo.aligned_height = pix->height;
+       frameinfo.size = pix->sizeimage;
+       frameinfo.field = pix->field;
+       frameinfo.colorspace = pix->colorspace;
+       frameinfo.xfer_func = pix->xfer_func;
+       frameinfo.ycbcr_enc = pix->ycbcr_enc;
+       frameinfo.quantization = pix->quantization;
+       ret = call_dec_op(dec, set_frameinfo, ctx, &frameinfo);
+       if (ret)
+               return ret;
+
+       /* then get what decoder can really do */
+       ret = call_dec_op(dec, get_frameinfo, ctx, &frameinfo);
+       if (ret)
+               return ret;
+
+       ctx->flags |= DELTA_FLAG_FRAMEINFO;
+       ctx->frameinfo = frameinfo;
+       dev_dbg(delta->dev,
+               "%s V4L2 SET_FMT (CAPTURE): frameinfo updated to %s\n",
+               ctx->name,
+               delta_frameinfo_str(&frameinfo, str, sizeof(str)));
+
+       pix->pixelformat = frameinfo.pixelformat;
+       pix->width = frameinfo.aligned_width;
+       pix->height = frameinfo.aligned_height;
+       pix->bytesperline = frame_stride(pix->width, pix->pixelformat);
+       pix->sizeimage = frameinfo.size;
+       pix->field = frameinfo.field;
+       pix->colorspace = frameinfo.colorspace;
+       pix->xfer_func = frameinfo.xfer_func;
+       pix->ycbcr_enc = frameinfo.ycbcr_enc;
+       pix->quantization = frameinfo.quantization;
+
+       return 0;
+}
+
+static int delta_g_selection(struct file *file, void *fh,
+                            struct v4l2_selection *s)
+{
+       struct delta_ctx *ctx = to_ctx(fh);
+       struct delta_frameinfo *frameinfo = &ctx->frameinfo;
+       struct v4l2_rect crop;
+
+       if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       if ((ctx->flags & DELTA_FLAG_FRAMEINFO) &&
+           (frameinfo->flags & DELTA_FRAMEINFO_FLAG_CROP)) {
+               crop = frameinfo->crop;
+       } else {
+               /* default to video dimensions */
+               crop.left = 0;
+               crop.top = 0;
+               crop.width = frameinfo->width;
+               crop.height = frameinfo->height;
+       }
+
+       switch (s->target) {
+       case V4L2_SEL_TGT_COMPOSE:
+       case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+               /* visible area inside video */
+               s->r = crop;
+               break;
+       case V4L2_SEL_TGT_COMPOSE_PADDED:
+       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+               /* up to aligned dimensions */
+               s->r.left = 0;
+               s->r.top = 0;
+               s->r.width = frameinfo->aligned_width;
+               s->r.height = frameinfo->aligned_height;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void delta_complete_eos(struct delta_ctx *ctx,
+                              struct delta_frame *frame)
+{
+       struct delta_dev *delta = ctx->dev;
+       const struct v4l2_event ev = {.type = V4L2_EVENT_EOS};
+
+       /*
+        * Send EOS to user:
+        * - by returning an empty frame flagged to V4L2_BUF_FLAG_LAST
+        * - and then send EOS event
+        */
+
+       /* empty frame */
+       frame->info.size = 0;
+
+       /* set the last buffer flag */
+       frame->flags |= V4L2_BUF_FLAG_LAST;
+
+       /* release frame to user */
+       delta_frame_done(ctx, frame, 0);
+
+       /* send EOS event */
+       v4l2_event_queue_fh(&ctx->fh, &ev);
+
+       dev_dbg(delta->dev, "%s EOS completed\n", ctx->name);
+}
+
+static int delta_try_decoder_cmd(struct file *file, void *fh,
+                                struct v4l2_decoder_cmd *cmd)
+{
+       if (cmd->cmd != V4L2_DEC_CMD_STOP)
+               return -EINVAL;
+
+       if (cmd->flags & V4L2_DEC_CMD_STOP_TO_BLACK)
+               return -EINVAL;
+
+       if (!(cmd->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) &&
+           (cmd->stop.pts != 0))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int delta_decoder_stop_cmd(struct delta_ctx *ctx, void *fh)
+{
+       const struct delta_dec *dec = ctx->dec;
+       struct delta_dev *delta = ctx->dev;
+       struct delta_frame *frame = NULL;
+       int ret = 0;
+
+       dev_dbg(delta->dev, "%s EOS received\n", ctx->name);
+
+       if (ctx->state != DELTA_STATE_READY)
+               return 0;
+
+       /* drain the decoder */
+       call_dec_op(dec, drain, ctx);
+
+       /* release to user drained frames */
+       while (1) {
+               frame = NULL;
+               ret = call_dec_op(dec, get_frame, ctx, &frame);
+               if (ret == -ENODATA) {
+                       /* no more decoded frames */
+                       break;
+               }
+               if (frame) {
+                       dev_dbg(delta->dev, "%s drain frame[%d]\n",
+                               ctx->name, frame->index);
+
+                       /* pop timestamp and mark frame with it */
+                       delta_pop_dts(ctx, &frame->dts);
+
+                       /* release decoded frame to user */
+                       delta_frame_done(ctx, frame, 0);
+               }
+       }
+
+       /* try to complete EOS */
+       ret = delta_get_free_frame(ctx, &frame);
+       if (ret)
+               goto delay_eos;
+
+       /* new frame available, EOS can now be completed */
+       delta_complete_eos(ctx, frame);
+
+       ctx->state = DELTA_STATE_EOS;
+
+       return 0;
+
+delay_eos:
+       /*
+        * EOS completion from driver is delayed because
+        * we don't have a free empty frame available.
+        * EOS completion is so delayed till next frame_queue() call
+        * to be sure to have a free empty frame available.
+        */
+       ctx->state = DELTA_STATE_WF_EOS;
+       dev_dbg(delta->dev, "%s EOS delayed\n", ctx->name);
+
+       return 0;
+}
+
+static int delta_decoder_cmd(struct file *file, void *fh,
+                            struct v4l2_decoder_cmd *cmd)
+{
+       struct delta_ctx *ctx = to_ctx(fh);
+       int ret = 0;
+
+       ret = delta_try_decoder_cmd(file, fh, cmd);
+       if (ret)
+               return ret;
+
+       return delta_decoder_stop_cmd(ctx, fh);
+}
+
+static int delta_subscribe_event(struct v4l2_fh *fh,
+                                const struct v4l2_event_subscription *sub)
+{
+       switch (sub->type) {
+       case V4L2_EVENT_EOS:
+               return v4l2_event_subscribe(fh, sub, 2, NULL);
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* v4l2 ioctl ops */
+static const struct v4l2_ioctl_ops delta_ioctl_ops = {
+       .vidioc_querycap = delta_querycap,
+       .vidioc_enum_fmt_vid_cap = delta_enum_fmt_frame,
+       .vidioc_g_fmt_vid_cap = delta_g_fmt_frame,
+       .vidioc_try_fmt_vid_cap = delta_try_fmt_frame,
+       .vidioc_s_fmt_vid_cap = delta_s_fmt_frame,
+       .vidioc_enum_fmt_vid_out = delta_enum_fmt_stream,
+       .vidioc_g_fmt_vid_out = delta_g_fmt_stream,
+       .vidioc_try_fmt_vid_out = delta_try_fmt_stream,
+       .vidioc_s_fmt_vid_out = delta_s_fmt_stream,
+       .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+       .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
+       .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+       .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
+       .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+       .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+       .vidioc_streamon = v4l2_m2m_ioctl_streamon,
+       .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
+       .vidioc_g_selection = delta_g_selection,
+       .vidioc_try_decoder_cmd = delta_try_decoder_cmd,
+       .vidioc_decoder_cmd = delta_decoder_cmd,
+       .vidioc_subscribe_event = delta_subscribe_event,
+       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+/*
+ * mem-to-mem operations
+ */
+
+static void delta_run_work(struct work_struct *work)
+{
+       struct delta_ctx *ctx = container_of(work, struct delta_ctx, run_work);
+       struct delta_dev *delta = ctx->dev;
+       const struct delta_dec *dec = ctx->dec;
+       struct delta_au *au;
+       struct delta_frame *frame = NULL;
+       int ret = 0;
+       bool discard = false;
+       struct vb2_v4l2_buffer *vbuf;
+
+       if (!dec) {
+               dev_err(delta->dev, "%s no decoder opened yet\n", ctx->name);
+               return;
+       }
+
+       /* protect instance against reentrancy */
+       mutex_lock(&ctx->lock);
+
+       vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+       if (!vbuf) {
+               dev_err(delta->dev, "%s no buffer to decode\n", ctx->name);
+               mutex_unlock(&ctx->lock);
+               return;
+       }
+       au = to_au(vbuf);
+       au->size = vb2_get_plane_payload(&vbuf->vb2_buf, 0);
+       au->dts = vbuf->vb2_buf.timestamp;
+
+       /* dump access unit */
+       dump_au(ctx, au);
+
+       /* enable the hardware */
+       if (!dec->pm) {
+               ret = delta_get_sync(ctx);
+               if (ret)
+                       goto err;
+       }
+
+       /* decode this access unit */
+       ret = call_dec_op(dec, decode, ctx, au);
+
+       /*
+        * if the (-ENODATA) value is returned, it refers to the interlaced
+        * stream case for which 2 access units are needed to get 1 frame.
+        * So, this returned value doesn't mean that the decoding fails, but
+        * indicates that the timestamp information of the access unit shall
+        * not be taken into account, and that the V4L2 buffer associated with
+        * the access unit shall be flagged with V4L2_BUF_FLAG_ERROR to inform
+        * the user of this situation
+        */
+       if (ret == -ENODATA) {
+               discard = true;
+       } else if (ret) {
+               dev_err(delta->dev, "%s decoding failed (%d)\n",
+                       ctx->name, ret);
+
+               /* disable the hardware */
+               if (!dec->pm)
+                       delta_put_autosuspend(ctx);
+
+               goto err;
+       }
+
+       /* disable the hardware */
+       if (!dec->pm)
+               delta_put_autosuspend(ctx);
+
+       /* push au timestamp in FIFO */
+       if (!discard)
+               delta_push_dts(ctx, au->dts);
+
+       /* get available decoded frames */
+       while (1) {
+               ret = call_dec_op(dec, get_frame, ctx, &frame);
+               if (ret == -ENODATA) {
+                       /* no more decoded frames */
+                       goto out;
+               }
+               if (ret) {
+                       dev_err(delta->dev, "%s  cannot get decoded frame (%d)\n",
+                               ctx->name, ret);
+                       goto out;
+               }
+               if (!frame) {
+                       dev_err(delta->dev,
+                               "%s  NULL decoded frame\n",
+                               ctx->name);
+                       ret = -EIO;
+                       goto out;
+               }
+
+               /* pop timestamp and mark frame with it */
+               delta_pop_dts(ctx, &frame->dts);
+
+               /* release decoded frame to user */
+               delta_frame_done(ctx, frame, 0);
+       }
+
+out:
+       requeue_free_frames(ctx);
+       delta_au_done(ctx, au, (discard ? -ENODATA : 0));
+       mutex_unlock(&ctx->lock);
+       v4l2_m2m_job_finish(delta->m2m_dev, ctx->fh.m2m_ctx);
+       return;
+
+err:
+       requeue_free_frames(ctx);
+       delta_au_done(ctx, au, ret);
+       mutex_unlock(&ctx->lock);
+       v4l2_m2m_job_finish(delta->m2m_dev, ctx->fh.m2m_ctx);
+}
+
+static void delta_device_run(void *priv)
+{
+       struct delta_ctx *ctx = priv;
+       struct delta_dev *delta = ctx->dev;
+
+       queue_work(delta->work_queue, &ctx->run_work);
+}
+
+static void delta_job_abort(void *priv)
+{
+       struct delta_ctx *ctx = priv;
+       struct delta_dev *delta = ctx->dev;
+
+       dev_dbg(delta->dev, "%s aborting job\n", ctx->name);
+
+       ctx->aborting = true;
+}
+
+static int delta_job_ready(void *priv)
+{
+       struct delta_ctx *ctx = priv;
+       struct delta_dev *delta = ctx->dev;
+       int src_bufs = v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx);
+
+       if (!src_bufs) {
+               dev_dbg(delta->dev, "%s not ready: not enough video buffers.\n",
+                       ctx->name);
+               return 0;
+       }
+
+       if (!v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)) {
+               dev_dbg(delta->dev, "%s not ready: not enough video capture buffers.\n",
+                       ctx->name);
+               return 0;
+       }
+
+       if (ctx->aborting) {
+               dev_dbg(delta->dev, "%s job not ready: aborting\n", ctx->name);
+               return 0;
+       }
+
+       dev_dbg(delta->dev, "%s job ready\n", ctx->name);
+
+       return 1;
+}
+
+/* mem-to-mem ops */
+static struct v4l2_m2m_ops delta_m2m_ops = {
+       .device_run     = delta_device_run,
+       .job_ready      = delta_job_ready,
+       .job_abort      = delta_job_abort,
+       .lock           = delta_lock,
+       .unlock         = delta_unlock,
+};
+
+/*
+ * VB2 queue operations
+ */
+
+static int delta_vb2_au_queue_setup(struct vb2_queue *vq,
+                                   unsigned int *num_buffers,
+                                   unsigned int *num_planes,
+                                   unsigned int sizes[],
+                                   struct device *alloc_devs[])
+{
+       struct delta_ctx *ctx = vb2_get_drv_priv(vq);
+       unsigned int size = ctx->max_au_size;
+
+       if (*num_planes)
+               return sizes[0] < size ? -EINVAL : 0;
+
+       *num_planes = 1;
+       if (*num_buffers < 1)
+               *num_buffers = 1;
+       if (*num_buffers > DELTA_MAX_AUS)
+               *num_buffers = DELTA_MAX_AUS;
+
+       sizes[0] = size;
+
+       return 0;
+}
+
+static int delta_vb2_au_prepare(struct vb2_buffer *vb)
+{
+       struct vb2_queue *q = vb->vb2_queue;
+       struct delta_ctx *ctx = vb2_get_drv_priv(q);
+       struct delta_dev *delta = ctx->dev;
+       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+       struct delta_au *au = to_au(vbuf);
+
+       if (!au->prepared) {
+               /* get memory addresses */
+               au->vaddr = vb2_plane_vaddr(&au->vbuf.vb2_buf, 0);
+               au->paddr = vb2_dma_contig_plane_dma_addr
+                               (&au->vbuf.vb2_buf, 0);
+               au->prepared = true;
+               dev_dbg(delta->dev, "%s au[%d] prepared; virt=0x%p, phy=0x%pad\n",
+                       ctx->name, vb->index, au->vaddr, &au->paddr);
+       }
+
+       if (vbuf->field == V4L2_FIELD_ANY)
+               vbuf->field = V4L2_FIELD_NONE;
+
+       return 0;
+}
+
+static int delta_setup_frame(struct delta_ctx *ctx,
+                            struct delta_frame *frame)
+{
+       struct delta_dev *delta = ctx->dev;
+       const struct delta_dec *dec = ctx->dec;
+
+       if (frame->index >= DELTA_MAX_FRAMES) {
+               dev_err(delta->dev,
+                       "%s frame index=%d exceeds output frame count (%d)\n",
+                       ctx->name, frame->index, DELTA_MAX_FRAMES);
+               return -EINVAL;
+       }
+
+       if (ctx->nb_of_frames >= DELTA_MAX_FRAMES) {
+               dev_err(delta->dev,
+                       "%s number of frames exceeds output frame count (%d > %d)\n",
+                       ctx->name, ctx->nb_of_frames, DELTA_MAX_FRAMES);
+               return -EINVAL;
+       }
+
+       if (frame->index != ctx->nb_of_frames) {
+               dev_warn(delta->dev,
+                        "%s frame index discontinuity detected, expected %d, got %d\n",
+                        ctx->name, ctx->nb_of_frames, frame->index);
+       }
+
+       frame->state = DELTA_FRAME_FREE;
+       ctx->frames[ctx->nb_of_frames] = frame;
+       ctx->nb_of_frames++;
+
+       /* setup frame on decoder side */
+       return call_dec_op(dec, setup_frame, ctx, frame);
+}
+
+/*
+ * default implementation of get_frameinfo decoder ops
+ * matching frame information from stream information
+ * & with default pixel format & default alignment.
+ */
+int delta_get_frameinfo_default(struct delta_ctx *ctx,
+                               struct delta_frameinfo *frameinfo)
+{
+       struct delta_streaminfo *streaminfo = &ctx->streaminfo;
+
+       memset(frameinfo, 0, sizeof(*frameinfo));
+       frameinfo->pixelformat = V4L2_PIX_FMT_NV12;
+       frameinfo->width = streaminfo->width;
+       frameinfo->height = streaminfo->height;
+       frameinfo->aligned_width = ALIGN(streaminfo->width,
+                                        DELTA_WIDTH_ALIGNMENT);
+       frameinfo->aligned_height = ALIGN(streaminfo->height,
+                                         DELTA_HEIGHT_ALIGNMENT);
+       frameinfo->size = frame_size(frameinfo->aligned_width,
+                                    frameinfo->aligned_height,
+                                    frameinfo->pixelformat);
+       if (streaminfo->flags & DELTA_STREAMINFO_FLAG_CROP) {
+               frameinfo->flags |= DELTA_FRAMEINFO_FLAG_CROP;
+               frameinfo->crop = streaminfo->crop;
+       }
+       if (streaminfo->flags & DELTA_STREAMINFO_FLAG_PIXELASPECT) {
+               frameinfo->flags |= DELTA_FRAMEINFO_FLAG_PIXELASPECT;
+               frameinfo->pixelaspect = streaminfo->pixelaspect;
+       }
+       frameinfo->field = streaminfo->field;
+
+       return 0;
+}
+
+/*
+ * default implementation of recycle decoder ops
+ * consisting to relax the "decoded" frame state
+ */
+int delta_recycle_default(struct delta_ctx *pctx,
+                         struct delta_frame *frame)
+{
+       frame->state &= ~DELTA_FRAME_DEC;
+
+       return 0;
+}
+
+static void dump_frames_status(struct delta_ctx *ctx)
+{
+       struct delta_dev *delta = ctx->dev;
+       unsigned int i;
+       struct delta_frame *frame;
+       unsigned char str[100] = "";
+
+       dev_info(delta->dev,
+                "%s dumping frames status...\n", ctx->name);
+
+       for (i = 0; i < ctx->nb_of_frames; i++) {
+               frame = ctx->frames[i];
+               dev_info(delta->dev,
+                        "%s frame[%d] %s\n",
+                        ctx->name, frame->index,
+                        frame_state_str(frame->state,
+                                        str, sizeof(str)));
+       }
+}
+
+int delta_get_free_frame(struct delta_ctx *ctx,
+                        struct delta_frame **pframe)
+{
+       struct delta_dev *delta = ctx->dev;
+       struct vb2_v4l2_buffer *vbuf;
+       struct delta_frame *frame;
+
+       *pframe = NULL;
+
+       vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+       if (!vbuf) {
+               dev_err(delta->dev, "%s no frame available",
+                       ctx->name);
+               return -EIO;
+       }
+
+       frame = to_frame(vbuf);
+       frame->state &= ~DELTA_FRAME_M2M;
+       if (frame->state != DELTA_FRAME_FREE) {
+               dev_err(delta->dev,
+                       "%s frame[%d] is not free\n",
+                       ctx->name, frame->index);
+               dump_frames_status(ctx);
+               return -ENODATA;
+       }
+
+       dev_dbg(delta->dev,
+               "%s get free frame[%d]\n", ctx->name, frame->index);
+
+       *pframe = frame;
+       return 0;
+}
+
+int delta_get_sync(struct delta_ctx *ctx)
+{
+       struct delta_dev *delta = ctx->dev;
+       int ret = 0;
+
+       /* enable the hardware */
+       ret = pm_runtime_get_sync(delta->dev);
+       if (ret < 0) {
+               dev_err(delta->dev, "%s pm_runtime_get_sync failed (%d)\n",
+                       __func__, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+void delta_put_autosuspend(struct delta_ctx *ctx)
+{
+       struct delta_dev *delta = ctx->dev;
+
+       pm_runtime_put_autosuspend(delta->dev);
+}
+
+static void delta_vb2_au_queue(struct vb2_buffer *vb)
+{
+       struct vb2_queue *q = vb->vb2_queue;
+       struct delta_ctx *ctx = vb2_get_drv_priv(q);
+       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+       v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
+}
+
+static int delta_vb2_au_start_streaming(struct vb2_queue *q,
+                                       unsigned int count)
+{
+       struct delta_ctx *ctx = vb2_get_drv_priv(q);
+       struct delta_dev *delta = ctx->dev;
+       const struct delta_dec *dec = ctx->dec;
+       struct delta_au *au;
+       int ret = 0;
+       struct vb2_v4l2_buffer *vbuf = NULL;
+       struct delta_streaminfo *streaminfo = &ctx->streaminfo;
+       struct delta_frameinfo *frameinfo = &ctx->frameinfo;
+       unsigned char str1[100] = "";
+       unsigned char str2[100] = "";
+
+       if ((ctx->state != DELTA_STATE_WF_FORMAT) &&
+           (ctx->state != DELTA_STATE_WF_STREAMINFO))
+               return 0;
+
+       if (ctx->state == DELTA_STATE_WF_FORMAT) {
+               /* open decoder if not yet done */
+               ret = delta_open_decoder(ctx,
+                                        ctx->streaminfo.streamformat,
+                                        ctx->frameinfo.pixelformat, &dec);
+               if (ret)
+                       goto err;
+               ctx->dec = dec;
+               ctx->state = DELTA_STATE_WF_STREAMINFO;
+       }
+
+       /*
+        * first buffer should contain stream header,
+        * decode it to get the infos related to stream
+        * such as width, height, dpb, ...
+        */
+       vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+       if (!vbuf) {
+               dev_err(delta->dev, "%s failed to start streaming, no stream header buffer enqueued\n",
+                       ctx->name);
+               ret = -EINVAL;
+               goto err;
+       }
+       au = to_au(vbuf);
+       au->size = vb2_get_plane_payload(&vbuf->vb2_buf, 0);
+       au->dts = vbuf->vb2_buf.timestamp;
+
+       delta_push_dts(ctx, au->dts);
+
+       /* dump access unit */
+       dump_au(ctx, au);
+
+       /* decode this access unit */
+       ret = call_dec_op(dec, decode, ctx, au);
+       if (ret) {
+               dev_err(delta->dev, "%s failed to start streaming, header decoding failed (%d)\n",
+                       ctx->name, ret);
+               goto err;
+       }
+
+       ret = call_dec_op(dec, get_streaminfo, ctx, streaminfo);
+       if (ret) {
+               dev_dbg_ratelimited(delta->dev,
+                                   "%s failed to start streaming, valid stream header not yet decoded\n",
+                                   ctx->name);
+               goto err;
+       }
+       ctx->flags |= DELTA_FLAG_STREAMINFO;
+
+       ret = call_dec_op(dec, get_frameinfo, ctx, frameinfo);
+       if (ret)
+               goto err;
+       ctx->flags |= DELTA_FLAG_FRAMEINFO;
+
+       ctx->state = DELTA_STATE_READY;
+
+       dev_dbg(delta->dev, "%s %s => %s\n", ctx->name,
+               delta_streaminfo_str(streaminfo, str1, sizeof(str1)),
+               delta_frameinfo_str(frameinfo, str2, sizeof(str2)));
+
+       delta_au_done(ctx, au, ret);
+       return 0;
+
+err:
+       /*
+        * return all buffers to vb2 in QUEUED state.
+        * This will give ownership back to userspace
+        */
+       if (vbuf)
+               v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_QUEUED);
+
+       while ((vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx)))
+               v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_QUEUED);
+       return ret;
+}
+
+static void delta_vb2_au_stop_streaming(struct vb2_queue *q)
+{
+       struct delta_ctx *ctx = vb2_get_drv_priv(q);
+       struct vb2_v4l2_buffer *vbuf;
+
+       delta_flush_dts(ctx);
+
+       /* return all buffers to vb2 in ERROR state */
+       while ((vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx)))
+               v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
+
+       ctx->au_num = 0;
+
+       ctx->aborting = false;
+}
+
+static int delta_vb2_frame_queue_setup(struct vb2_queue *vq,
+                                      unsigned int *num_buffers,
+                                      unsigned int *num_planes,
+                                      unsigned int sizes[],
+                                      struct device *alloc_devs[])
+{
+       struct delta_ctx *ctx = vb2_get_drv_priv(vq);
+       struct delta_dev *delta = ctx->dev;
+       struct delta_streaminfo *streaminfo = &ctx->streaminfo;
+       struct delta_frameinfo *frameinfo = &ctx->frameinfo;
+       unsigned int size = frameinfo->size;
+
+       /*
+        * the number of output buffers needed for decoding =
+        * user need (*num_buffers given, usually for display pipeline) +
+        * stream need (streaminfo->dpb) +
+        * decoding peak smoothing (depends on DELTA IP perf)
+        */
+       if (*num_buffers < DELTA_MIN_FRAME_USER) {
+               dev_dbg(delta->dev,
+                       "%s num_buffers too low (%d), increasing to %d\n",
+                       ctx->name, *num_buffers, DELTA_MIN_FRAME_USER);
+               *num_buffers = DELTA_MIN_FRAME_USER;
+       }
+
+       *num_buffers += streaminfo->dpb + DELTA_PEAK_FRAME_SMOOTHING;
+
+       if (*num_buffers > DELTA_MAX_FRAMES) {
+               dev_dbg(delta->dev,
+                       "%s output frame count too high (%d), cut to %d\n",
+                       ctx->name, *num_buffers, DELTA_MAX_FRAMES);
+               *num_buffers = DELTA_MAX_FRAMES;
+       }
+
+       if (*num_planes)
+               return sizes[0] < size ? -EINVAL : 0;
+
+       /* single plane for Y and CbCr */
+       *num_planes = 1;
+
+       sizes[0] = size;
+
+       ctx->nb_of_frames = 0;
+
+       return 0;
+}
+
+static int delta_vb2_frame_prepare(struct vb2_buffer *vb)
+{
+       struct vb2_queue *q = vb->vb2_queue;
+       struct delta_ctx *ctx = vb2_get_drv_priv(q);
+       struct delta_dev *delta = ctx->dev;
+       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+       struct delta_frame *frame = to_frame(vbuf);
+       int ret = 0;
+
+       if (!frame->prepared) {
+               frame->index = vbuf->vb2_buf.index;
+               frame->vaddr = vb2_plane_vaddr(&vbuf->vb2_buf, 0);
+               frame->paddr = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0);
+               frame->info = ctx->frameinfo;
+
+               ret = delta_setup_frame(ctx, frame);
+               if (ret) {
+                       dev_err(delta->dev,
+                               "%s setup_frame() failed (%d)\n",
+                               ctx->name, ret);
+                       return ret;
+               }
+               frame->prepared = true;
+               dev_dbg(delta->dev,
+                       "%s frame[%d] prepared; virt=0x%p, phy=0x%pad\n",
+                       ctx->name, vb->index, frame->vaddr,
+                       &frame->paddr);
+       }
+
+       frame->flags = vbuf->flags;
+
+       return 0;
+}
+
+static void delta_vb2_frame_finish(struct vb2_buffer *vb)
+{
+       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+       struct delta_frame *frame = to_frame(vbuf);
+
+       /* update V4L2 fields for user */
+       vb2_set_plane_payload(&vbuf->vb2_buf, 0, frame->info.size);
+       vb->timestamp = frame->dts;
+       vbuf->field = frame->field;
+       vbuf->flags = frame->flags;
+}
+
+static void delta_vb2_frame_queue(struct vb2_buffer *vb)
+{
+       struct vb2_queue *q = vb->vb2_queue;
+       struct delta_ctx *ctx = vb2_get_drv_priv(q);
+       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+       struct delta_frame *frame = to_frame(vbuf);
+
+       if (ctx->state == DELTA_STATE_WF_EOS) {
+               /* new frame available, EOS can now be completed */
+               delta_complete_eos(ctx, frame);
+
+               ctx->state = DELTA_STATE_EOS;
+
+               /* return, no need to recycle this buffer to decoder */
+               return;
+       }
+
+       /* recycle this frame */
+       delta_recycle(ctx, frame);
+}
+
+static void delta_vb2_frame_stop_streaming(struct vb2_queue *q)
+{
+       struct delta_ctx *ctx = vb2_get_drv_priv(q);
+       struct vb2_v4l2_buffer *vbuf;
+       struct delta_frame *frame;
+       const struct delta_dec *dec = ctx->dec;
+       unsigned int i;
+
+       delta_flush_dts(ctx);
+
+       call_dec_op(dec, flush, ctx);
+
+       /*
+        * return all buffers to vb2 in ERROR state
+        * & reset each frame state to OUT
+        */
+       for (i = 0; i < ctx->nb_of_frames; i++) {
+               frame = ctx->frames[i];
+               if (!(frame->state & DELTA_FRAME_OUT)) {
+                       vbuf = &frame->vbuf;
+                       v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
+               }
+               frame->state = DELTA_FRAME_OUT;
+       }
+
+       ctx->frame_num = 0;
+
+       ctx->aborting = false;
+}
+
+/* VB2 queue ops */
+static struct vb2_ops delta_vb2_au_ops = {
+       .queue_setup = delta_vb2_au_queue_setup,
+       .buf_prepare = delta_vb2_au_prepare,
+       .buf_queue = delta_vb2_au_queue,
+       .wait_prepare = vb2_ops_wait_prepare,
+       .wait_finish = vb2_ops_wait_finish,
+       .start_streaming = delta_vb2_au_start_streaming,
+       .stop_streaming = delta_vb2_au_stop_streaming,
+};
+
+static struct vb2_ops delta_vb2_frame_ops = {
+       .queue_setup = delta_vb2_frame_queue_setup,
+       .buf_prepare = delta_vb2_frame_prepare,
+       .buf_finish = delta_vb2_frame_finish,
+       .buf_queue = delta_vb2_frame_queue,
+       .wait_prepare = vb2_ops_wait_prepare,
+       .wait_finish = vb2_ops_wait_finish,
+       .stop_streaming = delta_vb2_frame_stop_streaming,
+};
+
+/*
+ * V4L2 file operations
+ */
+
+static int queue_init(void *priv,
+                     struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
+{
+       struct vb2_queue *q;
+       struct delta_ctx *ctx = priv;
+       struct delta_dev *delta = ctx->dev;
+       int ret;
+
+       /* setup vb2 queue for stream input */
+       q = src_vq;
+       q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+       q->io_modes = VB2_MMAP | VB2_DMABUF;
+       q->drv_priv = ctx;
+       /* overload vb2 buf with private au struct */
+       q->buf_struct_size = sizeof(struct delta_au);
+       q->ops = &delta_vb2_au_ops;
+       q->mem_ops = &vb2_dma_contig_memops;
+       q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+       q->lock = &delta->lock;
+       q->dev = delta->dev;
+
+       ret = vb2_queue_init(q);
+       if (ret)
+               return ret;
+
+       /* setup vb2 queue for frame output */
+       q = dst_vq;
+       q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       q->io_modes = VB2_MMAP | VB2_DMABUF;
+       q->drv_priv = ctx;
+       /* overload vb2 buf with private frame struct */
+       q->buf_struct_size = sizeof(struct delta_frame)
+                            + DELTA_MAX_FRAME_PRIV_SIZE;
+       q->ops = &delta_vb2_frame_ops;
+       q->mem_ops = &vb2_dma_contig_memops;
+       q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+       q->lock = &delta->lock;
+       q->dev = delta->dev;
+
+       return vb2_queue_init(q);
+}
+
+static int delta_open(struct file *file)
+{
+       struct delta_dev *delta = video_drvdata(file);
+       struct delta_ctx *ctx = NULL;
+       int ret = 0;
+
+       mutex_lock(&delta->lock);
+
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       if (!ctx) {
+               ret = -ENOMEM;
+               goto err;
+       }
+       ctx->dev = delta;
+
+       v4l2_fh_init(&ctx->fh, video_devdata(file));
+       file->private_data = &ctx->fh;
+       v4l2_fh_add(&ctx->fh);
+
+       INIT_WORK(&ctx->run_work, delta_run_work);
+       mutex_init(&ctx->lock);
+
+       ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(delta->m2m_dev, ctx,
+                                           queue_init);
+       if (IS_ERR(ctx->fh.m2m_ctx)) {
+               ret = PTR_ERR(ctx->fh.m2m_ctx);
+               dev_err(delta->dev, "%s failed to initialize m2m context (%d)\n",
+                       DELTA_PREFIX, ret);
+               goto err_fh_del;
+       }
+
+       /*
+        * wait stream format to determine which
+        * decoder to open
+        */
+       ctx->state = DELTA_STATE_WF_FORMAT;
+
+       INIT_LIST_HEAD(&ctx->dts);
+
+       /* set the instance name */
+       delta->instance_id++;
+       snprintf(ctx->name, sizeof(ctx->name), "[%3d:----]",
+                delta->instance_id);
+
+       /* default parameters for frame and stream */
+       set_default_params(ctx);
+
+       /* enable ST231 clocks */
+       if (delta->clk_st231)
+               if (clk_prepare_enable(delta->clk_st231))
+                       dev_warn(delta->dev, "failed to enable st231 clk\n");
+
+       /* enable FLASH_PROMIP clock */
+       if (delta->clk_flash_promip)
+               if (clk_prepare_enable(delta->clk_flash_promip))
+                       dev_warn(delta->dev, "failed to enable delta promip clk\n");
+
+       mutex_unlock(&delta->lock);
+
+       dev_dbg(delta->dev, "%s decoder instance created\n", ctx->name);
+
+       return 0;
+
+err_fh_del:
+       v4l2_fh_del(&ctx->fh);
+       v4l2_fh_exit(&ctx->fh);
+       kfree(ctx);
+err:
+       mutex_unlock(&delta->lock);
+
+       return ret;
+}
+
+static int delta_release(struct file *file)
+{
+       struct delta_ctx *ctx = to_ctx(file->private_data);
+       struct delta_dev *delta = ctx->dev;
+       const struct delta_dec *dec = ctx->dec;
+
+       mutex_lock(&delta->lock);
+
+       /* close decoder */
+       call_dec_op(dec, close, ctx);
+
+       /*
+        * trace a summary of instance
+        * before closing (debug purpose)
+        */
+       delta_trace_summary(ctx);
+
+       v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+
+       v4l2_fh_del(&ctx->fh);
+       v4l2_fh_exit(&ctx->fh);
+
+       /* disable ST231 clocks */
+       if (delta->clk_st231)
+               clk_disable_unprepare(delta->clk_st231);
+
+       /* disable FLASH_PROMIP clock */
+       if (delta->clk_flash_promip)
+               clk_disable_unprepare(delta->clk_flash_promip);
+
+       dev_dbg(delta->dev, "%s decoder instance released\n", ctx->name);
+
+       kfree(ctx);
+
+       mutex_unlock(&delta->lock);
+       return 0;
+}
+
+/* V4L2 file ops */
+static const struct v4l2_file_operations delta_fops = {
+       .owner = THIS_MODULE,
+       .open = delta_open,
+       .release = delta_release,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap = v4l2_m2m_fop_mmap,
+       .poll = v4l2_m2m_fop_poll,
+};
+
+/*
+ * Platform device operations
+ */
+
+static int delta_register_device(struct delta_dev *delta)
+{
+       int ret;
+       struct video_device *vdev;
+
+       if (!delta)
+               return -ENODEV;
+
+       delta->m2m_dev = v4l2_m2m_init(&delta_m2m_ops);
+       if (IS_ERR(delta->m2m_dev)) {
+               dev_err(delta->dev, "%s failed to initialize v4l2-m2m device\n",
+                       DELTA_PREFIX);
+               ret = PTR_ERR(delta->m2m_dev);
+               goto err;
+       }
+
+       vdev = video_device_alloc();
+       if (!vdev) {
+               dev_err(delta->dev, "%s failed to allocate video device\n",
+                       DELTA_PREFIX);
+               ret = -ENOMEM;
+               goto err_m2m_release;
+       }
+
+       vdev->fops = &delta_fops;
+       vdev->ioctl_ops = &delta_ioctl_ops;
+       vdev->release = video_device_release;
+       vdev->lock = &delta->lock;
+       vdev->vfl_dir = VFL_DIR_M2M;
+       vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M;
+       vdev->v4l2_dev = &delta->v4l2_dev;
+       snprintf(vdev->name, sizeof(vdev->name), "%s-%s",
+                DELTA_NAME, DELTA_FW_VERSION);
+
+       ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       if (ret) {
+               dev_err(delta->dev, "%s failed to register video device\n",
+                       DELTA_PREFIX);
+               goto err_vdev_release;
+       }
+
+       delta->vdev = vdev;
+       video_set_drvdata(vdev, delta);
+       return 0;
+
+err_vdev_release:
+       video_device_release(vdev);
+err_m2m_release:
+       v4l2_m2m_release(delta->m2m_dev);
+err:
+       return ret;
+}
+
+static void delta_unregister_device(struct delta_dev *delta)
+{
+       if (!delta)
+               return;
+
+       if (delta->m2m_dev)
+               v4l2_m2m_release(delta->m2m_dev);
+
+       video_unregister_device(delta->vdev);
+}
+
+static int delta_probe(struct platform_device *pdev)
+{
+       struct delta_dev *delta;
+       struct device *dev = &pdev->dev;
+       int ret;
+
+       delta = devm_kzalloc(dev, sizeof(*delta), GFP_KERNEL);
+       if (!delta) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       delta->dev = dev;
+       delta->pdev = pdev;
+       platform_set_drvdata(pdev, delta);
+
+       mutex_init(&delta->lock);
+
+       /* get clock resources */
+       delta->clk_delta = devm_clk_get(dev, "delta");
+       if (IS_ERR(delta->clk_delta)) {
+               dev_dbg(dev, "%s can't get delta clock\n", DELTA_PREFIX);
+               delta->clk_delta = NULL;
+       }
+
+       delta->clk_st231 = devm_clk_get(dev, "delta-st231");
+       if (IS_ERR(delta->clk_st231)) {
+               dev_dbg(dev, "%s can't get delta-st231 clock\n", DELTA_PREFIX);
+               delta->clk_st231 = NULL;
+       }
+
+       delta->clk_flash_promip = devm_clk_get(dev, "delta-flash-promip");
+       if (IS_ERR(delta->clk_flash_promip)) {
+               dev_dbg(dev, "%s can't get delta-flash-promip clock\n",
+                       DELTA_PREFIX);
+               delta->clk_flash_promip = NULL;
+       }
+
+       /* init pm_runtime used for power management */
+       pm_runtime_set_autosuspend_delay(dev, DELTA_HW_AUTOSUSPEND_DELAY_MS);
+       pm_runtime_use_autosuspend(dev);
+       pm_runtime_set_suspended(dev);
+       pm_runtime_enable(dev);
+
+       /* init firmware ipc channel */
+       ret = delta_ipc_init(delta);
+       if (ret) {
+               dev_err(delta->dev, "%s failed to initialize firmware ipc channel\n",
+                       DELTA_PREFIX);
+               goto err;
+       }
+
+       /* register all available decoders */
+       register_decoders(delta);
+
+       /* register all supported formats */
+       register_formats(delta);
+
+       /* register on V4L2 */
+       ret = v4l2_device_register(dev, &delta->v4l2_dev);
+       if (ret) {
+               dev_err(delta->dev, "%s failed to register V4L2 device\n",
+                       DELTA_PREFIX);
+               goto err;
+       }
+
+       delta->work_queue = create_workqueue(DELTA_NAME);
+       if (!delta->work_queue) {
+               dev_err(delta->dev, "%s failed to allocate work queue\n",
+                       DELTA_PREFIX);
+               ret = -ENOMEM;
+               goto err_v4l2;
+       }
+
+       /* register device */
+       ret = delta_register_device(delta);
+       if (ret)
+               goto err_work_queue;
+
+       dev_info(dev, "%s %s registered as /dev/video%d\n",
+                DELTA_PREFIX, delta->vdev->name, delta->vdev->num);
+
+       return 0;
+
+err_work_queue:
+       destroy_workqueue(delta->work_queue);
+err_v4l2:
+       v4l2_device_unregister(&delta->v4l2_dev);
+err:
+       return ret;
+}
+
+static int delta_remove(struct platform_device *pdev)
+{
+       struct delta_dev *delta = platform_get_drvdata(pdev);
+
+       delta_ipc_exit(delta);
+
+       delta_unregister_device(delta);
+
+       destroy_workqueue(delta->work_queue);
+
+       pm_runtime_put_autosuspend(delta->dev);
+       pm_runtime_disable(delta->dev);
+
+       v4l2_device_unregister(&delta->v4l2_dev);
+
+       return 0;
+}
+
+static int delta_runtime_suspend(struct device *dev)
+{
+       struct delta_dev *delta = dev_get_drvdata(dev);
+
+       if (delta->clk_delta)
+               clk_disable_unprepare(delta->clk_delta);
+
+       return 0;
+}
+
+static int delta_runtime_resume(struct device *dev)
+{
+       struct delta_dev *delta = dev_get_drvdata(dev);
+
+       if (delta->clk_delta)
+               if (clk_prepare_enable(delta->clk_delta))
+                       dev_warn(dev, "failed to prepare/enable delta clk\n");
+
+       return 0;
+}
+
+/* PM ops */
+static const struct dev_pm_ops delta_pm_ops = {
+       .runtime_suspend = delta_runtime_suspend,
+       .runtime_resume = delta_runtime_resume,
+};
+
+static const struct of_device_id delta_match_types[] = {
+       {
+        .compatible = "st,st-delta",
+       },
+       {
+        /* end node */
+       }
+};
+
+MODULE_DEVICE_TABLE(of, delta_match_types);
+
+static struct platform_driver delta_driver = {
+       .probe = delta_probe,
+       .remove = delta_remove,
+       .driver = {
+                  .name = DELTA_NAME,
+                  .of_match_table = delta_match_types,
+                  .pm = &delta_pm_ops},
+};
+
+module_platform_driver(delta_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Hugues Fruchet <hugues.fruchet@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics DELTA video decoder V4L2 driver");
diff --git a/drivers/media/platform/sti/delta/delta.h b/drivers/media/platform/sti/delta/delta.h
new file mode 100644 (file)
index 0000000..60c0732
--- /dev/null
@@ -0,0 +1,566 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2015
+ * Author: Hugues Fruchet <hugues.fruchet@st.com> for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef DELTA_H
+#define DELTA_H
+
+#include <linux/rpmsg.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "delta-cfg.h"
+
+/*
+ * enum delta_state - state of decoding instance
+ *
+ *@DELTA_STATE_WF_FORMAT:
+ *     Wait for compressed format to be set by V4L2 client in order
+ *     to know what is the relevant decoder to open.
+ *
+ *@DELTA_STATE_WF_STREAMINFO:
+ *     Wait for stream information to be available (bitstream
+ *     header parsing is done).
+ *
+ *@DELTA_STATE_READY:
+ *     Decoding instance is ready to decode compressed access unit.
+ *
+ *@DELTA_STATE_WF_EOS:
+ *     Decoding instance is waiting for EOS (End Of Stream) completion.
+ *
+ *@DELTA_STATE_EOS:
+ *     EOS (End Of Stream) is completed (signaled to user). Decoding instance
+ *     should then be closed.
+ */
+enum delta_state {
+       DELTA_STATE_WF_FORMAT,
+       DELTA_STATE_WF_STREAMINFO,
+       DELTA_STATE_READY,
+       DELTA_STATE_WF_EOS,
+       DELTA_STATE_EOS
+};
+
+/*
+ * struct delta_streaminfo - information about stream to decode
+ *
+ * @flags:             validity of fields (crop, pixelaspect, other)
+ * @width:             width of video stream
+ * @height:            height ""
+ * @streamformat:      fourcc compressed format of video (MJPEG, MPEG2, ...)
+ * @dpb:               number of frames needed to decode a single frame
+ *                     (h264 dpb, up to 16)
+ * @crop:              cropping window inside decoded frame (1920x1080@0,0
+ *                     inside 1920x1088 frame for ex.)
+ * @pixelaspect:       pixel aspect ratio of video (4/3, 5/4)
+ * @field:             interlaced or not
+ * @profile:           profile string
+ * @level:             level string
+ * @other:             other string information from codec
+ * @colorspace:                colorspace identifier
+ * @xfer_func:         transfer function identifier
+ * @ycbcr_enc:         Y'CbCr encoding identifier
+ * @quantization:      quantization identifier
+ */
+struct delta_streaminfo {
+       u32 flags;
+       u32 streamformat;
+       u32 width;
+       u32 height;
+       u32 dpb;
+       struct v4l2_rect crop;
+       struct v4l2_fract pixelaspect;
+       enum v4l2_field field;
+       u8 profile[32];
+       u8 level[32];
+       u8 other[32];
+       enum v4l2_colorspace colorspace;
+       enum v4l2_xfer_func xfer_func;
+       enum v4l2_ycbcr_encoding ycbcr_enc;
+       enum v4l2_quantization quantization;
+};
+
+#define DELTA_STREAMINFO_FLAG_CROP             0x0001
+#define DELTA_STREAMINFO_FLAG_PIXELASPECT      0x0002
+#define DELTA_STREAMINFO_FLAG_OTHER            0x0004
+
+/*
+ * struct delta_au - access unit structure.
+ *
+ * @vbuf:      video buffer information for V4L2
+ * @list:      V4L2 m2m list that the frame belongs to
+ * @prepared:  if set vaddr/paddr are resolved
+ * @vaddr:     virtual address (kernel can read/write)
+ * @paddr:     physical address (for hardware)
+ * @flags:     access unit type (V4L2_BUF_FLAG_KEYFRAME/PFRAME/BFRAME)
+ * @dts:       decoding timestamp of this access unit
+ */
+struct delta_au {
+       struct vb2_v4l2_buffer vbuf;    /* keep first */
+       struct list_head list;  /* keep second */
+
+       bool prepared;
+       u32 size;
+       void *vaddr;
+       dma_addr_t paddr;
+       u32 flags;
+       u64 dts;
+};
+
+/*
+ * struct delta_frameinfo - information about decoded frame
+ *
+ * @flags:             validity of fields (crop, pixelaspect)
+ * @pixelformat:       fourcc code for uncompressed video format
+ * @width:             width of frame
+ * @height:            height of frame
+ * @aligned_width:     width of frame (with encoder or decoder alignment
+ *                     constraint)
+ * @aligned_height:    height of frame (with encoder or decoder alignment
+ *                     constraint)
+ * @size:              maximum size in bytes required for data
+ * @crop:              cropping window inside frame (1920x1080@0,0
+ *                     inside 1920x1088 frame for ex.)
+ * @pixelaspect:       pixel aspect ratio of video (4/3, 5/4)
+ * @field:             interlaced mode
+ * @colorspace:                colorspace identifier
+ * @xfer_func:         transfer function identifier
+ * @ycbcr_enc:         Y'CbCr encoding identifier
+ * @quantization:      quantization identifier
+ */
+struct delta_frameinfo {
+       u32 flags;
+       u32 pixelformat;
+       u32 width;
+       u32 height;
+       u32 aligned_width;
+       u32 aligned_height;
+       u32 size;
+       struct v4l2_rect crop;
+       struct v4l2_fract pixelaspect;
+       enum v4l2_field field;
+       enum v4l2_colorspace colorspace;
+       enum v4l2_xfer_func xfer_func;
+       enum v4l2_ycbcr_encoding ycbcr_enc;
+       enum v4l2_quantization quantization;
+};
+
+#define DELTA_FRAMEINFO_FLAG_CROP              0x0001
+#define DELTA_FRAMEINFO_FLAG_PIXELASPECT       0x0002
+
+/*
+ * struct delta_frame - frame structure.
+ *
+ * @vbuf:      video buffer information for V4L2
+ * @list:      V4L2 m2m list that the frame belongs to
+ * @info:      frame information (width, height, format, alignment...)
+ * @prepared:  if set pix/vaddr/paddr are resolved
+ * @index:     frame index, aligned on V4L2 wow
+ * @vaddr:     virtual address (kernel can read/write)
+ * @paddr:     physical address (for hardware)
+ * @state:     frame state for frame lifecycle tracking
+ *             (DELTA_FRAME_FREE/DEC/OUT/REC/...)
+ * @flags:     frame type (V4L2_BUF_FLAG_KEYFRAME/PFRAME/BFRAME)
+ * @dts:       decoding timestamp of this frame
+ * @field:     field order for interlaced frame
+ */
+struct delta_frame {
+       struct vb2_v4l2_buffer vbuf;    /* keep first */
+       struct list_head list;  /* keep second */
+
+       struct delta_frameinfo info;
+       bool prepared;
+       u32 index;
+       void *vaddr;
+       dma_addr_t paddr;
+       u32 state;
+       u32 flags;
+       u64 dts;
+       enum v4l2_field field;
+};
+
+/* frame state for frame lifecycle tracking */
+#define DELTA_FRAME_FREE       0x00 /* is free and can be used for decoding */
+#define DELTA_FRAME_REF                0x01 /* is a reference frame */
+#define DELTA_FRAME_BSY                0x02 /* is owned by decoder and busy */
+#define DELTA_FRAME_DEC                0x04 /* contains decoded content */
+#define DELTA_FRAME_OUT                0x08 /* has been given to user */
+#define DELTA_FRAME_RDY                0x10 /* is ready but still held by decoder */
+#define DELTA_FRAME_M2M                0x20 /* is owned by mem2mem framework */
+
+/*
+ * struct delta_dts - decoding timestamp.
+ *
+ * @list:      list to chain timestamps
+ * @val:       timestamp in microseconds
+ */
+struct delta_dts {
+       struct list_head list;
+       u64 val;
+};
+
+struct delta_buf {
+       u32 size;
+       void *vaddr;
+       dma_addr_t paddr;
+       const char *name;
+       unsigned long attrs;
+};
+
+struct delta_ipc_ctx {
+       int cb_err;
+       u32 copro_hdl;
+       struct completion done;
+       struct delta_buf ipc_buf_struct;
+       struct delta_buf *ipc_buf;
+};
+
+struct delta_ipc_param {
+       u32 size;
+       void *data;
+};
+
+struct delta_ctx;
+
+/*
+ * struct delta_dec - decoder structure.
+ *
+ * @name:              name of this decoder
+ * @streamformat:      input stream format that this decoder support
+ * @pixelformat:       pixel format of decoded frame that this decoder support
+ * @max_width:         (optional) maximum width that can decode this decoder
+ *                     if not set, maximum width is DELTA_MAX_WIDTH
+ * @max_height:                (optional) maximum height that can decode this decoder
+ *                     if not set, maximum height is DELTA_MAX_HEIGHT
+ * @pm:                        (optional) if set, decoder will manage power on its own
+ * @open:              open this decoder
+ * @close:             close this decoder
+ * @setup_frame:       setup frame to be used by decoder, see below
+ * @get_streaminfo:    get stream related infos, see below
+ * @get_frameinfo:     get decoded frame related infos, see below
+ * @set_frameinfo:     (optional) set decoded frame related infos, see below
+ * @setup_frame:       setup frame to be used by decoder, see below
+ * @decode:            decode a single access unit, see below
+ * @get_frame:         get the next decoded frame available, see below
+ * @recycle:           recycle the given frame, see below
+ * @flush:             (optional) flush decoder, see below
+ * @drain:             (optional) drain decoder, see below
+ */
+struct delta_dec {
+       const char *name;
+       u32 streamformat;
+       u32 pixelformat;
+       u32 max_width;
+       u32 max_height;
+       bool pm;
+
+       /*
+        * decoder ops
+        */
+       int (*open)(struct delta_ctx *ctx);
+       int (*close)(struct delta_ctx *ctx);
+
+       /*
+        * setup_frame() - setup frame to be used by decoder
+        * @ctx:        (in) instance
+        * @frame:      (in) frame to use
+        *  @frame.index        (in) identifier of frame
+        *  @frame.vaddr        (in) virtual address (kernel can read/write)
+        *  @frame.paddr        (in) physical address (for hardware)
+        *
+        * Frame is to be allocated by caller, then given
+        * to decoder through this call.
+        * Several frames must be given to decoder (dpb),
+        * each frame is identified using its index.
+        */
+       int (*setup_frame)(struct delta_ctx *ctx, struct delta_frame *frame);
+
+       /*
+        * get_streaminfo() - get stream related infos
+        * @ctx:        (in) instance
+        * @streaminfo: (out) width, height, dpb,...
+        *
+        * Precondition: stream header must have been successfully
+        * parsed to have this call successful & @streaminfo valid.
+        * Header parsing must be done using decode(), giving
+        * explicitly header access unit or first access unit of bitstream.
+        * If no valid header is found, get_streaminfo will return -ENODATA,
+        * in this case the next bistream access unit must be decoded till
+        * get_streaminfo becomes successful.
+        */
+       int (*get_streaminfo)(struct delta_ctx *ctx,
+                             struct delta_streaminfo *streaminfo);
+
+       /*
+        * get_frameinfo() - get decoded frame related infos
+        * @ctx:        (in) instance
+        * @frameinfo:  (out) width, height, alignment, crop, ...
+        *
+        * Precondition: get_streaminfo() must be successful
+        */
+       int (*get_frameinfo)(struct delta_ctx *ctx,
+                            struct delta_frameinfo *frameinfo);
+
+       /*
+        * set_frameinfo() - set decoded frame related infos
+        * @ctx:        (in) instance
+        * @frameinfo:  (out) width, height, alignment, crop, ...
+        *
+        * Optional.
+        * Typically used to negotiate with decoder the output
+        * frame if decoder can do post-processing.
+        */
+       int (*set_frameinfo)(struct delta_ctx *ctx,
+                            struct delta_frameinfo *frameinfo);
+
+       /*
+        * decode() - decode a single access unit
+        * @ctx:        (in) instance
+        * @au:         (in/out) access unit
+        *  @au.size    (in) size of au to decode
+        *  @au.vaddr   (in) virtual address (kernel can read/write)
+        *  @au.paddr   (in) physical address (for hardware)
+        *  @au.flags   (out) au type (V4L2_BUF_FLAG_KEYFRAME/
+        *                      PFRAME/BFRAME)
+        *
+        * Decode the access unit given. Decode is synchronous;
+        * access unit memory is no more needed after this call.
+        * After this call, none, one or several frames could
+        * have been decoded, which can be retrieved using
+        * get_frame().
+        */
+       int (*decode)(struct delta_ctx *ctx, struct delta_au *au);
+
+       /*
+        * get_frame() - get the next decoded frame available
+        * @ctx:        (in) instance
+        * @frame:      (out) frame with decoded data:
+        *  @frame.index        (out) identifier of frame
+        *  @frame.field        (out) field order for interlaced frame
+        *  @frame.state        (out) frame state for frame lifecycle tracking
+        *  @frame.flags        (out) frame type (V4L2_BUF_FLAG_KEYFRAME/
+        *                      PFRAME/BFRAME)
+        *
+        * Get the next available decoded frame.
+        * If no frame is available, -ENODATA is returned.
+        * If a frame is available, frame structure is filled with
+        * relevant data, frame.index identifying this exact frame.
+        * When this frame is no more needed by upper layers,
+        * recycle() must be called giving this frame identifier.
+        */
+       int (*get_frame)(struct delta_ctx *ctx, struct delta_frame **frame);
+
+       /*
+        * recycle() - recycle the given frame
+        * @ctx:        (in) instance
+        * @frame:      (in) frame to recycle:
+        *  @frame.index        (in) identifier of frame
+        *
+        * recycle() is to be called by user when the decoded frame
+        * is no more needed (composition/display done).
+        * This frame will then be reused by decoder to proceed
+        * with next frame decoding.
+        * If not enough frames have been provided through setup_frame(),
+        * or recycle() is not called fast enough, the decoder can run out
+        * of available frames to proceed with decoding (starvation).
+        * This case is guarded by wq_recycle wait queue which ensures that
+        * decoder is called only if at least one frame is available.
+        */
+       int (*recycle)(struct delta_ctx *ctx, struct delta_frame *frame);
+
+       /*
+        * flush() - flush decoder
+        * @ctx:        (in) instance
+        *
+        * Optional.
+        * Reset decoder context and discard all internal buffers.
+        * This allows implementation of seek, which leads to discontinuity
+        * of input bitstream that decoder must know to restart its internal
+        * decoding logic.
+        */
+       int (*flush)(struct delta_ctx *ctx);
+
+       /*
+        * drain() - drain decoder
+        * @ctx:        (in) instance
+        *
+        * Optional.
+        * Mark decoder pending frames (decoded but not yet output) as ready
+        * so that they can be output to client at EOS (End Of Stream).
+        * get_frame() is to be called in a loop right after drain() to
+        * get all those pending frames.
+        */
+       int (*drain)(struct delta_ctx *ctx);
+};
+
+struct delta_dev;
+
+/*
+ * struct delta_ctx - instance structure.
+ *
+ * @flags:             validity of fields (streaminfo)
+ * @fh:                        V4L2 file handle
+ * @dev:               device context
+ * @dec:               selected decoder context for this instance
+ * @ipc_ctx:           context of IPC communication with firmware
+ * @state:             instance state
+ * @frame_num:         frame number
+ * @au_num:            access unit number
+ * @max_au_size:       max size of an access unit
+ * @streaminfo:                stream information (width, height, dpb, interlacing...)
+ * @frameinfo:         frame information (width, height, format, alignment...)
+ * @nb_of_frames:      number of frames available for decoding
+ * @frames:            array of decoding frames to keep track of frame
+ *                     state and manage frame recycling
+ * @decoded_frames:    nb of decoded frames from opening
+ * @output_frames:     nb of output frames from opening
+ * @dropped_frames:    nb of frames dropped (ie access unit not parsed
+ *                     or frame decoded but not output)
+ * @stream_errors:     nb of stream errors (corrupted, not supported, ...)
+ * @decode_errors:     nb of decode errors (firmware error)
+ * @sys_errors:                nb of system errors (memory, ipc, ...)
+ * @dts:               FIFO of decoding timestamp.
+ *                     output frames are timestamped with incoming access
+ *                     unit timestamps using this fifo.
+ * @name:              string naming this instance (debug purpose)
+ * @run_work:          decoding work
+ * @lock:              lock for decoding work serialization
+ * @aborting:          true if current job aborted
+ * @priv:              private decoder context for this instance, allocated
+ *                     by decoder @open time.
+ */
+struct delta_ctx {
+       u32 flags;
+       struct v4l2_fh fh;
+       struct delta_dev *dev;
+       const struct delta_dec *dec;
+       struct delta_ipc_ctx ipc_ctx;
+
+       enum delta_state state;
+       u32 frame_num;
+       u32 au_num;
+       size_t max_au_size;
+       struct delta_streaminfo streaminfo;
+       struct delta_frameinfo frameinfo;
+       u32 nb_of_frames;
+       struct delta_frame *frames[DELTA_MAX_FRAMES];
+       u32 decoded_frames;
+       u32 output_frames;
+       u32 dropped_frames;
+       u32 stream_errors;
+       u32 decode_errors;
+       u32 sys_errors;
+       struct list_head dts;
+       char name[100];
+       struct work_struct run_work;
+       struct mutex lock;
+       bool aborting;
+       void *priv;
+};
+
+#define DELTA_FLAG_STREAMINFO 0x0001
+#define DELTA_FLAG_FRAMEINFO 0x0002
+
+#define DELTA_MAX_FORMATS  DELTA_MAX_DECODERS
+
+/*
+ * struct delta_dev - device struct, 1 per probe (so single one for
+ * all platform life)
+ *
+ * @v4l2_dev:          v4l2 device
+ * @vdev:              v4l2 video device
+ * @pdev:              platform device
+ * @dev:               device
+ * @m2m_dev:           memory-to-memory V4L2 device
+ * @lock:              device lock, for crit section & V4L2 ops serialization.
+ * @clk_delta:         delta main clock
+ * @clk_st231:         st231 coprocessor main clock
+ * @clk_flash_promip:  flash promip clock
+ * @decoders:          list of registered decoders
+ * @nb_of_decoders:    nb of registered decoders
+ * @pixelformats:      supported uncompressed video formats
+ * @nb_of_pixelformats:        number of supported umcompressed video formats
+ * @streamformats:     supported compressed video formats
+ * @nb_of_streamformats:number of supported compressed video formats
+ * @instance_id:       rolling counter identifying an instance (debug purpose)
+ * @work_queue:                decoding job work queue
+ * @rpmsg_driver:      rpmsg IPC driver
+ * @rpmsg_device:      rpmsg IPC device
+ */
+struct delta_dev {
+       struct v4l2_device v4l2_dev;
+       struct video_device *vdev;
+       struct platform_device *pdev;
+       struct device *dev;
+       struct v4l2_m2m_dev *m2m_dev;
+       struct mutex lock;
+       struct clk *clk_delta;
+       struct clk *clk_st231;
+       struct clk *clk_flash_promip;
+       const struct delta_dec *decoders[DELTA_MAX_DECODERS];
+       u32 nb_of_decoders;
+       u32 pixelformats[DELTA_MAX_FORMATS];
+       u32 nb_of_pixelformats;
+       u32 streamformats[DELTA_MAX_FORMATS];
+       u32 nb_of_streamformats;
+       u8 instance_id;
+       struct workqueue_struct *work_queue;
+       struct rpmsg_driver rpmsg_driver;
+       struct rpmsg_device *rpmsg_device;
+};
+
+static inline char *frame_type_str(u32 flags)
+{
+       if (flags & V4L2_BUF_FLAG_KEYFRAME)
+               return "I";
+       if (flags & V4L2_BUF_FLAG_PFRAME)
+               return "P";
+       if (flags & V4L2_BUF_FLAG_BFRAME)
+               return "B";
+       if (flags & V4L2_BUF_FLAG_LAST)
+               return "EOS";
+       return "?";
+}
+
+static inline char *frame_field_str(enum v4l2_field field)
+{
+       if (field == V4L2_FIELD_NONE)
+               return "-";
+       if (field == V4L2_FIELD_TOP)
+               return "T";
+       if (field == V4L2_FIELD_BOTTOM)
+               return "B";
+       if (field == V4L2_FIELD_INTERLACED)
+               return "I";
+       if (field == V4L2_FIELD_INTERLACED_TB)
+               return "TB";
+       if (field == V4L2_FIELD_INTERLACED_BT)
+               return "BT";
+       return "?";
+}
+
+static inline char *frame_state_str(u32 state, char *str, unsigned int len)
+{
+       snprintf(str, len, "%s %s %s %s %s %s",
+                (state & DELTA_FRAME_REF)  ? "ref" : "   ",
+                (state & DELTA_FRAME_BSY)  ? "bsy" : "   ",
+                (state & DELTA_FRAME_DEC)  ? "dec" : "   ",
+                (state & DELTA_FRAME_OUT)  ? "out" : "   ",
+                (state & DELTA_FRAME_M2M)  ? "m2m" : "   ",
+                (state & DELTA_FRAME_RDY)  ? "rdy" : "   ");
+       return str;
+}
+
+int delta_get_frameinfo_default(struct delta_ctx *ctx,
+                               struct delta_frameinfo *frameinfo);
+int delta_recycle_default(struct delta_ctx *pctx,
+                         struct delta_frame *frame);
+
+int delta_get_free_frame(struct delta_ctx *ctx,
+                        struct delta_frame **pframe);
+
+int delta_get_sync(struct delta_ctx *ctx);
+void delta_put_autosuspend(struct delta_ctx *ctx);
+
+#endif /* DELTA_H */
index ffb69cebaef3d782b9388267362a9a40d7ad0cb4..e3ebe968472db99a3e801a2cd9948b49d01b73a4 100644 (file)
@@ -1,2 +1,3 @@
 obj-$(CONFIG_VIDEO_STI_HVA) := st-hva.o
 st-hva-y := hva-v4l2.o hva-hw.o hva-mem.o hva-h264.o
+st-hva-$(CONFIG_VIDEO_STI_HVA_DEBUGFS) += hva-debugfs.o
diff --git a/drivers/media/platform/sti/hva/hva-debugfs.c b/drivers/media/platform/sti/hva/hva-debugfs.c
new file mode 100644 (file)
index 0000000..83a6258
--- /dev/null
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2015
+ * Authors: Yannick Fertre <yannick.fertre@st.com>
+ *          Hugues Fruchet <hugues.fruchet@st.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/debugfs.h>
+
+#include "hva.h"
+#include "hva-hw.h"
+
+static void format_ctx(struct seq_file *s, struct hva_ctx *ctx)
+{
+       struct hva_streaminfo *stream = &ctx->streaminfo;
+       struct hva_frameinfo *frame = &ctx->frameinfo;
+       struct hva_controls *ctrls = &ctx->ctrls;
+       struct hva_ctx_dbg *dbg = &ctx->dbg;
+       u32 bitrate_mode, aspect, entropy, vui_sar, sei_fp;
+
+       seq_printf(s, "|-%s\n  |\n", ctx->name);
+
+       seq_printf(s, "  |-[%sframe info]\n",
+                  ctx->flags & HVA_FLAG_FRAMEINFO ? "" : "default ");
+       seq_printf(s, "  | |- pixel format=%4.4s\n"
+                     "  | |- wxh=%dx%d\n"
+                     "  | |- wxh (w/ encoder alignment constraint)=%dx%d\n"
+                     "  |\n",
+                     (char *)&frame->pixelformat,
+                     frame->width, frame->height,
+                     frame->aligned_width, frame->aligned_height);
+
+       seq_printf(s, "  |-[%sstream info]\n",
+                  ctx->flags & HVA_FLAG_STREAMINFO ? "" : "default ");
+       seq_printf(s, "  | |- stream format=%4.4s\n"
+                     "  | |- wxh=%dx%d\n"
+                     "  | |- %s\n"
+                     "  | |- %s\n"
+                     "  |\n",
+                     (char *)&stream->streamformat,
+                     stream->width, stream->height,
+                     stream->profile, stream->level);
+
+       bitrate_mode = V4L2_CID_MPEG_VIDEO_BITRATE_MODE;
+       aspect = V4L2_CID_MPEG_VIDEO_ASPECT;
+       seq_puts(s, "  |-[parameters]\n");
+       seq_printf(s, "  | |- %s\n"
+                     "  | |- bitrate=%d bps\n"
+                     "  | |- GOP size=%d\n"
+                     "  | |- video aspect=%s\n"
+                     "  | |- framerate=%d/%d\n",
+                     v4l2_ctrl_get_menu(bitrate_mode)[ctrls->bitrate_mode],
+                     ctrls->bitrate,
+                     ctrls->gop_size,
+                     v4l2_ctrl_get_menu(aspect)[ctrls->aspect],
+                     ctrls->time_per_frame.denominator,
+                     ctrls->time_per_frame.numerator);
+
+       entropy = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE;
+       vui_sar = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC;
+       sei_fp =  V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE;
+       if (stream->streamformat == V4L2_PIX_FMT_H264) {
+               seq_printf(s, "  | |- %s entropy mode\n"
+                             "  | |- CPB size=%d kB\n"
+                             "  | |- DCT8x8 enable=%s\n"
+                             "  | |- qpmin=%d\n"
+                             "  | |- qpmax=%d\n"
+                             "  | |- PAR enable=%s\n"
+                             "  | |- PAR id=%s\n"
+                             "  | |- SEI frame packing enable=%s\n"
+                             "  | |- SEI frame packing type=%s\n",
+                             v4l2_ctrl_get_menu(entropy)[ctrls->entropy_mode],
+                             ctrls->cpb_size,
+                             ctrls->dct8x8 ? "true" : "false",
+                             ctrls->qpmin,
+                             ctrls->qpmax,
+                             ctrls->vui_sar ? "true" : "false",
+                             v4l2_ctrl_get_menu(vui_sar)[ctrls->vui_sar_idc],
+                             ctrls->sei_fp ? "true" : "false",
+                             v4l2_ctrl_get_menu(sei_fp)[ctrls->sei_fp_type]);
+       }
+
+       if (ctx->sys_errors || ctx->encode_errors || ctx->frame_errors) {
+               seq_puts(s, "  |\n  |-[errors]\n");
+               seq_printf(s, "  | |- system=%d\n"
+                             "  | |- encoding=%d\n"
+                             "  | |- frame=%d\n",
+                             ctx->sys_errors,
+                             ctx->encode_errors,
+                             ctx->frame_errors);
+       }
+
+       seq_puts(s, "  |\n  |-[performances]\n");
+       seq_printf(s, "  | |- frames encoded=%d\n"
+                     "  | |- avg HW processing duration (0.1ms)=%d [min=%d, max=%d]\n"
+                     "  | |- avg encoding period (0.1ms)=%d [min=%d, max=%d]\n"
+                     "  | |- avg fps (0.1Hz)=%d\n"
+                     "  | |- max reachable fps (0.1Hz)=%d\n"
+                     "  | |- avg bitrate (kbps)=%d [min=%d, max=%d]\n"
+                     "  | |- last bitrate (kbps)=%d\n",
+                     dbg->cnt_duration,
+                     dbg->avg_duration,
+                     dbg->min_duration,
+                     dbg->max_duration,
+                     dbg->avg_period,
+                     dbg->min_period,
+                     dbg->max_period,
+                     dbg->avg_fps,
+                     dbg->max_fps,
+                     dbg->avg_bitrate,
+                     dbg->min_bitrate,
+                     dbg->max_bitrate,
+                     dbg->last_bitrate);
+}
+
+/*
+ * performance debug info
+ */
+void hva_dbg_perf_begin(struct hva_ctx *ctx)
+{
+       u64 div;
+       u32 period;
+       u32 bitrate;
+       struct hva_ctx_dbg *dbg = &ctx->dbg;
+       ktime_t prev = dbg->begin;
+
+       dbg->begin = ktime_get();
+
+       if (dbg->is_valid_period) {
+               /* encoding period */
+               div = (u64)ktime_us_delta(dbg->begin, prev);
+               do_div(div, 100);
+               period = (u32)div;
+               dbg->min_period = min(period, dbg->min_period);
+               dbg->max_period = max(period, dbg->max_period);
+               dbg->total_period += period;
+               dbg->cnt_period++;
+
+               /*
+                * minimum and maximum bitrates are based on the
+                * encoding period values upon a window of 32 samples
+                */
+               dbg->window_duration += period;
+               dbg->cnt_window++;
+               if (dbg->cnt_window >= 32) {
+                       /*
+                        * bitrate in kbps = (size * 8 / 1000) /
+                        *                   (duration / 10000)
+                        *                 = size * 80 / duration
+                        */
+                       if (dbg->window_duration > 0) {
+                               div = (u64)dbg->window_stream_size * 80;
+                               do_div(div, dbg->window_duration);
+                               bitrate = (u32)div;
+                               dbg->last_bitrate = bitrate;
+                               dbg->min_bitrate = min(bitrate,
+                                                      dbg->min_bitrate);
+                               dbg->max_bitrate = max(bitrate,
+                                                      dbg->max_bitrate);
+                       }
+                       dbg->window_stream_size = 0;
+                       dbg->window_duration = 0;
+                       dbg->cnt_window = 0;
+               }
+       }
+
+       /*
+        * filter sequences valid for performance:
+        * - begin/begin (no stream available) is an invalid sequence
+        * - begin/end is a valid sequence
+        */
+       dbg->is_valid_period = false;
+}
+
+void hva_dbg_perf_end(struct hva_ctx *ctx, struct hva_stream *stream)
+{
+       struct device *dev = ctx_to_dev(ctx);
+       u64 div;
+       u32 duration;
+       u32 bytesused;
+       u32 timestamp;
+       struct hva_ctx_dbg *dbg = &ctx->dbg;
+       ktime_t end = ktime_get();
+
+       /* stream bytesused and timestamp in us */
+       bytesused = vb2_get_plane_payload(&stream->vbuf.vb2_buf, 0);
+       div = stream->vbuf.vb2_buf.timestamp;
+       do_div(div, 1000);
+       timestamp = (u32)div;
+
+       /* encoding duration */
+       div = (u64)ktime_us_delta(end, dbg->begin);
+
+       dev_dbg(dev,
+               "%s perf stream[%d] dts=%d encoded using %d bytes in %d us",
+               ctx->name,
+               stream->vbuf.sequence,
+               timestamp,
+               bytesused, (u32)div);
+
+       do_div(div, 100);
+       duration = (u32)div;
+
+       dbg->min_duration = min(duration, dbg->min_duration);
+       dbg->max_duration = max(duration, dbg->max_duration);
+       dbg->total_duration += duration;
+       dbg->cnt_duration++;
+
+       /*
+        * the average bitrate is based on the total stream size
+        * and the total encoding periods
+        */
+       dbg->total_stream_size += bytesused;
+       dbg->window_stream_size += bytesused;
+
+       dbg->is_valid_period = true;
+}
+
+static void hva_dbg_perf_compute(struct hva_ctx *ctx)
+{
+       u64 div;
+       struct hva_ctx_dbg *dbg = &ctx->dbg;
+
+       if (dbg->cnt_duration > 0) {
+               div = (u64)dbg->total_duration;
+               do_div(div, dbg->cnt_duration);
+               dbg->avg_duration = (u32)div;
+       } else {
+               dbg->avg_duration = 0;
+       }
+
+       if (dbg->total_duration > 0) {
+               div = (u64)dbg->cnt_duration * 100000;
+               do_div(div, dbg->total_duration);
+               dbg->max_fps = (u32)div;
+       } else {
+               dbg->max_fps = 0;
+       }
+
+       if (dbg->cnt_period > 0) {
+               div = (u64)dbg->total_period;
+               do_div(div, dbg->cnt_period);
+               dbg->avg_period = (u32)div;
+       } else {
+               dbg->avg_period = 0;
+       }
+
+       if (dbg->total_period > 0) {
+               div = (u64)dbg->cnt_period * 100000;
+               do_div(div, dbg->total_period);
+               dbg->avg_fps = (u32)div;
+       } else {
+               dbg->avg_fps = 0;
+       }
+
+       if (dbg->total_period > 0) {
+               /*
+                * bitrate in kbps = (video size * 8 / 1000) /
+                *                   (video duration / 10000)
+                *                 = video size * 80 / video duration
+                */
+               div = (u64)dbg->total_stream_size * 80;
+               do_div(div, dbg->total_period);
+               dbg->avg_bitrate = (u32)div;
+       } else {
+               dbg->avg_bitrate = 0;
+       }
+}
+
+/*
+ * device debug info
+ */
+
+static int hva_dbg_device(struct seq_file *s, void *data)
+{
+       struct hva_dev *hva = s->private;
+
+       seq_printf(s, "[%s]\n", hva->v4l2_dev.name);
+       seq_printf(s, "registered as /dev/video%d\n", hva->vdev->num);
+
+       return 0;
+}
+
+static int hva_dbg_encoders(struct seq_file *s, void *data)
+{
+       struct hva_dev *hva = s->private;
+       unsigned int i = 0;
+
+       seq_printf(s, "[encoders]\n|- %d registered encoders:\n",
+                  hva->nb_of_encoders);
+
+       while (hva->encoders[i]) {
+               seq_printf(s, "|- %s: %4.4s => %4.4s\n", hva->encoders[i]->name,
+                          (char *)&hva->encoders[i]->pixelformat,
+                          (char *)&hva->encoders[i]->streamformat);
+               i++;
+       }
+
+       return 0;
+}
+
+static int hva_dbg_last(struct seq_file *s, void *data)
+{
+       struct hva_dev *hva = s->private;
+       struct hva_ctx *last_ctx = &hva->dbg.last_ctx;
+
+       if (last_ctx->flags & HVA_FLAG_STREAMINFO) {
+               seq_puts(s, "[last encoding]\n");
+
+               hva_dbg_perf_compute(last_ctx);
+               format_ctx(s, last_ctx);
+       } else {
+               seq_puts(s, "[no information recorded about last encoding]\n");
+       }
+
+       return 0;
+}
+
+static int hva_dbg_regs(struct seq_file *s, void *data)
+{
+       struct hva_dev *hva = s->private;
+
+       hva_hw_dump_regs(hva, s);
+
+       return 0;
+}
+
+#define hva_dbg_declare(name)                                            \
+       static int hva_dbg_##name##_open(struct inode *i, struct file *f) \
+       {                                                                 \
+               return single_open(f, hva_dbg_##name, i->i_private);      \
+       }                                                                 \
+       static const struct file_operations hva_dbg_##name##_fops = {     \
+               .open           = hva_dbg_##name##_open,                  \
+               .read           = seq_read,                               \
+               .llseek         = seq_lseek,                              \
+               .release        = single_release,                         \
+       }
+
+#define hva_dbg_create_entry(name)                                      \
+       debugfs_create_file(#name, 0444, hva->dbg.debugfs_entry, hva, \
+                           &hva_dbg_##name##_fops)
+
+hva_dbg_declare(device);
+hva_dbg_declare(encoders);
+hva_dbg_declare(last);
+hva_dbg_declare(regs);
+
+void hva_debugfs_create(struct hva_dev *hva)
+{
+       hva->dbg.debugfs_entry = debugfs_create_dir(HVA_NAME, NULL);
+       if (!hva->dbg.debugfs_entry)
+               goto err;
+
+       if (!hva_dbg_create_entry(device))
+               goto err;
+
+       if (!hva_dbg_create_entry(encoders))
+               goto err;
+
+       if (!hva_dbg_create_entry(last))
+               goto err;
+
+       if (!hva_dbg_create_entry(regs))
+               goto err;
+
+       return;
+
+err:
+       hva_debugfs_remove(hva);
+}
+
+void hva_debugfs_remove(struct hva_dev *hva)
+{
+       debugfs_remove_recursive(hva->dbg.debugfs_entry);
+       hva->dbg.debugfs_entry = NULL;
+}
+
+/*
+ * context (instance) debug info
+ */
+
+static int hva_dbg_ctx(struct seq_file *s, void *data)
+{
+       struct hva_ctx *ctx = s->private;
+
+       seq_printf(s, "[running encoding %d]\n", ctx->id);
+
+       hva_dbg_perf_compute(ctx);
+       format_ctx(s, ctx);
+
+       return 0;
+}
+
+hva_dbg_declare(ctx);
+
+void hva_dbg_ctx_create(struct hva_ctx *ctx)
+{
+       struct hva_dev *hva = ctx->hva_dev;
+       char name[4] = "";
+
+       ctx->dbg.min_duration = UINT_MAX;
+       ctx->dbg.min_period = UINT_MAX;
+       ctx->dbg.min_bitrate = UINT_MAX;
+
+       snprintf(name, sizeof(name), "%d", hva->instance_id);
+
+       ctx->dbg.debugfs_entry = debugfs_create_file(name, 0444,
+                                                    hva->dbg.debugfs_entry,
+                                                    ctx, &hva_dbg_ctx_fops);
+}
+
+void hva_dbg_ctx_remove(struct hva_ctx *ctx)
+{
+       struct hva_dev *hva = ctx->hva_dev;
+
+       if (ctx->flags & HVA_FLAG_STREAMINFO)
+               /* save context before removing */
+               memcpy(&hva->dbg.last_ctx, ctx, sizeof(*ctx));
+
+       debugfs_remove(ctx->dbg.debugfs_entry);
+}
index 8cc8467c0cd3d9a108528303b87a650461c7b7a4..e6f247a983c73bf1e4cc347248af51892f7d1b10 100644 (file)
@@ -607,6 +607,7 @@ static int hva_h264_prepare_task(struct hva_ctx *pctx,
                        "%s   width(%d) or height(%d) exceeds limits (%dx%d)\n",
                        pctx->name, frame_width, frame_height,
                        H264_MAX_SIZE_W, H264_MAX_SIZE_H);
+               pctx->frame_errors++;
                return -EINVAL;
        }
 
@@ -717,6 +718,7 @@ static int hva_h264_prepare_task(struct hva_ctx *pctx,
        default:
                dev_err(dev, "%s   invalid source pixel format\n",
                        pctx->name);
+               pctx->frame_errors++;
                return -EINVAL;
        }
 
@@ -741,6 +743,7 @@ static int hva_h264_prepare_task(struct hva_ctx *pctx,
 
        if (td->framerate_den == 0) {
                dev_err(dev, "%s   invalid framerate\n", pctx->name);
+               pctx->frame_errors++;
                return -EINVAL;
        }
 
@@ -831,6 +834,7 @@ static int hva_h264_prepare_task(struct hva_ctx *pctx,
            (payload > MAX_SPS_PPS_SIZE)) {
                dev_err(dev, "%s   invalid sps/pps size %d\n", pctx->name,
                        payload);
+               pctx->frame_errors++;
                return -EINVAL;
        }
 
@@ -842,6 +846,7 @@ static int hva_h264_prepare_task(struct hva_ctx *pctx,
                                                   (u8 *)stream->vaddr,
                                                   &payload)) {
                dev_err(dev, "%s   fail to get SEI nal\n", pctx->name);
+               pctx->frame_errors++;
                return -EINVAL;
        }
 
@@ -963,6 +968,7 @@ err_seq_info:
 err_ctx:
        devm_kfree(dev, ctx);
 err:
+       pctx->sys_errors++;
        return ret;
 }
 
index 68d625b412b6ce5e3a3c25920d516c3efbdad46e..ec25bdcfa3d1e11c776c2fe96d7671264c27234e 100644 (file)
@@ -9,6 +9,9 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS
+#include <linux/seq_file.h>
+#endif
 
 #include "hva.h"
 #include "hva-hw.h"
@@ -470,6 +473,7 @@ int hva_hw_execute_task(struct hva_ctx *ctx, enum hva_hw_cmd_type cmd,
 
        if (pm_runtime_get_sync(dev) < 0) {
                dev_err(dev, "%s     failed to get pm_runtime\n", ctx->name);
+               ctx->sys_errors++;
                ret = -EFAULT;
                goto out;
        }
@@ -481,6 +485,7 @@ int hva_hw_execute_task(struct hva_ctx *ctx, enum hva_hw_cmd_type cmd,
                break;
        default:
                dev_dbg(dev, "%s     unknown command 0x%x\n", ctx->name, cmd);
+               ctx->encode_errors++;
                ret = -EFAULT;
                goto out;
        }
@@ -511,6 +516,7 @@ int hva_hw_execute_task(struct hva_ctx *ctx, enum hva_hw_cmd_type cmd,
                                         msecs_to_jiffies(2000))) {
                dev_err(dev, "%s     %s: time out on completion\n", ctx->name,
                        __func__);
+               ctx->encode_errors++;
                ret = -EFAULT;
                goto out;
        }
@@ -518,6 +524,8 @@ int hva_hw_execute_task(struct hva_ctx *ctx, enum hva_hw_cmd_type cmd,
        /* get encoding status */
        ret = ctx->hw_err ? -EFAULT : 0;
 
+       ctx->encode_errors += ctx->hw_err ? 1 : 0;
+
 out:
        disable_irq(hva->irq_its);
        disable_irq(hva->irq_err);
@@ -536,3 +544,43 @@ out:
 
        return ret;
 }
+
+#ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS
+#define DUMP(reg) seq_printf(s, "%-30s: 0x%08X\n",\
+                            #reg, readl_relaxed(hva->regs + reg))
+
+void hva_hw_dump_regs(struct hva_dev *hva, struct seq_file *s)
+{
+       struct device *dev = hva_to_dev(hva);
+
+       mutex_lock(&hva->protect_mutex);
+
+       if (pm_runtime_get_sync(dev) < 0) {
+               seq_puts(s, "Cannot wake up IP\n");
+               mutex_unlock(&hva->protect_mutex);
+               return;
+       }
+
+       seq_printf(s, "Registers:\nReg @ = 0x%p\n", hva->regs);
+
+       DUMP(HVA_HIF_REG_RST);
+       DUMP(HVA_HIF_REG_RST_ACK);
+       DUMP(HVA_HIF_REG_MIF_CFG);
+       DUMP(HVA_HIF_REG_HEC_MIF_CFG);
+       DUMP(HVA_HIF_REG_CFL);
+       DUMP(HVA_HIF_REG_SFL);
+       DUMP(HVA_HIF_REG_LMI_ERR);
+       DUMP(HVA_HIF_REG_EMI_ERR);
+       DUMP(HVA_HIF_REG_HEC_MIF_ERR);
+       DUMP(HVA_HIF_REG_HEC_STS);
+       DUMP(HVA_HIF_REG_HVC_STS);
+       DUMP(HVA_HIF_REG_HJE_STS);
+       DUMP(HVA_HIF_REG_CNT);
+       DUMP(HVA_HIF_REG_HEC_CHKSYN_DIS);
+       DUMP(HVA_HIF_REG_CLK_GATING);
+       DUMP(HVA_HIF_REG_VERSION);
+
+       pm_runtime_put_autosuspend(dev);
+       mutex_unlock(&hva->protect_mutex);
+}
+#endif
index efb45b927524c7ede050454a86814d4cfd2ec787..b46017dcfae95a0a317ea2992f4937a5501edf4c 100644 (file)
@@ -38,5 +38,8 @@ int hva_hw_runtime_suspend(struct device *dev);
 int hva_hw_runtime_resume(struct device *dev);
 int hva_hw_execute_task(struct hva_ctx *ctx, enum hva_hw_cmd_type cmd,
                        struct hva_buffer *task);
+#ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS
+void hva_hw_dump_regs(struct hva_dev *hva, struct seq_file *s);
+#endif
 
 #endif /* HVA_HW_H */
index 649f66007ad666e68380c9fc36988f72d1664001..821c78ed208c0646c24daa2242b7b7254ab4b8b3 100644 (file)
@@ -17,14 +17,17 @@ int hva_mem_alloc(struct hva_ctx *ctx, u32 size, const char *name,
        void *base;
 
        b = devm_kzalloc(dev, sizeof(*b), GFP_KERNEL);
-       if (!b)
+       if (!b) {
+               ctx->sys_errors++;
                return -ENOMEM;
+       }
 
        base = dma_alloc_attrs(dev, size, &paddr, GFP_KERNEL | GFP_DMA,
                               DMA_ATTR_WRITE_COMBINE);
        if (!base) {
                dev_err(dev, "%s %s : dma_alloc_attrs failed for %s (size=%d)\n",
                        ctx->name, __func__, name, size);
+               ctx->sys_errors++;
                devm_kfree(dev, b);
                return -ENOMEM;
        }
index 6bf3c85882300f9f97c65dd9a2d10bf4c3f68369..1c4fc33cbcb5ac8205b49a03fe2cdfa4fbaec78e 100644 (file)
@@ -15,8 +15,6 @@
 #include "hva.h"
 #include "hva-hw.h"
 
-#define HVA_NAME "st-hva"
-
 #define MIN_FRAMES     1
 #define MIN_STREAMS    1
 
@@ -226,6 +224,28 @@ static int hva_open_encoder(struct hva_ctx *ctx, u32 streamformat,
        return ret;
 }
 
+static void hva_dbg_summary(struct hva_ctx *ctx)
+{
+       struct device *dev = ctx_to_dev(ctx);
+       struct hva_streaminfo *stream = &ctx->streaminfo;
+       struct hva_frameinfo *frame = &ctx->frameinfo;
+
+       if (!(ctx->flags & HVA_FLAG_STREAMINFO))
+               return;
+
+       dev_dbg(dev, "%s %4.4s %dx%d > %4.4s %dx%d %s %s: %d frames encoded, %d system errors, %d encoding errors, %d frame errors\n",
+               ctx->name,
+               (char *)&frame->pixelformat,
+               frame->aligned_width, frame->aligned_height,
+               (char *)&stream->streamformat,
+               stream->width, stream->height,
+               stream->profile, stream->level,
+               ctx->encoded_frames,
+               ctx->sys_errors,
+               ctx->encode_errors,
+               ctx->frame_errors);
+}
+
 /*
  * V4L2 ioctl operations
  */
@@ -614,19 +634,17 @@ static int hva_s_ctrl(struct v4l2_ctrl *ctrl)
                break;
        case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
                ctx->ctrls.profile = ctrl->val;
-               if (ctx->flags & HVA_FLAG_STREAMINFO)
-                       snprintf(ctx->streaminfo.profile,
-                                sizeof(ctx->streaminfo.profile),
-                                "%s profile",
-                                v4l2_ctrl_get_menu(ctrl->id)[ctrl->val]);
+               snprintf(ctx->streaminfo.profile,
+                        sizeof(ctx->streaminfo.profile),
+                        "%s profile",
+                        v4l2_ctrl_get_menu(ctrl->id)[ctrl->val]);
                break;
        case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
                ctx->ctrls.level = ctrl->val;
-               if (ctx->flags & HVA_FLAG_STREAMINFO)
-                       snprintf(ctx->streaminfo.level,
-                                sizeof(ctx->streaminfo.level),
-                                "level %s",
-                                v4l2_ctrl_get_menu(ctrl->id)[ctrl->val]);
+               snprintf(ctx->streaminfo.level,
+                        sizeof(ctx->streaminfo.level),
+                        "level %s",
+                        v4l2_ctrl_get_menu(ctrl->id)[ctrl->val]);
                break;
        case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
                ctx->ctrls.entropy_mode = ctrl->val;
@@ -793,6 +811,10 @@ static void hva_run_work(struct work_struct *work)
        /* protect instance against reentrancy */
        mutex_lock(&ctx->lock);
 
+#ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS
+       hva_dbg_perf_begin(ctx);
+#endif
+
        src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
        dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
 
@@ -812,6 +834,12 @@ static void hva_run_work(struct work_struct *work)
                dst_buf->field = V4L2_FIELD_NONE;
                dst_buf->sequence = ctx->stream_num - 1;
 
+               ctx->encoded_frames++;
+
+#ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS
+               hva_dbg_perf_end(ctx, stream);
+#endif
+
                v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
                v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
        }
@@ -1026,6 +1054,8 @@ err:
                        v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_QUEUED);
        }
 
+       ctx->sys_errors++;
+
        return ret;
 }
 
@@ -1150,6 +1180,7 @@ static int hva_open(struct file *file)
        if (ret) {
                dev_err(dev, "%s [x:x] failed to setup controls\n",
                        HVA_PREFIX);
+               ctx->sys_errors++;
                goto err_fh;
        }
        ctx->fh.ctrl_handler = &ctx->ctrl_handler;
@@ -1162,6 +1193,7 @@ static int hva_open(struct file *file)
                ret = PTR_ERR(ctx->fh.m2m_ctx);
                dev_err(dev, "%s failed to initialize m2m context (%d)\n",
                        HVA_PREFIX, ret);
+               ctx->sys_errors++;
                goto err_ctrls;
        }
 
@@ -1175,6 +1207,10 @@ static int hva_open(struct file *file)
        /* default parameters for frame and stream */
        set_default_params(ctx);
 
+#ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS
+       hva_dbg_ctx_create(ctx);
+#endif
+
        dev_info(dev, "%s encoder instance created\n", ctx->name);
 
        return 0;
@@ -1206,6 +1242,9 @@ static int hva_release(struct file *file)
                hva->nb_of_instances--;
        }
 
+       /* trace a summary of instance before closing (debug purpose) */
+       hva_dbg_summary(ctx);
+
        v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
 
        v4l2_ctrl_handler_free(&ctx->ctrl_handler);
@@ -1213,6 +1252,10 @@ static int hva_release(struct file *file)
        v4l2_fh_del(&ctx->fh);
        v4l2_fh_exit(&ctx->fh);
 
+#ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS
+       hva_dbg_ctx_remove(ctx);
+#endif
+
        dev_info(dev, "%s encoder instance released\n", ctx->name);
 
        kfree(ctx);
@@ -1337,6 +1380,10 @@ static int hva_probe(struct platform_device *pdev)
                goto err_hw;
        }
 
+#ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS
+       hva_debugfs_create(hva);
+#endif
+
        hva->work_queue = create_workqueue(HVA_NAME);
        if (!hva->work_queue) {
                dev_err(dev, "%s %s failed to allocate work queue\n",
@@ -1358,6 +1405,9 @@ static int hva_probe(struct platform_device *pdev)
 err_work_queue:
        destroy_workqueue(hva->work_queue);
 err_v4l2:
+#ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS
+       hva_debugfs_remove(hva);
+#endif
        v4l2_device_unregister(&hva->v4l2_dev);
 err_hw:
        hva_hw_remove(hva);
@@ -1376,6 +1426,10 @@ static int hva_remove(struct platform_device *pdev)
 
        hva_hw_remove(hva);
 
+#ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS
+       hva_debugfs_remove(hva);
+#endif
+
        v4l2_device_unregister(&hva->v4l2_dev);
 
        dev_info(dev, "%s %s removed\n", HVA_PREFIX, pdev->name);
index caa5808255411464fdf1685a14a5261ab0c186ce..0d749b257a211335bc85908ab30b9b68b7a68a65 100644 (file)
@@ -21,7 +21,8 @@
 
 #define ctx_to_hdev(c)  (c->hva_dev)
 
-#define HVA_PREFIX "[---:----]"
+#define HVA_NAME       "st-hva"
+#define HVA_PREFIX     "[---:----]"
 
 extern const struct hva_enc nv12h264enc;
 extern const struct hva_enc nv21h264enc;
@@ -153,6 +154,61 @@ struct hva_stream {
 #define to_hva_stream(vb) \
        container_of(vb, struct hva_stream, vbuf)
 
+#ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS
+/**
+ * struct hva_ctx_dbg - instance context debug info
+ *
+ * @debugfs_entry:      debugfs entry
+ * @is_valid_period:    true if the sequence is valid for performance
+ * @begin:              start time of last HW task
+ * @total_duration:     total HW processing durations in 0.1ms
+ * @cnt_duration:       number of HW processings
+ * @min_duration:       minimum HW processing duration in 0.1ms
+ * @max_duration:       maximum HW processing duration in 0.1ms
+ * @avg_duration:       average HW processing duration in 0.1ms
+ * @max_fps:            maximum frames encoded per second (in 0.1Hz)
+ * @total_period:       total encoding periods in 0.1ms
+ * @cnt_period:         number of periods
+ * @min_period:         minimum encoding period in 0.1ms
+ * @max_period:         maximum encoding period in 0.1ms
+ * @avg_period:         average encoding period in 0.1ms
+ * @total_stream_size:  total number of encoded bytes
+ * @avg_fps:            average frames encoded per second (in 0.1Hz)
+ * @window_duration:    duration of the sampling window in 0.1ms
+ * @cnt_window:         number of samples in the window
+ * @window_stream_size: number of encoded bytes upon the sampling window
+ * @last_bitrate:       bitrate upon the last sampling window
+ * @min_bitrate:        minimum bitrate in kbps
+ * @max_bitrate:        maximum bitrate in kbps
+ * @avg_bitrate:        average bitrate in kbps
+ */
+struct hva_ctx_dbg {
+       struct dentry   *debugfs_entry;
+       bool            is_valid_period;
+       ktime_t         begin;
+       u32             total_duration;
+       u32             cnt_duration;
+       u32             min_duration;
+       u32             max_duration;
+       u32             avg_duration;
+       u32             max_fps;
+       u32             total_period;
+       u32             cnt_period;
+       u32             min_period;
+       u32             max_period;
+       u32             avg_period;
+       u32             total_stream_size;
+       u32             avg_fps;
+       u32             window_duration;
+       u32             cnt_window;
+       u32             window_stream_size;
+       u32             last_bitrate;
+       u32             min_bitrate;
+       u32             max_bitrate;
+       u32             avg_bitrate;
+};
+#endif
+
 struct hva_dev;
 struct hva_enc;
 
@@ -182,6 +238,11 @@ struct hva_enc;
  * @priv:            private codec data for this instance, allocated
  *                   by encoder @open time
  * @hw_err:          true if hardware error detected
+ * @encoded_frames:  number of encoded frames
+ * @sys_errors:      number of system errors (memory, resource, pm...)
+ * @encode_errors:   number of encoding errors (hw/driver errors)
+ * @frame_errors:    number of frame errors (format, size, header...)
+ * @dbg:             context debug info
  */
 struct hva_ctx {
        struct hva_dev                  *hva_dev;
@@ -207,11 +268,31 @@ struct hva_ctx {
        struct hva_enc                  *enc;
        void                            *priv;
        bool                            hw_err;
+       u32                             encoded_frames;
+       u32                             sys_errors;
+       u32                             encode_errors;
+       u32                             frame_errors;
+#ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS
+       struct hva_ctx_dbg              dbg;
+#endif
 };
 
 #define HVA_FLAG_STREAMINFO    0x0001
 #define HVA_FLAG_FRAMEINFO     0x0002
 
+#ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS
+/**
+ * struct hva_dev_dbg - device debug info
+ *
+ * @debugfs_entry: debugfs entry
+ * @last_ctx:      debug information about last running instance context
+ */
+struct hva_dev_dbg {
+       struct dentry   *debugfs_entry;
+       struct hva_ctx  last_ctx;
+};
+#endif
+
 #define HVA_MAX_INSTANCES      16
 #define HVA_MAX_ENCODERS       10
 #define HVA_MAX_FORMATS                HVA_MAX_ENCODERS
@@ -250,6 +331,7 @@ struct hva_ctx {
  * @lmi_err_reg:         local memory interface error register value
  * @emi_err_reg:         external memory interface error register value
  * @hec_mif_err_reg:     HEC memory interface error register value
+ * @dbg:                 device debug info
  */
 struct hva_dev {
        struct v4l2_device      v4l2_dev;
@@ -284,6 +366,9 @@ struct hva_dev {
        u32                     lmi_err_reg;
        u32                     emi_err_reg;
        u32                     hec_mif_err_reg;
+#ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS
+       struct hva_dev_dbg      dbg;
+#endif
 };
 
 /**
@@ -312,4 +397,13 @@ struct hva_enc {
                                  struct hva_stream *stream);
 };
 
+#ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS
+void hva_debugfs_create(struct hva_dev *hva);
+void hva_debugfs_remove(struct hva_dev *hva);
+void hva_dbg_ctx_create(struct hva_ctx *ctx);
+void hva_dbg_ctx_remove(struct hva_ctx *ctx);
+void hva_dbg_perf_begin(struct hva_ctx *ctx);
+void hva_dbg_perf_end(struct hva_ctx *ctx, struct hva_stream *stream);
+#endif
+
 #endif /* HVA_H */
index 13bfd718416051d912a4a6f5ba529638f2db14c3..23472e3784ff169f0c05c9bcb473cccb6d9af0d0 100644 (file)
@@ -453,7 +453,7 @@ int vpdma_list_cleanup(struct vpdma_data *vpdma, int list_num,
        if (ret)
                return ret;
 
-       while (vpdma_list_busy(vpdma, list_num) && timeout--)
+       while (vpdma_list_busy(vpdma, list_num) && --timeout)
                ;
 
        if (timeout == 0) {
index a98f679bd88d0ba57ec1c8b99afc4174c6e1d88d..970b9b6dab25562200e6a0243b1d50218aafab45 100644 (file)
@@ -907,6 +907,7 @@ static int vim2m_open(struct file *file)
        if (hdl->error) {
                rc = hdl->error;
                v4l2_ctrl_handler_free(hdl);
+               kfree(ctx);
                goto open_unlock;
        }
        ctx->fh.ctrl_handler = hdl;
@@ -928,6 +929,7 @@ static int vim2m_open(struct file *file)
                rc = PTR_ERR(ctx->fh.m2m_ctx);
 
                v4l2_ctrl_handler_free(hdl);
+               v4l2_fh_exit(&ctx->fh);
                kfree(ctx);
                goto open_unlock;
        }
index c52dd87877941943ed8ac5a1adb0d2a42dec6272..a18e6fec219bb5fe7fa381d6076fdccdd18bcc9e 100644 (file)
@@ -63,7 +63,7 @@ static const struct vivid_fmt formats_ovl[] = {
 };
 
 /* The number of discrete webcam framesizes */
-#define VIVID_WEBCAM_SIZES 4
+#define VIVID_WEBCAM_SIZES 5
 /* The number of discrete webcam frameintervals */
 #define VIVID_WEBCAM_IVALS (VIVID_WEBCAM_SIZES * 2)
 
@@ -73,6 +73,7 @@ static const struct v4l2_frmsize_discrete webcam_sizes[VIVID_WEBCAM_SIZES] = {
        {  640, 360 },
        { 1280, 720 },
        { 1920, 1080 },
+       { 3840, 2160 },
 };
 
 /*
@@ -80,7 +81,9 @@ static const struct v4l2_frmsize_discrete webcam_sizes[VIVID_WEBCAM_SIZES] = {
  * elements in this array as there are in webcam_sizes.
  */
 static const struct v4l2_fract webcam_intervals[VIVID_WEBCAM_IVALS] = {
+       {  1, 1 },
        {  1, 2 },
+       {  1, 4 },
        {  1, 5 },
        {  1, 10 },
        {  1, 15 },
index cd209dccff1bd0f8f9679b124f619a59b831a5e3..b4b583f7137a54eb86f8592724603b296afb9347 100644 (file)
@@ -90,7 +90,7 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int width,
                if (ret == -ETIMEDOUT)
                        dev_err(vsp1->dev, "DRM pipeline stop timeout\n");
 
-               media_entity_pipeline_stop(&pipe->output->entity.subdev.entity);
+               media_pipeline_stop(&pipe->output->entity.subdev.entity);
 
                for (i = 0; i < bru->entity.source_pad; ++i) {
                        vsp1->drm->inputs[i].enabled = false;
@@ -196,7 +196,7 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int width,
        if (ret < 0)
                return ret;
 
-       ret = media_entity_pipeline_start(&pipe->output->entity.subdev.entity,
+       ret = media_pipeline_start(&pipe->output->entity.subdev.entity,
                                          &pipe->pipe);
        if (ret < 0) {
                dev_dbg(vsp1->dev, "%s: pipeline start failed\n", __func__);
index 41e8b096dab85893191aefea8de5e0265dcc64d3..3eaadbf7a876dd3c5400e7473304a6c7ad8f06cf 100644 (file)
@@ -548,20 +548,20 @@ out:
 static int vsp1_video_pipeline_build(struct vsp1_pipeline *pipe,
                                     struct vsp1_video *video)
 {
-       struct media_entity_graph graph;
+       struct media_graph graph;
        struct media_entity *entity = &video->video.entity;
        struct media_device *mdev = entity->graph_obj.mdev;
        unsigned int i;
        int ret;
 
        /* Walk the graph to locate the entities and video nodes. */
-       ret = media_entity_graph_walk_init(&graph, mdev);
+       ret = media_graph_walk_init(&graph, mdev);
        if (ret)
                return ret;
 
-       media_entity_graph_walk_start(&graph, entity);
+       media_graph_walk_start(&graph, entity);
 
-       while ((entity = media_entity_graph_walk_next(&graph))) {
+       while ((entity = media_graph_walk_next(&graph))) {
                struct v4l2_subdev *subdev;
                struct vsp1_rwpf *rwpf;
                struct vsp1_entity *e;
@@ -590,7 +590,7 @@ static int vsp1_video_pipeline_build(struct vsp1_pipeline *pipe,
                }
        }
 
-       media_entity_graph_walk_cleanup(&graph);
+       media_graph_walk_cleanup(&graph);
 
        /* We need one output and at least one input. */
        if (pipe->num_inputs == 0 || !pipe->output)
@@ -848,7 +848,7 @@ static void vsp1_video_stop_streaming(struct vb2_queue *vq)
        }
        mutex_unlock(&pipe->lock);
 
-       media_entity_pipeline_stop(&video->video.entity);
+       media_pipeline_stop(&video->video.entity);
        vsp1_video_pipeline_put(pipe);
 
        /* Remove all buffers from the IRQ queue. */
@@ -980,7 +980,7 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
                return PTR_ERR(pipe);
        }
 
-       ret = __media_entity_pipeline_start(&video->video.entity, &pipe->pipe);
+       ret = __media_pipeline_start(&video->video.entity, &pipe->pipe);
        if (ret < 0) {
                mutex_unlock(&mdev->graph_mutex);
                goto err_pipe;
@@ -1003,7 +1003,7 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
        return 0;
 
 err_stop:
-       media_entity_pipeline_stop(&video->video.entity);
+       media_pipeline_stop(&video->video.entity);
 err_pipe:
        vsp1_video_pipeline_put(pipe);
        return ret;
@@ -1021,6 +1021,7 @@ static const struct v4l2_ioctl_ops vsp1_video_ioctl_ops = {
        .vidioc_querybuf                = vb2_ioctl_querybuf,
        .vidioc_qbuf                    = vb2_ioctl_qbuf,
        .vidioc_dqbuf                   = vb2_ioctl_dqbuf,
+       .vidioc_expbuf                  = vb2_ioctl_expbuf,
        .vidioc_create_bufs             = vb2_ioctl_create_bufs,
        .vidioc_prepare_buf             = vb2_ioctl_prepare_buf,
        .vidioc_streamon                = vsp1_video_streamon,
index 1d5836c3fb7a8ff0fd0109627836fb3fdae03fb9..522cdfdd334518fd578e8440d451d37a504afc7e 100644 (file)
@@ -177,7 +177,7 @@ done:
 static int xvip_pipeline_validate(struct xvip_pipeline *pipe,
                                  struct xvip_dma *start)
 {
-       struct media_entity_graph graph;
+       struct media_graph graph;
        struct media_entity *entity = &start->video.entity;
        struct media_device *mdev = entity->graph_obj.mdev;
        unsigned int num_inputs = 0;
@@ -187,15 +187,15 @@ static int xvip_pipeline_validate(struct xvip_pipeline *pipe,
        mutex_lock(&mdev->graph_mutex);
 
        /* Walk the graph to locate the video nodes. */
-       ret = media_entity_graph_walk_init(&graph, entity->graph_obj.mdev);
+       ret = media_graph_walk_init(&graph, mdev);
        if (ret) {
                mutex_unlock(&mdev->graph_mutex);
                return ret;
        }
 
-       media_entity_graph_walk_start(&graph, entity);
+       media_graph_walk_start(&graph, entity);
 
-       while ((entity = media_entity_graph_walk_next(&graph))) {
+       while ((entity = media_graph_walk_next(&graph))) {
                struct xvip_dma *dma;
 
                if (entity->function != MEDIA_ENT_F_IO_V4L)
@@ -213,7 +213,7 @@ static int xvip_pipeline_validate(struct xvip_pipeline *pipe,
 
        mutex_unlock(&mdev->graph_mutex);
 
-       media_entity_graph_walk_cleanup(&graph);
+       media_graph_walk_cleanup(&graph);
 
        /* We need exactly one output and zero or one input. */
        if (num_outputs != 1 || num_inputs > 1)
@@ -409,7 +409,7 @@ static int xvip_dma_start_streaming(struct vb2_queue *vq, unsigned int count)
        pipe = dma->video.entity.pipe
             ? to_xvip_pipeline(&dma->video.entity) : &dma->pipe;
 
-       ret = media_entity_pipeline_start(&dma->video.entity, &pipe->pipe);
+       ret = media_pipeline_start(&dma->video.entity, &pipe->pipe);
        if (ret < 0)
                goto error;
 
@@ -435,7 +435,7 @@ static int xvip_dma_start_streaming(struct vb2_queue *vq, unsigned int count)
        return 0;
 
 error_stop:
-       media_entity_pipeline_stop(&dma->video.entity);
+       media_pipeline_stop(&dma->video.entity);
 
 error:
        /* Give back all queued buffers to videobuf2. */
@@ -463,7 +463,7 @@ static void xvip_dma_stop_streaming(struct vb2_queue *vq)
 
        /* Cleanup the pipeline and mark it as being stopped. */
        xvip_pipeline_cleanup(pipe);
-       media_entity_pipeline_stop(&dma->video.entity);
+       media_pipeline_stop(&dma->video.entity);
 
        /* Give back all queued buffers to videobuf2. */
        spin_lock_irq(&dma->queued_lock);
index 2ec1f6c4b27421d81dae68f62a9221178b579d55..9c49d1d10bee572066e14d35151595a878f124d9 100644 (file)
@@ -460,21 +460,21 @@ static const struct v4l2_ctrl_ops xtpg_ctrl_ops = {
        .s_ctrl = xtpg_s_ctrl,
 };
 
-static struct v4l2_subdev_core_ops xtpg_core_ops = {
+static const struct v4l2_subdev_core_ops xtpg_core_ops = {
 };
 
-static struct v4l2_subdev_video_ops xtpg_video_ops = {
+static const struct v4l2_subdev_video_ops xtpg_video_ops = {
        .s_stream = xtpg_s_stream,
 };
 
-static struct v4l2_subdev_pad_ops xtpg_pad_ops = {
+static const struct v4l2_subdev_pad_ops xtpg_pad_ops = {
        .enum_mbus_code         = xvip_enum_mbus_code,
        .enum_frame_size        = xtpg_enum_frame_size,
        .get_fmt                = xtpg_get_format,
        .set_fmt                = xtpg_set_format,
 };
 
-static struct v4l2_subdev_ops xtpg_ops = {
+static const struct v4l2_subdev_ops xtpg_ops = {
        .core   = &xtpg_core_ops,
        .video  = &xtpg_video_ops,
        .pad    = &xtpg_pad_ops,
index 2262b8139ca1e39d779d73fa22927467623f4683..53bc8c0100357c56ee5e4c678c76414c34be20b9 100644 (file)
  * but WITHOUT 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
 */
 
 #include <linux/kernel.h>
index 82affaedf06778ad73d0d40fa1a87b0e621630cd..cbaf850f47912792c75e8b9fed8de4b9258816ba 100644 (file)
@@ -309,9 +309,7 @@ static void cadet_handler(unsigned long data)
        /*
         * Clean up and exit
         */
-       init_timer(&dev->readtimer);
-       dev->readtimer.function = cadet_handler;
-       dev->readtimer.data = data;
+       setup_timer(&dev->readtimer, cadet_handler, data);
        dev->readtimer.expires = jiffies + msecs_to_jiffies(50);
        add_timer(&dev->readtimer);
 }
@@ -320,9 +318,7 @@ static void cadet_start_rds(struct cadet *dev)
 {
        dev->rdsstat = 1;
        outb(0x80, dev->io);        /* Select RDS fifo */
-       init_timer(&dev->readtimer);
-       dev->readtimer.function = cadet_handler;
-       dev->readtimer.data = (unsigned long)dev;
+       setup_timer(&dev->readtimer, cadet_handler, (unsigned long)dev);
        dev->readtimer.expires = jiffies + msecs_to_jiffies(50);
        add_timer(&dev->readtimer);
 }
index c309ee45a08e1ba3d5a747a35badac7767c15dfa..7312e469e850e8bbb0d3e54f02356de7a96d953e 100644 (file)
  * WITHOUT 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 St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #include <linux/module.h>
index ba4c01f1bd0c275213a993d9574fb70e18be8600..bab414919cf0647d53ea4f83116f5cb907c22255 100644 (file)
  * WITHOUT 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 St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #ifndef _RADIO_ISA_H_
index 0c5d2db3b8282280cb2bdcb03af790a2f4ceb394..53a7c2e87762ae7eeb9c6cbb12489debe2a5f890 100644 (file)
  * but WITHOUT 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
  */
 
 /* kernel includes */
index b3000ef85ee715d0c500c2ae0bbb7dcc62073448..c2010a905a4727358666b98609f408faf191554a 100644 (file)
  * but WITHOUT 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
  */
 
 #include <linux/kernel.h>
index c2927fd12615d30e7a019db7bb681a95830505db..95c12532e87a2dcd1ea62412d9ece6b33c5cdf18 100644 (file)
  * but WITHOUT 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
  */
 
 /*
index 85667a95f003a053ecfeb9a2ad3254453b543d31..23971f5502a8514d883751f094a9e0ccf3a45775 100644 (file)
  * but WITHOUT 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
 */
 
 #include <linux/init.h>
index 0e65a85d52c6667dac78d175b365cfff17e9ec11..b50638ec5f09633f268434789faec47e406b4835 100644 (file)
  * but WITHOUT 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
  */
 
 #include <linux/init.h>
index a1930b300c06d3bf14811b43b161056b14f346ab..9db8331a0c758dd5f4b0e8618b4833d389c8ab3c 100644 (file)
  * 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
- *
  * History:
  * 2008-12-06   Fabio Belavenuto <belavenuto@gmail.com>
  *              initial code
index 83fe7ab358dfaa6eecc0013f0e3fb1036caeedb8..04ed1a5d117789bcc598e039144bf7168ed09d90 100644 (file)
  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *   GNU General Public License for more details.
  *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
  */
 
 #include <linux/delay.h>
index 4bd942526a1bb83a07344074df77e3bfdec8dde5..6b5af3c8457b57852e65b67834fc7442431f0473 100644 (file)
  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *   GNU General Public License for more details.
  *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
  */
 
 #include <linux/videodev2.h>
index a82eb9678d6c5379a8d029fff5e85a4f4464f048..fc4d9a73ab17fc6ce41c466a43e761c2d2ea9576 100644 (file)
  * but WITHOUT 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/io.h>
index 9ce4b12299b4bc8c907db084dbdb94709927c75f..7240223dc15abae5a9dd00cf6662beaec8e2f196 100644 (file)
  * but WITHOUT 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
  */
 
 #include <linux/delay.h>
index ba8e357ba0a2dc1d856f386e79a24eee0c85a3ef..bf9eced906db4d0185ec1e73e2500adaaf5b5f13 100644 (file)
  * but WITHOUT 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/module.h>
index 1d827adab7ebbbbf2ef9ed873fa55494344e4aa5..cd76facc22f5cffc8de8f450af2b3ce5f2c292fb 100644 (file)
  * but WITHOUT 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
  */
 
 
index 9b81969d76b57df9e0da4bf61f45cd0e04d00263..b3034f80163fb349d50dd7cd8da1b725741cc418 100644 (file)
  * but WITHOUT 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
  */
 
 
index 1add136d37a32f327f32a3f04f786ea39863b8ad..571f29a34bf81e23f35fedae5a10ec9a6bc50d5d 100644 (file)
  * but WITHOUT 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
  */
 
 
index 6c0ca900702e9762e8ed1ae1e7fc6c3bc8f718c3..7d2defd9d3991e921f55d57cc6bbfc560aa8c6d0 100644 (file)
  * but WITHOUT 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
  */
 
 
index 6c7597383ca2e0d54f8b71147e449afedb3c75ba..6f93ef1249a6a2ada6989de6dc8bad0743289c03 100644 (file)
  * but WITHOUT 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
  */
 
 #include <linux/kernel.h>
index bc2a8b5442ae3e7370f9854f55c963c18ba8680d..60f026a58076bb1f28f24fe109fc436d0ddea574 100644 (file)
  * but WITHOUT 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
  */
 
 #include <linux/completion.h>
index 9f879f0ec0ef2de7e516d5b77830583525259670..ed210f4c476aa1ac3604e087e7fdb5d5c667d2ec 100644 (file)
  * but WITHOUT 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/module.h>
index dd203de5de9597265178bd3d6d27c87dc6e25c7f..1ff2eec4ed52ec7d269c3bc05afa7ca9b3abf29e 100644 (file)
  *  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 _FM_DRV_H
index 4be07656fbc0c4223c90cb51857f758688c550bb..74a1b3ecb30a087955ec0b412df86bbb11e4a2ec 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
  */
 
 #include <linux/module.h>
index d9b9c6cf83b40fe9f9a973ec3de930b784cd5b4d..7f1514eb1c07349720ecb7ae2d380beffdc8b81a 100644 (file)
  *  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 _FMDRV_COMMON_H
index e7455f82fadcaa5133c6474f7be51d7cfc083c5f..f689adc831ceb0f2e7e8217cedfa7c525389cb44 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
  */
 
 #include "fmdrv.h"
index 23922188882fb83fa6c0e484b16dc48c8720d83a..f647c9bc796a6e7b9fc893b3acff9b951a225a86 100644 (file)
  *  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 _FMDRV_RX_H
index 839970b0f313522a31edfc0430f0d15652f47526..47ac19466ed2c37cb6c3589286c1a77c0a885a85 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
  */
 
 #include <linux/delay.h>
index 11ae2e4c2d033e586bfcda18db1754aa9462fe8b..95e4daf7ba43227ccd54ee329d90f8d99e88e0a1 100644 (file)
  *  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 _FMDRV_TX_H
index fb42f0fd0c1f0fbe65cd2b8401854411e387f2ef..71423f45c05c2f2c9eb966f7e1dab03ff5c01df5 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
  */
 
 #include <linux/export.h>
index 0ba79d745e2f42925325035f6d15211fefd92026..9babb4ab2fad44683778672026aed5698d16aa74 100644 (file)
  *  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 _FMDRV_V4L2_H
index 629e8ca15ab37ef4f42a3c32cc114269f7f95a07..d1d3fd00ed89664a2dab5d4b4bd8178f028ca913 100644 (file)
@@ -235,6 +235,17 @@ config IR_MESON
           To compile this driver as a module, choose M here: the
           module will be called meson-ir.
 
+config IR_MTK
+       tristate "Mediatek IR remote receiver"
+       depends on RC_CORE
+       depends on ARCH_MEDIATEK || COMPILE_TEST
+       ---help---
+          Say Y if you want to use the IR remote receiver available
+          on Mediatek SoCs.
+
+          To compile this driver as a module, choose M here: the
+          module will be called mtk-cir.
+
 config IR_NUVOTON
        tristate "Nuvoton w836x7hg Consumer Infrared Transceiver"
        depends on PNP
@@ -261,6 +272,15 @@ config IR_REDRAT3
           To compile this driver as a module, choose M here: the
           module will be called redrat3.
 
+config IR_SPI
+       tristate "SPI connected IR LED"
+       depends on SPI && LIRC
+       ---help---
+         Say Y if you want to use an IR LED connected through SPI bus.
+
+         To compile this driver as a module, choose M here: the module will be
+         called ir-spi.
+
 config IR_STREAMZAP
        tristate "Streamzap PC Remote IR Receiver"
        depends on USB_ARCH_HAS_HCD
@@ -336,7 +356,7 @@ config IR_TTUSBIR
 
 config IR_RX51
        tristate "Nokia N900 IR transmitter diode"
-       depends on OMAP_DM_TIMER && PWM_OMAP_DMTIMER && ARCH_OMAP2PLUS && LIRC
+       depends on (OMAP_DM_TIMER && PWM_OMAP_DMTIMER && ARCH_OMAP2PLUS || COMPILE_TEST) && RC_CORE
        ---help---
           Say Y or M here if you want to enable support for the IR
           transmitter diode built in the Nokia N900 (RX51) device.
index 3a984ee301e256c9e9e38c085980ce5cc8740384..679aa0af85cd65d30d4bba4b1216eafdfeab4d98 100644 (file)
@@ -27,6 +27,7 @@ obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o
 obj-$(CONFIG_IR_ENE) += ene_ir.o
 obj-$(CONFIG_IR_REDRAT3) += redrat3.o
 obj-$(CONFIG_IR_RX51) += ir-rx51.o
+obj-$(CONFIG_IR_SPI) += ir-spi.o
 obj-$(CONFIG_IR_STREAMZAP) += streamzap.o
 obj-$(CONFIG_IR_WINBOND_CIR) += winbond-cir.o
 obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o
@@ -38,3 +39,4 @@ obj-$(CONFIG_RC_ST) += st_rc.o
 obj-$(CONFIG_IR_SUNXI) += sunxi-cir.o
 obj-$(CONFIG_IR_IMG) += img-ir/
 obj-$(CONFIG_IR_SERIAL) += serial_ir.o
+obj-$(CONFIG_IR_MTK) += mtk-cir.o
index 0884b7dc0e71314c500172d04f268c78f05015c7..9cf3e69de16a4cde23dcc4c166089223beae5f53 100644 (file)
  * 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
- *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  *
  * Hardware & software notes
@@ -764,7 +760,6 @@ static void ati_remote_rc_init(struct ati_remote *ati_remote)
        struct rc_dev *rdev = ati_remote->rdev;
 
        rdev->priv = ati_remote;
-       rdev->driver_type = RC_DRIVER_SCANCODE;
        rdev->allowed_protocols = RC_BIT_OTHER;
        rdev->driver_name = "ati_remote";
 
@@ -851,7 +846,7 @@ static int ati_remote_probe(struct usb_interface *interface,
        }
 
        ati_remote = kzalloc(sizeof (struct ati_remote), GFP_KERNEL);
-       rc_dev = rc_allocate_device();
+       rc_dev = rc_allocate_device(RC_DRIVER_SCANCODE);
        if (!ati_remote || !rc_dev)
                goto exit_free_dev_rdev;
 
index bd5512e64aeadf08cd4ff9474fedfccb09468038..60da963f40dca448b0cab7269de5e11724fa6a03 100644 (file)
  * 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
- *
  * Special thanks to:
  *   Sami R. <maesesami@gmail.com> for lot of help in debugging and therefore
  *    bringing to life support for transmission & learning mode.
@@ -1012,7 +1007,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
 
        /* allocate memory */
        dev = kzalloc(sizeof(struct ene_device), GFP_KERNEL);
-       rdev = rc_allocate_device();
+       rdev = rc_allocate_device(RC_DRIVER_IR_RAW);
        if (!dev || !rdev)
                goto exit_free_dev_rdev;
 
@@ -1058,8 +1053,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
        if (!dev->hw_learning_and_tx_capable)
                learning_mode_force = false;
 
-       rdev->driver_type = RC_DRIVER_IR_RAW;
-       rdev->allowed_protocols = RC_BIT_ALL;
+       rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
        rdev->priv = dev;
        rdev->open = ene_open;
        rdev->close = ene_close;
index a7911e3b9bc07d4e887dadf8a41a76cf6e1275c5..494646b2a2844e0edb5dc3c670de07241c19c73e 100644 (file)
  * WITHOUT 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
  */
 #include <linux/spinlock.h>
 
index ecab69ea3d5157d3ef6bce57a742fa7d01d81073..0d3562712f273c968653b95aa5a0dc772a176391 100644 (file)
  * WITHOUT 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
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -492,7 +487,7 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id
                return ret;
 
        /* input device for IR remote (and tx) */
-       rdev = rc_allocate_device();
+       rdev = rc_allocate_device(RC_DRIVER_IR_RAW);
        if (!rdev)
                goto exit_free_dev_rdev;
 
@@ -534,8 +529,7 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id
 
        /* Set up the rc device */
        rdev->priv = fintek;
-       rdev->driver_type = RC_DRIVER_IR_RAW;
-       rdev->allowed_protocols = RC_BIT_ALL;
+       rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
        rdev->open = fintek_open;
        rdev->close = fintek_close;
        rdev->input_name = FINTEK_DESCRIPTION;
index b698f3d2ced938582a80aa9c8075add338921fb9..ac34a774d018343d16a48c9e3ea1e56b91b0cca6 100644 (file)
  * WITHOUT 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
  */
 
 #include <linux/spinlock.h>
index 5b63b1f15cb18b4431c872923b88d1cd2c0bf764..4a4895e4d5993afddf0ef667ced79b055f21035b 100644 (file)
@@ -143,14 +143,13 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
        if (!gpio_dev)
                return -ENOMEM;
 
-       rcdev = rc_allocate_device();
+       rcdev = rc_allocate_device(RC_DRIVER_IR_RAW);
        if (!rcdev) {
                rc = -ENOMEM;
                goto err_allocate_device;
        }
 
        rcdev->priv = gpio_dev;
-       rcdev->driver_type = RC_DRIVER_IR_RAW;
        rcdev->input_name = GPIO_IR_DEVICE_NAME;
        rcdev->input_phys = GPIO_IR_DEVICE_NAME "/input0";
        rcdev->input_id.bustype = BUS_HOST;
@@ -165,7 +164,7 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
        if (pdata->allowed_protos)
                rcdev->allowed_protocols = pdata->allowed_protos;
        else
-               rcdev->allowed_protocols = RC_BIT_ALL;
+               rcdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
        rcdev->map_name = pdata->map_name ?: RC_MAP_EMPTY;
 
        gpio_dev->rcdev = rcdev;
index 5cf983be07a207f896dc11621095e21ebd91c79a..0f0ed4ea4d06bd3e4671d3ee6070eda2d496abbe 100644 (file)
@@ -190,7 +190,7 @@ static int igorplugusb_probe(struct usb_interface *intf,
 
        usb_make_path(udev, ir->phys, sizeof(ir->phys));
 
-       rc = rc_allocate_device();
+       rc = rc_allocate_device(RC_DRIVER_IR_RAW);
        if (!rc)
                goto fail;
 
@@ -198,13 +198,12 @@ static int igorplugusb_probe(struct usb_interface *intf,
        rc->input_phys = ir->phys;
        usb_to_input_id(udev, &rc->input_id);
        rc->dev.parent = &intf->dev;
-       rc->driver_type = RC_DRIVER_IR_RAW;
        /*
         * This device can only store 36 pulses + spaces, which is not enough
         * for the NEC protocol and many others.
         */
-       rc->allowed_protocols = RC_BIT_ALL & ~(RC_BIT_NEC | RC_BIT_NECX |
-                       RC_BIT_NEC32 | RC_BIT_RC6_6A_20 |
+       rc->allowed_protocols = RC_BIT_ALL_IR_DECODER & ~(RC_BIT_NEC |
+                       RC_BIT_NECX | RC_BIT_NEC32 | RC_BIT_RC6_6A_20 |
                        RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE |
                        RC_BIT_SONY20 | RC_BIT_MCE_KBD | RC_BIT_SANYO);
 
index 5f634545ddd81c6e98887ed93a8fc2abb8a29f21..ccf24fd7ec1bbc65b16ece57979b2025182617df 100644 (file)
  * but WITHOUT 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
  */
 
 #include <linux/device.h>
@@ -431,7 +427,7 @@ static int iguanair_probe(struct usb_interface *intf,
        struct usb_host_interface *idesc;
 
        ir = kzalloc(sizeof(*ir), GFP_KERNEL);
-       rc = rc_allocate_device();
+       rc = rc_allocate_device(RC_DRIVER_IR_RAW);
        if (!ir || !rc) {
                ret = -ENOMEM;
                goto out;
@@ -494,8 +490,7 @@ static int iguanair_probe(struct usb_interface *intf,
        rc->input_phys = ir->phys;
        usb_to_input_id(ir->udev, &rc->input_id);
        rc->dev.parent = &intf->dev;
-       rc->driver_type = RC_DRIVER_IR_RAW;
-       rc->allowed_protocols = RC_BIT_ALL;
+       rc->allowed_protocols = RC_BIT_ALL_IR_DECODER;
        rc->priv = ir;
        rc->open = iguanair_open;
        rc->close = iguanair_close;
@@ -504,7 +499,9 @@ static int iguanair_probe(struct usb_interface *intf,
        rc->tx_ir = iguanair_tx;
        rc->driver_name = DRIVER_NAME;
        rc->map_name = RC_MAP_RC6_MCE;
-       rc->timeout = MS_TO_NS(100);
+       rc->min_timeout = 1;
+       rc->timeout = IR_DEFAULT_TIMEOUT;
+       rc->max_timeout = 10 * IR_DEFAULT_TIMEOUT;
        rc->rx_resolution = RX_RESOLUTION;
 
        iguanair_set_tx_carrier(rc, 38000);
index 7bb71bc9f534d525d48f9fd97a56e2e749685185..431d33b36fb03d97f1379c45952563be806ffbf4 100644 (file)
@@ -488,7 +488,15 @@ static int img_ir_set_filter(struct rc_dev *dev, enum rc_filter_type type,
        /* convert scancode filter to raw filter */
        filter.minlen = 0;
        filter.maxlen = ~0;
-       ret = hw->decoder->filter(sc_filter, &filter, hw->enabled_protocols);
+       if (type == RC_FILTER_NORMAL) {
+               /* guess scancode from protocol */
+               ret = hw->decoder->filter(sc_filter, &filter,
+                                         dev->enabled_protocols);
+       } else {
+               /* for wakeup user provided exact protocol variant */
+               ret = hw->decoder->filter(sc_filter, &filter,
+                                         1ULL << dev->wakeup_protocol);
+       }
        if (ret)
                goto unlock;
        dev_dbg(priv->dev, "IR raw %sfilter=%016llx & %016llx\n",
@@ -581,6 +589,7 @@ static void img_ir_set_decoder(struct img_ir_priv *priv,
        /* clear the wakeup scancode filter */
        rdev->scancode_wakeup_filter.data = 0;
        rdev->scancode_wakeup_filter.mask = 0;
+       rdev->wakeup_protocol = RC_TYPE_UNKNOWN;
 
        /* clear raw filters */
        _img_ir_set_filter(priv, NULL);
@@ -685,7 +694,6 @@ success:
        if (!hw->decoder || !hw->decoder->filter)
                wakeup_protocols = 0;
        rdev->allowed_wakeup_protocols = wakeup_protocols;
-       rdev->enabled_wakeup_protocols = wakeup_protocols;
        return 0;
 }
 
@@ -701,7 +709,6 @@ static void img_ir_set_protocol(struct img_ir_priv *priv, u64 proto)
        mutex_lock(&rdev->lock);
        rdev->enabled_protocols = proto;
        rdev->allowed_wakeup_protocols = proto;
-       rdev->enabled_wakeup_protocols = proto;
        mutex_unlock(&rdev->lock);
 }
 
@@ -1071,7 +1078,7 @@ int img_ir_probe_hw(struct img_ir_priv *priv)
        }
 
        /* Allocate hardware decoder */
-       hw->rdev = rdev = rc_allocate_device();
+       hw->rdev = rdev = rc_allocate_device(RC_DRIVER_SCANCODE);
        if (!rdev) {
                dev_err(priv->dev, "cannot allocate input device\n");
                error = -ENOMEM;
index 09314933ea0871127e027dd45fced708924fb34a..044fd42b22a090b34a5fb64cbd2df0cba50192bb 100644 (file)
@@ -11,6 +11,7 @@
 
 #include "img-ir-hw.h"
 #include <linux/bitrev.h>
+#include <linux/log2.h>
 
 /* Convert NEC data to a scancode */
 static int img_ir_nec_scancode(int len, u64 raw, u64 enabled_protocols,
@@ -62,7 +63,23 @@ static int img_ir_nec_filter(const struct rc_scancode_filter *in,
        data       = in->data & 0xff;
        data_m     = in->mask & 0xff;
 
-       if ((in->data | in->mask) & 0xff000000) {
+       protocols &= RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32;
+
+       /*
+        * If only one bit is set, we were requested to do an exact
+        * protocol. This should be the case for wakeup filters; for
+        * normal filters, guess the protocol from the scancode.
+        */
+       if (!is_power_of_2(protocols)) {
+               if ((in->data | in->mask) & 0xff000000)
+                       protocols = RC_BIT_NEC32;
+               else if ((in->data | in->mask) & 0x00ff0000)
+                       protocols = RC_BIT_NECX;
+               else
+                       protocols = RC_BIT_NEC;
+       }
+
+       if (protocols == RC_BIT_NEC32) {
                /* 32-bit NEC (used by Apple and TiVo remotes) */
                /* scan encoding: as transmitted, MSBit = first received bit */
                addr       = bitrev8(in->data >> 24);
@@ -73,7 +90,7 @@ static int img_ir_nec_filter(const struct rc_scancode_filter *in,
                data_m     = bitrev8(in->mask >>  8);
                data_inv   = bitrev8(in->data >>  0);
                data_inv_m = bitrev8(in->mask >>  0);
-       } else if ((in->data | in->mask) & 0x00ff0000) {
+       } else if (protocols == RC_BIT_NECX) {
                /* Extended NEC */
                /* scan encoding AAaaDD */
                addr       = (in->data >> 16) & 0xff;
index 33f37ed87ad2909e5b53e1a4083c99e46d70d68d..8d2f8e2006e7bdce9ade9bc9fd3cb144d4d84126 100644 (file)
@@ -110,7 +110,7 @@ int img_ir_probe_raw(struct img_ir_priv *priv)
        setup_timer(&raw->timer, img_ir_echo_timer, (unsigned long)priv);
 
        /* Allocate raw decoder */
-       raw->rdev = rdev = rc_allocate_device();
+       raw->rdev = rdev = rc_allocate_device(RC_DRIVER_IR_RAW);
        if (!rdev) {
                dev_err(priv->dev, "cannot allocate raw input device\n");
                return -ENOMEM;
@@ -118,7 +118,6 @@ int img_ir_probe_raw(struct img_ir_priv *priv)
        rdev->priv = priv;
        rdev->map_name = RC_MAP_EMPTY;
        rdev->input_name = "IMG Infrared Decoder Raw";
-       rdev->driver_type = RC_DRIVER_IR_RAW;
 
        /* Register raw decoder */
        error = rc_register_device(rdev);
index 7f7375f82ed60017f0dfe6c0517b7ec93ecd85bb..3fcba271a419f8582ded5ecffa29413c2cb9e89d 100644 (file)
@@ -68,19 +68,29 @@ static int img_ir_sony_filter(const struct rc_scancode_filter *in,
        func     = (in->data >> 0)  & 0x7f;
        func_m   = (in->mask >> 0)  & 0x7f;
 
-       if (subdev & subdev_m) {
+       protocols &= RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20;
+
+       /*
+        * If only one bit is set, we were requested to do an exact
+        * protocol. This should be the case for wakeup filters; for
+        * normal filters, guess the protocol from the scancode.
+        */
+       if (!is_power_of_2(protocols)) {
+               if (subdev & subdev_m)
+                       protocols = RC_BIT_SONY20;
+               else if (dev & dev_m & 0xe0)
+                       protocols = RC_BIT_SONY15;
+               else
+                       protocols = RC_BIT_SONY12;
+       }
+
+       if (protocols == RC_BIT_SONY20) {
                /* can't encode subdev and higher device bits */
                if (dev & dev_m & 0xe0)
                        return -EINVAL;
-               /* subdevice (extended) bits only in 20 bit encoding */
-               if (!(protocols & RC_BIT_SONY20))
-                       return -EINVAL;
                len = 20;
                dev_m &= 0x1f;
-       } else if (dev & dev_m & 0xe0) {
-               /* upper device bits only in 15 bit encoding */
-               if (!(protocols & RC_BIT_SONY15))
-                       return -EINVAL;
+       } else if (protocols == RC_BIT_SONY15) {
                len = 15;
                subdev_m = 0;
        } else {
index 0785a24af8fc4acca86e11b74b372b8d9af29dcd..89823d24a38441cf7e3bcaef11b4f623eb78d01d 100644 (file)
  *   but WITHOUT 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.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
@@ -96,6 +92,7 @@ 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[];
 };
 
@@ -126,6 +123,12 @@ 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 */
@@ -328,6 +331,10 @@ 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
  *
@@ -411,6 +418,18 @@ static 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},
        {}
 };
 
@@ -1577,8 +1596,91 @@ static int imon_parse_press_type(struct imon_context *ictx,
 /**
  * Process the incoming packet
  */
-static void imon_incoming_packet(struct imon_context *ictx,
+/**
+ * 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,
                                 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;
@@ -1761,7 +1863,10 @@ static void usb_rx_callback_intf0(struct urb *urb)
                break;
 
        case 0:
-               imon_incoming_packet(ictx, urb, intfnum);
+               if (ictx->rdev->driver_type == RC_DRIVER_IR_RAW)
+                       imon_incoming_ir_raw(ictx, urb, intfnum);
+               else
+                       imon_incoming_scancode(ictx, urb, intfnum);
                break;
 
        default:
@@ -1802,7 +1907,10 @@ static void usb_rx_callback_intf1(struct urb *urb)
                break;
 
        case 0:
-               imon_incoming_packet(ictx, urb, intfnum);
+               if (ictx->rdev->driver_type == RC_DRIVER_IR_RAW)
+                       imon_incoming_ir_raw(ictx, urb, intfnum);
+               else
+                       imon_incoming_scancode(ictx, urb, intfnum);
                break;
 
        default:
@@ -1910,11 +2018,14 @@ 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;
@@ -1939,7 +2050,8 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx)
        const unsigned char fp_packet[] = { 0x40, 0x00, 0x00, 0x00,
                                            0x00, 0x00, 0x00, 0x88 };
 
-       rdev = rc_allocate_device();
+       rdev = rc_allocate_device(ictx->dev_descr->flags & IMON_IR_RAW ?
+                                 RC_DRIVER_IR_RAW : RC_DRIVER_SCANCODE);
        if (!rdev) {
                dev_err(ictx->dev, "remote control dev allocation failed\n");
                goto out;
@@ -1957,8 +2069,11 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx)
        rdev->dev.parent = ictx->dev;
 
        rdev->priv = ictx;
-       rdev->driver_type = RC_DRIVER_SCANCODE;
-       rdev->allowed_protocols = RC_BIT_OTHER | RC_BIT_RC6_MCE; /* iMON PAD or MCE */
+       if (ictx->dev_descr->flags & IMON_IR_RAW)
+               rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
+       else
+               /* iMON PAD or MCE */
+               rdev->allowed_protocols = RC_BIT_OTHER | RC_BIT_RC6_MCE;
        rdev->change_protocol = imon_ir_change_protocol;
        rdev->driver_name = MOD_NAME;
 
@@ -1976,7 +2091,8 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx)
 
        imon_set_display_type(ictx);
 
-       if (ictx->rc_type == RC_BIT_RC6_MCE)
+       if (ictx->rc_type == RC_BIT_RC6_MCE ||
+           ictx->dev_descr->flags & IMON_IR_RAW)
                rdev->map_name = RC_MAP_IMON_MCE;
        else
                rdev->map_name = RC_MAP_IMON_PAD;
index d26907e684dc2ba7bcd1e0af846b573c7c4f055d..50951f68685275985515c49841c5402141db006f 100644 (file)
@@ -229,7 +229,7 @@ static int hix5hd2_ir_probe(struct platform_device *pdev)
                return priv->irq;
        }
 
-       rdev = rc_allocate_device();
+       rdev = rc_allocate_device(RC_DRIVER_IR_RAW);
        if (!rdev)
                return -ENOMEM;
 
@@ -242,8 +242,7 @@ static int hix5hd2_ir_probe(struct platform_device *pdev)
        clk_prepare_enable(priv->clock);
        priv->rate = clk_get_rate(priv->clock);
 
-       rdev->driver_type = RC_DRIVER_IR_RAW;
-       rdev->allowed_protocols = RC_BIT_ALL;
+       rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
        rdev->priv = priv;
        rdev->open = hix5hd2_ir_open;
        rdev->close = hix5hd2_ir_close;
index 182402f7b4d152ae8befc0255b36e32183d0118b..674bf156edcbd4faaa46a6c4d8032f5b6ce03f7e 100644 (file)
@@ -170,9 +170,48 @@ out:
        return -EINVAL;
 }
 
+static const struct ir_raw_timings_pd ir_jvc_timings = {
+       .header_pulse  = JVC_HEADER_PULSE,
+       .header_space  = JVC_HEADER_SPACE,
+       .bit_pulse     = JVC_BIT_PULSE,
+       .bit_space[0]  = JVC_BIT_0_SPACE,
+       .bit_space[1]  = JVC_BIT_1_SPACE,
+       .trailer_pulse = JVC_TRAILER_PULSE,
+       .trailer_space = JVC_TRAILER_SPACE,
+       .msb_first     = 1,
+};
+
+/**
+ * ir_jvc_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_jvc_encode(enum rc_type protocol, u32 scancode,
+                        struct ir_raw_event *events, unsigned int max)
+{
+       struct ir_raw_event *e = events;
+       int ret;
+       u32 raw = (bitrev8((scancode >> 8) & 0xff) << 8) |
+                 (bitrev8((scancode >> 0) & 0xff) << 0);
+
+       ret = ir_raw_gen_pd(&e, max, &ir_jvc_timings, JVC_NBITS, raw);
+       if (ret < 0)
+               return ret;
+
+       return e - events;
+}
+
 static struct ir_raw_handler jvc_handler = {
        .protocols      = RC_BIT_JVC,
        .decode         = ir_jvc_decode,
+       .encode         = ir_jvc_encode,
 };
 
 static int __init ir_jvc_decode_init(void)
index c3277308a70b449acd415f946b984e8c8a00901b..8517d5153fcf211606280e5eb4c83ea4837bc4fc 100644 (file)
@@ -204,11 +204,17 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
 
        /* legacy support */
        case LIRC_GET_SEND_MODE:
-               val = LIRC_CAN_SEND_PULSE & LIRC_CAN_SEND_MASK;
+               if (!dev->tx_ir)
+                       return -ENOTTY;
+
+               val = LIRC_MODE_PULSE;
                break;
 
        case LIRC_SET_SEND_MODE:
-               if (val != (LIRC_MODE_PULSE & LIRC_CAN_SEND_MASK))
+               if (!dev->tx_ir)
+                       return -ENOTTY;
+
+               if (val != LIRC_MODE_PULSE)
                        return -EINVAL;
                return 0;
 
@@ -273,7 +279,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
        case LIRC_GET_MIN_TIMEOUT:
                if (!dev->max_timeout)
                        return -ENOSYS;
-               val = dev->min_timeout / 1000;
+               val = DIV_ROUND_UP(dev->min_timeout, 1000);
                break;
 
        case LIRC_GET_MAX_TIMEOUT:
@@ -341,7 +347,7 @@ static int ir_lirc_register(struct rc_dev *dev)
        struct lirc_driver *drv;
        struct lirc_buffer *rbuf;
        int rc = -ENOMEM;
-       unsigned long features;
+       unsigned long features = 0;
 
        drv = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
        if (!drv)
@@ -355,7 +361,8 @@ static int ir_lirc_register(struct rc_dev *dev)
        if (rc)
                goto rbuf_init_failed;
 
-       features = LIRC_CAN_REC_MODE2;
+       if (dev->driver_type != RC_DRIVER_IR_RAW_TX)
+               features |= LIRC_CAN_REC_MODE2;
        if (dev->tx_ir) {
                features |= LIRC_CAN_SEND_PULSE;
                if (dev->s_tx_mask)
index d80986251ee025490ccd01082dfdf8767b5522c2..5226d510e84779f0dcf0cb47372fd0ddd6cee058 100644 (file)
@@ -71,7 +71,7 @@ static unsigned char kbd_keycodes[256] = {
        KEY_6,          KEY_7,          KEY_8,          KEY_9,          KEY_0,
        KEY_ENTER,      KEY_ESC,        KEY_BACKSPACE,  KEY_TAB,        KEY_SPACE,
        KEY_MINUS,      KEY_EQUAL,      KEY_LEFTBRACE,  KEY_RIGHTBRACE, KEY_BACKSLASH,
-       KEY_RESERVED,   KEY_SEMICOLON,  KEY_APOSTROPHE, KEY_GRAVE,      KEY_COMMA,
+       KEY_BACKSLASH,  KEY_SEMICOLON,  KEY_APOSTROPHE, KEY_GRAVE,      KEY_COMMA,
        KEY_DOT,        KEY_SLASH,      KEY_CAPSLOCK,   KEY_F1,         KEY_F2,
        KEY_F3,         KEY_F4,         KEY_F5,         KEY_F6,         KEY_F7,
        KEY_F8,         KEY_F9,         KEY_F10,        KEY_F11,        KEY_F12,
index 2a9d155548ab3a648ce24062b1e8c5d8f1764a0a..3ce850314dcadb54c1829649244763bcdc06d864 100644 (file)
@@ -170,7 +170,10 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
                if (send_32bits) {
                        /* NEC transport, but modified protocol, used by at
                         * least Apple and TiVo remotes */
-                       scancode = data->bits;
+                       scancode = not_address << 24 |
+                               address     << 16 |
+                               not_command <<  8 |
+                               command;
                        IR_dprintk(1, "NEC (modified) scancode 0x%08x\n", scancode);
                        rc_type = RC_TYPE_NEC32;
                } else if ((address ^ not_address) != 0xff) {
@@ -201,9 +204,90 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
        return -EINVAL;
 }
 
+/**
+ * ir_nec_scancode_to_raw() - encode an NEC scancode ready for modulation.
+ * @protocol:  specific protocol to use
+ * @scancode:  a single NEC scancode.
+ * @raw:       raw data to be modulated.
+ */
+static u32 ir_nec_scancode_to_raw(enum rc_type protocol, u32 scancode)
+{
+       unsigned int addr, addr_inv, data, data_inv;
+
+       data = scancode & 0xff;
+
+       if (protocol == RC_TYPE_NEC32) {
+               /* 32-bit NEC (used by Apple and TiVo remotes) */
+               /* scan encoding: aaAAddDD */
+               addr_inv   = (scancode >> 24) & 0xff;
+               addr       = (scancode >> 16) & 0xff;
+               data_inv   = (scancode >>  8) & 0xff;
+       } else if (protocol == RC_TYPE_NECX) {
+               /* Extended NEC */
+               /* scan encoding AAaaDD */
+               addr       = (scancode >> 16) & 0xff;
+               addr_inv   = (scancode >>  8) & 0xff;
+               data_inv   = data ^ 0xff;
+       } else {
+               /* Normal NEC */
+               /* scan encoding: AADD */
+               addr       = (scancode >>  8) & 0xff;
+               addr_inv   = addr ^ 0xff;
+               data_inv   = data ^ 0xff;
+       }
+
+       /* raw encoding: ddDDaaAA */
+       return data_inv << 24 |
+              data     << 16 |
+              addr_inv <<  8 |
+              addr;
+}
+
+static const struct ir_raw_timings_pd ir_nec_timings = {
+       .header_pulse   = NEC_HEADER_PULSE,
+       .header_space   = NEC_HEADER_SPACE,
+       .bit_pulse      = NEC_BIT_PULSE,
+       .bit_space[0]   = NEC_BIT_0_SPACE,
+       .bit_space[1]   = NEC_BIT_1_SPACE,
+       .trailer_pulse  = NEC_TRAILER_PULSE,
+       .trailer_space  = NEC_TRAILER_SPACE,
+       .msb_first      = 0,
+};
+
+/**
+ * ir_nec_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_nec_encode(enum rc_type protocol, u32 scancode,
+                        struct ir_raw_event *events, unsigned int max)
+{
+       struct ir_raw_event *e = events;
+       int ret;
+       u32 raw;
+
+       /* Convert a NEC scancode to raw NEC data */
+       raw = ir_nec_scancode_to_raw(protocol, scancode);
+
+       /* Modulate the raw data using a pulse distance modulation */
+       ret = ir_raw_gen_pd(&e, max, &ir_nec_timings, NEC_NBITS, raw);
+       if (ret < 0)
+               return ret;
+
+       return e - events;
+}
+
 static struct ir_raw_handler nec_handler = {
        .protocols      = RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32,
        .decode         = ir_nec_decode,
+       .encode         = ir_nec_encode,
 };
 
 static int __init ir_nec_decode_init(void)
index a0fd4e6b2155b81e0605e58db2225d70cdf54fc1..fcfedf95def72a3dc9ffdd70d2a025210b8ea26f 100644 (file)
@@ -124,7 +124,7 @@ again:
                if (data->is_rc5x && data->count == RC5X_NBITS) {
                        /* RC5X */
                        u8 xdata, command, system;
-                       if (!(dev->enabled_protocols & RC_BIT_RC5X)) {
+                       if (!(dev->enabled_protocols & RC_BIT_RC5X_20)) {
                                data->state = STATE_INACTIVE;
                                return 0;
                        }
@@ -132,9 +132,9 @@ again:
                        command  = (data->bits & 0x00FC0) >> 6;
                        system   = (data->bits & 0x1F000) >> 12;
                        toggle   = (data->bits & 0x20000) ? 1 : 0;
-                       command += (data->bits & 0x01000) ? 0 : 0x40;
+                       command += (data->bits & 0x40000) ? 0 : 0x40;
                        scancode = system << 16 | command << 8 | xdata;
-                       protocol = RC_TYPE_RC5X;
+                       protocol = RC_TYPE_RC5X_20;
 
                } else if (!data->is_rc5x && data->count == RC5_NBITS) {
                        /* RC5 */
@@ -181,9 +181,106 @@ out:
        return -EINVAL;
 }
 
+static const struct ir_raw_timings_manchester ir_rc5_timings = {
+       .leader                 = RC5_UNIT,
+       .pulse_space_start      = 0,
+       .clock                  = RC5_UNIT,
+       .trailer_space          = RC5_UNIT * 10,
+};
+
+static const struct ir_raw_timings_manchester ir_rc5x_timings[2] = {
+       {
+               .leader                 = RC5_UNIT,
+               .pulse_space_start      = 0,
+               .clock                  = RC5_UNIT,
+               .trailer_space          = RC5X_SPACE,
+       },
+       {
+               .clock                  = RC5_UNIT,
+               .trailer_space          = RC5_UNIT * 10,
+       },
+};
+
+static const struct ir_raw_timings_manchester ir_rc5_sz_timings = {
+       .leader                         = RC5_UNIT,
+       .pulse_space_start              = 0,
+       .clock                          = RC5_UNIT,
+       .trailer_space                  = RC5_UNIT * 10,
+};
+
+/**
+ * ir_rc5_encode() - Encode a scancode as a stream of raw events
+ *
+ * @protocol:  protocol variant 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.
+ *             -EINVAL if the scancode is ambiguous or invalid.
+ */
+static int ir_rc5_encode(enum rc_type protocol, u32 scancode,
+                        struct ir_raw_event *events, unsigned int max)
+{
+       int ret;
+       struct ir_raw_event *e = events;
+       unsigned int data, xdata, command, commandx, system, pre_space_data;
+
+       /* Detect protocol and convert scancode to raw data */
+       if (protocol == RC_TYPE_RC5) {
+               /* decode scancode */
+               command  = (scancode & 0x003f) >> 0;
+               commandx = (scancode & 0x0040) >> 6;
+               system   = (scancode & 0x1f00) >> 8;
+               /* encode data */
+               data = !commandx << 12 | system << 6 | command;
+
+               /* Modulate the data */
+               ret = ir_raw_gen_manchester(&e, max, &ir_rc5_timings,
+                                           RC5_NBITS, data);
+               if (ret < 0)
+                       return ret;
+       } else if (protocol == RC_TYPE_RC5X_20) {
+               /* decode scancode */
+               xdata    = (scancode & 0x00003f) >> 0;
+               command  = (scancode & 0x003f00) >> 8;
+               commandx = !(scancode & 0x004000);
+               system   = (scancode & 0x1f0000) >> 16;
+
+               /* encode data */
+               data = commandx << 18 | system << 12 | command << 6 | xdata;
+
+               /* Modulate the data */
+               pre_space_data = data >> (RC5X_NBITS - CHECK_RC5X_NBITS);
+               ret = ir_raw_gen_manchester(&e, max, &ir_rc5x_timings[0],
+                                           CHECK_RC5X_NBITS, pre_space_data);
+               if (ret < 0)
+                       return ret;
+               ret = ir_raw_gen_manchester(&e, max - (e - events),
+                                           &ir_rc5x_timings[1],
+                                           RC5X_NBITS - CHECK_RC5X_NBITS,
+                                           data);
+               if (ret < 0)
+                       return ret;
+       } else if (protocol == RC_TYPE_RC5_SZ) {
+               /* RC5-SZ scancode is raw enough for Manchester as it is */
+               ret = ir_raw_gen_manchester(&e, max, &ir_rc5_sz_timings,
+                                           RC5_SZ_NBITS, scancode & 0x2fff);
+               if (ret < 0)
+                       return ret;
+       } else {
+               return -EINVAL;
+       }
+
+       return e - events;
+}
+
 static struct ir_raw_handler rc5_handler = {
-       .protocols      = RC_BIT_RC5 | RC_BIT_RC5X | RC_BIT_RC5_SZ,
+       .protocols      = RC_BIT_RC5 | RC_BIT_RC5X_20 | RC_BIT_RC5_SZ,
        .decode         = ir_rc5_decode,
+       .encode         = ir_rc5_encode,
 };
 
 static int __init ir_rc5_decode_init(void)
index 5cc54c967a80dd8ad29eb3eb50db437568bd073c..6fe2268dada0c938dcd8eaf82ee1edc8ee032a31 100644 (file)
@@ -286,11 +286,128 @@ out:
        return -EINVAL;
 }
 
+static const struct ir_raw_timings_manchester ir_rc6_timings[4] = {
+       {
+               .leader                 = RC6_PREFIX_PULSE,
+               .pulse_space_start      = 0,
+               .clock                  = RC6_UNIT,
+               .invert                 = 1,
+               .trailer_space          = RC6_PREFIX_SPACE,
+       },
+       {
+               .clock                  = RC6_UNIT,
+               .invert                 = 1,
+       },
+       {
+               .clock                  = RC6_UNIT * 2,
+               .invert                 = 1,
+       },
+       {
+               .clock                  = RC6_UNIT,
+               .invert                 = 1,
+               .trailer_space          = RC6_SUFFIX_SPACE,
+       },
+};
+
+/**
+ * ir_rc6_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.
+ *             -EINVAL if the scancode is ambiguous or invalid.
+ */
+static int ir_rc6_encode(enum rc_type protocol, u32 scancode,
+                        struct ir_raw_event *events, unsigned int max)
+{
+       int ret;
+       struct ir_raw_event *e = events;
+
+       if (protocol == RC_TYPE_RC6_0) {
+               /* Modulate the preamble */
+               ret = ir_raw_gen_manchester(&e, max, &ir_rc6_timings[0], 0, 0);
+               if (ret < 0)
+                       return ret;
+
+               /* Modulate the header (Start Bit & Mode-0) */
+               ret = ir_raw_gen_manchester(&e, max - (e - events),
+                                           &ir_rc6_timings[1],
+                                           RC6_HEADER_NBITS, (1 << 3));
+               if (ret < 0)
+                       return ret;
+
+               /* Modulate Trailer Bit */
+               ret = ir_raw_gen_manchester(&e, max - (e - events),
+                                           &ir_rc6_timings[2], 1, 0);
+               if (ret < 0)
+                       return ret;
+
+               /* Modulate rest of the data */
+               ret = ir_raw_gen_manchester(&e, max - (e - events),
+                                           &ir_rc6_timings[3], RC6_0_NBITS,
+                                           scancode);
+               if (ret < 0)
+                       return ret;
+
+       } else {
+               int bits;
+
+               switch (protocol) {
+               case RC_TYPE_RC6_MCE:
+               case RC_TYPE_RC6_6A_32:
+                       bits = 32;
+                       break;
+               case RC_TYPE_RC6_6A_24:
+                       bits = 24;
+                       break;
+               case RC_TYPE_RC6_6A_20:
+                       bits = 20;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               /* Modulate the preamble */
+               ret = ir_raw_gen_manchester(&e, max, &ir_rc6_timings[0], 0, 0);
+               if (ret < 0)
+                       return ret;
+
+               /* Modulate the header (Start Bit & Header-version 6 */
+               ret = ir_raw_gen_manchester(&e, max - (e - events),
+                                           &ir_rc6_timings[1],
+                                           RC6_HEADER_NBITS, (1 << 3 | 6));
+               if (ret < 0)
+                       return ret;
+
+               /* Modulate Trailer Bit */
+               ret = ir_raw_gen_manchester(&e, max - (e - events),
+                                           &ir_rc6_timings[2], 1, 0);
+               if (ret < 0)
+                       return ret;
+
+               /* Modulate rest of the data */
+               ret = ir_raw_gen_manchester(&e, max - (e - events),
+                                           &ir_rc6_timings[3],
+                                           bits,
+                                           scancode);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return e - events;
+}
+
 static struct ir_raw_handler rc6_handler = {
        .protocols      = RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 |
                          RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 |
                          RC_BIT_RC6_MCE,
        .decode         = ir_rc6_decode,
+       .encode         = ir_rc6_encode,
 };
 
 static int __init ir_rc6_decode_init(void)
index e6efa8c267a062b0aa28b7912e0999ac57ce7e9a..49265f02e772b471b9c3bbb7b49af03bc2dc21d1 100644 (file)
  */
 #include <linux/clk.h>
 #include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/uaccess.h>
 #include <linux/platform_device.h>
-#include <linux/sched.h>
 #include <linux/wait.h>
 #include <linux/pwm.h>
 #include <linux/of.h>
 #include <linux/hrtimer.h>
 
-#include <media/lirc.h>
-#include <media/lirc_dev.h>
+#include <media/rc-core.h>
 #include <linux/platform_data/media/ir-rx51.h>
 
-#define LIRC_RX51_DRIVER_FEATURES (LIRC_CAN_SET_SEND_DUTY_CYCLE |      \
-                                  LIRC_CAN_SET_SEND_CARRIER |          \
-                                  LIRC_CAN_SEND_PULSE)
-
-#define DRIVER_NAME "lirc_rx51"
-
 #define WBUF_LEN 256
 
-struct lirc_rx51 {
+struct ir_rx51 {
+       struct rc_dev *rcdev;
        struct pwm_device *pwm;
        struct hrtimer timer;
        struct device        *dev;
-       struct lirc_rx51_platform_data *pdata;
+       struct ir_rx51_platform_data *pdata;
        wait_queue_head_t     wqueue;
 
        unsigned int    freq;           /* carrier frequency */
@@ -50,38 +41,37 @@ struct lirc_rx51 {
        unsigned long   device_is_open;
 };
 
-static inline void lirc_rx51_on(struct lirc_rx51 *lirc_rx51)
+static inline void ir_rx51_on(struct ir_rx51 *ir_rx51)
 {
-       pwm_enable(lirc_rx51->pwm);
+       pwm_enable(ir_rx51->pwm);
 }
 
-static inline void lirc_rx51_off(struct lirc_rx51 *lirc_rx51)
+static inline void ir_rx51_off(struct ir_rx51 *ir_rx51)
 {
-       pwm_disable(lirc_rx51->pwm);
+       pwm_disable(ir_rx51->pwm);
 }
 
-static int init_timing_params(struct lirc_rx51 *lirc_rx51)
+static int init_timing_params(struct ir_rx51 *ir_rx51)
 {
-       struct pwm_device *pwm = lirc_rx51->pwm;
-       int duty, period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, lirc_rx51->freq);
+       struct pwm_device *pwm = ir_rx51->pwm;
+       int duty, period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, ir_rx51->freq);
 
-       duty = DIV_ROUND_CLOSEST(lirc_rx51->duty_cycle * period, 100);
+       duty = DIV_ROUND_CLOSEST(ir_rx51->duty_cycle * period, 100);
 
        pwm_config(pwm, duty, period);
 
        return 0;
 }
 
-static enum hrtimer_restart lirc_rx51_timer_cb(struct hrtimer *timer)
+static enum hrtimer_restart ir_rx51_timer_cb(struct hrtimer *timer)
 {
-       struct lirc_rx51 *lirc_rx51 =
-                       container_of(timer, struct lirc_rx51, timer);
+       struct ir_rx51 *ir_rx51 = container_of(timer, struct ir_rx51, timer);
        ktime_t now;
 
-       if (lirc_rx51->wbuf_index < 0) {
-               dev_err_ratelimited(lirc_rx51->dev,
-                               "BUG wbuf_index has value of %i\n",
-                               lirc_rx51->wbuf_index);
+       if (ir_rx51->wbuf_index < 0) {
+               dev_err_ratelimited(ir_rx51->dev,
+                                   "BUG wbuf_index has value of %i\n",
+                                   ir_rx51->wbuf_index);
                goto end;
        }
 
@@ -92,20 +82,20 @@ static enum hrtimer_restart lirc_rx51_timer_cb(struct hrtimer *timer)
        do {
                u64 ns;
 
-               if (lirc_rx51->wbuf_index >= WBUF_LEN)
+               if (ir_rx51->wbuf_index >= WBUF_LEN)
                        goto end;
-               if (lirc_rx51->wbuf[lirc_rx51->wbuf_index] == -1)
+               if (ir_rx51->wbuf[ir_rx51->wbuf_index] == -1)
                        goto end;
 
-               if (lirc_rx51->wbuf_index % 2)
-                       lirc_rx51_off(lirc_rx51);
+               if (ir_rx51->wbuf_index % 2)
+                       ir_rx51_off(ir_rx51);
                else
-                       lirc_rx51_on(lirc_rx51);
+                       ir_rx51_on(ir_rx51);
 
-               ns = 1000 * lirc_rx51->wbuf[lirc_rx51->wbuf_index];
+               ns = US_TO_NS(ir_rx51->wbuf[ir_rx51->wbuf_index]);
                hrtimer_add_expires_ns(timer, ns);
 
-               lirc_rx51->wbuf_index++;
+               ir_rx51->wbuf_index++;
 
                now = timer->base->get_time();
 
@@ -114,203 +104,112 @@ static enum hrtimer_restart lirc_rx51_timer_cb(struct hrtimer *timer)
        return HRTIMER_RESTART;
 end:
        /* Stop TX here */
-       lirc_rx51_off(lirc_rx51);
-       lirc_rx51->wbuf_index = -1;
+       ir_rx51_off(ir_rx51);
+       ir_rx51->wbuf_index = -1;
 
-       wake_up_interruptible(&lirc_rx51->wqueue);
+       wake_up_interruptible(&ir_rx51->wqueue);
 
        return HRTIMER_NORESTART;
 }
 
-static ssize_t lirc_rx51_write(struct file *file, const char *buf,
-                         size_t n, loff_t *ppos)
+static int ir_rx51_tx(struct rc_dev *dev, unsigned int *buffer,
+                     unsigned int count)
 {
-       int count, i;
-       struct lirc_rx51 *lirc_rx51 = file->private_data;
+       struct ir_rx51 *ir_rx51 = dev->priv;
 
-       if (n % sizeof(int))
+       if (count > WBUF_LEN)
                return -EINVAL;
 
-       count = n / sizeof(int);
-       if ((count > WBUF_LEN) || (count % 2 == 0))
-               return -EINVAL;
+       memcpy(ir_rx51->wbuf, buffer, count * sizeof(unsigned int));
 
        /* Wait any pending transfers to finish */
-       wait_event_interruptible(lirc_rx51->wqueue, lirc_rx51->wbuf_index < 0);
-
-       if (copy_from_user(lirc_rx51->wbuf, buf, n))
-               return -EFAULT;
-
-       /* Sanity check the input pulses */
-       for (i = 0; i < count; i++)
-               if (lirc_rx51->wbuf[i] < 0)
-                       return -EINVAL;
+       wait_event_interruptible(ir_rx51->wqueue, ir_rx51->wbuf_index < 0);
 
-       init_timing_params(lirc_rx51);
+       init_timing_params(ir_rx51);
        if (count < WBUF_LEN)
-               lirc_rx51->wbuf[count] = -1; /* Insert termination mark */
+               ir_rx51->wbuf[count] = -1; /* Insert termination mark */
 
        /*
         * Adjust latency requirements so the device doesn't go in too
         * deep sleep states
         */
-       lirc_rx51->pdata->set_max_mpu_wakeup_lat(lirc_rx51->dev, 50);
+       ir_rx51->pdata->set_max_mpu_wakeup_lat(ir_rx51->dev, 50);
 
-       lirc_rx51_on(lirc_rx51);
-       lirc_rx51->wbuf_index = 1;
-       hrtimer_start(&lirc_rx51->timer,
-                     ns_to_ktime(1000 * lirc_rx51->wbuf[0]),
+       ir_rx51_on(ir_rx51);
+       ir_rx51->wbuf_index = 1;
+       hrtimer_start(&ir_rx51->timer,
+                     ns_to_ktime(US_TO_NS(ir_rx51->wbuf[0])),
                      HRTIMER_MODE_REL);
        /*
         * Don't return back to the userspace until the transfer has
         * finished
         */
-       wait_event_interruptible(lirc_rx51->wqueue, lirc_rx51->wbuf_index < 0);
+       wait_event_interruptible(ir_rx51->wqueue, ir_rx51->wbuf_index < 0);
 
        /* We can sleep again */
-       lirc_rx51->pdata->set_max_mpu_wakeup_lat(lirc_rx51->dev, -1);
+       ir_rx51->pdata->set_max_mpu_wakeup_lat(ir_rx51->dev, -1);
 
-       return n;
+       return count;
 }
 
-static long lirc_rx51_ioctl(struct file *filep,
-                       unsigned int cmd, unsigned long arg)
+static int ir_rx51_open(struct rc_dev *dev)
 {
-       int result;
-       unsigned long value;
-       unsigned int ivalue;
-       struct lirc_rx51 *lirc_rx51 = filep->private_data;
-
-       switch (cmd) {
-       case LIRC_GET_SEND_MODE:
-               result = put_user(LIRC_MODE_PULSE, (unsigned long *)arg);
-               if (result)
-                       return result;
-               break;
-
-       case LIRC_SET_SEND_MODE:
-               result = get_user(value, (unsigned long *)arg);
-               if (result)
-                       return result;
-
-               /* only LIRC_MODE_PULSE supported */
-               if (value != LIRC_MODE_PULSE)
-                       return -ENOSYS;
-               break;
-
-       case LIRC_GET_REC_MODE:
-               result = put_user(0, (unsigned long *) arg);
-               if (result)
-                       return result;
-               break;
-
-       case LIRC_GET_LENGTH:
-               return -ENOSYS;
-               break;
-
-       case LIRC_SET_SEND_DUTY_CYCLE:
-               result = get_user(ivalue, (unsigned int *) arg);
-               if (result)
-                       return result;
-
-               if (ivalue <= 0 || ivalue > 100) {
-                       dev_err(lirc_rx51->dev, ": invalid duty cycle %d\n",
-                               ivalue);
-                       return -EINVAL;
-               }
-
-               lirc_rx51->duty_cycle = ivalue;
-               break;
-
-       case LIRC_SET_SEND_CARRIER:
-               result = get_user(ivalue, (unsigned int *) arg);
-               if (result)
-                       return result;
-
-               if (ivalue > 500000 || ivalue < 20000) {
-                       dev_err(lirc_rx51->dev, ": invalid carrier freq %d\n",
-                               ivalue);
-                       return -EINVAL;
-               }
-
-               lirc_rx51->freq = ivalue;
-               break;
-
-       case LIRC_GET_FEATURES:
-               result = put_user(LIRC_RX51_DRIVER_FEATURES,
-                                 (unsigned long *) arg);
-               if (result)
-                       return result;
-               break;
-
-       default:
-               return -ENOIOCTLCMD;
-       }
-
-       return 0;
-}
+       struct ir_rx51 *ir_rx51 = dev->priv;
 
-static int lirc_rx51_open(struct inode *inode, struct file *file)
-{
-       struct lirc_rx51 *lirc_rx51 = lirc_get_pdata(file);
-       BUG_ON(!lirc_rx51);
-
-       file->private_data = lirc_rx51;
-
-       if (test_and_set_bit(1, &lirc_rx51->device_is_open))
+       if (test_and_set_bit(1, &ir_rx51->device_is_open))
                return -EBUSY;
 
-       lirc_rx51->pwm = pwm_get(lirc_rx51->dev, NULL);
-       if (IS_ERR(lirc_rx51->pwm)) {
-               int res = PTR_ERR(lirc_rx51->pwm);
+       ir_rx51->pwm = pwm_get(ir_rx51->dev, NULL);
+       if (IS_ERR(ir_rx51->pwm)) {
+               int res = PTR_ERR(ir_rx51->pwm);
 
-               dev_err(lirc_rx51->dev, "pwm_get failed: %d\n", res);
+               dev_err(ir_rx51->dev, "pwm_get failed: %d\n", res);
                return res;
        }
 
        return 0;
 }
 
-static int lirc_rx51_release(struct inode *inode, struct file *file)
+static void ir_rx51_release(struct rc_dev *dev)
 {
-       struct lirc_rx51 *lirc_rx51 = file->private_data;
-
-       hrtimer_cancel(&lirc_rx51->timer);
-       lirc_rx51_off(lirc_rx51);
-       pwm_put(lirc_rx51->pwm);
+       struct ir_rx51 *ir_rx51 = dev->priv;
 
-       clear_bit(1, &lirc_rx51->device_is_open);
+       hrtimer_cancel(&ir_rx51->timer);
+       ir_rx51_off(ir_rx51);
+       pwm_put(ir_rx51->pwm);
 
-       return 0;
+       clear_bit(1, &ir_rx51->device_is_open);
 }
 
-static struct lirc_rx51 lirc_rx51 = {
+static struct ir_rx51 ir_rx51 = {
        .duty_cycle     = 50,
        .wbuf_index     = -1,
 };
 
-static const struct file_operations lirc_fops = {
-       .owner          = THIS_MODULE,
-       .write          = lirc_rx51_write,
-       .unlocked_ioctl = lirc_rx51_ioctl,
-       .read           = lirc_dev_fop_read,
-       .poll           = lirc_dev_fop_poll,
-       .open           = lirc_rx51_open,
-       .release        = lirc_rx51_release,
-};
+static int ir_rx51_set_duty_cycle(struct rc_dev *dev, u32 duty)
+{
+       struct ir_rx51 *ir_rx51 = dev->priv;
 
-static struct lirc_driver lirc_rx51_driver = {
-       .name           = DRIVER_NAME,
-       .minor          = -1,
-       .code_length    = 1,
-       .data           = &lirc_rx51,
-       .fops           = &lirc_fops,
-       .owner          = THIS_MODULE,
-};
+       ir_rx51->duty_cycle = duty;
+
+       return 0;
+}
+
+static int ir_rx51_set_tx_carrier(struct rc_dev *dev, u32 carrier)
+{
+       struct ir_rx51 *ir_rx51 = dev->priv;
+
+       if (carrier > 500000 || carrier < 20000)
+               return -EINVAL;
+
+       ir_rx51->freq = carrier;
+
+       return 0;
+}
 
 #ifdef CONFIG_PM
 
-static int lirc_rx51_suspend(struct platform_device *dev, pm_message_t state)
+static int ir_rx51_suspend(struct platform_device *dev, pm_message_t state)
 {
        /*
         * In case the device is still open, do not suspend. Normally
@@ -320,34 +219,34 @@ static int lirc_rx51_suspend(struct platform_device *dev, pm_message_t state)
         * were in a middle of a transmit. Thus, we defer any suspend
         * actions until transmit has completed.
         */
-       if (test_and_set_bit(1, &lirc_rx51.device_is_open))
+       if (test_and_set_bit(1, &ir_rx51.device_is_open))
                return -EAGAIN;
 
-       clear_bit(1, &lirc_rx51.device_is_open);
+       clear_bit(1, &ir_rx51.device_is_open);
 
        return 0;
 }
 
-static int lirc_rx51_resume(struct platform_device *dev)
+static int ir_rx51_resume(struct platform_device *dev)
 {
        return 0;
 }
 
 #else
 
-#define lirc_rx51_suspend      NULL
-#define lirc_rx51_resume       NULL
+#define ir_rx51_suspend        NULL
+#define ir_rx51_resume NULL
 
 #endif /* CONFIG_PM */
 
-static int lirc_rx51_probe(struct platform_device *dev)
+static int ir_rx51_probe(struct platform_device *dev)
 {
        struct pwm_device *pwm;
+       struct rc_dev *rcdev;
 
-       lirc_rx51_driver.features = LIRC_RX51_DRIVER_FEATURES;
-       lirc_rx51.pdata = dev->dev.platform_data;
+       ir_rx51.pdata = dev->dev.platform_data;
 
-       if (!lirc_rx51.pdata) {
+       if (!ir_rx51.pdata) {
                dev_err(&dev->dev, "Platform Data is missing\n");
                return -ENXIO;
        }
@@ -362,51 +261,56 @@ static int lirc_rx51_probe(struct platform_device *dev)
        }
 
        /* Use default, in case userspace does not set the carrier */
-       lirc_rx51.freq = DIV_ROUND_CLOSEST(pwm_get_period(pwm), NSEC_PER_SEC);
+       ir_rx51.freq = DIV_ROUND_CLOSEST(pwm_get_period(pwm), NSEC_PER_SEC);
        pwm_put(pwm);
 
-       hrtimer_init(&lirc_rx51.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-       lirc_rx51.timer.function = lirc_rx51_timer_cb;
+       hrtimer_init(&ir_rx51.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+       ir_rx51.timer.function = ir_rx51_timer_cb;
 
-       lirc_rx51.dev = &dev->dev;
-       lirc_rx51_driver.dev = &dev->dev;
-       lirc_rx51_driver.minor = lirc_register_driver(&lirc_rx51_driver);
-       init_waitqueue_head(&lirc_rx51.wqueue);
+       ir_rx51.dev = &dev->dev;
 
-       if (lirc_rx51_driver.minor < 0) {
-               dev_err(lirc_rx51.dev, ": lirc_register_driver failed: %d\n",
-                      lirc_rx51_driver.minor);
-               return lirc_rx51_driver.minor;
-       }
+       rcdev = devm_rc_allocate_device(&dev->dev, RC_DRIVER_IR_RAW_TX);
+       if (!rcdev)
+               return -ENOMEM;
 
-       return 0;
+       rcdev->priv = &ir_rx51;
+       rcdev->open = ir_rx51_open;
+       rcdev->close = ir_rx51_release;
+       rcdev->tx_ir = ir_rx51_tx;
+       rcdev->s_tx_duty_cycle = ir_rx51_set_duty_cycle;
+       rcdev->s_tx_carrier = ir_rx51_set_tx_carrier;
+       rcdev->driver_name = KBUILD_MODNAME;
+
+       ir_rx51.rcdev = rcdev;
+
+       return devm_rc_register_device(&dev->dev, ir_rx51.rcdev);
 }
 
-static int lirc_rx51_remove(struct platform_device *dev)
+static int ir_rx51_remove(struct platform_device *dev)
 {
-       return lirc_unregister_driver(lirc_rx51_driver.minor);
+       return 0;
 }
 
-static const struct of_device_id lirc_rx51_match[] = {
+static const struct of_device_id ir_rx51_match[] = {
        {
                .compatible = "nokia,n900-ir",
        },
        {},
 };
-MODULE_DEVICE_TABLE(of, lirc_rx51_match);
+MODULE_DEVICE_TABLE(of, ir_rx51_match);
 
-struct platform_driver lirc_rx51_platform_driver = {
-       .probe          = lirc_rx51_probe,
-       .remove         = lirc_rx51_remove,
-       .suspend        = lirc_rx51_suspend,
-       .resume         = lirc_rx51_resume,
+static struct platform_driver ir_rx51_platform_driver = {
+       .probe          = ir_rx51_probe,
+       .remove         = ir_rx51_remove,
+       .suspend        = ir_rx51_suspend,
+       .resume         = ir_rx51_resume,
        .driver         = {
-               .name   = DRIVER_NAME,
-               .of_match_table = of_match_ptr(lirc_rx51_match),
+               .name   = KBUILD_MODNAME,
+               .of_match_table = of_match_ptr(ir_rx51_match),
        },
 };
-module_platform_driver(lirc_rx51_platform_driver);
+module_platform_driver(ir_rx51_platform_driver);
 
-MODULE_DESCRIPTION("LIRC TX driver for Nokia RX51");
+MODULE_DESCRIPTION("IR TX driver for Nokia RX51");
 MODULE_AUTHOR("Nokia Corporation");
 MODULE_LICENSE("GPL");
index b07d9caebeb1d5c8c515e61f6163686eea54c46c..520bb77dcb62b31ba2915fc4b673365d69113c70 100644 (file)
@@ -176,9 +176,52 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
        return -EINVAL;
 }
 
+static const struct ir_raw_timings_pd ir_sanyo_timings = {
+       .header_pulse  = SANYO_HEADER_PULSE,
+       .header_space  = SANYO_HEADER_SPACE,
+       .bit_pulse     = SANYO_BIT_PULSE,
+       .bit_space[0]  = SANYO_BIT_0_SPACE,
+       .bit_space[1]  = SANYO_BIT_1_SPACE,
+       .trailer_pulse = SANYO_TRAILER_PULSE,
+       .trailer_space = SANYO_TRAILER_SPACE,
+       .msb_first     = 1,
+};
+
+/**
+ * ir_sanyo_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_sanyo_encode(enum rc_type protocol, u32 scancode,
+                          struct ir_raw_event *events, unsigned int max)
+{
+       struct ir_raw_event *e = events;
+       int ret;
+       u64 raw;
+
+       raw = ((u64)(bitrev16(scancode >> 8) & 0xfff8) << (8 + 8 + 13 - 3)) |
+             ((u64)(bitrev16(~scancode >> 8) & 0xfff8) << (8 + 8 +  0 - 3)) |
+             ((bitrev8(scancode) & 0xff) << 8) |
+             (bitrev8(~scancode) & 0xff);
+
+       ret = ir_raw_gen_pd(&e, max, &ir_sanyo_timings, SANYO_NBITS, raw);
+       if (ret < 0)
+               return ret;
+
+       return e - events;
+}
+
 static struct ir_raw_handler sanyo_handler = {
        .protocols      = RC_BIT_SANYO,
        .decode         = ir_sanyo_decode,
+       .encode         = ir_sanyo_encode,
 };
 
 static int __init ir_sanyo_decode_init(void)
index 317677f06f2c6e147d380bd3b4705df5e99224fe..b47e89e2c1bd1d6a2d347fd1c17451e798adf50d 100644 (file)
@@ -173,9 +173,59 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
        return -EINVAL;
 }
 
+static const struct ir_raw_timings_pd ir_sharp_timings = {
+       .header_pulse  = 0,
+       .header_space  = 0,
+       .bit_pulse     = SHARP_BIT_PULSE,
+       .bit_space[0]  = SHARP_BIT_0_PERIOD,
+       .bit_space[1]  = SHARP_BIT_1_PERIOD,
+       .trailer_pulse = SHARP_BIT_PULSE,
+       .trailer_space = SHARP_ECHO_SPACE,
+       .msb_first     = 1,
+};
+
+/**
+ * ir_sharp_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_sharp_encode(enum rc_type protocol, u32 scancode,
+                          struct ir_raw_event *events, unsigned int max)
+{
+       struct ir_raw_event *e = events;
+       int ret;
+       u32 raw;
+
+       raw = (((bitrev8(scancode >> 8) >> 3) << 8) & 0x1f00) |
+               bitrev8(scancode);
+       ret = ir_raw_gen_pd(&e, max, &ir_sharp_timings, SHARP_NBITS,
+                           (raw << 2) | 2);
+       if (ret < 0)
+               return ret;
+
+       max -= ret;
+
+       raw = (((bitrev8(scancode >> 8) >> 3) << 8) & 0x1f00) |
+               bitrev8(~scancode);
+       ret = ir_raw_gen_pd(&e, max, &ir_sharp_timings, SHARP_NBITS,
+                           (raw << 2) | 1);
+       if (ret < 0)
+               return ret;
+
+       return e - events;
+}
+
 static struct ir_raw_handler sharp_handler = {
        .protocols      = RC_BIT_SHARP,
        .decode         = ir_sharp_decode,
+       .encode         = ir_sharp_encode,
 };
 
 static int __init ir_sharp_decode_init(void)
index baa972c76e0e19a5f0b5651310df2c93daf0e8fa..355fa8198f5a12c9534eaba2b48dbd956cd0a5d3 100644 (file)
@@ -169,9 +169,57 @@ finish_state_machine:
        return 0;
 }
 
+static const struct ir_raw_timings_pl ir_sony_timings = {
+       .header_pulse  = SONY_HEADER_PULSE,
+       .bit_space     = SONY_BIT_SPACE,
+       .bit_pulse[0]  = SONY_BIT_0_PULSE,
+       .bit_pulse[1]  = SONY_BIT_1_PULSE,
+       .trailer_space = SONY_TRAILER_SPACE + SONY_BIT_SPACE,
+       .msb_first     = 0,
+};
+
+/**
+ * ir_sony_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_sony_encode(enum rc_type protocol, u32 scancode,
+                         struct ir_raw_event *events, unsigned int max)
+{
+       struct ir_raw_event *e = events;
+       u32 raw, len;
+       int ret;
+
+       if (protocol == RC_TYPE_SONY12) {
+               raw = (scancode & 0x7f) | ((scancode & 0x1f0000) >> 9);
+               len = 12;
+       } else if (protocol == RC_TYPE_SONY15) {
+               raw = (scancode & 0x7f) | ((scancode & 0xff0000) >> 9);
+               len = 15;
+       } else {
+               raw = (scancode & 0x7f) | ((scancode & 0x1f0000) >> 9) |
+                      ((scancode & 0xff00) << 4);
+               len = 20;
+       }
+
+       ret = ir_raw_gen_pl(&e, max, &ir_sony_timings, len, raw);
+       if (ret < 0)
+               return ret;
+
+       return e - events;
+}
+
 static struct ir_raw_handler sony_handler = {
        .protocols      = RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20,
        .decode         = ir_sony_decode,
+       .encode         = ir_sony_encode,
 };
 
 static int __init ir_sony_decode_init(void)
diff --git a/drivers/media/rc/ir-spi.c b/drivers/media/rc/ir-spi.c
new file mode 100644 (file)
index 0000000..c8863f3
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Author: Andi Shyti <andi.shyti@samsung.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.
+ *
+ * SPI driven IR LED device driver
+ */
+
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <media/rc-core.h>
+
+#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];
+       u16 pulse;
+       u16 space;
+
+       struct rc_dev *rc;
+       struct spi_device *spi;
+       struct regulator *regulator;
+};
+
+static int ir_spi_tx(struct rc_dev *dev,
+                    unsigned int *buffer, unsigned int count)
+{
+       int i;
+       int ret;
+       unsigned int len = 0;
+       struct ir_spi_data *idata = dev->priv;
+       struct spi_transfer xfer;
+
+       /* convert the pulse/space signal to raw binary signal */
+       for (i = 0; i < count; i++) {
+               int j;
+               u16 val = ((i + 1) % 2) ? idata->pulse : idata->space;
+
+               if (len + buffer[i] >= IR_SPI_MAX_BUFSIZE)
+                       return -EINVAL;
+
+               /*
+                * the first value in buffer is a pulse, so that 0, 2, 4, ...
+                * contain a pulse duration. On the contrary, 1, 3, 5, ...
+                * contain a space duration.
+                */
+               val = (i % 2) ? idata->space : idata->pulse;
+               for (j = 0; j < buffer[i]; j++)
+                       idata->tx_buf[len++] = val;
+       }
+
+       memset(&xfer, 0, sizeof(xfer));
+
+       xfer.speed_hz = idata->freq;
+       xfer.len = len * sizeof(*idata->tx_buf);
+       xfer.tx_buf = idata->tx_buf;
+
+       ret = regulator_enable(idata->regulator);
+       if (ret)
+               return ret;
+
+       ret = spi_sync_transfer(idata->spi, &xfer, 1);
+       if (ret)
+               dev_err(&idata->spi->dev, "unable to deliver the signal\n");
+
+       regulator_disable(idata->regulator);
+
+       return ret ? ret : count;
+}
+
+static int ir_spi_set_tx_carrier(struct rc_dev *dev, u32 carrier)
+{
+       struct ir_spi_data *idata = dev->priv;
+
+       if (!carrier)
+               return -EINVAL;
+
+       idata->freq = carrier;
+
+       return 0;
+}
+
+static int ir_spi_set_duty_cycle(struct rc_dev *dev, u32 duty_cycle)
+{
+       struct ir_spi_data *idata = dev->priv;
+
+       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;
+
+       if (idata->negated) {
+               idata->pulse = ~idata->pulse;
+               idata->space = 0xffff;
+       } else {
+               idata->space = 0;
+       }
+
+       return 0;
+}
+
+static int ir_spi_probe(struct spi_device *spi)
+{
+       int ret;
+       u8 dc;
+       struct ir_spi_data *idata;
+
+       idata = devm_kzalloc(&spi->dev, sizeof(*idata), GFP_KERNEL);
+       if (!idata)
+               return -ENOMEM;
+
+       idata->regulator = devm_regulator_get(&spi->dev, "irda_regulator");
+       if (IS_ERR(idata->regulator))
+               return PTR_ERR(idata->regulator);
+
+       idata->rc = devm_rc_allocate_device(&spi->dev, RC_DRIVER_IR_RAW_TX);
+       if (!idata->rc)
+               return -ENOMEM;
+
+       idata->rc->tx_ir           = ir_spi_tx;
+       idata->rc->s_tx_carrier    = ir_spi_set_tx_carrier;
+       idata->rc->s_tx_duty_cycle = ir_spi_set_duty_cycle;
+       idata->rc->driver_name     = IR_SPI_DRIVER_NAME;
+       idata->rc->priv            = idata;
+       idata->spi                 = spi;
+
+       idata->negated = of_property_read_bool(spi->dev.of_node,
+                                                       "led-active-low");
+       ret = of_property_read_u8(spi->dev.of_node, "duty-cycle", &dc);
+       if (ret)
+               dc = 50;
+
+       /* ir_spi_set_duty_cycle cannot fail,
+        * it returns int to be compatible with the
+        * rc->s_tx_duty_cycle function
+        */
+       ir_spi_set_duty_cycle(idata->rc, dc);
+
+       idata->freq = IR_SPI_DEFAULT_FREQUENCY;
+
+       return devm_rc_register_device(&spi->dev, idata->rc);
+}
+
+static int ir_spi_remove(struct spi_device *spi)
+{
+       return 0;
+}
+
+static const struct of_device_id ir_spi_of_match[] = {
+       { .compatible = "ir-spi-led" },
+       {},
+};
+
+static struct spi_driver ir_spi_driver = {
+       .probe = ir_spi_probe,
+       .remove = ir_spi_remove,
+       .driver = {
+               .name = IR_SPI_DRIVER_NAME,
+               .of_match_table = ir_spi_of_match,
+       },
+};
+
+module_spi_driver(ir_spi_driver);
+
+MODULE_AUTHOR("Andi Shyti <andi.shyti@samsung.com>");
+MODULE_DESCRIPTION("SPI IR LED");
+MODULE_LICENSE("GPL v2");
index 367b28bed627f69025adc554afc830fc20ac72aa..e9e4befbbebb8126220f02e79e9278e69b23fe5a 100644 (file)
  * 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.
- *
  * Inspired by the original lirc_it87 and lirc_ite8709 drivers, on top of the
  * skeleton provided by the nuvoton-cir driver.
  *
@@ -1470,7 +1465,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
                return ret;
 
        /* input device for IR remote (and tx) */
-       rdev = rc_allocate_device();
+       rdev = rc_allocate_device(RC_DRIVER_IR_RAW);
        if (!rdev)
                goto exit_free_dev_rdev;
        itdev->rdev = rdev;
@@ -1561,8 +1556,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
 
        /* set up ir-core props */
        rdev->priv = itdev;
-       rdev->driver_type = RC_DRIVER_IR_RAW;
-       rdev->allowed_protocols = RC_BIT_ALL;
+       rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
        rdev->open = ite_open;
        rdev->close = ite_close;
        rdev->s_idle = ite_s_idle;
index aa899a0b9750770da5ee1a4b8a079d8f6d21bc4a..0e8ebc880d1fcae829f4dad3424c3ec67fd5118d 100644 (file)
  * WITHOUT 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.
  */
 
 /* platform driver name to register */
index d7b13fae1267533d446483173bcc3617c075fca9..ffe9e612f8d6c63249b810ca612f61db2fb1b4a9 100644 (file)
@@ -21,6 +21,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
                        rc-cec.o \
                        rc-cinergy-1400.o \
                        rc-cinergy.o \
+                       rc-d680-dmb.o \
                        rc-delock-61959.o \
                        rc-dib0700-nec.o \
                        rc-dib0700-rc5.o \
@@ -31,6 +32,8 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
                        rc-dntv-live-dvbt-pro.o \
                        rc-dtt200u.o \
                        rc-dvbsky.o \
+                       rc-dvico-mce.o \
+                       rc-dvico-portable.o \
                        rc-em-terratec.o \
                        rc-encore-enltv2.o \
                        rc-encore-enltv.o \
@@ -41,6 +44,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
                        rc-flyvideo.o \
                        rc-fusionhdtv-mce.o \
                        rc-gadmei-rm008z.o \
+                       rc-geekbox.o \
                        rc-genius-tvgo-a11mce.o \
                        rc-gotview7135.o \
                        rc-imon-mce.o \
diff --git a/drivers/media/rc/keymaps/rc-d680-dmb.c b/drivers/media/rc/keymaps/rc-d680-dmb.c
new file mode 100644 (file)
index 0000000..bb5745d
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * keymap imported from cxusb.c
+ *
+ * Copyright (C) 2016 Sean Young
+ *
+ * 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.
+ */
+
+#include <media/rc-map.h>
+#include <linux/module.h>
+
+static struct rc_map_table rc_map_d680_dmb_table[] = {
+       { 0x0038, KEY_SWITCHVIDEOMODE },        /* TV/AV */
+       { 0x080c, KEY_ZOOM },
+       { 0x0800, KEY_0 },
+       { 0x0001, KEY_1 },
+       { 0x0802, KEY_2 },
+       { 0x0003, KEY_3 },
+       { 0x0804, KEY_4 },
+       { 0x0005, KEY_5 },
+       { 0x0806, KEY_6 },
+       { 0x0007, KEY_7 },
+       { 0x0808, KEY_8 },
+       { 0x0009, KEY_9 },
+       { 0x000a, KEY_MUTE },
+       { 0x0829, KEY_BACK },
+       { 0x0012, KEY_CHANNELUP },
+       { 0x0813, KEY_CHANNELDOWN },
+       { 0x002b, KEY_VOLUMEUP },
+       { 0x082c, KEY_VOLUMEDOWN },
+       { 0x0020, KEY_UP },
+       { 0x0821, KEY_DOWN },
+       { 0x0011, KEY_LEFT },
+       { 0x0810, KEY_RIGHT },
+       { 0x000d, KEY_OK },
+       { 0x081f, KEY_RECORD },
+       { 0x0017, KEY_PLAYPAUSE },
+       { 0x0816, KEY_PLAYPAUSE },
+       { 0x000b, KEY_STOP },
+       { 0x0827, KEY_FASTFORWARD },
+       { 0x0026, KEY_REWIND },
+       { 0x081e, KEY_UNKNOWN },    /* Time Shift */
+       { 0x000e, KEY_UNKNOWN },    /* Snapshot */
+       { 0x082d, KEY_UNKNOWN },    /* Mouse Cursor */
+       { 0x000f, KEY_UNKNOWN },    /* Minimize/Maximize */
+       { 0x0814, KEY_SHUFFLE },    /* Shuffle */
+       { 0x0025, KEY_POWER },
+};
+
+static struct rc_map_list d680_dmb_map = {
+       .map = {
+               .scan    = rc_map_d680_dmb_table,
+               .size    = ARRAY_SIZE(rc_map_d680_dmb_table),
+               .rc_type = RC_TYPE_UNKNOWN,     /* Legacy IR type */
+               .name    = RC_MAP_D680_DMB,
+       }
+};
+
+static int __init init_rc_map_d680_dmb(void)
+{
+       return rc_map_register(&d680_dmb_map);
+}
+
+static void __exit exit_rc_map_d680_dmb(void)
+{
+       rc_map_unregister(&d680_dmb_map);
+}
+
+module_init(init_rc_map_d680_dmb)
+module_exit(exit_rc_map_d680_dmb)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-dvico-mce.c b/drivers/media/rc/keymaps/rc-dvico-mce.c
new file mode 100644 (file)
index 0000000..e5f098c
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * keymap imported from cxusb.c
+ *
+ * Copyright (C) 2016 Sean Young
+ *
+ * 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.
+ */
+
+#include <media/rc-map.h>
+#include <linux/module.h>
+
+static struct rc_map_table rc_map_dvico_mce_table[] = {
+       { 0xfe02, KEY_TV },
+       { 0xfe0e, KEY_MP3 },
+       { 0xfe1a, KEY_DVD },
+       { 0xfe1e, KEY_FAVORITES },
+       { 0xfe16, KEY_SETUP },
+       { 0xfe46, KEY_POWER2 },
+       { 0xfe0a, KEY_EPG },
+       { 0xfe49, KEY_BACK },
+       { 0xfe4d, KEY_MENU },
+       { 0xfe51, KEY_UP },
+       { 0xfe5b, KEY_LEFT },
+       { 0xfe5f, KEY_RIGHT },
+       { 0xfe53, KEY_DOWN },
+       { 0xfe5e, KEY_OK },
+       { 0xfe59, KEY_INFO },
+       { 0xfe55, KEY_TAB },
+       { 0xfe0f, KEY_PREVIOUSSONG },/* Replay */
+       { 0xfe12, KEY_NEXTSONG },       /* Skip */
+       { 0xfe42, KEY_ENTER      },     /* Windows/Start */
+       { 0xfe15, KEY_VOLUMEUP },
+       { 0xfe05, KEY_VOLUMEDOWN },
+       { 0xfe11, KEY_CHANNELUP },
+       { 0xfe09, KEY_CHANNELDOWN },
+       { 0xfe52, KEY_CAMERA },
+       { 0xfe5a, KEY_TUNER },  /* Live */
+       { 0xfe19, KEY_OPEN },
+       { 0xfe0b, KEY_1 },
+       { 0xfe17, KEY_2 },
+       { 0xfe1b, KEY_3 },
+       { 0xfe07, KEY_4 },
+       { 0xfe50, KEY_5 },
+       { 0xfe54, KEY_6 },
+       { 0xfe48, KEY_7 },
+       { 0xfe4c, KEY_8 },
+       { 0xfe58, KEY_9 },
+       { 0xfe13, KEY_ANGLE },  /* Aspect */
+       { 0xfe03, KEY_0 },
+       { 0xfe1f, KEY_ZOOM },
+       { 0xfe43, KEY_REWIND },
+       { 0xfe47, KEY_PLAYPAUSE },
+       { 0xfe4f, KEY_FASTFORWARD },
+       { 0xfe57, KEY_MUTE },
+       { 0xfe0d, KEY_STOP },
+       { 0xfe01, KEY_RECORD },
+       { 0xfe4e, KEY_POWER },
+};
+
+static struct rc_map_list dvico_mce_map = {
+       .map = {
+               .scan    = rc_map_dvico_mce_table,
+               .size    = ARRAY_SIZE(rc_map_dvico_mce_table),
+               .rc_type = RC_TYPE_UNKNOWN,     /* Legacy IR type */
+               .name    = RC_MAP_DVICO_MCE,
+       }
+};
+
+static int __init init_rc_map_dvico_mce(void)
+{
+       return rc_map_register(&dvico_mce_map);
+}
+
+static void __exit exit_rc_map_dvico_mce(void)
+{
+       rc_map_unregister(&dvico_mce_map);
+}
+
+module_init(init_rc_map_dvico_mce)
+module_exit(exit_rc_map_dvico_mce)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-dvico-portable.c b/drivers/media/rc/keymaps/rc-dvico-portable.c
new file mode 100644 (file)
index 0000000..94ceeee
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * keymap imported from cxusb.c
+ *
+ * Copyright (C) 2016 Sean Young
+ *
+ * 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.
+ */
+
+#include <media/rc-map.h>
+#include <linux/module.h>
+
+static struct rc_map_table rc_map_dvico_portable_table[] = {
+       { 0xfc02, KEY_SETUP },       /* Profile */
+       { 0xfc43, KEY_POWER2 },
+       { 0xfc06, KEY_EPG },
+       { 0xfc5a, KEY_BACK },
+       { 0xfc05, KEY_MENU },
+       { 0xfc47, KEY_INFO },
+       { 0xfc01, KEY_TAB },
+       { 0xfc42, KEY_PREVIOUSSONG },/* Replay */
+       { 0xfc49, KEY_VOLUMEUP },
+       { 0xfc09, KEY_VOLUMEDOWN },
+       { 0xfc54, KEY_CHANNELUP },
+       { 0xfc0b, KEY_CHANNELDOWN },
+       { 0xfc16, KEY_CAMERA },
+       { 0xfc40, KEY_TUNER },  /* ATV/DTV */
+       { 0xfc45, KEY_OPEN },
+       { 0xfc19, KEY_1 },
+       { 0xfc18, KEY_2 },
+       { 0xfc1b, KEY_3 },
+       { 0xfc1a, KEY_4 },
+       { 0xfc58, KEY_5 },
+       { 0xfc59, KEY_6 },
+       { 0xfc15, KEY_7 },
+       { 0xfc14, KEY_8 },
+       { 0xfc17, KEY_9 },
+       { 0xfc44, KEY_ANGLE },  /* Aspect */
+       { 0xfc55, KEY_0 },
+       { 0xfc07, KEY_ZOOM },
+       { 0xfc0a, KEY_REWIND },
+       { 0xfc08, KEY_PLAYPAUSE },
+       { 0xfc4b, KEY_FASTFORWARD },
+       { 0xfc5b, KEY_MUTE },
+       { 0xfc04, KEY_STOP },
+       { 0xfc56, KEY_RECORD },
+       { 0xfc57, KEY_POWER },
+       { 0xfc41, KEY_UNKNOWN },    /* INPUT */
+       { 0xfc00, KEY_UNKNOWN },    /* HD */
+};
+
+static struct rc_map_list dvico_portable_map = {
+       .map = {
+               .scan    = rc_map_dvico_portable_table,
+               .size    = ARRAY_SIZE(rc_map_dvico_portable_table),
+               .rc_type = RC_TYPE_UNKNOWN,     /* Legacy IR type */
+               .name    = RC_MAP_DVICO_PORTABLE,
+       }
+};
+
+static int __init init_rc_map_dvico_portable(void)
+{
+       return rc_map_register(&dvico_portable_map);
+}
+
+static void __exit exit_rc_map_dvico_portable(void)
+{
+       rc_map_unregister(&dvico_portable_map);
+}
+
+module_init(init_rc_map_dvico_portable)
+module_exit(exit_rc_map_dvico_portable)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab");
diff --git a/drivers/media/rc/keymaps/rc-geekbox.c b/drivers/media/rc/keymaps/rc-geekbox.c
new file mode 100644 (file)
index 0000000..affc4c4
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Keytable for the GeekBox remote controller
+ *
+ * Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.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.
+ *
+ * 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 <media/rc-map.h>
+#include <linux/module.h>
+
+static struct rc_map_table geekbox[] = {
+       { 0x01, KEY_BACK },
+       { 0x02, KEY_DOWN },
+       { 0x03, KEY_UP },
+       { 0x07, KEY_OK },
+       { 0x0b, KEY_VOLUMEUP },
+       { 0x0e, KEY_LEFT },
+       { 0x13, KEY_MENU },
+       { 0x14, KEY_POWER },
+       { 0x1a, KEY_RIGHT },
+       { 0x48, KEY_HOME },
+       { 0x58, KEY_VOLUMEDOWN },
+       { 0x5c, KEY_SCREEN },
+};
+
+static struct rc_map_list geekbox_map = {
+       .map = {
+               .scan    = geekbox,
+               .size    = ARRAY_SIZE(geekbox),
+               .rc_type = RC_TYPE_NEC,
+               .name    = RC_MAP_GEEKBOX,
+       }
+};
+
+static int __init init_rc_map_geekbox(void)
+{
+       return rc_map_register(&geekbox_map);
+}
+
+static void __exit exit_rc_map_geekbox(void)
+{
+       rc_map_unregister(&geekbox_map);
+}
+
+module_init(init_rc_map_geekbox)
+module_exit(exit_rc_map_geekbox)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
index ef4006fe4de0a6ca48d7bb3b6fa059bfa5af59fd..5be567506bcd48383933299127bbe87f6ac2102b 100644 (file)
@@ -86,6 +86,7 @@ static struct rc_map_table rc6_mce[] = {
        { 0x800f045e, KEY_BLUE },
 
        { 0x800f0465, KEY_POWER2 },     /* TV Power */
+       { 0x800f0469, KEY_MESSENGER },
        { 0x800f046e, KEY_PLAYPAUSE },
        { 0x800f046f, KEY_PLAYER },     /* Start media application (NEW) */
 
index f9733bb289d63441c7d2f249ebc30f69c960c84c..02c9c243c060b7e414928970f13f7a11595bd3a3 100644 (file)
  * License, or (at your option) any later version.
  *
  *
- * 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 PROGRAM IS PROVIDED "AS IS" AND BOTH THE COPYRIGHT HOLDER AND
  * TECHNISAT DIGITAL UK LTD DISCLAIM ALL WARRANTIES WITH REGARD TO
  * THIS PROGRAM INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY OR
index 454e062956925ee6b82ad195f10ca6bca82d4516..5cc1b456e3299893b37e27f92310453cfc0e898f 100644 (file)
  * Initial mapping is for the TiVo remote included in the Nero LiquidTV bundle,
  * which also ships with a TiVo-branded IR transceiver, supported by the mceusb
  * driver. Note that the remote uses an NEC-ish protocol, but instead of having
- * a command/not_command pair, it has a vendor ID of 0xa10c, but some keys, the
+ * a command/not_command pair, it has a vendor ID of 0x3085, but some keys, the
  * NEC extended checksums do pass, so the table presently has the intended
  * values and the checksum-passed versions for those keys.
  */
 static struct rc_map_table tivo[] = {
-       { 0xa10c900f, KEY_MEDIA },      /* TiVo Button */
-       { 0xa10c0807, KEY_POWER2 },     /* TV Power */
-       { 0xa10c8807, KEY_TV },         /* Live TV/Swap */
-       { 0xa10c2c03, KEY_VIDEO_NEXT }, /* TV Input */
-       { 0xa10cc807, KEY_INFO },
-       { 0xa10cfa05, KEY_CYCLEWINDOWS }, /* Window */
+       { 0x3085f009, KEY_MEDIA },      /* TiVo Button */
+       { 0x3085e010, KEY_POWER2 },     /* TV Power */
+       { 0x3085e011, KEY_TV },         /* Live TV/Swap */
+       { 0x3085c034, KEY_VIDEO_NEXT }, /* TV Input */
+       { 0x3085e013, KEY_INFO },
+       { 0x3085a05f, KEY_CYCLEWINDOWS }, /* Window */
        { 0x0085305f, KEY_CYCLEWINDOWS },
-       { 0xa10c6c03, KEY_EPG },        /* Guide */
+       { 0x3085c036, KEY_EPG },        /* Guide */
 
-       { 0xa10c2807, KEY_UP },
-       { 0xa10c6807, KEY_DOWN },
-       { 0xa10ce807, KEY_LEFT },
-       { 0xa10ca807, KEY_RIGHT },
+       { 0x3085e014, KEY_UP },
+       { 0x3085e016, KEY_DOWN },
+       { 0x3085e017, KEY_LEFT },
+       { 0x3085e015, KEY_RIGHT },
 
-       { 0xa10c1807, KEY_SCROLLDOWN }, /* Red Thumbs Down */
-       { 0xa10c9807, KEY_SELECT },
-       { 0xa10c5807, KEY_SCROLLUP },   /* Green Thumbs Up */
+       { 0x3085e018, KEY_SCROLLDOWN }, /* Red Thumbs Down */
+       { 0x3085e019, KEY_SELECT },
+       { 0x3085e01a, KEY_SCROLLUP },   /* Green Thumbs Up */
 
-       { 0xa10c3807, KEY_VOLUMEUP },
-       { 0xa10cb807, KEY_VOLUMEDOWN },
-       { 0xa10cd807, KEY_MUTE },
-       { 0xa10c040b, KEY_RECORD },
-       { 0xa10c7807, KEY_CHANNELUP },
-       { 0xa10cf807, KEY_CHANNELDOWN },
+       { 0x3085e01c, KEY_VOLUMEUP },
+       { 0x3085e01d, KEY_VOLUMEDOWN },
+       { 0x3085e01b, KEY_MUTE },
+       { 0x3085d020, KEY_RECORD },
+       { 0x3085e01e, KEY_CHANNELUP },
+       { 0x3085e01f, KEY_CHANNELDOWN },
        { 0x0085301f, KEY_CHANNELDOWN },
 
-       { 0xa10c840b, KEY_PLAY },
-       { 0xa10cc40b, KEY_PAUSE },
-       { 0xa10ca40b, KEY_SLOW },
-       { 0xa10c440b, KEY_REWIND },
-       { 0xa10c240b, KEY_FASTFORWARD },
-       { 0xa10c640b, KEY_PREVIOUS },
-       { 0xa10ce40b, KEY_NEXT },       /* ->| */
+       { 0x3085d021, KEY_PLAY },
+       { 0x3085d023, KEY_PAUSE },
+       { 0x3085d025, KEY_SLOW },
+       { 0x3085d022, KEY_REWIND },
+       { 0x3085d024, KEY_FASTFORWARD },
+       { 0x3085d026, KEY_PREVIOUS },
+       { 0x3085d027, KEY_NEXT },       /* ->| */
 
-       { 0xa10c220d, KEY_ZOOM },       /* Aspect */
-       { 0xa10c120d, KEY_STOP },
-       { 0xa10c520d, KEY_DVD },        /* DVD Menu */
+       { 0x3085b044, KEY_ZOOM },       /* Aspect */
+       { 0x3085b048, KEY_STOP },
+       { 0x3085b04a, KEY_DVD },        /* DVD Menu */
 
-       { 0xa10c140b, KEY_NUMERIC_1 },
-       { 0xa10c940b, KEY_NUMERIC_2 },
-       { 0xa10c540b, KEY_NUMERIC_3 },
-       { 0xa10cd40b, KEY_NUMERIC_4 },
-       { 0xa10c340b, KEY_NUMERIC_5 },
-       { 0xa10cb40b, KEY_NUMERIC_6 },
-       { 0xa10c740b, KEY_NUMERIC_7 },
-       { 0xa10cf40b, KEY_NUMERIC_8 },
+       { 0x3085d028, KEY_NUMERIC_1 },
+       { 0x3085d029, KEY_NUMERIC_2 },
+       { 0x3085d02a, KEY_NUMERIC_3 },
+       { 0x3085d02b, KEY_NUMERIC_4 },
+       { 0x3085d02c, KEY_NUMERIC_5 },
+       { 0x3085d02d, KEY_NUMERIC_6 },
+       { 0x3085d02e, KEY_NUMERIC_7 },
+       { 0x3085d02f, KEY_NUMERIC_8 },
        { 0x0085302f, KEY_NUMERIC_8 },
-       { 0xa10c0c03, KEY_NUMERIC_9 },
-       { 0xa10c8c03, KEY_NUMERIC_0 },
-       { 0xa10ccc03, KEY_ENTER },
-       { 0xa10c4c03, KEY_CLEAR },
+       { 0x3085c030, KEY_NUMERIC_9 },
+       { 0x3085c031, KEY_NUMERIC_0 },
+       { 0x3085c033, KEY_ENTER },
+       { 0x3085c032, KEY_CLEAR },
 };
 
 static struct rc_map_list tivo_map = {
index 3854809e853110ea74867d5ecda8f08acb3609b6..a54ca531d8ef85280c8cf9df7b7b19ac226f7032 100644 (file)
  *  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
- *
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -472,7 +468,7 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file)
                if (retval) {
                        module_put(cdev->owner);
                        ir->open--;
-               } else {
+               } else if (ir->buf) {
                        lirc_buffer_clear(ir->buf);
                }
                if (ir->task)
@@ -582,7 +578,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                result = put_user(ir->d.features, (__u32 __user *)arg);
                break;
        case LIRC_GET_REC_MODE:
-               if (LIRC_CAN_REC(ir->d.features)) {
+               if (!LIRC_CAN_REC(ir->d.features)) {
                        result = -ENOTTY;
                        break;
                }
@@ -592,7 +588,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                                  (__u32 __user *)arg);
                break;
        case LIRC_SET_REC_MODE:
-               if (LIRC_CAN_REC(ir->d.features)) {
+               if (!LIRC_CAN_REC(ir->d.features)) {
                        result = -ENOTTY;
                        break;
                }
@@ -651,6 +647,9 @@ ssize_t lirc_dev_fop_read(struct file *file,
                return -ENODEV;
        }
 
+       if (!LIRC_CAN_REC(ir->d.features))
+               return -EINVAL;
+
        dev_dbg(ir->d.dev, LOGHEAD "read called\n", ir->d.name, ir->d.minor);
 
        buf = kzalloc(ir->chunk_size, GFP_KERNEL);
index 9bf69179eee0e7b21b11b6e0a4b1e220254f8181..238d8eaf7d94f8e2a1346b4c9889176d8a21e3b0 100644 (file)
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
  */
 
 #include <linux/device.h>
@@ -890,7 +886,7 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier)
                        cmdbuf[3] = MCE_IRDATA_TRAILER;
                        dev_dbg(ir->dev, "disabling carrier modulation");
                        mce_async_out(ir, cmdbuf, sizeof(cmdbuf));
-                       return carrier;
+                       return 0;
                }
 
                for (prescaler = 0; prescaler < 4; ++prescaler) {
@@ -904,7 +900,7 @@ static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier)
 
                                /* Transmit new carrier to mce device */
                                mce_async_out(ir, cmdbuf, sizeof(cmdbuf));
-                               return carrier;
+                               return 0;
                        }
                }
 
@@ -1181,7 +1177,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
        struct rc_dev *rc;
        int ret;
 
-       rc = rc_allocate_device();
+       rc = rc_allocate_device(RC_DRIVER_IR_RAW);
        if (!rc) {
                dev_err(dev, "remote dev allocation failed");
                goto out;
@@ -1201,8 +1197,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
        usb_to_input_id(ir->usbdev, &rc->input_id);
        rc->dev.parent = dev;
        rc->priv = ir;
-       rc->driver_type = RC_DRIVER_IR_RAW;
-       rc->allowed_protocols = RC_BIT_ALL;
+       rc->allowed_protocols = RC_BIT_ALL_IR_DECODER;
        rc->timeout = MS_TO_NS(100);
        if (!ir->flags.no_tx) {
                rc->s_tx_mask = mceusb_set_tx_mask;
index 7eb3f4f1ddcd670d501432528a2472dc0775d55f..5576dbd6b1a4daa9fb5d96da7ee88e4bc056878c 100644 (file)
@@ -131,7 +131,7 @@ static int meson_ir_probe(struct platform_device *pdev)
                return ir->irq;
        }
 
-       ir->rc = rc_allocate_device();
+       ir->rc = rc_allocate_device(RC_DRIVER_IR_RAW);
        if (!ir->rc) {
                dev_err(dev, "failed to allocate rc device\n");
                return -ENOMEM;
@@ -144,8 +144,7 @@ static int meson_ir_probe(struct platform_device *pdev)
        map_name = of_get_property(node, "linux,rc-map-name", NULL);
        ir->rc->map_name = map_name ? map_name : RC_MAP_EMPTY;
        ir->rc->dev.parent = dev;
-       ir->rc->driver_type = RC_DRIVER_IR_RAW;
-       ir->rc->allowed_protocols = RC_BIT_ALL;
+       ir->rc->allowed_protocols = RC_BIT_ALL_IR_DECODER;
        ir->rc->rx_resolution = US_TO_NS(MESON_TRATE);
        ir->rc->timeout = MS_TO_NS(200);
        ir->rc->driver_name = DRIVER_NAME;
diff --git a/drivers/media/rc/mtk-cir.c b/drivers/media/rc/mtk-cir.c
new file mode 100644 (file)
index 0000000..f1e164e
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * Driver for Mediatek IR Receiver Controller
+ *
+ * Copyright (C) 2017 Sean Wang <sean.wang@mediatek.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 <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/reset.h>
+#include <media/rc-core.h>
+
+#define MTK_IR_DEV KBUILD_MODNAME
+
+/* Register to enable PWM and IR */
+#define MTK_CONFIG_HIGH_REG       0x0c
+/* Enable IR pulse width detection */
+#define MTK_PWM_EN               BIT(13)
+/* Enable IR hardware function */
+#define MTK_IR_EN                BIT(0)
+
+/* Register to setting sample period */
+#define MTK_CONFIG_LOW_REG        0x10
+/* Field to set sample period */
+#define CHK_PERIOD               DIV_ROUND_CLOSEST(MTK_IR_SAMPLE,  \
+                                                   MTK_IR_CLK_PERIOD)
+#define MTK_CHK_PERIOD            (((CHK_PERIOD) << 8) & (GENMASK(20, 8)))
+#define MTK_CHK_PERIOD_MASK      (GENMASK(20, 8))
+
+/* Register to clear state of state machine */
+#define MTK_IRCLR_REG             0x20
+/* Bit to restart IR receiving */
+#define MTK_IRCLR                BIT(0)
+
+/* Register containing pulse width data */
+#define MTK_CHKDATA_REG(i)        (0x88 + 4 * (i))
+#define MTK_WIDTH_MASK           (GENMASK(7, 0))
+
+/* Register to enable IR interrupt */
+#define MTK_IRINT_EN_REG          0xcc
+/* Bit to enable interrupt */
+#define MTK_IRINT_EN             BIT(0)
+
+/* Register to ack IR interrupt */
+#define MTK_IRINT_CLR_REG         0xd0
+/* Bit to clear interrupt status */
+#define MTK_IRINT_CLR            BIT(0)
+
+/* Maximum count of samples */
+#define MTK_MAX_SAMPLES                  0xff
+/* Indicate the end of IR message */
+#define MTK_IR_END(v, p)         ((v) == MTK_MAX_SAMPLES && (p) == 0)
+/* Number of registers to record the pulse width */
+#define MTK_CHKDATA_SZ           17
+/* Source clock frequency */
+#define MTK_IR_BASE_CLK                  273000000
+/* Frequency after IR internal divider */
+#define MTK_IR_CLK_FREQ                  (MTK_IR_BASE_CLK / 4)
+/* Period for MTK_IR_CLK in ns*/
+#define MTK_IR_CLK_PERIOD        DIV_ROUND_CLOSEST(1000000000ul,  \
+                                                   MTK_IR_CLK_FREQ)
+/* Sample period in ns */
+#define MTK_IR_SAMPLE            (MTK_IR_CLK_PERIOD * 0xc00)
+
+/*
+ * struct mtk_ir -     This is the main datasructure for holding the state
+ *                     of the driver
+ * @dev:               The device pointer
+ * @rc:                        The rc instrance
+ * @irq:               The IRQ that we are using
+ * @base:              The mapped register i/o base
+ * @clk:               The clock that we are using
+ */
+struct mtk_ir {
+       struct device   *dev;
+       struct rc_dev   *rc;
+       void __iomem    *base;
+       int             irq;
+       struct clk      *clk;
+};
+
+static void mtk_w32_mask(struct mtk_ir *ir, u32 val, u32 mask, unsigned int reg)
+{
+       u32 tmp;
+
+       tmp = __raw_readl(ir->base + reg);
+       tmp = (tmp & ~mask) | val;
+       __raw_writel(tmp, ir->base + reg);
+}
+
+static void mtk_w32(struct mtk_ir *ir, u32 val, unsigned int reg)
+{
+       __raw_writel(val, ir->base + reg);
+}
+
+static u32 mtk_r32(struct mtk_ir *ir, unsigned int reg)
+{
+       return __raw_readl(ir->base + reg);
+}
+
+static inline void mtk_irq_disable(struct mtk_ir *ir, u32 mask)
+{
+       u32 val;
+
+       val = mtk_r32(ir, MTK_IRINT_EN_REG);
+       mtk_w32(ir, val & ~mask, MTK_IRINT_EN_REG);
+}
+
+static inline void mtk_irq_enable(struct mtk_ir *ir, u32 mask)
+{
+       u32 val;
+
+       val = mtk_r32(ir, MTK_IRINT_EN_REG);
+       mtk_w32(ir, val | mask, MTK_IRINT_EN_REG);
+}
+
+static irqreturn_t mtk_ir_irq(int irqno, void *dev_id)
+{
+       struct mtk_ir *ir = dev_id;
+       u8  wid = 0;
+       u32 i, j, val;
+       DEFINE_IR_RAW_EVENT(rawir);
+
+       /*
+        * Reset decoder state machine explicitly is required
+        * because 1) the longest duration for space MTK IR hardware
+        * could record is not safely long. e.g  12ms if rx resolution
+        * is 46us by default. There is still the risk to satisfying
+        * every decoder to reset themselves through long enough
+        * trailing spaces and 2) the IRQ handler guarantees that
+        * start of IR message is always contained in and starting
+        * from register MTK_CHKDATA_REG(0).
+        */
+       ir_raw_event_reset(ir->rc);
+
+       /* First message must be pulse */
+       rawir.pulse = false;
+
+       /* Handle all pulse and space IR controller captures */
+       for (i = 0 ; i < MTK_CHKDATA_SZ ; i++) {
+               val = mtk_r32(ir, MTK_CHKDATA_REG(i));
+               dev_dbg(ir->dev, "@reg%d=0x%08x\n", i, val);
+
+               for (j = 0 ; j < 4 ; j++) {
+                       wid = (val & (MTK_WIDTH_MASK << j * 8)) >> j * 8;
+                       rawir.pulse = !rawir.pulse;
+                       rawir.duration = wid * (MTK_IR_SAMPLE + 1);
+                       ir_raw_event_store_with_filter(ir->rc, &rawir);
+               }
+       }
+
+       /*
+        * The maximum number of edges the IR controller can
+        * hold is MTK_CHKDATA_SZ * 4. So if received IR messages
+        * is over the limit, the last incomplete IR message would
+        * be appended trailing space and still would be sent into
+        * ir-rc-raw to decode. That helps it is possible that it
+        * has enough information to decode a scancode even if the
+        * trailing end of the message is missing.
+        */
+       if (!MTK_IR_END(wid, rawir.pulse)) {
+               rawir.pulse = false;
+               rawir.duration = MTK_MAX_SAMPLES * (MTK_IR_SAMPLE + 1);
+               ir_raw_event_store_with_filter(ir->rc, &rawir);
+       }
+
+       ir_raw_event_handle(ir->rc);
+
+       /*
+        * Restart controller for the next receive that would
+        * clear up all CHKDATA registers
+        */
+       mtk_w32_mask(ir, 0x1, MTK_IRCLR, MTK_IRCLR_REG);
+
+       /* Clear interrupt status */
+       mtk_w32_mask(ir, 0x1, MTK_IRINT_CLR, MTK_IRINT_CLR_REG);
+
+       return IRQ_HANDLED;
+}
+
+static int mtk_ir_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *dn = dev->of_node;
+       struct resource *res;
+       struct mtk_ir *ir;
+       u32 val;
+       int ret = 0;
+       const char *map_name;
+
+       ir = devm_kzalloc(dev, sizeof(struct mtk_ir), GFP_KERNEL);
+       if (!ir)
+               return -ENOMEM;
+
+       ir->dev = dev;
+
+       if (!of_device_is_compatible(dn, "mediatek,mt7623-cir"))
+               return -ENODEV;
+
+       ir->clk = devm_clk_get(dev, "clk");
+       if (IS_ERR(ir->clk)) {
+               dev_err(dev, "failed to get a ir clock.\n");
+               return PTR_ERR(ir->clk);
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       ir->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(ir->base)) {
+               dev_err(dev, "failed to map registers\n");
+               return PTR_ERR(ir->base);
+       }
+
+       ir->rc = devm_rc_allocate_device(dev, RC_DRIVER_IR_RAW);
+       if (!ir->rc) {
+               dev_err(dev, "failed to allocate device\n");
+               return -ENOMEM;
+       }
+
+       ir->rc->priv = ir;
+       ir->rc->input_name = MTK_IR_DEV;
+       ir->rc->input_phys = MTK_IR_DEV "/input0";
+       ir->rc->input_id.bustype = BUS_HOST;
+       ir->rc->input_id.vendor = 0x0001;
+       ir->rc->input_id.product = 0x0001;
+       ir->rc->input_id.version = 0x0001;
+       map_name = of_get_property(dn, "linux,rc-map-name", NULL);
+       ir->rc->map_name = map_name ?: RC_MAP_EMPTY;
+       ir->rc->dev.parent = dev;
+       ir->rc->driver_name = MTK_IR_DEV;
+       ir->rc->allowed_protocols = RC_BIT_ALL;
+       ir->rc->rx_resolution = MTK_IR_SAMPLE;
+       ir->rc->timeout = MTK_MAX_SAMPLES * (MTK_IR_SAMPLE + 1);
+
+       ret = devm_rc_register_device(dev, ir->rc);
+       if (ret) {
+               dev_err(dev, "failed to register rc device\n");
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, ir);
+
+       ir->irq = platform_get_irq(pdev, 0);
+       if (ir->irq < 0) {
+               dev_err(dev, "no irq resource\n");
+               return -ENODEV;
+       }
+
+       /*
+        * Enable interrupt after proper hardware
+        * setup and IRQ handler registration
+        */
+       if (clk_prepare_enable(ir->clk)) {
+               dev_err(dev, "try to enable ir_clk failed\n");
+               ret = -EINVAL;
+               goto exit_clkdisable_clk;
+       }
+
+       mtk_irq_disable(ir, MTK_IRINT_EN);
+
+       ret = devm_request_irq(dev, ir->irq, mtk_ir_irq, 0, MTK_IR_DEV, ir);
+       if (ret) {
+               dev_err(dev, "failed request irq\n");
+               goto exit_clkdisable_clk;
+       }
+
+       /* Enable IR and PWM */
+       val = mtk_r32(ir, MTK_CONFIG_HIGH_REG);
+       val |= MTK_PWM_EN | MTK_IR_EN;
+       mtk_w32(ir, val, MTK_CONFIG_HIGH_REG);
+
+       /* Setting sample period */
+       mtk_w32_mask(ir, MTK_CHK_PERIOD, MTK_CHK_PERIOD_MASK,
+                    MTK_CONFIG_LOW_REG);
+
+       mtk_irq_enable(ir, MTK_IRINT_EN);
+
+       dev_info(dev, "Initialized MT7623 IR driver, sample period = %luus\n",
+                DIV_ROUND_CLOSEST(MTK_IR_SAMPLE, 1000));
+
+       return 0;
+
+exit_clkdisable_clk:
+       clk_disable_unprepare(ir->clk);
+
+       return ret;
+}
+
+static int mtk_ir_remove(struct platform_device *pdev)
+{
+       struct mtk_ir *ir = platform_get_drvdata(pdev);
+
+       /*
+        * Avoid contention between remove handler and
+        * IRQ handler so that disabling IR interrupt and
+        * waiting for pending IRQ handler to complete
+        */
+       mtk_irq_disable(ir, MTK_IRINT_EN);
+       synchronize_irq(ir->irq);
+
+       clk_disable_unprepare(ir->clk);
+
+       return 0;
+}
+
+static const struct of_device_id mtk_ir_match[] = {
+       { .compatible = "mediatek,mt7623-cir" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, mtk_ir_match);
+
+static struct platform_driver mtk_ir_driver = {
+       .probe          = mtk_ir_probe,
+       .remove         = mtk_ir_remove,
+       .driver = {
+               .name = MTK_IR_DEV,
+               .of_match_table = mtk_ir_match,
+       },
+};
+
+module_platform_driver(mtk_ir_driver);
+
+MODULE_DESCRIPTION("Mediatek IR Receiver Controller Driver");
+MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
+MODULE_LICENSE("GPL");
index 4b78c891eb7794935390b7bd60aacb4fb6a0886c..b109f8246b968d99cacde9b6ee73719f554a4bfd 100644 (file)
  * WITHOUT 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
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -176,6 +171,41 @@ static void nvt_set_ioaddr(struct nvt_dev *nvt, unsigned long *ioaddr)
        }
 }
 
+static void nvt_write_wakeup_codes(struct rc_dev *dev,
+                                  const u8 *wbuf, int count)
+{
+       u8 tolerance, config;
+       struct nvt_dev *nvt = dev->priv;
+       int i;
+
+       /* hardcode the tolerance to 10% */
+       tolerance = DIV_ROUND_UP(count, 10);
+
+       spin_lock(&nvt->lock);
+
+       nvt_clear_cir_wake_fifo(nvt);
+       nvt_cir_wake_reg_write(nvt, count, CIR_WAKE_FIFO_CMP_DEEP);
+       nvt_cir_wake_reg_write(nvt, tolerance, CIR_WAKE_FIFO_CMP_TOL);
+
+       config = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON);
+
+       /* enable writes to wake fifo */
+       nvt_cir_wake_reg_write(nvt, config | CIR_WAKE_IRCON_MODE1,
+                              CIR_WAKE_IRCON);
+
+       if (count)
+               pr_info("Wake samples (%d) =", count);
+       else
+               pr_info("Wake sample fifo cleared");
+
+       for (i = 0; i < count; i++)
+               nvt_cir_wake_reg_write(nvt, wbuf[i], CIR_WAKE_WR_FIFO_DATA);
+
+       nvt_cir_wake_reg_write(nvt, config, CIR_WAKE_IRCON);
+
+       spin_unlock(&nvt->lock);
+}
+
 static ssize_t wakeup_data_show(struct device *dev,
                                struct device_attribute *attr,
                                char *buf)
@@ -214,9 +244,7 @@ static ssize_t wakeup_data_store(struct device *dev,
                                 const char *buf, size_t len)
 {
        struct rc_dev *rc_dev = to_rc_dev(dev);
-       struct nvt_dev *nvt = rc_dev->priv;
-       unsigned long flags;
-       u8 tolerance, config, wake_buf[WAKEUP_MAX_SIZE];
+       u8 wake_buf[WAKEUP_MAX_SIZE];
        char **argv;
        int i, count;
        unsigned int val;
@@ -245,27 +273,7 @@ static ssize_t wakeup_data_store(struct device *dev,
                        wake_buf[i] |= BUF_PULSE_BIT;
        }
 
-       /* hardcode the tolerance to 10% */
-       tolerance = DIV_ROUND_UP(count, 10);
-
-       spin_lock_irqsave(&nvt->lock, flags);
-
-       nvt_clear_cir_wake_fifo(nvt);
-       nvt_cir_wake_reg_write(nvt, count, CIR_WAKE_FIFO_CMP_DEEP);
-       nvt_cir_wake_reg_write(nvt, tolerance, CIR_WAKE_FIFO_CMP_TOL);
-
-       config = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON);
-
-       /* enable writes to wake fifo */
-       nvt_cir_wake_reg_write(nvt, config | CIR_WAKE_IRCON_MODE1,
-                              CIR_WAKE_IRCON);
-
-       for (i = 0; i < count; i++)
-               nvt_cir_wake_reg_write(nvt, wake_buf[i], CIR_WAKE_WR_FIFO_DATA);
-
-       nvt_cir_wake_reg_write(nvt, config, CIR_WAKE_IRCON);
-
-       spin_unlock_irqrestore(&nvt->lock, flags);
+       nvt_write_wakeup_codes(rc_dev, wake_buf, count);
 
        ret = len;
 out:
@@ -662,6 +670,62 @@ static int nvt_set_tx_carrier(struct rc_dev *dev, u32 carrier)
        return 0;
 }
 
+static int nvt_ir_raw_set_wakeup_filter(struct rc_dev *dev,
+                                       struct rc_scancode_filter *sc_filter)
+{
+       u8 buf_val;
+       int i, ret, count;
+       unsigned int val;
+       struct ir_raw_event *raw;
+       u8 wake_buf[WAKEUP_MAX_SIZE];
+       bool complete;
+
+       /* Require mask to be set */
+       if (!sc_filter->mask)
+               return 0;
+
+       raw = kmalloc_array(WAKEUP_MAX_SIZE, sizeof(*raw), GFP_KERNEL);
+       if (!raw)
+               return -ENOMEM;
+
+       ret = ir_raw_encode_scancode(dev->wakeup_protocol, sc_filter->data,
+                                    raw, WAKEUP_MAX_SIZE);
+       complete = (ret != -ENOBUFS);
+       if (!complete)
+               ret = WAKEUP_MAX_SIZE;
+       else if (ret < 0)
+               goto out_raw;
+
+       /* Inspect the ir samples */
+       for (i = 0, count = 0; i < ret && count < WAKEUP_MAX_SIZE; ++i) {
+               /* NS to US */
+               val = DIV_ROUND_UP(raw[i].duration, 1000L) / SAMPLE_PERIOD;
+
+               /* Split too large values into several smaller ones */
+               while (val > 0 && count < WAKEUP_MAX_SIZE) {
+                       /* Skip last value for better comparison tolerance */
+                       if (complete && i == ret - 1 && val < BUF_LEN_MASK)
+                               break;
+
+                       /* Clamp values to BUF_LEN_MASK at most */
+                       buf_val = (val > BUF_LEN_MASK) ? BUF_LEN_MASK : val;
+
+                       wake_buf[count] = buf_val;
+                       val -= buf_val;
+                       if ((raw[i]).pulse)
+                               wake_buf[count] |= BUF_PULSE_BIT;
+                       count++;
+               }
+       }
+
+       nvt_write_wakeup_codes(dev, wake_buf, count);
+       ret = 0;
+out_raw:
+       kfree(raw);
+
+       return ret;
+}
+
 /*
  * nvt_tx_ir
  *
@@ -998,7 +1062,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
                return -ENOMEM;
 
        /* input device for IR remote (and tx) */
-       nvt->rdev = devm_rc_allocate_device(&pdev->dev);
+       nvt->rdev = devm_rc_allocate_device(&pdev->dev, RC_DRIVER_IR_RAW);
        if (!nvt->rdev)
                return -ENOMEM;
        rdev = nvt->rdev;
@@ -1061,12 +1125,14 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
 
        /* Set up the rc device */
        rdev->priv = nvt;
-       rdev->driver_type = RC_DRIVER_IR_RAW;
-       rdev->allowed_protocols = RC_BIT_ALL;
+       rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
+       rdev->allowed_wakeup_protocols = RC_BIT_ALL_IR_ENCODER;
+       rdev->encode_wakeup = true;
        rdev->open = nvt_open;
        rdev->close = nvt_close;
        rdev->tx_ir = nvt_tx_ir;
        rdev->s_tx_carrier = nvt_set_tx_carrier;
+       rdev->s_wakeup_filter = nvt_ir_raw_set_wakeup_filter;
        rdev->input_name = "Nuvoton w836x7hg Infrared Remote Transceiver";
        rdev->input_phys = "nuvoton/cir0";
        rdev->input_id.bustype = BUS_HOST;
index c41c5765e1d21e556bc6cac2bd9832cf27badf89..88a29df38a57f8ffb082df109ea8777605684bc9 100644 (file)
  * WITHOUT 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
  */
 
 #include <linux/spinlock.h>
index 585d5e52118d538f7fc764d2793bd98384c72b44..a70a5c55743436979066af1d3cba00e5243fe3a0 100644 (file)
@@ -20,7 +20,6 @@
 #define        MAX_IR_EVENT_SIZE       512
 
 #include <linux/slab.h>
-#include <linux/spinlock.h>
 #include <media/rc-core.h>
 
 struct ir_raw_handler {
@@ -28,6 +27,8 @@ struct ir_raw_handler {
 
        u64 protocols; /* which are handled by this handler */
        int (*decode)(struct rc_dev *dev, struct ir_raw_event event);
+       int (*encode)(enum rc_type protocol, u32 scancode,
+                     struct ir_raw_event *events, unsigned int max);
 
        /* These two should only be used by the lirc decoder */
        int (*raw_register)(struct rc_dev *dev);
@@ -37,7 +38,6 @@ struct ir_raw_handler {
 struct ir_raw_event_ctrl {
        struct list_head                list;           /* to keep track of raw clients */
        struct task_struct              *thread;
-       spinlock_t                      lock;
        /* fifo for the pulse/space durations */
        DECLARE_KFIFO(kfifo, struct ir_raw_event, MAX_IR_EVENT_SIZE);
        ktime_t                         last_event;     /* when last event occurred */
@@ -154,6 +154,111 @@ static inline bool is_timing_event(struct ir_raw_event ev)
 #define TO_US(duration)                        DIV_ROUND_CLOSEST((duration), 1000)
 #define TO_STR(is_pulse)               ((is_pulse) ? "pulse" : "space")
 
+/* functions for IR encoders */
+
+static inline void init_ir_raw_event_duration(struct ir_raw_event *ev,
+                                             unsigned int pulse,
+                                             u32 duration)
+{
+       init_ir_raw_event(ev);
+       ev->duration = duration;
+       ev->pulse = pulse;
+}
+
+/**
+ * struct ir_raw_timings_manchester - Manchester coding timings
+ * @leader:            duration of leader pulse (if any) 0 if continuing
+ *                     existing signal (see @pulse_space_start)
+ * @pulse_space_start: 1 for starting with pulse (0 for starting with space)
+ * @clock:             duration of each pulse/space in ns
+ * @invert:            if set clock logic is inverted
+ *                     (0 = space + pulse, 1 = pulse + space)
+ * @trailer_space:     duration of trailer space in ns
+ */
+struct ir_raw_timings_manchester {
+       unsigned int leader;
+       unsigned int pulse_space_start:1;
+       unsigned int clock;
+       unsigned int invert:1;
+       unsigned int trailer_space;
+};
+
+int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max,
+                         const struct ir_raw_timings_manchester *timings,
+                         unsigned int n, unsigned int data);
+
+/**
+ * ir_raw_gen_pulse_space() - generate pulse and space raw events.
+ * @ev:                        Pointer to pointer to next free raw event.
+ *                     Will be incremented for each raw event written.
+ * @max:               Pointer to number of raw events available in buffer.
+ *                     Will be decremented for each raw event written.
+ * @pulse_width:       Width of pulse in ns.
+ * @space_width:       Width of space in ns.
+ *
+ * Returns:    0 on success.
+ *             -ENOBUFS if there isn't enough buffer space to write both raw
+ *             events. In this case @max events will have been written.
+ */
+static inline int ir_raw_gen_pulse_space(struct ir_raw_event **ev,
+                                        unsigned int *max,
+                                        unsigned int pulse_width,
+                                        unsigned int space_width)
+{
+       if (!*max)
+               return -ENOBUFS;
+       init_ir_raw_event_duration((*ev)++, 1, pulse_width);
+       if (!--*max)
+               return -ENOBUFS;
+       init_ir_raw_event_duration((*ev)++, 0, space_width);
+       --*max;
+       return 0;
+}
+
+/**
+ * struct ir_raw_timings_pd - pulse-distance modulation timings
+ * @header_pulse:      duration of header pulse in ns (0 for none)
+ * @header_space:      duration of header space in ns
+ * @bit_pulse:         duration of bit pulse in ns
+ * @bit_space:         duration of bit space (for logic 0 and 1) in ns
+ * @trailer_pulse:     duration of trailer pulse in ns
+ * @trailer_space:     duration of trailer space in ns
+ * @msb_first:         1 if most significant bit is sent first
+ */
+struct ir_raw_timings_pd {
+       unsigned int header_pulse;
+       unsigned int header_space;
+       unsigned int bit_pulse;
+       unsigned int bit_space[2];
+       unsigned int trailer_pulse;
+       unsigned int trailer_space;
+       unsigned int msb_first:1;
+};
+
+int ir_raw_gen_pd(struct ir_raw_event **ev, unsigned int max,
+                 const struct ir_raw_timings_pd *timings,
+                 unsigned int n, u64 data);
+
+/**
+ * struct ir_raw_timings_pl - pulse-length modulation timings
+ * @header_pulse:      duration of header pulse in ns (0 for none)
+ * @bit_space:         duration of bit space in ns
+ * @bit_pulse:         duration of bit pulse (for logic 0 and 1) in ns
+ * @trailer_space:     duration of trailer space in ns
+ * @msb_first:         1 if most significant bit is sent first
+ */
+struct ir_raw_timings_pl {
+       unsigned int header_pulse;
+       unsigned int bit_space;
+       unsigned int bit_pulse[2];
+       unsigned int trailer_space;
+       unsigned int msb_first:1;
+};
+
+int ir_raw_gen_pl(struct ir_raw_event **ev, unsigned int max,
+                 const struct ir_raw_timings_pl *timings,
+                 unsigned int n, u64 data);
+
 /*
  * Routines from rc-raw.c to be used internally and by decoders
  */
index 1c42a9f2f2901b417ab7fdd258fdb416546aeeea..7fa84b64a2ae53c71476f83d89b8eb7062c73643 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/mutex.h>
 #include <linux/kmod.h>
 #include <linux/sched.h>
-#include <linux/freezer.h>
 #include "rc-core-priv.h"
 
 /* Used to keep track of IR raw clients, protected by ir_raw_handler_lock */
@@ -34,32 +33,26 @@ static int ir_raw_event_thread(void *data)
        struct ir_raw_handler *handler;
        struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data;
 
-       while (!kthread_should_stop()) {
-
-               spin_lock_irq(&raw->lock);
-
-               if (!kfifo_len(&raw->kfifo)) {
-                       set_current_state(TASK_INTERRUPTIBLE);
-
-                       if (kthread_should_stop())
-                               set_current_state(TASK_RUNNING);
-
-                       spin_unlock_irq(&raw->lock);
-                       schedule();
-                       continue;
+       while (1) {
+               mutex_lock(&ir_raw_handler_lock);
+               while (kfifo_out(&raw->kfifo, &ev, 1)) {
+                       list_for_each_entry(handler, &ir_raw_handler_list, list)
+                               if (raw->dev->enabled_protocols &
+                                   handler->protocols || !handler->protocols)
+                                       handler->decode(raw->dev, ev);
+                       raw->prev_ev = ev;
                }
+               mutex_unlock(&ir_raw_handler_lock);
 
-               if(!kfifo_out(&raw->kfifo, &ev, 1))
-                       dev_err(&raw->dev->dev, "IR event FIFO is empty!\n");
-               spin_unlock_irq(&raw->lock);
+               set_current_state(TASK_INTERRUPTIBLE);
 
-               mutex_lock(&ir_raw_handler_lock);
-               list_for_each_entry(handler, &ir_raw_handler_list, list)
-                       if (raw->dev->enabled_protocols & handler->protocols ||
-                           !handler->protocols)
-                               handler->decode(raw->dev, ev);
-               raw->prev_ev = ev;
-               mutex_unlock(&ir_raw_handler_lock);
+               if (kthread_should_stop()) {
+                       __set_current_state(TASK_RUNNING);
+                       break;
+               } else if (!kfifo_is_empty(&raw->kfifo))
+                       set_current_state(TASK_RUNNING);
+
+               schedule();
        }
 
        return 0;
@@ -218,14 +211,10 @@ EXPORT_SYMBOL_GPL(ir_raw_event_set_idle);
  */
 void ir_raw_event_handle(struct rc_dev *dev)
 {
-       unsigned long flags;
-
        if (!dev->raw)
                return;
 
-       spin_lock_irqsave(&dev->raw->lock, flags);
        wake_up_process(dev->raw->thread);
-       spin_unlock_irqrestore(&dev->raw->lock, flags);
 }
 EXPORT_SYMBOL_GPL(ir_raw_event_handle);
 
@@ -246,10 +235,254 @@ static void ir_raw_disable_protocols(struct rc_dev *dev, u64 protocols)
 {
        mutex_lock(&dev->lock);
        dev->enabled_protocols &= ~protocols;
-       dev->enabled_wakeup_protocols &= ~protocols;
        mutex_unlock(&dev->lock);
 }
 
+/**
+ * ir_raw_gen_manchester() - Encode data with Manchester (bi-phase) modulation.
+ * @ev:                Pointer to pointer to next free event. *@ev is incremented for
+ *             each raw event filled.
+ * @max:       Maximum number of raw events to fill.
+ * @timings:   Manchester modulation timings.
+ * @n:         Number of bits of data.
+ * @data:      Data bits to encode.
+ *
+ * Encodes the @n least significant bits of @data using Manchester (bi-phase)
+ * modulation with the timing characteristics described by @timings, writing up
+ * to @max raw IR events using the *@ev pointer.
+ *
+ * Returns:    0 on success.
+ *             -ENOBUFS if there isn't enough space in the array to fit the
+ *             full encoded data. In this case all @max events will have been
+ *             written.
+ */
+int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max,
+                         const struct ir_raw_timings_manchester *timings,
+                         unsigned int n, unsigned int data)
+{
+       bool need_pulse;
+       unsigned int i;
+       int ret = -ENOBUFS;
+
+       i = 1 << (n - 1);
+
+       if (timings->leader) {
+               if (!max--)
+                       return ret;
+               if (timings->pulse_space_start) {
+                       init_ir_raw_event_duration((*ev)++, 1, timings->leader);
+
+                       if (!max--)
+                               return ret;
+                       init_ir_raw_event_duration((*ev), 0, timings->leader);
+               } else {
+                       init_ir_raw_event_duration((*ev), 1, timings->leader);
+               }
+               i >>= 1;
+       } else {
+               /* continue existing signal */
+               --(*ev);
+       }
+       /* from here on *ev will point to the last event rather than the next */
+
+       while (n && i > 0) {
+               need_pulse = !(data & i);
+               if (timings->invert)
+                       need_pulse = !need_pulse;
+               if (need_pulse == !!(*ev)->pulse) {
+                       (*ev)->duration += timings->clock;
+               } else {
+                       if (!max--)
+                               goto nobufs;
+                       init_ir_raw_event_duration(++(*ev), need_pulse,
+                                                  timings->clock);
+               }
+
+               if (!max--)
+                       goto nobufs;
+               init_ir_raw_event_duration(++(*ev), !need_pulse,
+                                          timings->clock);
+               i >>= 1;
+       }
+
+       if (timings->trailer_space) {
+               if (!(*ev)->pulse)
+                       (*ev)->duration += timings->trailer_space;
+               else if (!max--)
+                       goto nobufs;
+               else
+                       init_ir_raw_event_duration(++(*ev), 0,
+                                                  timings->trailer_space);
+       }
+
+       ret = 0;
+nobufs:
+       /* point to the next event rather than last event before returning */
+       ++(*ev);
+       return ret;
+}
+EXPORT_SYMBOL(ir_raw_gen_manchester);
+
+/**
+ * ir_raw_gen_pd() - Encode data to raw events with pulse-distance modulation.
+ * @ev:                Pointer to pointer to next free event. *@ev is incremented for
+ *             each raw event filled.
+ * @max:       Maximum number of raw events to fill.
+ * @timings:   Pulse distance modulation timings.
+ * @n:         Number of bits of data.
+ * @data:      Data bits to encode.
+ *
+ * Encodes the @n least significant bits of @data using pulse-distance
+ * modulation with the timing characteristics described by @timings, writing up
+ * to @max raw IR events using the *@ev pointer.
+ *
+ * Returns:    0 on success.
+ *             -ENOBUFS if there isn't enough space in the array to fit the
+ *             full encoded data. In this case all @max events will have been
+ *             written.
+ */
+int ir_raw_gen_pd(struct ir_raw_event **ev, unsigned int max,
+                 const struct ir_raw_timings_pd *timings,
+                 unsigned int n, u64 data)
+{
+       int i;
+       int ret;
+       unsigned int space;
+
+       if (timings->header_pulse) {
+               ret = ir_raw_gen_pulse_space(ev, &max, timings->header_pulse,
+                                            timings->header_space);
+               if (ret)
+                       return ret;
+       }
+
+       if (timings->msb_first) {
+               for (i = n - 1; i >= 0; --i) {
+                       space = timings->bit_space[(data >> i) & 1];
+                       ret = ir_raw_gen_pulse_space(ev, &max,
+                                                    timings->bit_pulse,
+                                                    space);
+                       if (ret)
+                               return ret;
+               }
+       } else {
+               for (i = 0; i < n; ++i, data >>= 1) {
+                       space = timings->bit_space[data & 1];
+                       ret = ir_raw_gen_pulse_space(ev, &max,
+                                                    timings->bit_pulse,
+                                                    space);
+                       if (ret)
+                               return ret;
+               }
+       }
+
+       ret = ir_raw_gen_pulse_space(ev, &max, timings->trailer_pulse,
+                                    timings->trailer_space);
+       return ret;
+}
+EXPORT_SYMBOL(ir_raw_gen_pd);
+
+/**
+ * ir_raw_gen_pl() - Encode data to raw events with pulse-length modulation.
+ * @ev:                Pointer to pointer to next free event. *@ev is incremented for
+ *             each raw event filled.
+ * @max:       Maximum number of raw events to fill.
+ * @timings:   Pulse distance modulation timings.
+ * @n:         Number of bits of data.
+ * @data:      Data bits to encode.
+ *
+ * Encodes the @n least significant bits of @data using space-distance
+ * modulation with the timing characteristics described by @timings, writing up
+ * to @max raw IR events using the *@ev pointer.
+ *
+ * Returns:    0 on success.
+ *             -ENOBUFS if there isn't enough space in the array to fit the
+ *             full encoded data. In this case all @max events will have been
+ *             written.
+ */
+int ir_raw_gen_pl(struct ir_raw_event **ev, unsigned int max,
+                 const struct ir_raw_timings_pl *timings,
+                 unsigned int n, u64 data)
+{
+       int i;
+       int ret = -ENOBUFS;
+       unsigned int pulse;
+
+       if (!max--)
+               return ret;
+
+       init_ir_raw_event_duration((*ev)++, 1, timings->header_pulse);
+
+       if (timings->msb_first) {
+               for (i = n - 1; i >= 0; --i) {
+                       if (!max--)
+                               return ret;
+                       init_ir_raw_event_duration((*ev)++, 0,
+                                                  timings->bit_space);
+                       if (!max--)
+                               return ret;
+                       pulse = timings->bit_pulse[(data >> i) & 1];
+                       init_ir_raw_event_duration((*ev)++, 1, pulse);
+               }
+       } else {
+               for (i = 0; i < n; ++i, data >>= 1) {
+                       if (!max--)
+                               return ret;
+                       init_ir_raw_event_duration((*ev)++, 0,
+                                                  timings->bit_space);
+                       if (!max--)
+                               return ret;
+                       pulse = timings->bit_pulse[data & 1];
+                       init_ir_raw_event_duration((*ev)++, 1, pulse);
+               }
+       }
+
+       if (!max--)
+               return ret;
+
+       init_ir_raw_event_duration((*ev)++, 0, timings->trailer_space);
+
+       return 0;
+}
+EXPORT_SYMBOL(ir_raw_gen_pl);
+
+/**
+ * ir_raw_encode_scancode() - Encode a scancode as raw events
+ *
+ * @protocol:          protocol
+ * @scancode:          scancode filter describing a single scancode
+ * @events:            array of raw events to write into
+ * @max:               max number of raw events
+ *
+ * Attempts to encode the scancode as raw 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.
+ *             -EINVAL if the scancode is ambiguous or invalid, or if no
+ *             compatible encoder was found.
+ */
+int ir_raw_encode_scancode(enum rc_type protocol, u32 scancode,
+                          struct ir_raw_event *events, unsigned int max)
+{
+       struct ir_raw_handler *handler;
+       int ret = -EINVAL;
+       u64 mask = 1ULL << protocol;
+
+       mutex_lock(&ir_raw_handler_lock);
+       list_for_each_entry(handler, &ir_raw_handler_list, list) {
+               if (handler->protocols & mask && handler->encode) {
+                       ret = handler->encode(protocol, scancode, events, max);
+                       if (ret >= 0 || ret == -ENOBUFS)
+                               break;
+               }
+       }
+       mutex_unlock(&ir_raw_handler_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL(ir_raw_encode_scancode);
+
 /*
  * Used to (un)register raw event clients
  */
@@ -269,13 +502,18 @@ int ir_raw_event_register(struct rc_dev *dev)
        dev->change_protocol = change_protocol;
        INIT_KFIFO(dev->raw->kfifo);
 
-       spin_lock_init(&dev->raw->lock);
-       dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw,
-                                      "rc%u", dev->minor);
+       /*
+        * raw transmitters do not need any event registration
+        * because the event is coming from userspace
+        */
+       if (dev->driver_type != RC_DRIVER_IR_RAW_TX) {
+               dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw,
+                                              "rc%u", dev->minor);
 
-       if (IS_ERR(dev->raw->thread)) {
-               rc = PTR_ERR(dev->raw->thread);
-               goto out;
+               if (IS_ERR(dev->raw->thread)) {
+                       rc = PTR_ERR(dev->raw->thread);
+                       goto out;
+               }
        }
 
        mutex_lock(&ir_raw_handler_lock);
index 63dace8198b0b3dbcb116108e238351fe9684a9e..62195af24fbe7769a8d806454a15329eb72fa8da 100644 (file)
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
  */
 
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/sched.h>
+#include <linux/slab.h>
 #include <media/rc-core.h>
 
 #define DRIVER_NAME    "rc-loopback"
@@ -176,12 +173,47 @@ static int loop_set_carrier_report(struct rc_dev *dev, int enable)
        return 0;
 }
 
+static int loop_set_wakeup_filter(struct rc_dev *dev,
+                                 struct rc_scancode_filter *sc)
+{
+       static const unsigned int max = 512;
+       struct ir_raw_event *raw;
+       int ret;
+       int i;
+
+       /* fine to disable filter */
+       if (!sc->mask)
+               return 0;
+
+       /* encode the specified filter and loop it back */
+       raw = kmalloc_array(max, sizeof(*raw), GFP_KERNEL);
+       if (!raw)
+               return -ENOMEM;
+
+       ret = ir_raw_encode_scancode(dev->wakeup_protocol, sc->data, raw, max);
+       /* still loop back the partial raw IR even if it's incomplete */
+       if (ret == -ENOBUFS)
+               ret = max;
+       if (ret >= 0) {
+               /* do the loopback */
+               for (i = 0; i < ret; ++i)
+                       ir_raw_event_store(dev, &raw[i]);
+               ir_raw_event_handle(dev);
+
+               ret = 0;
+       }
+
+       kfree(raw);
+
+       return ret;
+}
+
 static int __init loop_init(void)
 {
        struct rc_dev *rc;
        int ret;
 
-       rc = rc_allocate_device();
+       rc = rc_allocate_device(RC_DRIVER_IR_RAW);
        if (!rc) {
                printk(KERN_ERR DRIVER_NAME ": rc_dev allocation failed\n");
                return -ENOMEM;
@@ -194,8 +226,9 @@ static int __init loop_init(void)
        rc->driver_name         = DRIVER_NAME;
        rc->map_name            = RC_MAP_EMPTY;
        rc->priv                = &loopdev;
-       rc->driver_type         = RC_DRIVER_IR_RAW;
-       rc->allowed_protocols   = RC_BIT_ALL;
+       rc->allowed_protocols   = RC_BIT_ALL_IR_DECODER;
+       rc->allowed_wakeup_protocols = RC_BIT_ALL_IR_ENCODER;
+       rc->encode_wakeup       = true;
        rc->timeout             = 100 * 1000 * 1000; /* 100 ms */
        rc->min_timeout         = 1;
        rc->max_timeout         = UINT_MAX;
@@ -209,6 +242,7 @@ static int __init loop_init(void)
        rc->s_idle              = loop_set_idle;
        rc->s_learning_mode     = loop_set_learning_mode;
        rc->s_carrier_report    = loop_set_carrier_report;
+       rc->s_wakeup_filter     = loop_set_wakeup_filter;
 
        loopdev.txmask          = RXMASK_REGULAR;
        loopdev.txcarrier       = 36000;
index dedaf38c5ff6cceee42e29f5871794f1bad23b1d..2424946740e64fb602f55a30d5f158a212cc88ce 100644 (file)
@@ -724,6 +724,72 @@ void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protocol,
 }
 EXPORT_SYMBOL_GPL(rc_keydown_notimeout);
 
+/**
+ * rc_validate_filter() - checks that the scancode and mask are valid and
+ *                       provides sensible defaults
+ * @dev:       the struct rc_dev descriptor of the device
+ * @filter:    the scancode and mask
+ * @return:    0 or -EINVAL if the filter is not valid
+ */
+static int rc_validate_filter(struct rc_dev *dev,
+                             struct rc_scancode_filter *filter)
+{
+       static u32 masks[] = {
+               [RC_TYPE_RC5] = 0x1f7f,
+               [RC_TYPE_RC5X_20] = 0x1f7f3f,
+               [RC_TYPE_RC5_SZ] = 0x2fff,
+               [RC_TYPE_SONY12] = 0x1f007f,
+               [RC_TYPE_SONY15] = 0xff007f,
+               [RC_TYPE_SONY20] = 0x1fff7f,
+               [RC_TYPE_JVC] = 0xffff,
+               [RC_TYPE_NEC] = 0xffff,
+               [RC_TYPE_NECX] = 0xffffff,
+               [RC_TYPE_NEC32] = 0xffffffff,
+               [RC_TYPE_SANYO] = 0x1fffff,
+               [RC_TYPE_RC6_0] = 0xffff,
+               [RC_TYPE_RC6_6A_20] = 0xfffff,
+               [RC_TYPE_RC6_6A_24] = 0xffffff,
+               [RC_TYPE_RC6_6A_32] = 0xffffffff,
+               [RC_TYPE_RC6_MCE] = 0xffff7fff,
+               [RC_TYPE_SHARP] = 0x1fff,
+       };
+       u32 s = filter->data;
+       enum rc_type protocol = dev->wakeup_protocol;
+
+       switch (protocol) {
+       case RC_TYPE_NECX:
+               if ((((s >> 16) ^ ~(s >> 8)) & 0xff) == 0)
+                       return -EINVAL;
+               break;
+       case RC_TYPE_NEC32:
+               if ((((s >> 24) ^ ~(s >> 16)) & 0xff) == 0)
+                       return -EINVAL;
+               break;
+       case RC_TYPE_RC6_MCE:
+               if ((s & 0xffff0000) != 0x800f0000)
+                       return -EINVAL;
+               break;
+       case RC_TYPE_RC6_6A_32:
+               if ((s & 0xffff0000) == 0x800f0000)
+                       return -EINVAL;
+               break;
+       default:
+               break;
+       }
+
+       filter->data &= masks[protocol];
+       filter->mask &= masks[protocol];
+
+       /*
+        * If we have to raw encode the IR for wakeup, we cannot have a mask
+        */
+       if (dev->encode_wakeup &&
+           filter->mask != 0 && filter->mask != masks[protocol])
+               return -EINVAL;
+
+       return 0;
+}
+
 int rc_open(struct rc_dev *rdev)
 {
        int rval = 0;
@@ -796,7 +862,7 @@ static const struct {
        { RC_BIT_OTHER,         "other",        NULL                    },
        { RC_BIT_UNKNOWN,       "unknown",      NULL                    },
        { RC_BIT_RC5 |
-         RC_BIT_RC5X,          "rc-5",         "ir-rc5-decoder"        },
+         RC_BIT_RC5X_20,       "rc-5",         "ir-rc5-decoder"        },
        { RC_BIT_NEC |
          RC_BIT_NECX |
          RC_BIT_NEC32,         "nec",          "ir-nec-decoder"        },
@@ -830,11 +896,6 @@ struct rc_filter_attribute {
 };
 #define to_rc_filter_attr(a) container_of(a, struct rc_filter_attribute, attr)
 
-#define RC_PROTO_ATTR(_name, _mode, _show, _store, _type)              \
-       struct rc_filter_attribute dev_attr_##_name = {                 \
-               .attr = __ATTR(_name, _mode, _show, _store),            \
-               .type = (_type),                                        \
-       }
 #define RC_FILTER_ATTR(_name, _mode, _show, _store, _type, _mask)      \
        struct rc_filter_attribute dev_attr_##_name = {                 \
                .attr = __ATTR(_name, _mode, _show, _store),            \
@@ -860,13 +921,13 @@ static bool lirc_is_present(void)
 }
 
 /**
- * show_protocols() - shows the current/wakeup IR protocol(s)
+ * show_protocols() - shows the current IR protocol(s)
  * @device:    the device descriptor
  * @mattr:     the device attribute struct
  * @buf:       a pointer to the output buffer
  *
  * This routine is a callback routine for input read the IR protocol type(s).
- * it is trigged by reading /sys/class/rc/rc?/[wakeup_]protocols.
+ * it is trigged by reading /sys/class/rc/rc?/protocols.
  * It returns the protocol names of supported protocols.
  * Enabled protocols are printed in brackets.
  *
@@ -877,7 +938,6 @@ static ssize_t show_protocols(struct device *device,
                              struct device_attribute *mattr, char *buf)
 {
        struct rc_dev *dev = to_rc_dev(device);
-       struct rc_filter_attribute *fattr = to_rc_filter_attr(mattr);
        u64 allowed, enabled;
        char *tmp = buf;
        int i;
@@ -891,15 +951,10 @@ static ssize_t show_protocols(struct device *device,
 
        mutex_lock(&dev->lock);
 
-       if (fattr->type == RC_FILTER_NORMAL) {
-               enabled = dev->enabled_protocols;
-               allowed = dev->allowed_protocols;
-               if (dev->raw && !allowed)
-                       allowed = ir_raw_get_allowed_protocols();
-       } else {
-               enabled = dev->enabled_wakeup_protocols;
-               allowed = dev->allowed_wakeup_protocols;
-       }
+       enabled = dev->enabled_protocols;
+       allowed = dev->allowed_protocols;
+       if (dev->raw && !allowed)
+               allowed = ir_raw_get_allowed_protocols();
 
        mutex_unlock(&dev->lock);
 
@@ -997,7 +1052,6 @@ static int parse_protocol_change(u64 *protocols, const char *buf)
 }
 
 static void ir_raw_load_modules(u64 *protocols)
-
 {
        u64 available;
        int i, ret;
@@ -1030,8 +1084,7 @@ static void ir_raw_load_modules(u64 *protocols)
                if (!(*protocols & proto_names[i].type & ~available))
                        continue;
 
-               pr_err("Loaded IR protocol module %s, \
-                      but protocol %s still not available\n",
+               pr_err("Loaded IR protocol module %s, but protocol %s still not available\n",
                       proto_names[i].module_name,
                       proto_names[i].name);
                *protocols &= ~proto_names[i].type;
@@ -1058,11 +1111,8 @@ static ssize_t store_protocols(struct device *device,
                               const char *buf, size_t len)
 {
        struct rc_dev *dev = to_rc_dev(device);
-       struct rc_filter_attribute *fattr = to_rc_filter_attr(mattr);
        u64 *current_protocols;
-       int (*change_protocol)(struct rc_dev *dev, u64 *rc_type);
        struct rc_scancode_filter *filter;
-       int (*set_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter);
        u64 old_protocols, new_protocols;
        ssize_t rc;
 
@@ -1073,21 +1123,11 @@ static ssize_t store_protocols(struct device *device,
        if (!atomic_read(&dev->initialized))
                return -ERESTARTSYS;
 
-       if (fattr->type == RC_FILTER_NORMAL) {
-               IR_dprintk(1, "Normal protocol change requested\n");
-               current_protocols = &dev->enabled_protocols;
-               change_protocol = dev->change_protocol;
-               filter = &dev->scancode_filter;
-               set_filter = dev->s_filter;
-       } else {
-               IR_dprintk(1, "Wakeup protocol change requested\n");
-               current_protocols = &dev->enabled_wakeup_protocols;
-               change_protocol = dev->change_wakeup_protocol;
-               filter = &dev->scancode_wakeup_filter;
-               set_filter = dev->s_wakeup_filter;
-       }
+       IR_dprintk(1, "Normal protocol change requested\n");
+       current_protocols = &dev->enabled_protocols;
+       filter = &dev->scancode_filter;
 
-       if (!change_protocol) {
+       if (!dev->change_protocol) {
                IR_dprintk(1, "Protocol switching not supported\n");
                return -EINVAL;
        }
@@ -1100,7 +1140,7 @@ static ssize_t store_protocols(struct device *device,
        if (rc < 0)
                goto out;
 
-       rc = change_protocol(dev, &new_protocols);
+       rc = dev->change_protocol(dev, &new_protocols);
        if (rc < 0) {
                IR_dprintk(1, "Error setting protocols to 0x%llx\n",
                           (long long)new_protocols);
@@ -1123,16 +1163,16 @@ static ssize_t store_protocols(struct device *device,
         * Try setting the same filter with the new protocol (if any).
         * Fall back to clearing the filter.
         */
-       if (set_filter && filter->mask) {
+       if (dev->s_filter && filter->mask) {
                if (new_protocols)
-                       rc = set_filter(dev, filter);
+                       rc = dev->s_filter(dev, filter);
                else
                        rc = -1;
 
                if (rc < 0) {
                        filter->data = 0;
                        filter->mask = 0;
-                       set_filter(dev, filter);
+                       dev->s_filter(dev, filter);
                }
        }
 
@@ -1221,7 +1261,6 @@ static ssize_t store_filter(struct device *device,
        int ret;
        unsigned long val;
        int (*set_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter);
-       u64 *enabled_protocols;
 
        /* Device is being removed */
        if (!dev)
@@ -1236,11 +1275,9 @@ static ssize_t store_filter(struct device *device,
 
        if (fattr->type == RC_FILTER_NORMAL) {
                set_filter = dev->s_filter;
-               enabled_protocols = &dev->enabled_protocols;
                filter = &dev->scancode_filter;
        } else {
                set_filter = dev->s_wakeup_filter;
-               enabled_protocols = &dev->enabled_wakeup_protocols;
                filter = &dev->scancode_wakeup_filter;
        }
 
@@ -1255,7 +1292,22 @@ static ssize_t store_filter(struct device *device,
        else
                new_filter.data = val;
 
-       if (!*enabled_protocols && val) {
+       if (fattr->type == RC_FILTER_WAKEUP) {
+               /*
+                * Refuse to set a filter unless a protocol is enabled
+                * and the filter is valid for that protocol
+                */
+               if (dev->wakeup_protocol != RC_TYPE_UNKNOWN)
+                       ret = rc_validate_filter(dev, &new_filter);
+               else
+                       ret = -EINVAL;
+
+               if (ret != 0)
+                       goto unlock;
+       }
+
+       if (fattr->type == RC_FILTER_NORMAL && !dev->enabled_protocols &&
+           val) {
                /* refuse to set a filter unless a protocol is enabled */
                ret = -EINVAL;
                goto unlock;
@@ -1272,6 +1324,182 @@ unlock:
        return (ret < 0) ? ret : len;
 }
 
+/*
+ * This is the list of all variants of all protocols, which is used by
+ * the wakeup_protocols sysfs entry. In the protocols sysfs entry some
+ * some protocols are grouped together (e.g. nec = nec + necx + nec32).
+ *
+ * For wakeup we need to know the exact protocol variant so the hardware
+ * can be programmed exactly what to expect.
+ */
+static const char * const proto_variant_names[] = {
+       [RC_TYPE_UNKNOWN] = "unknown",
+       [RC_TYPE_OTHER] = "other",
+       [RC_TYPE_RC5] = "rc-5",
+       [RC_TYPE_RC5X_20] = "rc-5x-20",
+       [RC_TYPE_RC5_SZ] = "rc-5-sz",
+       [RC_TYPE_JVC] = "jvc",
+       [RC_TYPE_SONY12] = "sony-12",
+       [RC_TYPE_SONY15] = "sony-15",
+       [RC_TYPE_SONY20] = "sony-20",
+       [RC_TYPE_NEC] = "nec",
+       [RC_TYPE_NECX] = "nec-x",
+       [RC_TYPE_NEC32] = "nec-32",
+       [RC_TYPE_SANYO] = "sanyo",
+       [RC_TYPE_MCE_KBD] = "mce_kbd",
+       [RC_TYPE_RC6_0] = "rc-6-0",
+       [RC_TYPE_RC6_6A_20] = "rc-6-6a-20",
+       [RC_TYPE_RC6_6A_24] = "rc-6-6a-24",
+       [RC_TYPE_RC6_6A_32] = "rc-6-6a-32",
+       [RC_TYPE_RC6_MCE] = "rc-6-mce",
+       [RC_TYPE_SHARP] = "sharp",
+       [RC_TYPE_XMP] = "xmp",
+       [RC_TYPE_CEC] = "cec",
+};
+
+/**
+ * show_wakeup_protocols() - shows the wakeup IR protocol
+ * @device:    the device descriptor
+ * @mattr:     the device attribute struct
+ * @buf:       a pointer to the output buffer
+ *
+ * This routine is a callback routine for input read the IR protocol type(s).
+ * it is trigged by reading /sys/class/rc/rc?/wakeup_protocols.
+ * It returns the protocol names of supported protocols.
+ * The enabled protocols are printed in brackets.
+ *
+ * dev->lock is taken to guard against races between device
+ * registration, store_protocols and show_protocols.
+ */
+static ssize_t show_wakeup_protocols(struct device *device,
+                                    struct device_attribute *mattr,
+                                    char *buf)
+{
+       struct rc_dev *dev = to_rc_dev(device);
+       u64 allowed;
+       enum rc_type enabled;
+       char *tmp = buf;
+       int i;
+
+       /* Device is being removed */
+       if (!dev)
+               return -EINVAL;
+
+       if (!atomic_read(&dev->initialized))
+               return -ERESTARTSYS;
+
+       mutex_lock(&dev->lock);
+
+       allowed = dev->allowed_wakeup_protocols;
+       enabled = dev->wakeup_protocol;
+
+       mutex_unlock(&dev->lock);
+
+       IR_dprintk(1, "%s: allowed - 0x%llx, enabled - %d\n",
+                  __func__, (long long)allowed, enabled);
+
+       for (i = 0; i < ARRAY_SIZE(proto_variant_names); i++) {
+               if (allowed & (1ULL << i)) {
+                       if (i == enabled)
+                               tmp += sprintf(tmp, "[%s] ",
+                                               proto_variant_names[i]);
+                       else
+                               tmp += sprintf(tmp, "%s ",
+                                               proto_variant_names[i]);
+               }
+       }
+
+       if (tmp != buf)
+               tmp--;
+       *tmp = '\n';
+
+       return tmp + 1 - buf;
+}
+
+/**
+ * store_wakeup_protocols() - changes the wakeup IR protocol(s)
+ * @device:    the device descriptor
+ * @mattr:     the device attribute struct
+ * @buf:       a pointer to the input buffer
+ * @len:       length of the input buffer
+ *
+ * This routine is for changing the IR protocol type.
+ * It is trigged by writing to /sys/class/rc/rc?/wakeup_protocols.
+ * Returns @len on success or a negative error code.
+ *
+ * dev->lock is taken to guard against races between device
+ * registration, store_protocols and show_protocols.
+ */
+static ssize_t store_wakeup_protocols(struct device *device,
+                                     struct device_attribute *mattr,
+                                     const char *buf, size_t len)
+{
+       struct rc_dev *dev = to_rc_dev(device);
+       enum rc_type protocol;
+       ssize_t rc;
+       u64 allowed;
+       int i;
+
+       /* Device is being removed */
+       if (!dev)
+               return -EINVAL;
+
+       if (!atomic_read(&dev->initialized))
+               return -ERESTARTSYS;
+
+       mutex_lock(&dev->lock);
+
+       allowed = dev->allowed_wakeup_protocols;
+
+       if (sysfs_streq(buf, "none")) {
+               protocol = RC_TYPE_UNKNOWN;
+       } else {
+               for (i = 0; i < ARRAY_SIZE(proto_variant_names); i++) {
+                       if ((allowed & (1ULL << i)) &&
+                           sysfs_streq(buf, proto_variant_names[i])) {
+                               protocol = i;
+                               break;
+                       }
+               }
+
+               if (i == ARRAY_SIZE(proto_variant_names)) {
+                       rc = -EINVAL;
+                       goto out;
+               }
+
+               if (dev->encode_wakeup) {
+                       u64 mask = 1ULL << protocol;
+
+                       ir_raw_load_modules(&mask);
+                       if (!mask) {
+                               rc = -EINVAL;
+                               goto out;
+                       }
+               }
+       }
+
+       if (dev->wakeup_protocol != protocol) {
+               dev->wakeup_protocol = protocol;
+               IR_dprintk(1, "Wakeup protocol changed to %d\n", protocol);
+
+               if (protocol == RC_TYPE_RC6_MCE)
+                       dev->scancode_wakeup_filter.data = 0x800f0000;
+               else
+                       dev->scancode_wakeup_filter.data = 0;
+               dev->scancode_wakeup_filter.mask = 0;
+
+               rc = dev->s_wakeup_filter(dev, &dev->scancode_wakeup_filter);
+               if (rc == 0)
+                       rc = len;
+       } else {
+               rc = len;
+       }
+
+out:
+       mutex_unlock(&dev->lock);
+       return rc;
+}
+
 static void rc_dev_release(struct device *device)
 {
        struct rc_dev *dev = to_rc_dev(device);
@@ -1301,10 +1529,9 @@ static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env)
 /*
  * Static device attribute struct with the sysfs attributes for IR's
  */
-static RC_PROTO_ATTR(protocols, S_IRUGO | S_IWUSR,
-                    show_protocols, store_protocols, RC_FILTER_NORMAL);
-static RC_PROTO_ATTR(wakeup_protocols, S_IRUGO | S_IWUSR,
-                    show_protocols, store_protocols, RC_FILTER_WAKEUP);
+static DEVICE_ATTR(protocols, 0644, show_protocols, store_protocols);
+static DEVICE_ATTR(wakeup_protocols, 0644, show_wakeup_protocols,
+                  store_wakeup_protocols);
 static RC_FILTER_ATTR(filter, S_IRUGO|S_IWUSR,
                      show_filter, store_filter, RC_FILTER_NORMAL, false);
 static RC_FILTER_ATTR(filter_mask, S_IRUGO|S_IWUSR,
@@ -1315,7 +1542,7 @@ static RC_FILTER_ATTR(wakeup_filter_mask, S_IRUGO|S_IWUSR,
                      show_filter, store_filter, RC_FILTER_WAKEUP, true);
 
 static struct attribute *rc_dev_protocol_attrs[] = {
-       &dev_attr_protocols.attr.attr,
+       &dev_attr_protocols.attr,
        NULL,
 };
 
@@ -1323,15 +1550,6 @@ static struct attribute_group rc_dev_protocol_attr_grp = {
        .attrs  = rc_dev_protocol_attrs,
 };
 
-static struct attribute *rc_dev_wakeup_protocol_attrs[] = {
-       &dev_attr_wakeup_protocols.attr.attr,
-       NULL,
-};
-
-static struct attribute_group rc_dev_wakeup_protocol_attr_grp = {
-       .attrs  = rc_dev_wakeup_protocol_attrs,
-};
-
 static struct attribute *rc_dev_filter_attrs[] = {
        &dev_attr_filter.attr.attr,
        &dev_attr_filter_mask.attr.attr,
@@ -1345,6 +1563,7 @@ static struct attribute_group rc_dev_filter_attr_grp = {
 static struct attribute *rc_dev_wakeup_filter_attrs[] = {
        &dev_attr_wakeup_filter.attr.attr,
        &dev_attr_wakeup_filter_mask.attr.attr,
+       &dev_attr_wakeup_protocols.attr,
        NULL,
 };
 
@@ -1357,7 +1576,7 @@ static struct device_type rc_dev_type = {
        .uevent         = rc_dev_uevent,
 };
 
-struct rc_dev *rc_allocate_device(void)
+struct rc_dev *rc_allocate_device(enum rc_driver_type type)
 {
        struct rc_dev *dev;
 
@@ -1365,25 +1584,31 @@ struct rc_dev *rc_allocate_device(void)
        if (!dev)
                return NULL;
 
-       dev->input_dev = input_allocate_device();
-       if (!dev->input_dev) {
-               kfree(dev);
-               return NULL;
-       }
+       if (type != RC_DRIVER_IR_RAW_TX) {
+               dev->input_dev = input_allocate_device();
+               if (!dev->input_dev) {
+                       kfree(dev);
+                       return NULL;
+               }
 
-       dev->input_dev->getkeycode = ir_getkeycode;
-       dev->input_dev->setkeycode = ir_setkeycode;
-       input_set_drvdata(dev->input_dev, dev);
+               dev->input_dev->getkeycode = ir_getkeycode;
+               dev->input_dev->setkeycode = ir_setkeycode;
+               input_set_drvdata(dev->input_dev, dev);
 
-       spin_lock_init(&dev->rc_map.lock);
-       spin_lock_init(&dev->keylock);
+               setup_timer(&dev->timer_keyup, ir_timer_keyup,
+                           (unsigned long)dev);
+
+               spin_lock_init(&dev->rc_map.lock);
+               spin_lock_init(&dev->keylock);
+       }
        mutex_init(&dev->lock);
-       setup_timer(&dev->timer_keyup, ir_timer_keyup, (unsigned long)dev);
 
        dev->dev.type = &rc_dev_type;
        dev->dev.class = &rc_class;
        device_initialize(&dev->dev);
 
+       dev->driver_type = type;
+
        __module_get(THIS_MODULE);
        return dev;
 }
@@ -1410,7 +1635,8 @@ static void devm_rc_alloc_release(struct device *dev, void *res)
        rc_free_device(*(struct rc_dev **)res);
 }
 
-struct rc_dev *devm_rc_allocate_device(struct device *dev)
+struct rc_dev *devm_rc_allocate_device(struct device *dev,
+                                      enum rc_driver_type type)
 {
        struct rc_dev **dr, *rc;
 
@@ -1418,7 +1644,7 @@ struct rc_dev *devm_rc_allocate_device(struct device *dev)
        if (!dr)
                return NULL;
 
-       rc = rc_allocate_device();
+       rc = rc_allocate_device(type);
        if (!rc) {
                devres_free(dr);
                return NULL;
@@ -1433,16 +1659,12 @@ struct rc_dev *devm_rc_allocate_device(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(devm_rc_allocate_device);
 
-int rc_register_device(struct rc_dev *dev)
+static int rc_setup_rx_device(struct rc_dev *dev)
 {
-       static bool raw_init = false; /* raw decoders loaded? */
-       struct rc_map *rc_map;
-       const char *path;
-       int attr = 0;
-       int minor;
        int rc;
+       struct rc_map *rc_map;
 
-       if (!dev || !dev->map_name)
+       if (!dev->map_name)
                return -EINVAL;
 
        rc_map = rc_map_get(dev->map_name);
@@ -1451,6 +1673,19 @@ int rc_register_device(struct rc_dev *dev)
        if (!rc_map || !rc_map->scan || rc_map->size == 0)
                return -EINVAL;
 
+       rc = ir_setkeytable(dev, rc_map);
+       if (rc)
+               return rc;
+
+       if (dev->change_protocol) {
+               u64 rc_type = (1ll << rc_map->rc_type);
+
+               rc = dev->change_protocol(dev, &rc_type);
+               if (rc < 0)
+                       goto out_table;
+               dev->enabled_protocols = rc_type;
+       }
+
        set_bit(EV_KEY, dev->input_dev->evbit);
        set_bit(EV_REP, dev->input_dev->evbit);
        set_bit(EV_MSC, dev->input_dev->evbit);
@@ -1460,6 +1695,61 @@ int rc_register_device(struct rc_dev *dev)
        if (dev->close)
                dev->input_dev->close = ir_close;
 
+       /*
+        * Default delay of 250ms is too short for some protocols, especially
+        * since the timeout is currently set to 250ms. Increase it to 500ms,
+        * to avoid wrong repetition of the keycodes. Note that this must be
+        * set after the call to input_register_device().
+        */
+       dev->input_dev->rep[REP_DELAY] = 500;
+
+       /*
+        * As a repeat event on protocols like RC-5 and NEC take as long as
+        * 110/114ms, using 33ms as a repeat period is not the right thing
+        * to do.
+        */
+       dev->input_dev->rep[REP_PERIOD] = 125;
+
+       dev->input_dev->dev.parent = &dev->dev;
+       memcpy(&dev->input_dev->id, &dev->input_id, sizeof(dev->input_id));
+       dev->input_dev->phys = dev->input_phys;
+       dev->input_dev->name = dev->input_name;
+
+       /* rc_open will be called here */
+       rc = input_register_device(dev->input_dev);
+       if (rc)
+               goto out_table;
+
+       return 0;
+
+out_table:
+       ir_free_table(&dev->rc_map);
+
+       return rc;
+}
+
+static void rc_free_rx_device(struct rc_dev *dev)
+{
+       if (!dev || dev->driver_type == RC_DRIVER_IR_RAW_TX)
+               return;
+
+       ir_free_table(&dev->rc_map);
+
+       input_unregister_device(dev->input_dev);
+       dev->input_dev = NULL;
+}
+
+int rc_register_device(struct rc_dev *dev)
+{
+       static bool raw_init; /* 'false' default value, raw decoders loaded? */
+       const char *path;
+       int attr = 0;
+       int minor;
+       int rc;
+
+       if (!dev)
+               return -EINVAL;
+
        minor = ida_simple_get(&rc_ida, 0, RC_DEV_MAX, GFP_KERNEL);
        if (minor < 0)
                return minor;
@@ -1470,89 +1760,51 @@ int rc_register_device(struct rc_dev *dev)
        atomic_set(&dev->initialized, 0);
 
        dev->dev.groups = dev->sysfs_groups;
-       dev->sysfs_groups[attr++] = &rc_dev_protocol_attr_grp;
+       if (dev->driver_type != RC_DRIVER_IR_RAW_TX)
+               dev->sysfs_groups[attr++] = &rc_dev_protocol_attr_grp;
        if (dev->s_filter)
                dev->sysfs_groups[attr++] = &rc_dev_filter_attr_grp;
        if (dev->s_wakeup_filter)
                dev->sysfs_groups[attr++] = &rc_dev_wakeup_filter_attr_grp;
-       if (dev->change_wakeup_protocol)
-               dev->sysfs_groups[attr++] = &rc_dev_wakeup_protocol_attr_grp;
        dev->sysfs_groups[attr++] = NULL;
 
        rc = device_add(&dev->dev);
        if (rc)
                goto out_unlock;
 
-       rc = ir_setkeytable(dev, rc_map);
-       if (rc)
-               goto out_dev;
-
-       dev->input_dev->dev.parent = &dev->dev;
-       memcpy(&dev->input_dev->id, &dev->input_id, sizeof(dev->input_id));
-       dev->input_dev->phys = dev->input_phys;
-       dev->input_dev->name = dev->input_name;
-
-       rc = input_register_device(dev->input_dev);
-       if (rc)
-               goto out_table;
-
-       /*
-        * Default delay of 250ms is too short for some protocols, especially
-        * since the timeout is currently set to 250ms. Increase it to 500ms,
-        * to avoid wrong repetition of the keycodes. Note that this must be
-        * set after the call to input_register_device().
-        */
-       dev->input_dev->rep[REP_DELAY] = 500;
-
-       /*
-        * As a repeat event on protocols like RC-5 and NEC take as long as
-        * 110/114ms, using 33ms as a repeat period is not the right thing
-        * to do.
-        */
-       dev->input_dev->rep[REP_PERIOD] = 125;
-
        path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
        dev_info(&dev->dev, "%s as %s\n",
                dev->input_name ?: "Unspecified device", path ?: "N/A");
        kfree(path);
 
-       if (dev->driver_type == RC_DRIVER_IR_RAW) {
+       if (dev->driver_type != RC_DRIVER_IR_RAW_TX) {
+               rc = rc_setup_rx_device(dev);
+               if (rc)
+                       goto out_dev;
+       }
+
+       if (dev->driver_type == RC_DRIVER_IR_RAW ||
+           dev->driver_type == RC_DRIVER_IR_RAW_TX) {
                if (!raw_init) {
                        request_module_nowait("ir-lirc-codec");
                        raw_init = true;
                }
                rc = ir_raw_event_register(dev);
                if (rc < 0)
-                       goto out_input;
-       }
-
-       if (dev->change_protocol) {
-               u64 rc_type = (1ll << rc_map->rc_type);
-               rc = dev->change_protocol(dev, &rc_type);
-               if (rc < 0)
-                       goto out_raw;
-               dev->enabled_protocols = rc_type;
+                       goto out_rx;
        }
 
        /* Allow the RC sysfs nodes to be accessible */
        atomic_set(&dev->initialized, 1);
 
-       IR_dprintk(1, "Registered rc%u (driver: %s, remote: %s, mode %s)\n",
+       IR_dprintk(1, "Registered rc%u (driver: %s)\n",
                   dev->minor,
-                  dev->driver_name ? dev->driver_name : "unknown",
-                  rc_map->name ? rc_map->name : "unknown",
-                  dev->driver_type == RC_DRIVER_IR_RAW ? "raw" : "cooked");
+                  dev->driver_name ? dev->driver_name : "unknown");
 
        return 0;
 
-out_raw:
-       if (dev->driver_type == RC_DRIVER_IR_RAW)
-               ir_raw_event_unregister(dev);
-out_input:
-       input_unregister_device(dev->input_dev);
-       dev->input_dev = NULL;
-out_table:
-       ir_free_table(&dev->rc_map);
+out_rx:
+       rc_free_rx_device(dev);
 out_dev:
        device_del(&dev->dev);
 out_unlock:
@@ -1598,12 +1850,7 @@ void rc_unregister_device(struct rc_dev *dev)
        if (dev->driver_type == RC_DRIVER_IR_RAW)
                ir_raw_event_unregister(dev);
 
-       /* Freeing the table should also call the stop callback */
-       ir_free_table(&dev->rc_map);
-       IR_dprintk(1, "Freed keycode table\n");
-
-       input_unregister_device(dev->input_dev);
-       dev->input_dev = NULL;
+       rc_free_rx_device(dev);
 
        device_del(&dev->dev);
 
index 2784f5dae398ee9483a36cdeec5217a9a1f6fcc7..56d43be2756b8c645e633cd9b03f6729a387a982 100644 (file)
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
  */
 
 #include <asm/unaligned.h>
@@ -945,7 +941,7 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3)
        int ret;
        u16 prod = le16_to_cpu(rr3->udev->descriptor.idProduct);
 
-       rc = rc_allocate_device();
+       rc = rc_allocate_device(RC_DRIVER_IR_RAW);
        if (!rc)
                return NULL;
 
@@ -960,8 +956,7 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3)
        usb_to_input_id(rr3->udev, &rc->input_id);
        rc->dev.parent = dev;
        rc->priv = rr3;
-       rc->driver_type = RC_DRIVER_IR_RAW;
-       rc->allowed_protocols = RC_BIT_ALL;
+       rc->allowed_protocols = RC_BIT_ALL_IR_DECODER;
        rc->min_timeout = MS_TO_NS(RR3_RX_MIN_TIMEOUT);
        rc->max_timeout = MS_TO_NS(RR3_RX_MAX_TIMEOUT);
        rc->timeout = US_TO_NS(redrat3_get_timeout(rr3));
index 436bd58b5f05f252098ec433ac7305feb033034e..923fb2299553cb96c0db87368a322ea875da4652 100644 (file)
@@ -137,6 +137,7 @@ struct serial_ir {
        ktime_t lastkt;
        struct rc_dev *rcdev;
        struct platform_device *pdev;
+       struct timer_list timeout_timer;
 
        unsigned int freq;
        unsigned int duty_cycle;
@@ -395,9 +396,14 @@ static irqreturn_t serial_ir_irq_handler(int i, void *blah)
                        frbwrite(data, !(dcd ^ sense));
                        serial_ir.lastkt = kt;
                        last_dcd = dcd;
-                       ir_raw_event_handle(serial_ir.rcdev);
                }
        } while (!(sinp(UART_IIR) & UART_IIR_NO_INT)); /* still pending ? */
+
+       mod_timer(&serial_ir.timeout_timer,
+                 jiffies + nsecs_to_jiffies(serial_ir.rcdev->timeout));
+
+       ir_raw_event_handle(serial_ir.rcdev);
+
        return IRQ_HANDLED;
 }
 
@@ -471,6 +477,16 @@ static int hardware_init_port(void)
        return 0;
 }
 
+static void serial_ir_timeout(unsigned long arg)
+{
+       DEFINE_IR_RAW_EVENT(ev);
+
+       ev.timeout = true;
+       ev.duration = serial_ir.rcdev->timeout;
+       ir_raw_event_store_with_filter(serial_ir.rcdev, &ev);
+       ir_raw_event_handle(serial_ir.rcdev);
+}
+
 static int serial_ir_probe(struct platform_device *dev)
 {
        int i, nlow, nhigh, result;
@@ -500,6 +516,9 @@ static int serial_ir_probe(struct platform_device *dev)
                return -EBUSY;
        }
 
+       setup_timer(&serial_ir.timeout_timer, serial_ir_timeout,
+                   (unsigned long)&serial_ir);
+
        result = hardware_init_port();
        if (result < 0)
                return result;
@@ -738,7 +757,7 @@ static int __init serial_ir_init_module(void)
        if (result)
                return result;
 
-       rcdev = devm_rc_allocate_device(&serial_ir.pdev->dev);
+       rcdev = devm_rc_allocate_device(&serial_ir.pdev->dev, RC_DRIVER_IR_RAW);
        if (!rcdev) {
                result = -ENOMEM;
                goto serial_cleanup;
@@ -777,11 +796,12 @@ static int __init serial_ir_init_module(void)
        rcdev->open = serial_ir_open;
        rcdev->close = serial_ir_close;
        rcdev->dev.parent = &serial_ir.pdev->dev;
-       rcdev->driver_type = RC_DRIVER_IR_RAW;
-       rcdev->allowed_protocols = RC_BIT_ALL;
+       rcdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
        rcdev->driver_name = KBUILD_MODNAME;
        rcdev->map_name = RC_MAP_RC6_MCE;
+       rcdev->min_timeout = 1;
        rcdev->timeout = IR_DEFAULT_TIMEOUT;
+       rcdev->max_timeout = 10 * IR_DEFAULT_TIMEOUT;
        rcdev->rx_resolution = 250000;
 
        serial_ir.rcdev = rcdev;
@@ -797,6 +817,7 @@ serial_cleanup:
 
 static void __exit serial_ir_exit_module(void)
 {
+       del_timer_sync(&serial_ir.timeout_timer);
        rc_unregister_device(serial_ir.rcdev);
        serial_ir_exit();
 }
index 1fa0c9d1c5083766c53bafe11d5e955bdd6c838a..f0d7190e391952be799b5265d8a78c217bbc9430 100644 (file)
@@ -235,7 +235,7 @@ static int st_rc_probe(struct platform_device *pdev)
        if (!rc_dev)
                return -ENOMEM;
 
-       rdev = rc_allocate_device();
+       rdev = rc_allocate_device(RC_DRIVER_IR_RAW);
 
        if (!rdev)
                return -ENOMEM;
@@ -290,8 +290,7 @@ static int st_rc_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, rc_dev);
        st_rc_hardware_init(rc_dev);
 
-       rdev->driver_type = RC_DRIVER_IR_RAW;
-       rdev->allowed_protocols = RC_BIT_ALL;
+       rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
        /* rx sampling rate is 10Mhz */
        rdev->rx_resolution = 100;
        rdev->timeout = US_TO_NS(MAX_SYMB_TIME);
index 53f9b0af358a463acdaa91e64c679c952f69a3cc..b09c45abb5f3280d2b2c474ea49528bf9333e35f 100644 (file)
  *  but WITHOUT 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
  */
 
 #include <linux/device.h>
@@ -291,7 +287,7 @@ static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz)
        struct device *dev = sz->dev;
        int ret;
 
-       rdev = rc_allocate_device();
+       rdev = rc_allocate_device(RC_DRIVER_IR_RAW);
        if (!rdev) {
                dev_err(dev, "remote dev allocation failed\n");
                goto out;
@@ -308,8 +304,7 @@ static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz)
        usb_to_input_id(sz->usbdev, &rdev->input_id);
        rdev->dev.parent = dev;
        rdev->priv = sz;
-       rdev->driver_type = RC_DRIVER_IR_RAW;
-       rdev->allowed_protocols = RC_BIT_ALL;
+       rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
        rdev->driver_name = DRIVER_NAME;
        rdev->map_name = RC_MAP_STREAMZAP;
 
index eaadc081760ae1ec21a5a3ff018ad42ee497c5f0..25b006167810221a26181e9128070ea12eb4ee15 100644 (file)
@@ -212,7 +212,7 @@ static int sunxi_ir_probe(struct platform_device *pdev)
                goto exit_clkdisable_clk;
        }
 
-       ir->rc = rc_allocate_device();
+       ir->rc = rc_allocate_device(RC_DRIVER_IR_RAW);
        if (!ir->rc) {
                dev_err(dev, "failed to allocate device\n");
                ret = -ENOMEM;
@@ -229,8 +229,7 @@ static int sunxi_ir_probe(struct platform_device *pdev)
        ir->map_name = of_get_property(dn, "linux,rc-map-name", NULL);
        ir->rc->map_name = ir->map_name ?: RC_MAP_EMPTY;
        ir->rc->dev.parent = dev;
-       ir->rc->driver_type = RC_DRIVER_IR_RAW;
-       ir->rc->allowed_protocols = RC_BIT_ALL;
+       ir->rc->allowed_protocols = RC_BIT_ALL_IR_DECODER;
        ir->rc->rx_resolution = SUNXI_IR_SAMPLE;
        ir->rc->timeout = MS_TO_NS(SUNXI_IR_TIMEOUT);
        ir->rc->driver_name = SUNXI_IR_DEV;
index bc214e2b3a368941c857d5b176fa28ada8fd7c80..23be7702e2dfbf0ee4989cb968ed81288aef68cd 100644 (file)
  * but WITHOUT 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
  */
 
 #include <linux/module.h>
@@ -205,7 +201,7 @@ static int ttusbir_probe(struct usb_interface *intf,
        int altsetting = -1;
 
        tt = kzalloc(sizeof(*tt), GFP_KERNEL);
-       rc = rc_allocate_device();
+       rc = rc_allocate_device(RC_DRIVER_IR_RAW);
        if (!tt || !rc) {
                ret = -ENOMEM;
                goto out;
@@ -317,12 +313,14 @@ static int ttusbir_probe(struct usb_interface *intf,
        rc->input_phys = tt->phys;
        usb_to_input_id(tt->udev, &rc->input_id);
        rc->dev.parent = &intf->dev;
-       rc->driver_type = RC_DRIVER_IR_RAW;
-       rc->allowed_protocols = RC_BIT_ALL;
+       rc->allowed_protocols = RC_BIT_ALL_IR_DECODER;
        rc->priv = tt;
        rc->driver_name = DRIVER_NAME;
        rc->map_name = RC_MAP_TT_1500;
-       rc->timeout = MS_TO_NS(100);
+       rc->min_timeout = 1;
+       rc->timeout = IR_DEFAULT_TIMEOUT;
+       rc->max_timeout = 10 * IR_DEFAULT_TIMEOUT;
+
        /*
         * The precision is NS_PER_BIT, but since every 8th bit can be
         * overwritten with garbage the accuracy is at best 2 * NS_PER_BIT.
index 78491ed48d92eae15fd5b72d6b46462d40e3dde5..dc1c8305ad23572933f63caa1e340592e40c65a4 100644 (file)
  *  but WITHOUT 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.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -194,7 +190,6 @@ enum wbcir_txstate {
 #define WBCIR_NAME     "Winbond CIR"
 #define WBCIR_ID_FAMILY          0xF1 /* Family ID for the WPCD376I    */
 #define        WBCIR_ID_CHIP            0x04 /* Chip ID for the WPCD376I       */
-#define INVALID_SCANCODE   0x7FFFFFFF /* Invalid with all protos       */
 #define WAKEUP_IOMEM_LEN         0x10 /* Wake-Up I/O Reg Len           */
 #define EHFUNC_IOMEM_LEN         0x10 /* Enhanced Func I/O Reg Len     */
 #define SP_IOMEM_LEN             0x08 /* Serial Port 3 (IR) Reg Len    */
@@ -225,10 +220,6 @@ struct wbcir_data {
        u32 txcarrier;
 };
 
-static enum wbcir_protocol protocol = IR_PROTOCOL_RC6;
-module_param(protocol, uint, 0444);
-MODULE_PARM_DESC(protocol, "IR protocol to use for the power-on command (0 = RC5, 1 = NEC, 2 = RC6A, default)");
-
 static bool invert; /* default = 0 */
 module_param(invert, bool, 0444);
 MODULE_PARM_DESC(invert, "Invert the signal from the IR receiver");
@@ -237,15 +228,6 @@ static bool txandrx; /* default = 0 */
 module_param(txandrx, bool, 0444);
 MODULE_PARM_DESC(txandrx, "Allow simultaneous TX and RX");
 
-static unsigned int wake_sc = 0x800F040C;
-module_param(wake_sc, uint, 0644);
-MODULE_PARM_DESC(wake_sc, "Scancode of the power-on IR command");
-
-static unsigned int wake_rc6mode = 6;
-module_param(wake_rc6mode, uint, 0644);
-MODULE_PARM_DESC(wake_rc6mode, "RC6 mode for the power-on command (0 = 0, 6 = 6A, default)");
-
-
 
 /*****************************************************************************
  *
@@ -696,138 +678,153 @@ wbcir_shutdown(struct pnp_dev *device)
 {
        struct device *dev = &device->dev;
        struct wbcir_data *data = pnp_get_drvdata(device);
+       struct rc_dev *rc = data->dev;
        bool do_wake = true;
        u8 match[11];
        u8 mask[11];
        u8 rc6_csl = 0;
+       u8 proto;
+       u32 wake_sc = rc->scancode_wakeup_filter.data;
+       u32 mask_sc = rc->scancode_wakeup_filter.mask;
        int i;
 
        memset(match, 0, sizeof(match));
        memset(mask, 0, sizeof(mask));
 
-       if (wake_sc == INVALID_SCANCODE || !device_may_wakeup(dev)) {
+       if (!mask_sc || !device_may_wakeup(dev)) {
                do_wake = false;
                goto finish;
        }
 
-       switch (protocol) {
-       case IR_PROTOCOL_RC5:
-               if (wake_sc > 0xFFF) {
-                       do_wake = false;
-                       dev_err(dev, "RC5 - Invalid wake scancode\n");
-                       break;
-               }
-
+       switch (rc->wakeup_protocol) {
+       case RC_TYPE_RC5:
                /* Mask = 13 bits, ex toggle */
-               mask[0] = 0xFF;
-               mask[1] = 0x17;
+               mask[0]  = (mask_sc & 0x003f);
+               mask[0] |= (mask_sc & 0x0300) >> 2;
+               mask[1]  = (mask_sc & 0x1c00) >> 10;
+               if (mask_sc & 0x0040)                 /* 2nd start bit  */
+                       match[1] |= 0x10;
 
-               match[0]  = (wake_sc & 0x003F);      /* 6 command bits */
-               match[0] |= (wake_sc & 0x0180) >> 1; /* 2 address bits */
-               match[1]  = (wake_sc & 0x0E00) >> 9; /* 3 address bits */
-               if (!(wake_sc & 0x0040))             /* 2nd start bit  */
+               match[0]  = (wake_sc & 0x003F);       /* 6 command bits */
+               match[0] |= (wake_sc & 0x0300) >> 2;  /* 2 address bits */
+               match[1]  = (wake_sc & 0x1c00) >> 10; /* 3 address bits */
+               if (!(wake_sc & 0x0040))              /* 2nd start bit  */
                        match[1] |= 0x10;
 
+               proto = IR_PROTOCOL_RC5;
                break;
 
-       case IR_PROTOCOL_NEC:
-               if (wake_sc > 0xFFFFFF) {
-                       do_wake = false;
-                       dev_err(dev, "NEC - Invalid wake scancode\n");
-                       break;
-               }
+       case RC_TYPE_NEC:
+               mask[1] = bitrev8(mask_sc);
+               mask[0] = mask[1];
+               mask[3] = bitrev8(mask_sc >> 8);
+               mask[2] = mask[3];
 
-               mask[0] = mask[1] = mask[2] = mask[3] = 0xFF;
-
-               match[1] = bitrev8((wake_sc & 0xFF));
+               match[1] = bitrev8(wake_sc);
                match[0] = ~match[1];
+               match[3] = bitrev8(wake_sc >> 8);
+               match[2] = ~match[3];
 
-               match[3] = bitrev8((wake_sc & 0xFF00) >> 8);
-               if (wake_sc > 0xFFFF)
-                       match[2] = bitrev8((wake_sc & 0xFF0000) >> 16);
-               else
-                       match[2] = ~match[3];
+               proto = IR_PROTOCOL_NEC;
+               break;
+
+       case RC_TYPE_NECX:
+               mask[1] = bitrev8(mask_sc);
+               mask[0] = mask[1];
+               mask[2] = bitrev8(mask_sc >> 8);
+               mask[3] = bitrev8(mask_sc >> 16);
 
+               match[1] = bitrev8(wake_sc);
+               match[0] = ~match[1];
+               match[2] = bitrev8(wake_sc >> 8);
+               match[3] = bitrev8(wake_sc >> 16);
+
+               proto = IR_PROTOCOL_NEC;
                break;
 
-       case IR_PROTOCOL_RC6:
+       case RC_TYPE_NEC32:
+               mask[0] = bitrev8(mask_sc);
+               mask[1] = bitrev8(mask_sc >> 8);
+               mask[2] = bitrev8(mask_sc >> 16);
+               mask[3] = bitrev8(mask_sc >> 24);
 
-               if (wake_rc6mode == 0) {
-                       if (wake_sc > 0xFFFF) {
-                               do_wake = false;
-                               dev_err(dev, "RC6 - Invalid wake scancode\n");
-                               break;
-                       }
+               match[0] = bitrev8(wake_sc);
+               match[1] = bitrev8(wake_sc >> 8);
+               match[2] = bitrev8(wake_sc >> 16);
+               match[3] = bitrev8(wake_sc >> 24);
 
-                       /* Command */
-                       match[0] = wbcir_to_rc6cells(wake_sc >>  0);
-                       mask[0]  = 0xFF;
-                       match[1] = wbcir_to_rc6cells(wake_sc >>  4);
-                       mask[1]  = 0xFF;
-
-                       /* Address */
-                       match[2] = wbcir_to_rc6cells(wake_sc >>  8);
-                       mask[2]  = 0xFF;
-                       match[3] = wbcir_to_rc6cells(wake_sc >> 12);
-                       mask[3]  = 0xFF;
-
-                       /* Header */
-                       match[4] = 0x50; /* mode1 = mode0 = 0, ignore toggle */
-                       mask[4]  = 0xF0;
-                       match[5] = 0x09; /* start bit = 1, mode2 = 0 */
-                       mask[5]  = 0x0F;
-
-                       rc6_csl = 44;
-
-               } else if (wake_rc6mode == 6) {
-                       i = 0;
-
-                       /* Command */
-                       match[i]  = wbcir_to_rc6cells(wake_sc >>  0);
-                       mask[i++] = 0xFF;
-                       match[i]  = wbcir_to_rc6cells(wake_sc >>  4);
-                       mask[i++] = 0xFF;
-
-                       /* Address + Toggle */
-                       match[i]  = wbcir_to_rc6cells(wake_sc >>  8);
-                       mask[i++] = 0xFF;
-                       match[i]  = wbcir_to_rc6cells(wake_sc >> 12);
-                       mask[i++] = 0x3F;
-
-                       /* Customer bits 7 - 0 */
-                       match[i]  = wbcir_to_rc6cells(wake_sc >> 16);
-                       mask[i++] = 0xFF;
+               proto = IR_PROTOCOL_NEC;
+               break;
+
+       case RC_TYPE_RC6_0:
+               /* Command */
+               match[0] = wbcir_to_rc6cells(wake_sc >> 0);
+               mask[0]  = wbcir_to_rc6cells(mask_sc >> 0);
+               match[1] = wbcir_to_rc6cells(wake_sc >> 4);
+               mask[1]  = wbcir_to_rc6cells(mask_sc >> 4);
+
+               /* Address */
+               match[2] = wbcir_to_rc6cells(wake_sc >>  8);
+               mask[2]  = wbcir_to_rc6cells(mask_sc >>  8);
+               match[3] = wbcir_to_rc6cells(wake_sc >> 12);
+               mask[3]  = wbcir_to_rc6cells(mask_sc >> 12);
+
+               /* Header */
+               match[4] = 0x50; /* mode1 = mode0 = 0, ignore toggle */
+               mask[4]  = 0xF0;
+               match[5] = 0x09; /* start bit = 1, mode2 = 0 */
+               mask[5]  = 0x0F;
+
+               rc6_csl = 44;
+               proto = IR_PROTOCOL_RC6;
+               break;
+
+       case RC_TYPE_RC6_6A_24:
+       case RC_TYPE_RC6_6A_32:
+       case RC_TYPE_RC6_MCE:
+               i = 0;
+
+               /* Command */
+               match[i]  = wbcir_to_rc6cells(wake_sc >>  0);
+               mask[i++] = wbcir_to_rc6cells(mask_sc >>  0);
+               match[i]  = wbcir_to_rc6cells(wake_sc >>  4);
+               mask[i++] = wbcir_to_rc6cells(mask_sc >>  4);
+
+               /* Address + Toggle */
+               match[i]  = wbcir_to_rc6cells(wake_sc >>  8);
+               mask[i++] = wbcir_to_rc6cells(mask_sc >>  8);
+               match[i]  = wbcir_to_rc6cells(wake_sc >> 12);
+               mask[i++] = wbcir_to_rc6cells(mask_sc >> 12);
+
+               /* Customer bits 7 - 0 */
+               match[i]  = wbcir_to_rc6cells(wake_sc >> 16);
+               mask[i++] = wbcir_to_rc6cells(mask_sc >> 16);
+
+               if (rc->wakeup_protocol == RC_TYPE_RC6_6A_20) {
+                       rc6_csl = 52;
+               } else {
                        match[i]  = wbcir_to_rc6cells(wake_sc >> 20);
-                       mask[i++] = 0xFF;
+                       mask[i++] = wbcir_to_rc6cells(mask_sc >> 20);
 
-                       if (wake_sc & 0x80000000) {
+                       if (rc->wakeup_protocol == RC_TYPE_RC6_6A_24) {
+                               rc6_csl = 60;
+                       } else {
                                /* Customer range bit and bits 15 - 8 */
                                match[i]  = wbcir_to_rc6cells(wake_sc >> 24);
-                               mask[i++] = 0xFF;
+                               mask[i++] = wbcir_to_rc6cells(mask_sc >> 24);
                                match[i]  = wbcir_to_rc6cells(wake_sc >> 28);
-                               mask[i++] = 0xFF;
+                               mask[i++] = wbcir_to_rc6cells(mask_sc >> 28);
                                rc6_csl = 76;
-                       } else if (wake_sc <= 0x007FFFFF) {
-                               rc6_csl = 60;
-                       } else {
-                               do_wake = false;
-                               dev_err(dev, "RC6 - Invalid wake scancode\n");
-                               break;
                        }
-
-                       /* Header */
-                       match[i]  = 0x93; /* mode1 = mode0 = 1, submode = 0 */
-                       mask[i++] = 0xFF;
-                       match[i]  = 0x0A; /* start bit = 1, mode2 = 1 */
-                       mask[i++] = 0x0F;
-
-               } else {
-                       do_wake = false;
-                       dev_err(dev, "RC6 - Invalid wake mode\n");
                }
 
+               /* Header */
+               match[i]  = 0x93; /* mode1 = mode0 = 1, submode = 0 */
+               mask[i++] = 0xFF;
+               match[i]  = 0x0A; /* start bit = 1, mode2 = 1 */
+               mask[i++] = 0x0F;
+               proto = IR_PROTOCOL_RC6;
                break;
-
        default:
                do_wake = false;
                break;
@@ -855,7 +852,8 @@ finish:
                wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x01, 0x07);
 
                /* Set CEIR_EN */
-               wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, 0x01, 0x01);
+               wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL,
+                              (proto << 4) | 0x01, 0x31);
 
        } else {
                /* Clear BUFF_EN, Clear END_EN, Clear MATCH_EN */
@@ -875,6 +873,15 @@ finish:
        disable_irq(data->irq);
 }
 
+/*
+ * Wakeup handling is done on shutdown.
+ */
+static int
+wbcir_set_wakeup_filter(struct rc_dev *rc, struct rc_scancode_filter *filter)
+{
+       return 0;
+}
+
 static int
 wbcir_suspend(struct pnp_dev *device, pm_message_t state)
 {
@@ -887,16 +894,11 @@ wbcir_suspend(struct pnp_dev *device, pm_message_t state)
 static void
 wbcir_init_hw(struct wbcir_data *data)
 {
-       u8 tmp;
-
        /* Disable interrupts */
        wbcir_set_irqmask(data, WBCIR_IRQ_NONE);
 
-       /* Set PROT_SEL, RX_INV, Clear CEIR_EN (needed for the led) */
-       tmp = protocol << 4;
-       if (invert)
-               tmp |= 0x08;
-       outb(tmp, data->wbase + WBCIR_REG_WCEIR_CTL);
+       /* Set RX_INV, Clear CEIR_EN (needed for the led) */
+       wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, invert ? 8 : 0, 0x09);
 
        /* Clear status bits NEC_REP, BUFF, MSG_END, MATCH */
        wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_STS, 0x17, 0x17);
@@ -1059,13 +1061,12 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
        if (err)
                goto exit_free_data;
 
-       data->dev = rc_allocate_device();
+       data->dev = rc_allocate_device(RC_DRIVER_IR_RAW);
        if (!data->dev) {
                err = -ENOMEM;
                goto exit_unregister_led;
        }
 
-       data->dev->driver_type = RC_DRIVER_IR_RAW;
        data->dev->driver_name = DRVNAME;
        data->dev->input_name = WBCIR_NAME;
        data->dev->input_phys = "wbcir/cir0";
@@ -1083,7 +1084,15 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
        data->dev->dev.parent = &device->dev;
        data->dev->timeout = MS_TO_NS(100);
        data->dev->rx_resolution = US_TO_NS(2);
-       data->dev->allowed_protocols = RC_BIT_ALL;
+       data->dev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
+       data->dev->allowed_wakeup_protocols = RC_BIT_NEC | RC_BIT_NECX |
+                       RC_BIT_NEC32 | RC_BIT_RC5 | RC_BIT_RC6_0 |
+                       RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 |
+                       RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE;
+       data->dev->wakeup_protocol = RC_TYPE_RC6_MCE;
+       data->dev->scancode_wakeup_filter.data = 0x800f040c;
+       data->dev->scancode_wakeup_filter.mask = 0xffff7fff;
+       data->dev->s_wakeup_filter = wbcir_set_wakeup_filter;
 
        err = rc_register_device(data->dev);
        if (err)
@@ -1199,15 +1208,6 @@ wbcir_init(void)
 {
        int ret;
 
-       switch (protocol) {
-       case IR_PROTOCOL_RC5:
-       case IR_PROTOCOL_NEC:
-       case IR_PROTOCOL_RC6:
-               break;
-       default:
-               pr_err("Invalid power-on protocol\n");
-       }
-
        ret = pnp_register_driver(&wbcir_driver);
        if (ret)
                pr_err("Unable to register driver\n");
index 00489a9df4e4c6e45a450512bb37613995b53bcc..192b1c7740df23f99b77230643a5e4b1ccab34fa 100644 (file)
  * but WITHOUT 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 "fc0011.h"
index 1a86ce1d3fcf03bbc87fcb884eb9621a1b25414c..0fbf0114bdcd437c176f1e5972235af8bb5973e2 100644 (file)
  * but WITHOUT 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 _FC0012_PRIV_H_
index 30508f44e5f934134bbecd7ff74266cfd6f1a6ba..dcc323ffbde75a111b089601b8cd50392ddb20e3 100644 (file)
  * but WITHOUT 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 "fc0012.h"
index 4a23e418daf08495d38335a9fbd49e061e78645c..64d07a2adb2ef4ec133a8dea56ea8f1f6714792f 100644 (file)
  * but WITHOUT 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 _FC0012_H_
index bfd49dedea22963da4820afdd0d0211821b16d0c..2eeaca8abae52226a614be8c97a3a69f92cfbb4d 100644 (file)
  *    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 _FC0013_PRIV_H_
index f7cf0e9e7c99b486c12a0421f6f52b24270b14e5..91dfa770a5cc76ad90424d5d8354786c0296071a 100644 (file)
  *    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 "fc0013.h"
index 8c34105c938342e29d97898d70943a6da945d075..4431e7ceb43da3f3bd20cd57893d6d6523dd711a 100644 (file)
  *    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 _FC0013_H_
index 71881815693432c1f87bed233bd1b04701f1067b..3a96ff76c19558815a30694de26dd932febf13e8 100644 (file)
  * but WITHOUT 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 _FC001X_COMMON_H_
index 6c3ef2181fcdc5b6f0a318feb5f1aef7bfb234d1..27e5bc1c3cb5d8b84f5f7cdab041c3cb2b1f5fff 100644 (file)
  *  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 "it913x.h"
+#include <linux/platform_device.h>
 #include <linux/regmap.h>
 
 struct it913x_dev {
-       struct i2c_client *client;
+       struct platform_device *pdev;
        struct regmap *regmap;
        struct dvb_frontend *fe;
        u8 chip_ver:2;
@@ -39,13 +36,14 @@ struct it913x_dev {
 static int it913x_init(struct dvb_frontend *fe)
 {
        struct it913x_dev *dev = fe->tuner_priv;
+       struct platform_device *pdev = dev->pdev;
        int ret;
        unsigned int utmp;
        u8 iqik_m_cal, nv_val, buf[2];
        static const u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2};
        unsigned long timeout;
 
-       dev_dbg(&dev->client->dev, "role %u\n", dev->role);
+       dev_dbg(&pdev->dev, "role %u\n", dev->role);
 
        ret = regmap_write(dev->regmap, 0x80ec4c, 0x68);
        if (ret)
@@ -73,7 +71,7 @@ static int it913x_init(struct dvb_frontend *fe)
                iqik_m_cal = 6;
                break;
        default:
-               dev_err(&dev->client->dev, "unknown clock identifier %d\n", utmp);
+               dev_err(&pdev->dev, "unknown clock identifier %d\n", utmp);
                goto err;
        }
 
@@ -98,14 +96,14 @@ static int it913x_init(struct dvb_frontend *fe)
                        break;
        }
 
-       dev_dbg(&dev->client->dev, "r_fbc_m_bdry took %u ms, val %u\n",
+       dev_dbg(&pdev->dev, "r_fbc_m_bdry took %u ms, val %u\n",
                        jiffies_to_msecs(jiffies) -
                        (jiffies_to_msecs(timeout) - TIMEOUT), utmp);
 
        dev->fn_min = dev->xtal * utmp;
        dev->fn_min /= (dev->fdiv * nv_val);
        dev->fn_min *= 1000;
-       dev_dbg(&dev->client->dev, "fn_min %u\n", dev->fn_min);
+       dev_dbg(&pdev->dev, "fn_min %u\n", dev->fn_min);
 
        /*
         * Chip version BX never sets that flag so we just wait 50ms in that
@@ -125,7 +123,7 @@ static int it913x_init(struct dvb_frontend *fe)
                                break;
                }
 
-               dev_dbg(&dev->client->dev, "p_tsm_init_mode took %u ms, val %u\n",
+               dev_dbg(&pdev->dev, "p_tsm_init_mode took %u ms, val %u\n",
                                jiffies_to_msecs(jiffies) -
                                (jiffies_to_msecs(timeout) - TIMEOUT), utmp);
        } else {
@@ -152,16 +150,17 @@ static int it913x_init(struct dvb_frontend *fe)
 
        return 0;
 err:
-       dev_dbg(&dev->client->dev, "failed %d\n", ret);
+       dev_dbg(&pdev->dev, "failed %d\n", ret);
        return ret;
 }
 
 static int it913x_sleep(struct dvb_frontend *fe)
 {
        struct it913x_dev *dev = fe->tuner_priv;
+       struct platform_device *pdev = dev->pdev;
        int ret, len;
 
-       dev_dbg(&dev->client->dev, "role %u\n", dev->role);
+       dev_dbg(&pdev->dev, "role %u\n", dev->role);
 
        dev->active = false;
 
@@ -178,7 +177,7 @@ static int it913x_sleep(struct dvb_frontend *fe)
        else
                len = 15;
 
-       dev_dbg(&dev->client->dev, "role %u, len %d\n", dev->role, len);
+       dev_dbg(&pdev->dev, "role %u, len %d\n", dev->role, len);
 
        ret = regmap_bulk_write(dev->regmap, 0x80ec02,
                        "\x3f\x1f\x3f\x3e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
@@ -210,13 +209,14 @@ static int it913x_sleep(struct dvb_frontend *fe)
 
        return 0;
 err:
-       dev_dbg(&dev->client->dev, "failed %d\n", ret);
+       dev_dbg(&pdev->dev, "failed %d\n", ret);
        return ret;
 }
 
 static int it913x_set_params(struct dvb_frontend *fe)
 {
        struct it913x_dev *dev = fe->tuner_priv;
+       struct platform_device *pdev = dev->pdev;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int ret;
        unsigned int utmp;
@@ -224,7 +224,7 @@ static int it913x_set_params(struct dvb_frontend *fe)
        u16 iqik_m_cal, n_div;
        u8 u8tmp, n, l_band, lna_band;
 
-       dev_dbg(&dev->client->dev, "role=%u, frequency %u, bandwidth_hz %u\n",
+       dev_dbg(&pdev->dev, "role=%u, frequency %u, bandwidth_hz %u\n",
                        dev->role, c->frequency, c->bandwidth_hz);
 
        if (!dev->active) {
@@ -290,7 +290,7 @@ static int it913x_set_params(struct dvb_frontend *fe)
        pre_lo_freq += (u32) n << 13;
        /* Frequency OMEGA_IQIK_M_CAL_MID*/
        t_cal_freq = pre_lo_freq + (u32)iqik_m_cal;
-       dev_dbg(&dev->client->dev, "t_cal_freq %u, pre_lo_freq %u\n",
+       dev_dbg(&pdev->dev, "t_cal_freq %u, pre_lo_freq %u\n",
                        t_cal_freq, pre_lo_freq);
 
        if (c->frequency <=         440000000) {
@@ -369,7 +369,7 @@ static int it913x_set_params(struct dvb_frontend *fe)
 
        return 0;
 err:
-       dev_dbg(&dev->client->dev, "failed %d\n", ret);
+       dev_dbg(&pdev->dev, "failed %d\n", ret);
        return ret;
 }
 
@@ -385,40 +385,32 @@ static const struct dvb_tuner_ops it913x_tuner_ops = {
        .set_params = it913x_set_params,
 };
 
-static int it913x_probe(struct i2c_client *client,
-               const struct i2c_device_id *id)
+static int it913x_probe(struct platform_device *pdev)
 {
-       struct it913x_config *cfg = client->dev.platform_data;
-       struct dvb_frontend *fe = cfg->fe;
+       struct it913x_platform_data *pdata = pdev->dev.platform_data;
+       struct dvb_frontend *fe = pdata->fe;
        struct it913x_dev *dev;
+       const struct platform_device_id *id = platform_get_device_id(pdev);
        int ret;
        char *chip_ver_str;
-       static const struct regmap_config regmap_config = {
-               .reg_bits = 24,
-               .val_bits = 8,
-       };
 
        dev = kzalloc(sizeof(struct it913x_dev), GFP_KERNEL);
        if (dev == NULL) {
                ret = -ENOMEM;
-               dev_err(&client->dev, "kzalloc() failed\n");
+               dev_err(&pdev->dev, "kzalloc() failed\n");
                goto err;
        }
 
-       dev->client = client;
-       dev->fe = cfg->fe;
-       dev->chip_ver = cfg->chip_ver;
-       dev->role = cfg->role;
-       dev->regmap = regmap_init_i2c(client, &regmap_config);
-       if (IS_ERR(dev->regmap)) {
-               ret = PTR_ERR(dev->regmap);
-               goto err_kfree;
-       }
+       dev->pdev = pdev;
+       dev->regmap = pdata->regmap;
+       dev->fe = pdata->fe;
+       dev->chip_ver = id->driver_data;
+       dev->role = pdata->role;
 
        fe->tuner_priv = dev;
        memcpy(&fe->ops.tuner_ops, &it913x_tuner_ops,
                        sizeof(struct dvb_tuner_ops));
-       i2c_set_clientdata(client, dev);
+       platform_set_drvdata(pdev, dev);
 
        if (dev->chip_ver == 1)
                chip_ver_str = "AX";
@@ -427,41 +419,37 @@ static int it913x_probe(struct i2c_client *client,
        else
                chip_ver_str = "??";
 
-       dev_info(&dev->client->dev, "ITE IT913X %s successfully attached\n",
-                       chip_ver_str);
-       dev_dbg(&dev->client->dev, "chip_ver %u, role %u\n",
-                       dev->chip_ver, dev->role);
+       dev_info(&pdev->dev, "ITE IT913X %s successfully attached\n",
+                chip_ver_str);
+       dev_dbg(&pdev->dev, "chip_ver %u, role %u\n", dev->chip_ver, dev->role);
        return 0;
-
-err_kfree:
-       kfree(dev);
 err:
-       dev_dbg(&client->dev, "failed %d\n", ret);
+       dev_dbg(&pdev->dev, "failed %d\n", ret);
        return ret;
 }
 
-static int it913x_remove(struct i2c_client *client)
+static int it913x_remove(struct platform_device *pdev)
 {
-       struct it913x_dev *dev = i2c_get_clientdata(client);
+       struct it913x_dev *dev = platform_get_drvdata(pdev);
        struct dvb_frontend *fe = dev->fe;
 
-       dev_dbg(&client->dev, "\n");
+       dev_dbg(&pdev->dev, "\n");
 
        memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
        fe->tuner_priv = NULL;
-       regmap_exit(dev->regmap);
        kfree(dev);
 
        return 0;
 }
 
-static const struct i2c_device_id it913x_id_table[] = {
-       {"it913x", 0},
-       {}
+static const struct platform_device_id it913x_id_table[] = {
+       {"it9133ax-tuner", 1},
+       {"it9133bx-tuner", 2},
+       {},
 };
-MODULE_DEVICE_TABLE(i2c, it913x_id_table);
+MODULE_DEVICE_TABLE(platform, it913x_id_table);
 
-static struct i2c_driver it913x_driver = {
+static struct platform_driver it913x_driver = {
        .driver = {
                .name   = "it913x",
                .suppress_bind_attrs    = true,
@@ -471,7 +459,7 @@ static struct i2c_driver it913x_driver = {
        .id_table       = it913x_id_table,
 };
 
-module_i2c_driver(it913x_driver);
+module_platform_driver(it913x_driver);
 
 MODULE_DESCRIPTION("ITE IT913X silicon tuner driver");
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
index 33de53d4a566e1dd63b0de7e6883b7ebb16d7fe7..226f657228fbbd5a0f12166c1ffec6745d17d8c8 100644 (file)
  *  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 IT913X_H
 
 #include "dvb_frontend.h"
 
-/*
- * I2C address
- * 0x38, 0x3a, 0x3c, 0x3e
+/**
+ * struct it913x_platform_data - Platform data for the it913x driver
+ * @regmap: af9033 demod driver regmap.
+ * @dvb_frontend: af9033 demod driver DVB frontend.
+ * @role: Chip role, single or dual configuration.
  */
-struct it913x_config {
-       /*
-        * pointer to DVB frontend
-        */
-       struct dvb_frontend *fe;
 
-       /*
-        * chip version
-        * 1 = IT9135 AX
-        * 2 = IT9135 BX
-        */
-       unsigned int chip_ver:2;
-
-       /*
-        * tuner role
-        */
+struct it913x_platform_data {
+       struct regmap *regmap;
+       struct dvb_frontend *fe;
 #define IT913X_ROLE_SINGLE         0
 #define IT913X_ROLE_DUAL_MASTER    1
 #define IT913X_ROLE_DUAL_SLAVE     2
index c3f10925b0d4f99620c0b4fc09604ff0b74cd101..a86c081149154d29df8c7234d6de3b1ecd4149c0 100644 (file)
  *  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/module.h>
index aadd9fea59e4fffe062af7f50206be6936493c29..3120c54ec154e469e2095eebd945061478f4a579 100644 (file)
  *  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 __MAX2165_H__
index 91bbe021a08d321aa3233d2209b766986e838722..20d7751881a3345535111c5ac92d319bef8f542f 100644 (file)
  *  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 __MAX2165_PRIV_H__
index aba580b4ac2cd2779e076c61d64cfef98f87042b..12f545ef12430824e402ca19b8db47d57e38432a 100644 (file)
  *  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/module.h>
index 6b40df33928458be61baf4ac9bb9a8a3fef6337f..f68133fb9760a875863bd5d3cb8ae0da57df2e72 100644 (file)
  *  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 MC44S803_H
index 14a92780906d7775cd4093b6b52c299d0900a103..52325395dfe7fb147f7d3b8bee972c676606b166 100644 (file)
  *  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 MC44S803_PRIV_H
index 94077ea78dde401b07afb58bff12775e016d029c..2e487f9a2cc3fb678aa173b93a9bb141cc23ba69 100644 (file)
  *  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.=
  */
 
 /* In that file, frequencies are expressed in kiloHertz to avoid 32 bits overflows */
@@ -71,13 +67,24 @@ static int mt2060_writereg(struct mt2060_priv *priv, u8 reg, u8 val)
 // Writes a set of consecutive registers
 static int mt2060_writeregs(struct mt2060_priv *priv,u8 *buf, u8 len)
 {
+       int rem, val_len;
+       u8 xfer_buf[16];
        struct i2c_msg msg = {
-               .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len
+               .addr = priv->cfg->i2c_address, .flags = 0, .buf = xfer_buf
        };
-       if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
-               printk(KERN_WARNING "mt2060 I2C write failed (len=%i)\n",(int)len);
-               return -EREMOTEIO;
+
+       for (rem = len - 1; rem > 0; rem -= priv->i2c_max_regs) {
+               val_len = min_t(int, rem, priv->i2c_max_regs);
+               msg.len = 1 + val_len;
+               xfer_buf[0] = buf[0] + len - 1 - rem;
+               memcpy(&xfer_buf[1], &buf[1 + len - 1 - rem], val_len);
+
+               if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+                       printk(KERN_WARNING "mt2060 I2C write failed (len=%i)\n", val_len);
+                       return -EREMOTEIO;
+               }
        }
+
        return 0;
 }
 
@@ -306,9 +313,16 @@ static int mt2060_init(struct dvb_frontend *fe)
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
 
+       if (priv->sleep) {
+               ret = mt2060_writereg(priv, REG_MISC_CTRL, 0x20);
+               if (ret)
+                       goto err_i2c_gate_ctrl;
+       }
+
        ret = mt2060_writereg(priv, REG_VGAG,
                              (priv->cfg->clock_out << 6) | 0x33);
 
+err_i2c_gate_ctrl:
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
 
@@ -325,7 +339,13 @@ static int mt2060_sleep(struct dvb_frontend *fe)
 
        ret = mt2060_writereg(priv, REG_VGAG,
                              (priv->cfg->clock_out << 6) | 0x30);
+       if (ret)
+               goto err_i2c_gate_ctrl;
+
+       if (priv->sleep)
+               ret = mt2060_writereg(priv, REG_MISC_CTRL, 0xe8);
 
+err_i2c_gate_ctrl:
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
 
@@ -369,6 +389,7 @@ struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter
        priv->cfg      = cfg;
        priv->i2c      = i2c;
        priv->if1_freq = if1;
+       priv->i2c_max_regs = ~0;
 
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
@@ -396,6 +417,98 @@ struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter
 }
 EXPORT_SYMBOL(mt2060_attach);
 
+static int mt2060_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct mt2060_platform_data *pdata = client->dev.platform_data;
+       struct dvb_frontend *fe;
+       struct mt2060_priv *dev;
+       int ret;
+       u8 chip_id;
+
+       dev_dbg(&client->dev, "\n");
+
+       if (!pdata) {
+               dev_err(&client->dev, "Cannot proceed without platform data\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL);
+       if (!dev) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       fe = pdata->dvb_frontend;
+       dev->config.i2c_address = client->addr;
+       dev->config.clock_out = pdata->clock_out;
+       dev->cfg = &dev->config;
+       dev->i2c = client->adapter;
+       dev->if1_freq = pdata->if1 ? pdata->if1 : 1220;
+       dev->client = client;
+       dev->i2c_max_regs = pdata->i2c_write_max ? pdata->i2c_write_max - 1 : ~0;
+       dev->sleep = true;
+
+       ret = mt2060_readreg(dev, REG_PART_REV, &chip_id);
+       if (ret) {
+               ret = -ENODEV;
+               goto err;
+       }
+
+       dev_dbg(&client->dev, "chip id=%02x\n", chip_id);
+
+       if (chip_id != PART_REV) {
+               ret = -ENODEV;
+               goto err;
+       }
+
+       /* Power on, calibrate, sleep */
+       ret = mt2060_writereg(dev, REG_MISC_CTRL, 0x20);
+       if (ret)
+               goto err;
+       mt2060_calibrate(dev);
+       ret = mt2060_writereg(dev, REG_MISC_CTRL, 0xe8);
+       if (ret)
+               goto err;
+
+       dev_info(&client->dev, "Microtune MT2060 successfully identified\n");
+       memcpy(&fe->ops.tuner_ops, &mt2060_tuner_ops, sizeof(fe->ops.tuner_ops));
+       fe->ops.tuner_ops.release = NULL;
+       fe->tuner_priv = dev;
+       i2c_set_clientdata(client, dev);
+
+       return 0;
+err:
+       dev_dbg(&client->dev, "failed=%d\n", ret);
+       return ret;
+}
+
+static int mt2060_remove(struct i2c_client *client)
+{
+       dev_dbg(&client->dev, "\n");
+
+       return 0;
+}
+
+static const struct i2c_device_id mt2060_id_table[] = {
+       {"mt2060", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, mt2060_id_table);
+
+static struct i2c_driver mt2060_driver = {
+       .driver = {
+               .name = "mt2060",
+               .suppress_bind_attrs = true,
+       },
+       .probe          = mt2060_probe,
+       .remove         = mt2060_remove,
+       .id_table       = mt2060_id_table,
+};
+
+module_i2c_driver(mt2060_driver);
+
 MODULE_AUTHOR("Olivier DANET");
 MODULE_DESCRIPTION("Microtune MT2060 silicon tuner driver");
 MODULE_LICENSE("GPL");
index 6efed359a24fd2cefadfffaf378294b4a112b535..cc534eb41378ffbeff1982d35cd6d65d92c2c059 100644 (file)
  *  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 MT2060_H
 struct dvb_frontend;
 struct i2c_adapter;
 
+/*
+ * I2C address
+ * 0x60, ...
+ */
+
+/**
+ * struct mt2060_platform_data - Platform data for the mt2060 driver
+ * @clock_out: Clock output setting. 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1.
+ * @if1: First IF used [MHz]. 0 defaults to 1220.
+ * @i2c_write_max: Maximum number of bytes I2C adapter can write at once.
+ *  0 defaults to maximum.
+ * @dvb_frontend: DVB frontend.
+ */
+
+struct mt2060_platform_data {
+       u8 clock_out;
+       u16 if1;
+       unsigned int i2c_write_max:5;
+       struct dvb_frontend *dvb_frontend;
+};
+
+
+/* configuration struct for mt2060_attach() */
 struct mt2060_config {
        u8 i2c_address;
        u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */
index 2b60de6c707dfd884812376358089fde51600233..a6c931c1a5a7bb831c7ed3631a253c9cce7c8d3d 100644 (file)
  *  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 MT2060_PRIV_H
 struct mt2060_priv {
        struct mt2060_config *cfg;
        struct i2c_adapter   *i2c;
+       struct i2c_client *client;
+       struct mt2060_config config;
 
+       u8 i2c_max_regs;
        u32 frequency;
        u16 if1_freq;
        u8  fmfreq;
+
+       /*
+        * Use REG_MISC_CTRL register for sleep. That drops sleep power usage
+        * about 0.9W (huge!). Register bit meanings are unknown, so let it be
+        * disabled by default to avoid possible regression. Convert driver to
+        * i2c model in order to enable it.
+        */
+       bool sleep;
 };
 
 #endif
index e7790e4afcfec35ec866249b90654d912aa36d21..dd85d58fa8d05b75ccedffff9276e28d387eed09 100644 (file)
  *  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/module.h>
index 8267a6ae5d848bc12bb1bbb7e2f1fc5ab7ffd561..050da5540b15119b6d5643867568c809e41ebb75 100644 (file)
  *  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 __MT2131_H__
index 91283b599cb3ed7ee3872ac7b74550d7248f40f0..d2b6f29182cc17cc28376e263f5b44a91d100b1d 100644 (file)
  *  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 __MT2131_PRIV_H__
index b16dfa5e85fb0c78a7316a558d742ac9cd10ae2c..4081fd97c3b2cad0b71e0bd53d87c6ad8b2805c6 100644 (file)
  *  but WITHOUT 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/i2c.h>
index e786d1f23ff1b7c0da087361903c576778fdd75c..273f61aeb8be34f6062d81539dbfad259b2f78f9 100644 (file)
  *  but WITHOUT 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 __MXL5007T_H__
index a2c6cd1c3923a2ff0e02ba27451725940463f758..ee33b7cc7682435c2e39e5145e2e36c3c4dec568 100644 (file)
  *  but WITHOUT 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 "qt1010.h"
 #include "qt1010_priv.h"
index e3198f23437c1af9d70b340415d567e970d24832..276e59e8503261e9d0fdfa1e6bf83a517f3d89d9 100644 (file)
  *  but WITHOUT 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 QT1010_H
index 2c42d3f016366d5f7cb8b11baebee9d1342a3ea3..4cb78ecc89857c064632d75eab98822933639f3a 100644 (file)
  *  but WITHOUT 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 QT1010_PRIV_H
index 8357a3c08a701916b154d89eae50a55e8250196d..c56fcf5d48e335834ea3fe957dfea34c8c6edde1 100644 (file)
  *    but WITHOUT 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 "tda18218_priv.h"
index 076b5f2e888d4a4b4ef5e97ef27cc82c0cdc6ea7..9c0e3fd7ed7f86eadcaf3cbf6a80439c276ef12f 100644 (file)
  *    but WITHOUT 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 TDA18218_H
index 285b77366c8d0104c17db0c1a24b5c8cd0ff41d3..9d04781966e769bdee82bf06d8706386a99d193b 100644 (file)
  *    but WITHOUT 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 TDA18218_PRIV_H
index 2137eadf30f192144d1f01b1fa29f5bcca6954fc..8400808f8f7fe1c77822941f0890757131ba219b 100644 (file)
  *  but WITHOUT 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/module.h>
index 03eef9b87a24e11c2e5a015b3d1037a03fb15b8b..e30948e4ff87eae8070250181f7ea1328d108974 100644 (file)
  *  but WITHOUT 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/module.h>
index 40517860cf67ff85b261dc3470c2343da27b1835..8af93b63ff9ed3a797642dd43f34501062ac10d6 100644 (file)
  *  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 __XC4000_H__
index 796e7638b3b257a03c14d2f4b761631d43efe42a..0345b274eccc0c88aa94f7539401340acf18dfcf 100644 (file)
  *  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/module.h>
index 336bd49eb09b2d4d59e64b61cfc703deec1227a0..42bbec2409fdf3c6499970f8c8cdb5da96382ddf 100644 (file)
  *  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 __XC5000_H__
index 6b469e8c4c6e209d0001c0ff8e9150057fee1c43..313f659f0bfb00554d8a7c74b57de6b6432d7903 100644 (file)
  *  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 "au0828.h"
index 48a1882c2b6bec47464cb48992d3b3af3081a6ea..1f4412ee6da44ba676f3fe5889b135ae4d2ca261 100644 (file)
  *  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.
  */
 
 #define AU0828_BOARD_UNKNOWN           0
index bf53553d262449db469ea9461fb763cc61ebfa40..739df61cec4f7049a838d27d6c80b4d7ec682040 100644 (file)
  *  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 "au0828.h"
@@ -153,9 +149,11 @@ static void au0828_unregister_media_device(struct au0828_dev *dev)
        }
 
        /* clear enable_source, disable_source */
+       mutex_lock(&mdev->graph_mutex);
        dev->media_dev->source_priv = NULL;
        dev->media_dev->enable_source = NULL;
        dev->media_dev->disable_source = NULL;
+       mutex_unlock(&mdev->graph_mutex);
 
        media_device_unregister(dev->media_dev);
        media_device_cleanup(dev->media_dev);
@@ -278,6 +276,7 @@ create_link:
        }
 }
 
+/* Callers should hold graph_mutex */
 static int au0828_enable_source(struct media_entity *entity,
                                struct media_pipeline *pipe)
 {
@@ -291,8 +290,6 @@ static int au0828_enable_source(struct media_entity *entity,
        if (!mdev)
                return -ENODEV;
 
-       mutex_lock(&mdev->graph_mutex);
-
        dev = mdev->source_priv;
 
        /*
@@ -397,7 +394,7 @@ static int au0828_enable_source(struct media_entity *entity,
                goto end;
        }
 
-       ret = __media_entity_pipeline_start(entity, pipe);
+       ret = __media_pipeline_start(entity, pipe);
        if (ret) {
                pr_err("Start Pipeline: %s->%s Error %d\n",
                        source->name, entity->name, ret);
@@ -419,12 +416,12 @@ static int au0828_enable_source(struct media_entity *entity,
                 dev->active_source->name, dev->active_sink->name,
                 dev->active_link_owner->name, ret);
 end:
-       mutex_unlock(&mdev->graph_mutex);
        pr_debug("au0828_enable_source() end %s %d %d\n",
                 entity->name, entity->function, ret);
        return ret;
 }
 
+/* Callers should hold graph_mutex */
 static void au0828_disable_source(struct media_entity *entity)
 {
        int ret = 0;
@@ -434,13 +431,10 @@ static void au0828_disable_source(struct media_entity *entity)
        if (!mdev)
                return;
 
-       mutex_lock(&mdev->graph_mutex);
        dev = mdev->source_priv;
 
-       if (!dev->active_link) {
-               ret = -ENODEV;
-               goto end;
-       }
+       if (!dev->active_link)
+               return;
 
        /* link is active - stop pipeline from source (tuner) */
        if (dev->active_link->sink->entity == dev->active_sink &&
@@ -450,8 +444,8 @@ static void au0828_disable_source(struct media_entity *entity)
                 * has active pipeline
                */
                if (dev->active_link_owner != entity)
-                       goto end;
-               __media_entity_pipeline_stop(entity);
+                       return;
+               __media_pipeline_stop(entity);
                ret = __media_entity_setup_link(dev->active_link, 0);
                if (ret)
                        pr_err("Deactivate link Error %d\n", ret);
@@ -465,9 +459,6 @@ static void au0828_disable_source(struct media_entity *entity)
                dev->active_source = NULL;
                dev->active_sink = NULL;
        }
-
-end:
-       mutex_unlock(&mdev->graph_mutex);
 }
 #endif
 
@@ -549,9 +540,11 @@ static int au0828_media_device_register(struct au0828_dev *dev,
                return ret;
        }
        /* set enable_source */
+       mutex_lock(&dev->media_dev->graph_mutex);
        dev->media_dev->source_priv = (void *) dev;
        dev->media_dev->enable_source = au0828_enable_source;
        dev->media_dev->disable_source = au0828_disable_source;
+       mutex_unlock(&dev->media_dev->graph_mutex);
 #endif
        return 0;
 }
index 0e174e86061404d6e01f36d8ff2db5e0f856702b..7e0c9b795e52409dd2449b3b6bbce160a3303df2 100644 (file)
  *  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 "au0828.h"
index ae7ac6669769f3cdcc2d2ba01db5cc0c73ce5039..42b352bb4f020523f7c3a9e284217d36b411b3ea 100644 (file)
  *  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 "au0828.h"
index 1e66e7828d8f2921ad954e5568534ebb55dbffde..9ec919c68482df5c5c97e4a41d421f71411422ee 100644 (file)
@@ -298,7 +298,7 @@ int au0828_rc_register(struct au0828_dev *dev)
                return -ENODEV;
 
        ir = kzalloc(sizeof(*ir), GFP_KERNEL);
-       rc = rc_allocate_device();
+       rc = rc_allocate_device(RC_DRIVER_IR_RAW);
        if (!ir || !rc)
                goto error;
 
@@ -343,7 +343,6 @@ int au0828_rc_register(struct au0828_dev *dev)
        rc->input_id.product = le16_to_cpu(dev->usbdev->descriptor.idProduct);
        rc->dev.parent = &dev->usbdev->dev;
        rc->driver_name = "au0828-input";
-       rc->driver_type = RC_DRIVER_IR_RAW;
        rc->allowed_protocols = RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32 |
                                                                RC_BIT_RC5;
 
index 2140f4cfb645679901e71853a940240a64024029..7aaf10739c8b2cfe14bfc618c631320f758e1da4 100644 (file)
  *  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.
  */
 
 /* We'll start to rename these registers once we have a better
index 7a10eaa38f672e715f237ecb92c76ad97e8e1ea3..16f9125a985a2787687743c95d9911ddcb778029 100644 (file)
  * but WITHOUT 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.
  */
 
 /* Developer Notes:
index dd7b378fe0706111d0473b74bc45cb5a7ee7b134..88e59748ebc27335d4832147cbfde6b0a4f3925f 100644 (file)
  *  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.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index cdef677d57ecf5910d83882df79f6d3a33fe8e8b..81f72c0b561fb7bdd4f0278abef69d8f362aa4a6 100644 (file)
  *  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 __CPIA2_H__
index 0310fd6ed1033ced21cf8c509666852b17c128b7..431dd0b4b3323671039fc9b2a71926fcc681dd6f 100644 (file)
  *  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.
- *
  *  Stripped of 2.4 stuff ready for main kernel submit by
  *             Alan Cox <alan@lxorguk.ukuu.org.uk>
  *
index 3bbec514a967a86fcc2079718500557d4aa2738a..eebe46ea9c0158b6887bc1d9e092873707ac7f9e 100644 (file)
  *  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 CPIA2_REGISTER_HEADER
index 37f9b30b0abc73f5ea024a979d61ba4ff157b401..1c7e16e5d88b53f0258fd2bcd749e10299945ec0 100644 (file)
  *  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.
- *
  *  Stripped of 2.4 stuff ready for main kernel submit by
  *             Alan Cox <alan@lxorguk.ukuu.org.uk>
  ****************************************************************************/
@@ -551,12 +547,10 @@ static int write_packet(struct usb_device *udev,
        if (!registers || size <= 0)
                return -EINVAL;
 
-       buf = kmalloc(size, GFP_KERNEL);
+       buf = kmemdup(registers, size, GFP_KERNEL);
        if (!buf)
                return -ENOMEM;
 
-       memcpy(buf, registers, size);
-
        ret = usb_control_msg(udev,
                               usb_sndctrlpipe(udev, 0),
                               request,
index 9caea8344547a790db13b04690d5d5c14aaf9451..7122023e7004995a5cd8912b4b77175b695acb11 100644 (file)
  *  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.
- *
  *  Stripped of 2.4 stuff ready for main kernel submit by
  *             Alan Cox <alan@lxorguk.ukuu.org.uk>
  ****************************************************************************/
index 0cced3e5b040bfddc8696d030aa3752003108e9f..58de80bff4c761296d85ae942899e87c1317476e 100644 (file)
@@ -50,6 +50,7 @@ config VIDEO_CX231XX_DVB
        select DVB_LGDT3306A if MEDIA_SUBDRV_AUTOSELECT
        select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT
        select DVB_SI2165 if MEDIA_SUBDRV_AUTOSELECT
+       select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT
        select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT
 
        ---help---
index 29d450c15f293bed2b59dc92c207fedef5cd67c5..509d9711d590047c4017ceab8b6987a891be6e71 100644 (file)
  *  but WITHOUT 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 "cx231xx.h"
index 8263c4b0610b4e44457f6c867a387e3a9a89d06d..cf80842dfa082f8d14104377f7c61c15bcc25fe6 100644 (file)
  *  but WITHOUT 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 "cx231xx.h"
index 36bc25494319dbf1b48d2414c1e0b3f76965dc64..f730fdbc915670225ff2ca08a9f4cc60340523ed 100644 (file)
@@ -841,6 +841,33 @@ struct cx231xx_board cx231xx_boards[] = {
                        .gpio = NULL,
                } },
        },
+       [CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD] = {
+               .name = "Evromedia USB Full Hybrid Full HD",
+               .tuner_type = TUNER_ABSENT,
+               .demod_addr = 0x64, /* 0xc8 >> 1 */
+               .demod_i2c_master = I2C_1_MUX_3,
+               .has_dvb = 1,
+               .ir_i2c_master = I2C_0,
+               .norm = V4L2_STD_PAL,
+               .output_mode = OUT_MODE_VIP11,
+               .tuner_addr = 0x60, /* 0xc0 >> 1 */
+               .tuner_i2c_master = I2C_2,
+               .input = {{
+                       .type = CX231XX_VMUX_TELEVISION,
+                       .vmux = 0,
+                       .amux = CX231XX_AMUX_VIDEO,
+               }, {
+                       .type = CX231XX_VMUX_COMPOSITE1,
+                       .vmux = CX231XX_VIN_2_1,
+                       .amux = CX231XX_AMUX_LINE_IN,
+               }, {
+                       .type = CX231XX_VMUX_SVIDEO,
+                       .vmux = CX231XX_VIN_1_1 |
+                               (CX231XX_VIN_1_2 << 8) |
+                               CX25840_SVIDEO_ON,
+                       .amux = CX231XX_AMUX_LINE_IN,
+               } },
+       },
 };
 const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards);
 
@@ -908,6 +935,8 @@ struct usb_device_id cx231xx_id_table[] = {
         .driver_info = CX231XX_BOARD_OTG102},
        {USB_DEVICE(USB_VID_TERRATEC, 0x00a6),
         .driver_info = CX231XX_BOARD_TERRATEC_GRABBY},
+       {USB_DEVICE(0x1b80, 0xd3b2),
+       .driver_info = CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD},
        {},
 };
 
index 550ec932f931950b28e072dd7b918bf33223bf1e..46646ecd2dbcf6a53af13210f28f1368c1e92c10 100644 (file)
@@ -355,7 +355,12 @@ int cx231xx_send_vendor_cmd(struct cx231xx *dev,
         */
        if ((ven_req->wLength > 4) && ((ven_req->bRequest == 0x4) ||
                                        (ven_req->bRequest == 0x5) ||
-                                       (ven_req->bRequest == 0x6))) {
+                                       (ven_req->bRequest == 0x6) ||
+
+                                       /* Internal Master 3 Bus can send
+                                        * and receive only 4 bytes per time
+                                        */
+                                       (ven_req->bRequest == 0x2))) {
                unsend_size = 0;
                pdata = ven_req->pBuff;
 
index 2b63c2f6d3b0644fdf023b37202140806cc7d7b4..2b9eb9fd7c52b64f46d8c7d1efb0f44e504dfc67 100644 (file)
  *  but WITHOUT 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 _CX231XX_DIF_H
index 2868546999caff703a4a1c2a5ebc7a7af339f24e..46427fd3b220dc211f8a29bcd04a747ead171089 100644 (file)
@@ -33,6 +33,7 @@
 #include "s5h1411.h"
 #include "lgdt3305.h"
 #include "si2165.h"
+#include "si2168.h"
 #include "mb86a20s.h"
 #include "si2157.h"
 #include "lgdt3306a.h"
@@ -949,6 +950,75 @@ static int dvb_init(struct cx231xx *dev)
                           &pv_tda18271_config);
                break;
 
+       case CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD:
+       {
+               struct si2157_config si2157_config = {};
+               struct si2168_config si2168_config = {};
+               struct i2c_board_info info = {};
+               struct i2c_client *client;
+               struct i2c_adapter *adapter;
+
+               /* attach demodulator chip */
+               si2168_config.ts_mode = SI2168_TS_SERIAL; /* from *.inf file */
+               si2168_config.fe = &dev->dvb->frontend;
+               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)) {
+                       i2c_unregister_device(client);
+                       result = -ENODEV;
+                       goto out_free;
+               }
+
+               dvb->i2c_client_demod = client;
+
+               /* attach tuner chip */
+               si2157_config.fe = dev->dvb->frontend;
+#ifdef CONFIG_MEDIA_CONTROLLER_DVB
+               si2157_config.mdev = dev->media_dev;
+#endif
+               si2157_config.if_port = 1;
+               si2157_config.inversion = false;
+
+               memset(&info, 0, sizeof(info));
+               strlcpy(info.type, "si2157", sizeof(info.type));
+               info.addr = dev->board.tuner_addr;
+               info.platform_data = &si2157_config;
+
+               request_module(info.type);
+               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);
+                       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;
+               }
+
+               dev->cx231xx_reset_analog_tuner = NULL;
+               dev->dvb->i2c_client_tuner = client;
+               break;
+       }
        default:
                dev_err(dev->dev,
                        "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
index 15d8d1b5f05ca73feb8817e3b6c1132d45f17f04..6e80f3c573f36a623bf2b30309642cdd9dba25d3 100644 (file)
@@ -72,7 +72,7 @@ int cx231xx_ir_init(struct cx231xx *dev)
 
        memset(&info, 0, sizeof(struct i2c_board_info));
        memset(&dev->init_data, 0, sizeof(dev->init_data));
-       dev->init_data.rc_dev = rc_allocate_device();
+       dev->init_data.rc_dev = rc_allocate_device(RC_DRIVER_SCANCODE);
        if (!dev->init_data.rc_dev)
                return -ENOMEM;
 
index 90c867683076017f818a81d6db15dfb0c97adb95..d9792ea4bbc63ea2882e4b196af0040185d561c3 100644 (file)
@@ -78,6 +78,7 @@
 #define CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx 20
 #define CX231XX_BOARD_HAUPPAUGE_955Q 21
 #define CX231XX_BOARD_TERRATEC_GRABBY 22
+#define CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD 23
 
 /* Limits minimum and default number of buffers */
 #define CX231XX_MIN_BUF                 4
index 524533d3eb291c7f22b5c131ab7479b134031428..0e4944b2b0f4d3a70eec4a0958f4ecccf1ea3803 100644 (file)
@@ -156,3 +156,11 @@ config DVB_USB_DVBSKY
        select DVB_SP2 if MEDIA_SUBDRV_AUTOSELECT
        help
          Say Y here to support the USB receivers from DVBSky.
+
+config DVB_USB_ZD1301
+       tristate "ZyDAS ZD1301"
+       depends on DVB_USB_V2
+       select DVB_ZD1301_DEMOD if MEDIA_SUBDRV_AUTOSELECT
+       select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT
+       help
+         Say Y here to support the ZyDAS ZD1301 DVB USB receiver.
index f10d4df0eae5c2962e4a20de60de3145a082ea83..969f68e55265e1a20331f11ebfe35755a11ef5a9 100644 (file)
@@ -40,6 +40,9 @@ obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o
 dvb-usb-dvbsky-objs := dvbsky.o
 obj-$(CONFIG_DVB_USB_DVBSKY) += dvb-usb-dvbsky.o
 
+dvb-usb-zd1301-objs := zd1301.o
+obj-$(CONFIG_DVB_USB_ZD1301) += zd1301.o
+
 ccflags-y += -I$(srctree)/drivers/media/dvb-core
 ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
 ccflags-y += -I$(srctree)/drivers/media/tuners
index 29011dfabb11047f20318d3f8cf5b3dfc34a5dfc..caa1e6101f5890e08ffc8148938f52f9e945bf4c 100644 (file)
  *    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 "af9015.h"
index 1db1bb0d57bcd1c858151588693b6fc5b821a85d..2dd9231a8ece878e44e22147edc391e88b94f7f4 100644 (file)
  *    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 AF9015_H
index c673726d9b70185080f58f4dd7f7ade81d916cee..4df9486e19b9bb020ca2d0844d2df0f7144179b1 100644 (file)
@@ -335,14 +335,12 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
                        /* TODO: correct limits > 40 */
                        ret = -EOPNOTSUPP;
                } else if ((msg[0].addr == state->af9033_i2c_addr[0]) ||
-                          (msg[0].addr == state->af9033_i2c_addr[1]) ||
-                          (state->chip_type == 0x9135)) {
+                          (msg[0].addr == state->af9033_i2c_addr[1])) {
                        /* demod access via firmware interface */
                        u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 |
                                        msg[0].buf[2];
 
-                       if (msg[0].addr == state->af9033_i2c_addr[1] ||
-                           msg[0].addr == (state->af9033_i2c_addr[1] >> 1))
+                       if (msg[0].addr == state->af9033_i2c_addr[1])
                                reg |= 0x100000;
 
                        ret = af9035_rd_regs(d, reg, &msg[1].buf[0],
@@ -396,14 +394,12 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
                        /* TODO: correct limits > 40 */
                        ret = -EOPNOTSUPP;
                } else if ((msg[0].addr == state->af9033_i2c_addr[0]) ||
-                          (msg[0].addr == state->af9033_i2c_addr[1]) ||
-                          (state->chip_type == 0x9135)) {
+                          (msg[0].addr == state->af9033_i2c_addr[1])) {
                        /* demod access via firmware interface */
                        u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 |
                                        msg[0].buf[2];
 
-                       if (msg[0].addr == state->af9033_i2c_addr[1] ||
-                           msg[0].addr == (state->af9033_i2c_addr[1] >> 1))
+                       if (msg[0].addr == state->af9033_i2c_addr[1])
                                reg |= 0x100000;
 
                        ret = af9035_wr_regs(d, reg, &msg[0].buf[3],
@@ -496,7 +492,8 @@ static int af9035_identify_state(struct dvb_usb_device *d, const char **name)
 {
        struct state *state = d_to_priv(d);
        struct usb_interface *intf = d->intf;
-       int ret, ts_mode_invalid;
+       int ret, i, ts_mode_invalid;
+       unsigned int utmp, eeprom_addr;
        u8 tmp;
        u8 wbuf[1] = { 1 };
        u8 rbuf[4];
@@ -518,25 +515,48 @@ static int af9035_identify_state(struct dvb_usb_device *d, const char **name)
                 state->prechip_version, state->chip_version, state->chip_type);
 
        if (state->chip_type == 0x9135) {
-               if (state->chip_version == 0x02)
+               if (state->chip_version == 0x02) {
                        *name = AF9035_FIRMWARE_IT9135_V2;
-               else
+                       utmp = 0x00461d;
+               } else {
                        *name = AF9035_FIRMWARE_IT9135_V1;
-               state->eeprom_addr = EEPROM_BASE_IT9135;
+                       utmp = 0x00461b;
+               }
+
+               /* Check if eeprom exists */
+               ret = af9035_rd_reg(d, utmp, &tmp);
+               if (ret < 0)
+                       goto err;
+
+               if (tmp == 0x00) {
+                       dev_dbg(&intf->dev, "no eeprom\n");
+                       state->no_eeprom = true;
+                       goto check_firmware_status;
+               }
+
+               eeprom_addr = EEPROM_BASE_IT9135;
        } else if (state->chip_type == 0x9306) {
                *name = AF9035_FIRMWARE_IT9303;
-               state->eeprom_addr = EEPROM_BASE_IT9135;
+               state->no_eeprom = true;
+               goto check_firmware_status;
        } else {
                *name = AF9035_FIRMWARE_AF9035;
-               state->eeprom_addr = EEPROM_BASE_AF9035;
+               eeprom_addr = EEPROM_BASE_AF9035;
+       }
+
+       /* Read and store eeprom */
+       for (i = 0; i < 256; i += 32) {
+               ret = af9035_rd_regs(d, eeprom_addr + i, &state->eeprom[i], 32);
+               if (ret < 0)
+                       goto err;
        }
 
+       dev_dbg(&intf->dev, "eeprom dump:\n");
+       for (i = 0; i < 256; i += 16)
+               dev_dbg(&intf->dev, "%*ph\n", 16, &state->eeprom[i]);
 
        /* check for dual tuner mode */
-       ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_TS_MODE, &tmp);
-       if (ret < 0)
-               goto err;
-
+       tmp = state->eeprom[EEPROM_TS_MODE];
        ts_mode_invalid = 0;
        switch (tmp) {
        case 0:
@@ -560,7 +580,7 @@ static int af9035_identify_state(struct dvb_usb_device *d, const char **name)
        if (ts_mode_invalid)
                dev_info(&intf->dev, "ts mode=%d not supported, defaulting to single tuner mode!", tmp);
 
-
+check_firmware_status:
        ret = af9035_ctrl_msg(d, &req);
        if (ret < 0)
                goto err;
@@ -750,15 +770,11 @@ static int af9035_download_firmware(struct dvb_usb_device *d,
                        goto err;
 
                /* tell the slave I2C address */
-               ret = af9035_rd_reg(d,
-                               state->eeprom_addr + EEPROM_2ND_DEMOD_ADDR,
-                               &tmp);
-               if (ret < 0)
-                       goto err;
+               tmp = state->eeprom[EEPROM_2ND_DEMOD_ADDR];
 
-               /* use default I2C address if eeprom has no address set */
+               /* Use default I2C address if eeprom has no address set */
                if (!tmp)
-                       tmp = 0x3a;
+                       tmp = 0x1d << 1; /* 8-bit format used by chip */
 
                if ((state->chip_type == 0x9135) ||
                                (state->chip_type == 0x9306)) {
@@ -819,11 +835,11 @@ static int af9035_read_config(struct dvb_usb_device *d)
        struct state *state = d_to_priv(d);
        int ret, i;
        u8 tmp;
-       u16 tmp16, addr;
+       u16 tmp16;
 
-       /* demod I2C "address" */
-       state->af9033_i2c_addr[0] = 0x38;
-       state->af9033_i2c_addr[1] = 0x3a;
+       /* Demod I2C address */
+       state->af9033_i2c_addr[0] = 0x1c;
+       state->af9033_i2c_addr[1] = 0x1d;
        state->af9033_config[0].adc_multiplier = AF9033_ADC_MULTIPLIER_2X;
        state->af9033_config[1].adc_multiplier = AF9033_ADC_MULTIPLIER_2X;
        state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB;
@@ -837,20 +853,16 @@ static int af9035_read_config(struct dvb_usb_device *d)
                if (state->chip_version == 0x02) {
                        state->af9033_config[0].tuner = AF9033_TUNER_IT9135_60;
                        state->af9033_config[1].tuner = AF9033_TUNER_IT9135_60;
-                       tmp16 = 0x00461d; /* eeprom memory mapped location */
                } else {
                        state->af9033_config[0].tuner = AF9033_TUNER_IT9135_38;
                        state->af9033_config[1].tuner = AF9033_TUNER_IT9135_38;
-                       tmp16 = 0x00461b; /* eeprom memory mapped location */
                }
 
-               /* check if eeprom exists */
-               ret = af9035_rd_reg(d, tmp16, &tmp);
-               if (ret < 0)
-                       goto err;
+               if (state->no_eeprom) {
+                       /* Remote controller to NEC polling by default */
+                       state->ir_mode = 0x05;
+                       state->ir_type = 0x00;
 
-               if (tmp == 0x00) {
-                       dev_dbg(&intf->dev, "no eeprom\n");
                        goto skip_eeprom;
                }
        } else if (state->chip_type == 0x9306) {
@@ -861,29 +873,25 @@ static int af9035_read_config(struct dvb_usb_device *d)
                return 0;
        }
 
+       /* Remote controller */
+       state->ir_mode = state->eeprom[EEPROM_IR_MODE];
+       state->ir_type = state->eeprom[EEPROM_IR_TYPE];
 
        if (state->dual_mode) {
-               /* read 2nd demodulator I2C address */
-               ret = af9035_rd_reg(d,
-                               state->eeprom_addr + EEPROM_2ND_DEMOD_ADDR,
-                               &tmp);
-               if (ret < 0)
-                       goto err;
-
+               /* Read 2nd demodulator I2C address. 8-bit format on eeprom */
+               tmp = state->eeprom[EEPROM_2ND_DEMOD_ADDR];
                if (tmp)
-                       state->af9033_i2c_addr[1] = tmp;
+                       state->af9033_i2c_addr[1] = tmp >> 1;
 
-               dev_dbg(&intf->dev, "2nd demod I2C addr=%02x\n", tmp);
+               dev_dbg(&intf->dev, "2nd demod I2C addr=%02x\n",
+                       state->af9033_i2c_addr[1]);
        }
 
-       addr = state->eeprom_addr;
-
        for (i = 0; i < state->dual_mode + 1; i++) {
-               /* tuner */
-               ret = af9035_rd_reg(d, addr + EEPROM_1_TUNER_ID, &tmp);
-               if (ret < 0)
-                       goto err;
+               unsigned int eeprom_offset = 0;
 
+               /* tuner */
+               tmp = state->eeprom[EEPROM_1_TUNER_ID + eeprom_offset];
                dev_dbg(&intf->dev, "[%d]tuner=%02x\n", i, tmp);
 
                /* tuner sanity check */
@@ -956,21 +964,13 @@ static int af9035_read_config(struct dvb_usb_device *d)
                }
 
                /* tuner IF frequency */
-               ret = af9035_rd_reg(d, addr + EEPROM_1_IF_L, &tmp);
-               if (ret < 0)
-                       goto err;
-
-               tmp16 = tmp;
-
-               ret = af9035_rd_reg(d, addr + EEPROM_1_IF_H, &tmp);
-               if (ret < 0)
-                       goto err;
-
+               tmp = state->eeprom[EEPROM_1_IF_L + eeprom_offset];
+               tmp16 = tmp << 0;
+               tmp = state->eeprom[EEPROM_1_IF_H + eeprom_offset];
                tmp16 |= tmp << 8;
-
                dev_dbg(&intf->dev, "[%d]IF=%d\n", i, tmp16);
 
-               addr += 0x10; /* shift for the 2nd tuner params */
+               eeprom_offset += 0x10; /* shift for the 2nd tuner params */
        }
 
 skip_eeprom:
@@ -1247,30 +1247,11 @@ static int af9035_frontend_detach(struct dvb_usb_adapter *adap)
        struct state *state = adap_to_priv(adap);
        struct dvb_usb_device *d = adap_to_d(adap);
        struct usb_interface *intf = d->intf;
-       int demod2;
 
        dev_dbg(&intf->dev, "adap->id=%d\n", adap->id);
 
-       /*
-        * For dual tuner devices we have to resolve 2nd demod client, as there
-        * is two different kind of tuner drivers; one is using I2C binding
-        * and the other is using DVB attach/detach binding.
-        */
-       switch (state->af9033_config[adap->id].tuner) {
-       case AF9033_TUNER_IT9135_38:
-       case AF9033_TUNER_IT9135_51:
-       case AF9033_TUNER_IT9135_52:
-       case AF9033_TUNER_IT9135_60:
-       case AF9033_TUNER_IT9135_61:
-       case AF9033_TUNER_IT9135_62:
-               demod2 = 2;
-               break;
-       default:
-               demod2 = 1;
-       }
-
        if (adap->id == 1) {
-               if (state->i2c_client[demod2])
+               if (state->i2c_client[1])
                        af9035_del_i2c_dev(d);
        } else if (adap->id == 0) {
                if (state->i2c_client[0])
@@ -1510,50 +1491,58 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap)
        case AF9033_TUNER_IT9135_38:
        case AF9033_TUNER_IT9135_51:
        case AF9033_TUNER_IT9135_52:
-       {
-               struct it913x_config it913x_config = {
-                       .fe = adap->fe[0],
-                       .chip_ver = 1,
-               };
-
-               if (state->dual_mode) {
-                       if (adap->id == 0)
-                               it913x_config.role = IT913X_ROLE_DUAL_MASTER;
-                       else
-                               it913x_config.role = IT913X_ROLE_DUAL_SLAVE;
-               }
-
-               ret = af9035_add_i2c_dev(d, "it913x",
-                               state->af9033_i2c_addr[adap->id] >> 1,
-                               &it913x_config, &d->i2c_adap);
-               if (ret)
-                       goto err;
-
-               fe = adap->fe[0];
-               break;
-       }
        case AF9033_TUNER_IT9135_60:
        case AF9033_TUNER_IT9135_61:
        case AF9033_TUNER_IT9135_62:
        {
-               struct it913x_config it913x_config = {
+               struct platform_device *pdev;
+               const char *name;
+               struct it913x_platform_data it913x_pdata = {
+                       .regmap = state->af9033_config[adap->id].regmap,
                        .fe = adap->fe[0],
-                       .chip_ver = 2,
                };
 
+               switch (state->af9033_config[adap->id].tuner) {
+               case AF9033_TUNER_IT9135_38:
+               case AF9033_TUNER_IT9135_51:
+               case AF9033_TUNER_IT9135_52:
+                       name = "it9133ax-tuner";
+                       break;
+               case AF9033_TUNER_IT9135_60:
+               case AF9033_TUNER_IT9135_61:
+               case AF9033_TUNER_IT9135_62:
+                       name = "it9133bx-tuner";
+                       break;
+               default:
+                       ret = -ENODEV;
+                       goto err;
+               }
+
                if (state->dual_mode) {
                        if (adap->id == 0)
-                               it913x_config.role = IT913X_ROLE_DUAL_MASTER;
+                               it913x_pdata.role = IT913X_ROLE_DUAL_MASTER;
                        else
-                               it913x_config.role = IT913X_ROLE_DUAL_SLAVE;
+                               it913x_pdata.role = IT913X_ROLE_DUAL_SLAVE;
+               } else {
+                       it913x_pdata.role = IT913X_ROLE_SINGLE;
                }
 
-               ret = af9035_add_i2c_dev(d, "it913x",
-                               state->af9033_i2c_addr[adap->id] >> 1,
-                               &it913x_config, &d->i2c_adap);
-               if (ret)
+               request_module("%s", "it913x");
+               pdev = platform_device_register_data(&d->intf->dev, name,
+                                                    PLATFORM_DEVID_AUTO,
+                                                    &it913x_pdata,
+                                                    sizeof(it913x_pdata));
+               if (IS_ERR(pdev) || !pdev->dev.driver) {
+                       ret = -ENODEV;
+                       goto err;
+               }
+               if (!try_module_get(pdev->dev.driver->owner)) {
+                       platform_device_unregister(pdev);
+                       ret = -ENODEV;
                        goto err;
+               }
 
+               state->platform_device_tuner[adap->id] = pdev;
                fe = adap->fe[0];
                break;
        }
@@ -1675,12 +1664,6 @@ static int af9035_tuner_detach(struct dvb_usb_adapter *adap)
        switch (state->af9033_config[adap->id].tuner) {
        case AF9033_TUNER_TUA9001:
        case AF9033_TUNER_FC2580:
-       case AF9033_TUNER_IT9135_38:
-       case AF9033_TUNER_IT9135_51:
-       case AF9033_TUNER_IT9135_52:
-       case AF9033_TUNER_IT9135_60:
-       case AF9033_TUNER_IT9135_61:
-       case AF9033_TUNER_IT9135_62:
                if (adap->id == 1) {
                        if (state->i2c_client[3])
                                af9035_del_i2c_dev(d);
@@ -1688,6 +1671,23 @@ static int af9035_tuner_detach(struct dvb_usb_adapter *adap)
                        if (state->i2c_client[1])
                                af9035_del_i2c_dev(d);
                }
+               break;
+       case AF9033_TUNER_IT9135_38:
+       case AF9033_TUNER_IT9135_51:
+       case AF9033_TUNER_IT9135_52:
+       case AF9033_TUNER_IT9135_60:
+       case AF9033_TUNER_IT9135_61:
+       case AF9033_TUNER_IT9135_62:
+       {
+               struct platform_device *pdev;
+
+               pdev = state->platform_device_tuner[adap->id];
+               if (pdev) {
+                       module_put(pdev->dev.driver->owner);
+                       platform_device_unregister(pdev);
+               }
+               break;
+       }
        }
 
        return 0;
@@ -1872,25 +1872,13 @@ static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
 {
        struct state *state = d_to_priv(d);
        struct usb_interface *intf = d->intf;
-       int ret;
-       u8 tmp;
-
-       ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_IR_MODE, &tmp);
-       if (ret < 0)
-               goto err;
 
-       dev_dbg(&intf->dev, "ir_mode=%02x\n", tmp);
+       dev_dbg(&intf->dev, "ir_mode=%02x ir_type=%02x\n",
+               state->ir_mode, state->ir_type);
 
        /* don't activate rc if in HID mode or if not available */
-       if (tmp == 5) {
-               ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_IR_TYPE,
-                               &tmp);
-               if (ret < 0)
-                       goto err;
-
-               dev_dbg(&intf->dev, "ir_type=%02x\n", tmp);
-
-               switch (tmp) {
+       if (state->ir_mode == 0x05) {
+               switch (state->ir_type) {
                case 0: /* NEC */
                default:
                        rc->allowed_protos = RC_BIT_NEC | RC_BIT_NECX |
@@ -1910,11 +1898,6 @@ static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
        }
 
        return 0;
-
-err:
-       dev_dbg(&intf->dev, "failed=%d\n", ret);
-
-       return ret;
 }
 #else
        #define af9035_get_rc_config NULL
index 1f83c9218ad06a54b8d974e4762e6fb8a22e5931..a76e6bf0ab1ee13801241dd3b912994e4e05dab8 100644 (file)
@@ -22,6 +22,7 @@
 #ifndef AF9035_H
 #define AF9035_H
 
+#include <linux/platform_device.h>
 #include "dvb_usb.h"
 #include "af9033.h"
 #include "tua9001.h"
@@ -61,15 +62,19 @@ struct state {
        u8 prechip_version;
        u8 chip_version;
        u16 chip_type;
+       u8 eeprom[256];
+       bool no_eeprom;
+       u8 ir_mode;
+       u8 ir_type;
        u8 dual_mode:1;
        u8 no_read:1;
-       u16 eeprom_addr;
        u8 af9033_i2c_addr[2];
        struct af9033_config af9033_config[2];
        struct af9033_ops ops;
        #define AF9035_I2C_CLIENT_MAX 4
        struct i2c_client *i2c_client[AF9035_I2C_CLIENT_MAX];
        struct i2c_adapter *i2c_adapter_demod;
+       struct platform_device *platform_device_tuner[2];
 };
 
 static const u32 clock_lut_af9035[] = {
index ae917c042a52e7737a74e536328906014dbe34aa..6795c0c609b186dcd7d1a88857918e7796a7eb33 100644 (file)
  *    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.
- *
  * TODO:
  * - add smart card reader support for Conditional Access (CA)
  *
index 3ca2bca4ebafacc581bfd3cc3aa17c3d087c209b..393e2fce2aed04a880e5de81344fca359a2ebbde 100644 (file)
  *    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.
- *
  * TODO:
  * - add smart card reader support for Conditional Access (CA)
  *
index ae6a671b7fd55dae414501628918d4d00f4a5336..6ee01cb64ca5ac1a45c288678c5c867dc5aa0e9d 100644 (file)
  *    but WITHOUT 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 "au6610.h"
index ea337bfc00b111aae5de96e85f370fddefa73cf2..aacfcc6fa0f56a3dce90aac469666a1d7720f4c3 100644 (file)
  *    but WITHOUT 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 AU6610_H
index f67b14bc32e3e653174dbae9e6d64567c657b389..e596031a708d06d69b20af0c2de0a60183b334c2 100644 (file)
  *    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 "ce6230.h"
index 299e57e3390b8714549b867bf67df3adc02f6b24..b25b3b938e492ffd669031180205b485fd01dcd4 100644 (file)
  *    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 CE6230_H
index a8e6624fbe8347fb48055d0048cd4bf84575edc1..955fb0d075070a2ee62b0afa698268049fd90f09 100644 (file)
@@ -147,7 +147,7 @@ static int dvb_usbv2_remote_init(struct dvb_usb_device *d)
        if (!d->rc.map_name)
                return 0;
 
-       dev = rc_allocate_device();
+       dev = rc_allocate_device(d->rc.driver_type);
        if (!dev) {
                ret = -ENOMEM;
                goto err;
@@ -162,7 +162,6 @@ static int dvb_usbv2_remote_init(struct dvb_usb_device *d)
        /* TODO: likely RC-core should took const char * */
        dev->driver_name = (char *) d->props->driver_name;
        dev->map_name = d->rc.map_name;
-       dev->driver_type = d->rc.driver_type;
        dev->allowed_protocols = d->rc.allowed_protos;
        dev->change_protocol = d->rc.change_protocol;
        dev->priv = d;
@@ -1013,8 +1012,8 @@ EXPORT_SYMBOL(dvb_usbv2_probe);
 void dvb_usbv2_disconnect(struct usb_interface *intf)
 {
        struct dvb_usb_device *d = usb_get_intfdata(intf);
-       const char *name = d->name;
-       struct device dev = d->udev->dev;
+       const char *devname = kstrdup(dev_name(&d->udev->dev), GFP_KERNEL);
+       const char *drvname = d->name;
 
        dev_dbg(&d->udev->dev, "%s: bInterfaceNumber=%d\n", __func__,
                        intf->cur_altsetting->desc.bInterfaceNumber);
@@ -1024,8 +1023,9 @@ void dvb_usbv2_disconnect(struct usb_interface *intf)
 
        dvb_usbv2_exit(d);
 
-       dev_info(&dev, "%s: '%s' successfully deinitialized and disconnected\n",
-                       KBUILD_MODNAME, name);
+       pr_info("%s: '%s:%s' successfully deinitialized and disconnected\n",
+               KBUILD_MODNAME, drvname, devname);
+       kfree(devname);
 }
 EXPORT_SYMBOL(dvb_usbv2_disconnect);
 
index 0636eac37bbbf8aa0af02cef377c1f54373ae5a2..5730760e4e93b67ac54a0d2551154be17064bd80 100644 (file)
  *    but WITHOUT 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 "dvb_usb.h"
index 0c2b377704ff18daba836e2af3151a7765982092..1db8aeef36553d67d63ca04fd6013fce883e9471 100644 (file)
  *    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 "ec168.h"
index 615a6569421f55298a07b4770711f0ef9e895113..704955bcaa102b946ea865c0baea9d00c3005388 100644 (file)
  *    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 EC168_H
index 5fea02672685b41cf46f0eb31c67b7fc763c0fde..924adfdb660da3b7dcdc339a06cd8ec921d2bf8d 100644 (file)
  * 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.
- *
  *
  * see Documentation/dvb/README.dvb-usb for more information
  *
@@ -99,9 +95,7 @@ static int dvb_usb_lme2510_debug;
 } while (0)
 #define deb_info(level, args...) lme_debug(dvb_usb_lme2510_debug, level, args)
 #define debug_data_snipet(level, name, p) \
-        deb_info(level, name" (%02x%02x%02x%02x%02x%02x%02x%02x)", \
-               *p, *(p+1), *(p+2), *(p+3), *(p+4), \
-                       *(p+5), *(p+6), *(p+7));
+        deb_info(level, name" (%8phN)", p);
 #define info(args...) pr_info(DVB_USB_LOG_PREFIX": "args)
 
 module_param_named(debug, dvb_usb_lme2510_debug, int, 0644);
@@ -315,7 +309,7 @@ static void lme2510_int_response(struct urb *lme_urb)
 {
        struct dvb_usb_adapter *adap = lme_urb->context;
        struct lme2510_state *st = adap_to_priv(adap);
-       static u8 *ibuf, *rbuf;
+       u8 *ibuf, *rbuf;
        int i = 0, offset;
        u32 key;
        u8 signal_lock = 0;
@@ -1002,8 +996,9 @@ static int lme_name(struct dvb_usb_adapter *adap)
        struct dvb_usb_device *d = adap_to_d(adap);
        struct lme2510_state *st = adap_to_priv(adap);
        const char *desc = d->name;
-       char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395",
-                               " SHARP:BS2F7HZ0194", " RS2000"};
+       static const char * const fe_name[] = {
+               "", " LG TDQY-P001F", " SHARP:BS2F7HZ7395",
+               " SHARP:BS2F7HZ0194", " RS2000"};
        char *name = adap->fe[0]->ops.info.name;
 
        strlcpy(name, desc, 128);
@@ -1124,7 +1119,7 @@ static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap)
 {
        struct dvb_usb_device *d = adap_to_d(adap);
        struct lme2510_state *st = adap_to_priv(adap);
-       char *tun_msg[] = {"", "TDA8263", "IX2505V", "DVB_PLL_OPERA", "RS2000"};
+       static const char * const tun_msg[] = {"", "TDA8263", "IX2505V", "DVB_PLL_OPERA", "RS2000"};
        int ret = 0;
 
        switch (st->tuner_config) {
@@ -1178,10 +1173,7 @@ static int lme2510_powerup(struct dvb_usb_device *d, int onoff)
 
        mutex_lock(&d->i2c_mutex);
 
-       if (onoff)
-               ret = lme2510_usb_talk(d, lnb_on, len, rbuf, rlen);
-       else
-               ret = lme2510_usb_talk(d, lnb_off, len, rbuf, rlen);
+       ret = lme2510_usb_talk(d, onoff ? lnb_on : lnb_off, len, rbuf, rlen);
 
        st->i2c_talk_onoff = 1;
 
index 639e156e0c1b0edf7cebb8d62350e1b835021c0a..f0ed37da73d42798fe9e028d1005180022c23742 100644 (file)
  *  but WITHOUT 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 "mxl111sf-demod.h"
index e6eae9d88e9f2a36dbead11d6ee615a5ea5518bb..9cb4972ce7a3ef0dc6dc946b82827e26703dcaca 100644 (file)
  *  but WITHOUT 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 __MXL111SF_DEMOD_H__
index 2180c13a6dcc18497c92fdfc05e49f61cfb7ad94..c66861c9342bfe34200f59ee6af59e84a7a1e7cc 100644 (file)
  *  but WITHOUT 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 "mxl111sf-gpio.h"
index 16fa4d4daf88d368e85ab5aecf4e9bf7455a41f6..af2c7bc8f3014dd483d89bfac166d56b063ac171 100644 (file)
  *  but WITHOUT 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 _DVB_USB_MXL111SF_GPIO_H_
index 6427137a09ef8abf1075990c4e996e602c3079c0..ffb49c28b15a985a312e69d81989f55377f8c9f2 100644 (file)
  *  but WITHOUT 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 "mxl111sf-i2c.h"
index c486fe02f01879e467d5304eb465fa9f6054ee80..28877c7a8175ac067563524e545998db105ff42b 100644 (file)
  *  but WITHOUT 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 _DVB_USB_MXL111SF_I2C_H_
index 5b0191178f9fc6ce4d219a9aa76894b56de4830e..ffb6e7c72f57492860d7a4fdad80d3544f8db969 100644 (file)
  *  but WITHOUT 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 "mxl111sf-phy.h"
index 25aa4a1ea755c0ec767bfe4b135227bf752df6b3..0a61e8a565848891459f51847bd97946395b3d07 100644 (file)
  *  but WITHOUT 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 _DVB_USB_MXL111SF_PHY_H_
index 1f4bfbcdbabb34b4c8dc7ee05b71fa6acc44a19d..ad3f806dcc7a9ba10d07ca98fd1d7c0267350229 100644 (file)
  *  but WITHOUT 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 _DVB_USB_MXL111SF_REG_H_
index f84bef6034dcb73eee483172ba5b0d4f2da010b8..240d736bf1bb39e2e1f8430aab35c2aa2bd04a8a 100644 (file)
  *  but WITHOUT 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 "mxl111sf-tuner.h"
index e96d9a444ed1aae155a439503bf99323d0d493b4..11ea07a7327180cc508a468ce196c74f9c0690c4 100644 (file)
  *  but WITHOUT 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 __MXL111SF_TUNER_H__
index c583c638e4681878ff46d1596f40f54b456b2848..e16ca07acf1db68b337e5adae429aac976e20d6b 100644 (file)
@@ -1778,7 +1778,7 @@ static int rtl2832u_get_rc_config(struct dvb_usb_device *d,
        /* load empty to enable rc */
        if (!rc->map_name)
                rc->map_name = RC_MAP_EMPTY;
-       rc->allowed_protos = RC_BIT_ALL;
+       rc->allowed_protos = RC_BIT_ALL_IR_DECODER;
        rc->driver_type = RC_DRIVER_IR_RAW;
        rc->query = rtl2832u_rc_query;
        rc->interval = 200;
diff --git a/drivers/media/usb/dvb-usb-v2/zd1301.c b/drivers/media/usb/dvb-usb-v2/zd1301.c
new file mode 100644 (file)
index 0000000..d1eb4b7
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * ZyDAS ZD1301 driver (USB interface)
+ *
+ * Copyright (C) 2015 Antti Palosaari <crope@iki.fi>
+ *
+ *    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 "dvb_usb.h"
+#include "zd1301_demod.h"
+#include "mt2060.h"
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+struct zd1301_dev {
+       #define BUF_LEN 8
+       u8 buf[BUF_LEN]; /* bulk USB control message */
+       struct zd1301_demod_platform_data demod_pdata;
+       struct mt2060_platform_data mt2060_pdata;
+       struct platform_device *platform_device_demod;
+       struct i2c_client *i2c_client_tuner;
+};
+
+static int zd1301_ctrl_msg(struct dvb_usb_device *d, const u8 *wbuf,
+                          unsigned int wlen, u8 *rbuf, unsigned int rlen)
+{
+       struct zd1301_dev *dev = d_to_priv(d);
+       struct usb_interface *intf = d->intf;
+       int ret, actual_length;
+
+       mutex_lock(&d->usb_mutex);
+
+       memcpy(&dev->buf, wbuf, wlen);
+
+       dev_dbg(&intf->dev, ">>> %*ph\n", wlen, dev->buf);
+
+       ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev, 0x04), dev->buf,
+                          wlen, &actual_length, 1000);
+       if (ret) {
+               dev_err(&intf->dev, "1st usb_bulk_msg() failed %d\n", ret);
+               goto err_mutex_unlock;
+       }
+
+       if (rlen) {
+               ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, 0x83),
+                                  dev->buf, rlen, &actual_length, 1000);
+               if (ret) {
+                       dev_err(&intf->dev,
+                               "2nd usb_bulk_msg() failed %d\n", ret);
+                       goto err_mutex_unlock;
+               }
+
+               dev_dbg(&intf->dev, "<<< %*ph\n", actual_length, dev->buf);
+
+               if (actual_length != rlen) {
+                       /*
+                        * Chip replies often with 3 byte len stub. On that case
+                        * we have to query new reply.
+                        */
+                       dev_dbg(&intf->dev, "repeating reply message\n");
+
+                       ret = usb_bulk_msg(d->udev,
+                                          usb_rcvbulkpipe(d->udev, 0x83),
+                                          dev->buf, rlen, &actual_length,
+                                          1000);
+                       if (ret) {
+                               dev_err(&intf->dev,
+                                       "3rd usb_bulk_msg() failed %d\n", ret);
+                               goto err_mutex_unlock;
+                       }
+
+                       dev_dbg(&intf->dev,
+                               "<<< %*ph\n", actual_length, dev->buf);
+               }
+
+               memcpy(rbuf, dev->buf, rlen);
+       }
+
+err_mutex_unlock:
+       mutex_unlock(&d->usb_mutex);
+       return ret;
+}
+
+static int zd1301_demod_wreg(void *reg_priv, u16 reg, u8 val)
+{
+       struct dvb_usb_device *d = reg_priv;
+       struct usb_interface *intf = d->intf;
+       int ret;
+       u8 buf[7] = {0x07, 0x00, 0x03, 0x01,
+                    (reg >> 0) & 0xff, (reg >> 8) & 0xff, val};
+
+       ret = zd1301_ctrl_msg(d, buf, 7, NULL, 0);
+       if (ret)
+               goto err;
+
+       return 0;
+err:
+       dev_dbg(&intf->dev, "failed=%d\n", ret);
+       return ret;
+}
+
+static int zd1301_demod_rreg(void *reg_priv, u16 reg, u8 *val)
+{
+       struct dvb_usb_device *d = reg_priv;
+       struct usb_interface *intf = d->intf;
+       int ret;
+       u8 buf[7] = {0x07, 0x00, 0x04, 0x01,
+                    (reg >> 0) & 0xff, (reg >> 8) & 0xff, 0};
+
+       ret = zd1301_ctrl_msg(d, buf, 7, buf, 7);
+       if (ret)
+               goto err;
+
+       *val = buf[6];
+
+       return 0;
+err:
+       dev_dbg(&intf->dev, "failed=%d\n", ret);
+       return ret;
+}
+
+static int zd1301_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       struct dvb_usb_device *d = adap_to_d(adap);
+       struct zd1301_dev *dev = adap_to_priv(adap);
+       struct usb_interface *intf = d->intf;
+       struct platform_device *pdev;
+       struct i2c_client *client;
+       struct i2c_board_info board_info;
+       struct i2c_adapter *adapter;
+       struct dvb_frontend *frontend;
+       int ret;
+
+       dev_dbg(&intf->dev, "\n");
+
+       /* Add platform demod */
+       dev->demod_pdata.reg_priv = d;
+       dev->demod_pdata.reg_read = zd1301_demod_rreg;
+       dev->demod_pdata.reg_write = zd1301_demod_wreg;
+       request_module("%s", "zd1301_demod");
+       pdev = platform_device_register_data(&intf->dev,
+                                            "zd1301_demod",
+                                            PLATFORM_DEVID_AUTO,
+                                            &dev->demod_pdata,
+                                            sizeof(dev->demod_pdata));
+       if (IS_ERR(pdev)) {
+               ret = PTR_ERR(pdev);
+               goto err;
+       }
+       if (!pdev->dev.driver) {
+               ret = -ENODEV;
+               goto err;
+       }
+       if (!try_module_get(pdev->dev.driver->owner)) {
+               ret = -ENODEV;
+               goto err_platform_device_unregister;
+       }
+
+       adapter = zd1301_demod_get_i2c_adapter(pdev);
+       frontend = zd1301_demod_get_dvb_frontend(pdev);
+       if (!adapter || !frontend) {
+               ret = -ENODEV;
+               goto err_module_put_demod;
+       }
+
+       /* Add I2C tuner */
+       dev->mt2060_pdata.i2c_write_max = 9;
+       dev->mt2060_pdata.dvb_frontend = frontend;
+       memset(&board_info, 0, sizeof(board_info));
+       strlcpy(board_info.type, "mt2060", I2C_NAME_SIZE);
+       board_info.addr = 0x60;
+       board_info.platform_data = &dev->mt2060_pdata;
+       request_module("%s", "mt2060");
+       client = i2c_new_device(adapter, &board_info);
+       if (!client || !client->dev.driver) {
+               ret = -ENODEV;
+               goto err_module_put_demod;
+       }
+       if (!try_module_get(client->dev.driver->owner)) {
+               ret = -ENODEV;
+               goto err_i2c_unregister_device;
+       }
+
+       dev->platform_device_demod = pdev;
+       dev->i2c_client_tuner = client;
+       adap->fe[0] = frontend;
+
+       return 0;
+err_i2c_unregister_device:
+       i2c_unregister_device(client);
+err_module_put_demod:
+       module_put(pdev->dev.driver->owner);
+err_platform_device_unregister:
+       platform_device_unregister(pdev);
+err:
+       dev_dbg(&intf->dev, "failed=%d\n", ret);
+       return ret;
+}
+
+static int zd1301_frontend_detach(struct dvb_usb_adapter *adap)
+{
+       struct dvb_usb_device *d = adap_to_d(adap);
+       struct zd1301_dev *dev = d_to_priv(d);
+       struct usb_interface *intf = d->intf;
+       struct platform_device *pdev;
+       struct i2c_client *client;
+
+       dev_dbg(&intf->dev, "\n");
+
+       client = dev->i2c_client_tuner;
+       pdev = dev->platform_device_demod;
+
+       /* Remove I2C tuner */
+       if (client) {
+               module_put(client->dev.driver->owner);
+               i2c_unregister_device(client);
+       }
+
+       /* Remove platform demod */
+       if (pdev) {
+               module_put(pdev->dev.driver->owner);
+               platform_device_unregister(pdev);
+       }
+
+       return 0;
+}
+
+static int zd1301_streaming_ctrl(struct dvb_frontend *fe, int onoff)
+{
+       struct dvb_usb_device *d = fe_to_d(fe);
+       struct usb_interface *intf = d->intf;
+       int ret;
+       u8 buf[3] = {0x03, 0x00, onoff ? 0x07 : 0x08};
+
+       dev_dbg(&intf->dev, "onoff=%d\n", onoff);
+
+       ret = zd1301_ctrl_msg(d, buf, 3, NULL, 0);
+       if (ret)
+               goto err;
+
+       return 0;
+err:
+       dev_dbg(&intf->dev, "failed=%d\n", ret);
+       return ret;
+}
+
+static const struct dvb_usb_device_properties zd1301_props = {
+       .driver_name = KBUILD_MODNAME,
+       .owner = THIS_MODULE,
+       .adapter_nr = adapter_nr,
+       .size_of_priv = sizeof(struct zd1301_dev),
+
+       .frontend_attach = zd1301_frontend_attach,
+       .frontend_detach = zd1301_frontend_detach,
+       .streaming_ctrl  = zd1301_streaming_ctrl,
+
+       .num_adapters = 1,
+       .adapter = {
+               {
+                       .stream = DVB_USB_STREAM_BULK(0x81, 6, 21 * 188),
+               },
+       },
+};
+
+static const struct usb_device_id zd1301_id_table[] = {
+       {DVB_USB_DEVICE(USB_VID_ZYDAS, 0x13a1, &zd1301_props,
+                       "ZyDAS ZD1301 reference design", NULL)},
+       {}
+};
+MODULE_DEVICE_TABLE(usb, zd1301_id_table);
+
+/* Usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver zd1301_usb_driver = {
+       .name = KBUILD_MODNAME,
+       .id_table = zd1301_id_table,
+       .probe = dvb_usbv2_probe,
+       .disconnect = dvb_usbv2_disconnect,
+       .suspend = dvb_usbv2_suspend,
+       .resume = dvb_usbv2_resume,
+       .reset_resume = dvb_usbv2_reset_resume,
+       .no_dynamic_id = 1,
+       .soft_unbind = 1,
+};
+module_usb_driver(zd1301_usb_driver);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("ZyDAS ZD1301 driver");
+MODULE_LICENSE("GPL");
index 9862d3e6b8e8ff44896f18addaf0cfcb916fa65e..544bdf18fb2fe4d4d41dfa67f5e9eeac5b7cc1a1 100644 (file)
  * 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.
- *
  * see Documentation/dvb/README.dvb-usb for more information
  */
 #include "af9005.h"
index 7e3961d0db6b8c64018596ece3896b77bbaeffe0..9b29ffa9307502431c9c4ce79bb3d759ee1e18bc 100644 (file)
  * 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.
- *
  * see Documentation/dvb/README.dvb-usb for more information
  */
 #include "af9005.h"
index f5f476841aea0ca5103a69b7d979674ef37d03cd..986763b1b2b32a2688a2f9a75db4392bf2bc2d5e 100644 (file)
  * 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.
- *
  * see Documentation/dvb/README.dvb-usb for more information
  */
 #include "af9005.h"
index 6a2bf3de845668c162cf679fdab5eaaf775005c0..a1eae0fa02edda2e70304bf8016a97632e86a65a 100644 (file)
  * 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.
- *
  * see Documentation/dvb/README.dvb-usb for more information
  */
 #ifndef _DVB_USB_AF9005_H_
index 6404205560eb4d190844688c3111cc19721fd79e..6131aa7914a9a1333be69eb367447b0c411ebdeb 100644 (file)
  * 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 "cinergyT2.h"
index bbb10fab65bceb82c22bbb5369f40dd72181a229..f9772ad0a2a5c114ebbae1c70f381b84f6525ea5 100644 (file)
  * 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 "cinergyT2.h"
index 84efe03771eb1da8278cf613fd051f2b58f17b35..c04b819be160d0f762f0d4dfaf5871416a721cc6 100644 (file)
  * 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 _DVB_USB_CINERGYT2_H_
index 9b8771eb31d44d87515d82ca7f69fbd04b6efec3..51620e02292f588b6643862c3207aa6d5cd75948 100644 (file)
@@ -59,23 +59,24 @@ static int cxusb_ctrl_msg(struct dvb_usb_device *d,
                          u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
 {
        struct cxusb_state *st = d->priv;
-       int ret, wo;
+       int ret;
 
        if (1 + wlen > MAX_XFER_SIZE) {
                warn("i2c wr: len=%d is too big!\n", wlen);
                return -EOPNOTSUPP;
        }
 
-       wo = (rbuf == NULL || rlen == 0); /* write-only */
+       if (rlen > MAX_XFER_SIZE) {
+               warn("i2c rd: len=%d is too big!\n", rlen);
+               return -EOPNOTSUPP;
+       }
 
        mutex_lock(&d->data_mutex);
        st->data[0] = cmd;
        memcpy(&st->data[1], wbuf, wlen);
-       if (wo)
-               ret = dvb_usb_generic_write(d, st->data, 1 + wlen);
-       else
-               ret = dvb_usb_generic_rw(d, st->data, 1 + wlen,
-                                        rbuf, rlen, 0);
+       ret = dvb_usb_generic_rw(d, st->data, 1 + wlen, st->data, rlen, 0);
+       if (!ret && rbuf && rlen)
+               memcpy(rbuf, st->data, rlen);
 
        mutex_unlock(&d->data_mutex);
        return ret;
@@ -450,209 +451,46 @@ static int cxusb_d680_dmb_streaming_ctrl(
        }
 }
 
-static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+static int cxusb_rc_query(struct dvb_usb_device *d)
 {
-       struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
        u8 ircode[4];
-       int i;
 
        cxusb_ctrl_msg(d, CMD_GET_IR_CODE, NULL, 0, ircode, 4);
 
-       *event = 0;
-       *state = REMOTE_NO_KEY_PRESSED;
-
-       for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {
-               if (rc5_custom(&keymap[i]) == ircode[2] &&
-                   rc5_data(&keymap[i]) == ircode[3]) {
-                       *event = keymap[i].keycode;
-                       *state = REMOTE_KEY_PRESSED;
-
-                       return 0;
-               }
-       }
-
+       if (ircode[2] || ircode[3])
+               rc_keydown(d->rc_dev, RC_TYPE_UNKNOWN,
+                          RC_SCANCODE_RC5(ircode[2], ircode[3]), 0);
        return 0;
 }
 
-static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event,
-                                   int *state)
+static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d)
 {
-       struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
        u8 ircode[4];
-       int i;
        struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD,
                               .buf = ircode, .len = 4 };
 
-       *event = 0;
-       *state = REMOTE_NO_KEY_PRESSED;
-
        if (cxusb_i2c_xfer(&d->i2c_adap, &msg, 1) != 1)
                return 0;
 
-       for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {
-               if (rc5_custom(&keymap[i]) == ircode[1] &&
-                   rc5_data(&keymap[i]) == ircode[2]) {
-                       *event = keymap[i].keycode;
-                       *state = REMOTE_KEY_PRESSED;
-
-                       return 0;
-               }
-       }
-
+       if (ircode[1] || ircode[2])
+               rc_keydown(d->rc_dev, RC_TYPE_UNKNOWN,
+                          RC_SCANCODE_RC5(ircode[1], ircode[2]), 0);
        return 0;
 }
 
-static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event,
-               int *state)
+static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d)
 {
-       struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
        u8 ircode[2];
-       int i;
-
-       *event = 0;
-       *state = REMOTE_NO_KEY_PRESSED;
 
        if (cxusb_ctrl_msg(d, 0x10, NULL, 0, ircode, 2) < 0)
                return 0;
 
-       for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {
-               if (rc5_custom(&keymap[i]) == ircode[0] &&
-                   rc5_data(&keymap[i]) == ircode[1]) {
-                       *event = keymap[i].keycode;
-                       *state = REMOTE_KEY_PRESSED;
-
-                       return 0;
-               }
-       }
-
+       if (ircode[0] || ircode[1])
+               rc_keydown(d->rc_dev, RC_TYPE_UNKNOWN,
+                          RC_SCANCODE_RC5(ircode[0], ircode[1]), 0);
        return 0;
 }
 
-static struct rc_map_table rc_map_dvico_mce_table[] = {
-       { 0xfe02, KEY_TV },
-       { 0xfe0e, KEY_MP3 },
-       { 0xfe1a, KEY_DVD },
-       { 0xfe1e, KEY_FAVORITES },
-       { 0xfe16, KEY_SETUP },
-       { 0xfe46, KEY_POWER2 },
-       { 0xfe0a, KEY_EPG },
-       { 0xfe49, KEY_BACK },
-       { 0xfe4d, KEY_MENU },
-       { 0xfe51, KEY_UP },
-       { 0xfe5b, KEY_LEFT },
-       { 0xfe5f, KEY_RIGHT },
-       { 0xfe53, KEY_DOWN },
-       { 0xfe5e, KEY_OK },
-       { 0xfe59, KEY_INFO },
-       { 0xfe55, KEY_TAB },
-       { 0xfe0f, KEY_PREVIOUSSONG },/* Replay */
-       { 0xfe12, KEY_NEXTSONG },       /* Skip */
-       { 0xfe42, KEY_ENTER      },     /* Windows/Start */
-       { 0xfe15, KEY_VOLUMEUP },
-       { 0xfe05, KEY_VOLUMEDOWN },
-       { 0xfe11, KEY_CHANNELUP },
-       { 0xfe09, KEY_CHANNELDOWN },
-       { 0xfe52, KEY_CAMERA },
-       { 0xfe5a, KEY_TUNER },  /* Live */
-       { 0xfe19, KEY_OPEN },
-       { 0xfe0b, KEY_1 },
-       { 0xfe17, KEY_2 },
-       { 0xfe1b, KEY_3 },
-       { 0xfe07, KEY_4 },
-       { 0xfe50, KEY_5 },
-       { 0xfe54, KEY_6 },
-       { 0xfe48, KEY_7 },
-       { 0xfe4c, KEY_8 },
-       { 0xfe58, KEY_9 },
-       { 0xfe13, KEY_ANGLE },  /* Aspect */
-       { 0xfe03, KEY_0 },
-       { 0xfe1f, KEY_ZOOM },
-       { 0xfe43, KEY_REWIND },
-       { 0xfe47, KEY_PLAYPAUSE },
-       { 0xfe4f, KEY_FASTFORWARD },
-       { 0xfe57, KEY_MUTE },
-       { 0xfe0d, KEY_STOP },
-       { 0xfe01, KEY_RECORD },
-       { 0xfe4e, KEY_POWER },
-};
-
-static struct rc_map_table rc_map_dvico_portable_table[] = {
-       { 0xfc02, KEY_SETUP },       /* Profile */
-       { 0xfc43, KEY_POWER2 },
-       { 0xfc06, KEY_EPG },
-       { 0xfc5a, KEY_BACK },
-       { 0xfc05, KEY_MENU },
-       { 0xfc47, KEY_INFO },
-       { 0xfc01, KEY_TAB },
-       { 0xfc42, KEY_PREVIOUSSONG },/* Replay */
-       { 0xfc49, KEY_VOLUMEUP },
-       { 0xfc09, KEY_VOLUMEDOWN },
-       { 0xfc54, KEY_CHANNELUP },
-       { 0xfc0b, KEY_CHANNELDOWN },
-       { 0xfc16, KEY_CAMERA },
-       { 0xfc40, KEY_TUNER },  /* ATV/DTV */
-       { 0xfc45, KEY_OPEN },
-       { 0xfc19, KEY_1 },
-       { 0xfc18, KEY_2 },
-       { 0xfc1b, KEY_3 },
-       { 0xfc1a, KEY_4 },
-       { 0xfc58, KEY_5 },
-       { 0xfc59, KEY_6 },
-       { 0xfc15, KEY_7 },
-       { 0xfc14, KEY_8 },
-       { 0xfc17, KEY_9 },
-       { 0xfc44, KEY_ANGLE },  /* Aspect */
-       { 0xfc55, KEY_0 },
-       { 0xfc07, KEY_ZOOM },
-       { 0xfc0a, KEY_REWIND },
-       { 0xfc08, KEY_PLAYPAUSE },
-       { 0xfc4b, KEY_FASTFORWARD },
-       { 0xfc5b, KEY_MUTE },
-       { 0xfc04, KEY_STOP },
-       { 0xfc56, KEY_RECORD },
-       { 0xfc57, KEY_POWER },
-       { 0xfc41, KEY_UNKNOWN },    /* INPUT */
-       { 0xfc00, KEY_UNKNOWN },    /* HD */
-};
-
-static struct rc_map_table rc_map_d680_dmb_table[] = {
-       { 0x0038, KEY_UNKNOWN },        /* TV/AV */
-       { 0x080c, KEY_ZOOM },
-       { 0x0800, KEY_0 },
-       { 0x0001, KEY_1 },
-       { 0x0802, KEY_2 },
-       { 0x0003, KEY_3 },
-       { 0x0804, KEY_4 },
-       { 0x0005, KEY_5 },
-       { 0x0806, KEY_6 },
-       { 0x0007, KEY_7 },
-       { 0x0808, KEY_8 },
-       { 0x0009, KEY_9 },
-       { 0x000a, KEY_MUTE },
-       { 0x0829, KEY_BACK },
-       { 0x0012, KEY_CHANNELUP },
-       { 0x0813, KEY_CHANNELDOWN },
-       { 0x002b, KEY_VOLUMEUP },
-       { 0x082c, KEY_VOLUMEDOWN },
-       { 0x0020, KEY_UP },
-       { 0x0821, KEY_DOWN },
-       { 0x0011, KEY_LEFT },
-       { 0x0810, KEY_RIGHT },
-       { 0x000d, KEY_OK },
-       { 0x081f, KEY_RECORD },
-       { 0x0017, KEY_PLAYPAUSE },
-       { 0x0816, KEY_PLAYPAUSE },
-       { 0x000b, KEY_STOP },
-       { 0x0827, KEY_FASTFORWARD },
-       { 0x0026, KEY_REWIND },
-       { 0x081e, KEY_UNKNOWN },    /* Time Shift */
-       { 0x000e, KEY_UNKNOWN },    /* Snapshot */
-       { 0x082d, KEY_UNKNOWN },    /* Mouse Cursor */
-       { 0x000f, KEY_UNKNOWN },    /* Minimize/Maximize */
-       { 0x0814, KEY_UNKNOWN },    /* Shuffle */
-       { 0x0025, KEY_POWER },
-};
-
 static int cxusb_dee1601_demod_init(struct dvb_frontend* fe)
 {
        static u8 clock_config []  = { CLOCK_CTL,  0x38, 0x28 };
@@ -1000,7 +838,7 @@ static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap)
                return -EIO;
 
        /* try to determine if there is no IR decoder on the I2C bus */
-       for (i = 0; adap->dev->props.rc.legacy.rc_map_table != NULL && i < 5; i++) {
+       for (i = 0; adap->dev->props.rc.core.rc_codes && i < 5; i++) {
                msleep(20);
                if (cxusb_i2c_xfer(&adap->dev->i2c_adap, &msg, 1) != 1)
                        goto no_IR;
@@ -1008,7 +846,7 @@ static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap)
                        continue;
                if (ircode[2] + ircode[3] != 0xff) {
 no_IR:
-                       adap->dev->props.rc.legacy.rc_map_table = NULL;
+                       adap->dev->props.rc.core.rc_codes = NULL;
                        info("No IR receiver detected on this device.");
                        break;
                }
@@ -1720,11 +1558,12 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = {
 
        .i2c_algo         = &cxusb_i2c_algo,
 
-       .rc.legacy = {
-               .rc_interval      = 100,
-               .rc_map_table     = rc_map_dvico_portable_table,
-               .rc_map_size      = ARRAY_SIZE(rc_map_dvico_portable_table),
-               .rc_query         = cxusb_rc_query,
+       .rc.core = {
+               .rc_interval    = 100,
+               .rc_codes       = RC_MAP_DVICO_PORTABLE,
+               .module_name    = KBUILD_MODNAME,
+               .rc_query       = cxusb_rc_query,
+               .allowed_protos = RC_BIT_UNKNOWN,
        },
 
        .generic_bulk_ctrl_endpoint = 0x01,
@@ -1776,11 +1615,12 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = {
 
        .i2c_algo         = &cxusb_i2c_algo,
 
-       .rc.legacy = {
-               .rc_interval      = 150,
-               .rc_map_table     = rc_map_dvico_mce_table,
-               .rc_map_size      = ARRAY_SIZE(rc_map_dvico_mce_table),
-               .rc_query         = cxusb_rc_query,
+       .rc.core = {
+               .rc_interval    = 100,
+               .rc_codes       = RC_MAP_DVICO_MCE,
+               .module_name    = KBUILD_MODNAME,
+               .rc_query       = cxusb_rc_query,
+               .allowed_protos = RC_BIT_UNKNOWN,
        },
 
        .generic_bulk_ctrl_endpoint = 0x01,
@@ -1840,11 +1680,12 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = {
 
        .i2c_algo         = &cxusb_i2c_algo,
 
-       .rc.legacy = {
-               .rc_interval      = 100,
-               .rc_map_table     = rc_map_dvico_portable_table,
-               .rc_map_size      = ARRAY_SIZE(rc_map_dvico_portable_table),
-               .rc_query         = cxusb_rc_query,
+       .rc.core = {
+               .rc_interval    = 100,
+               .rc_codes       = RC_MAP_DVICO_PORTABLE,
+               .module_name    = KBUILD_MODNAME,
+               .rc_query       = cxusb_rc_query,
+               .allowed_protos = RC_BIT_UNKNOWN,
        },
 
        .generic_bulk_ctrl_endpoint = 0x01,
@@ -1895,11 +1736,12 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = {
 
        .i2c_algo         = &cxusb_i2c_algo,
 
-       .rc.legacy = {
-               .rc_interval      = 100,
-               .rc_map_table     = rc_map_dvico_portable_table,
-               .rc_map_size      = ARRAY_SIZE(rc_map_dvico_portable_table),
-               .rc_query         = cxusb_rc_query,
+       .rc.core = {
+               .rc_interval    = 100,
+               .rc_codes       = RC_MAP_DVICO_PORTABLE,
+               .module_name    = KBUILD_MODNAME,
+               .rc_query       = cxusb_rc_query,
+               .allowed_protos = RC_BIT_UNKNOWN,
        },
 
        .generic_bulk_ctrl_endpoint = 0x01,
@@ -1949,11 +1791,12 @@ static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = {
 
        .generic_bulk_ctrl_endpoint = 0x01,
 
-       .rc.legacy = {
-               .rc_interval      = 100,
-               .rc_map_table     = rc_map_dvico_mce_table,
-               .rc_map_size      = ARRAY_SIZE(rc_map_dvico_mce_table),
-               .rc_query         = cxusb_bluebird2_rc_query,
+       .rc.core = {
+               .rc_interval    = 100,
+               .rc_codes       = RC_MAP_DVICO_MCE,
+               .module_name    = KBUILD_MODNAME,
+               .rc_query       = cxusb_bluebird2_rc_query,
+               .allowed_protos = RC_BIT_UNKNOWN,
        },
 
        .num_device_descs = 1,
@@ -2002,11 +1845,12 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = {
 
        .generic_bulk_ctrl_endpoint = 0x01,
 
-       .rc.legacy = {
-               .rc_interval      = 100,
-               .rc_map_table     = rc_map_dvico_portable_table,
-               .rc_map_size      = ARRAY_SIZE(rc_map_dvico_portable_table),
-               .rc_query         = cxusb_bluebird2_rc_query,
+       .rc.core = {
+               .rc_interval    = 100,
+               .rc_codes       = RC_MAP_DVICO_PORTABLE,
+               .module_name    = KBUILD_MODNAME,
+               .rc_query       = cxusb_bluebird2_rc_query,
+               .allowed_protos = RC_BIT_UNKNOWN,
        },
 
        .num_device_descs = 1,
@@ -2057,11 +1901,12 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_prope
 
        .generic_bulk_ctrl_endpoint = 0x01,
 
-       .rc.legacy = {
-               .rc_interval      = 100,
-               .rc_map_table     = rc_map_dvico_portable_table,
-               .rc_map_size      = ARRAY_SIZE(rc_map_dvico_portable_table),
-               .rc_query         = cxusb_rc_query,
+       .rc.core = {
+               .rc_interval    = 100,
+               .rc_codes       = RC_MAP_DVICO_PORTABLE,
+               .module_name    = KBUILD_MODNAME,
+               .rc_query       = cxusb_rc_query,
+               .allowed_protos = RC_BIT_UNKNOWN,
        },
 
        .num_device_descs = 1,
@@ -2155,11 +2000,12 @@ struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = {
 
        .generic_bulk_ctrl_endpoint = 0x01,
 
-       .rc.legacy = {
-               .rc_interval      = 100,
-               .rc_map_table     = rc_map_dvico_mce_table,
-               .rc_map_size      = ARRAY_SIZE(rc_map_dvico_mce_table),
-               .rc_query         = cxusb_rc_query,
+       .rc.core = {
+               .rc_interval    = 100,
+               .rc_codes       = RC_MAP_DVICO_MCE,
+               .module_name    = KBUILD_MODNAME,
+               .rc_query       = cxusb_rc_query,
+               .allowed_protos = RC_BIT_UNKNOWN,
        },
 
        .num_device_descs = 1,
@@ -2208,11 +2054,12 @@ static struct dvb_usb_device_properties cxusb_d680_dmb_properties = {
 
        .generic_bulk_ctrl_endpoint = 0x01,
 
-       .rc.legacy = {
-               .rc_interval      = 100,
-               .rc_map_table     = rc_map_d680_dmb_table,
-               .rc_map_size      = ARRAY_SIZE(rc_map_d680_dmb_table),
-               .rc_query         = cxusb_d680_dmb_rc_query,
+       .rc.core = {
+               .rc_interval    = 100,
+               .rc_codes       = RC_MAP_D680_DMB,
+               .module_name    = KBUILD_MODNAME,
+               .rc_query       = cxusb_d680_dmb_rc_query,
+               .allowed_protos = RC_BIT_UNKNOWN,
        },
 
        .num_device_descs = 1,
@@ -2262,11 +2109,12 @@ static struct dvb_usb_device_properties cxusb_mygica_d689_properties = {
 
        .generic_bulk_ctrl_endpoint = 0x01,
 
-       .rc.legacy = {
-               .rc_interval      = 100,
-               .rc_map_table     = rc_map_d680_dmb_table,
-               .rc_map_size      = ARRAY_SIZE(rc_map_d680_dmb_table),
-               .rc_query         = cxusb_d680_dmb_rc_query,
+       .rc.core = {
+               .rc_interval    = 100,
+               .rc_codes       = RC_MAP_D680_DMB,
+               .module_name    = KBUILD_MODNAME,
+               .rc_query       = cxusb_d680_dmb_rc_query,
+               .allowed_protos = RC_BIT_UNKNOWN,
        },
 
        .num_device_descs = 1,
@@ -2315,11 +2163,12 @@ static struct dvb_usb_device_properties cxusb_mygica_t230_properties = {
 
        .generic_bulk_ctrl_endpoint = 0x01,
 
-       .rc.legacy = {
-               .rc_interval      = 100,
-               .rc_map_table     = rc_map_d680_dmb_table,
-               .rc_map_size      = ARRAY_SIZE(rc_map_d680_dmb_table),
-               .rc_query         = cxusb_d680_dmb_rc_query,
+       .rc.core = {
+               .rc_interval    = 100,
+               .rc_codes       = RC_MAP_D680_DMB,
+               .module_name    = KBUILD_MODNAME,
+               .rc_query       = cxusb_d680_dmb_rc_query,
+               .allowed_protos = RC_BIT_UNKNOWN,
        },
 
        .num_device_descs = 1,
index b29d4894c2f1ca914088880785e0157c2cdfcff5..81d7fd4f7776ef629ad0ea93d619ce9bc0c4c653 100644 (file)
@@ -3815,6 +3815,7 @@ struct usb_device_id dib0700_usb_id_table[] = {
        { USB_DEVICE(USB_VID_PCTV,      USB_PID_PCTV_2002E_SE) },
        { USB_DEVICE(USB_VID_PCTV,      USB_PID_DIBCOM_STK8096PVR) },
        { USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK8096PVR) },
+       { USB_DEVICE(USB_VID_HAMA,      USB_PID_HAMA_DVBT_HYBRID) },
        { 0 }           /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -4379,7 +4380,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        },
                },
 
-               .num_device_descs = 9,
+               .num_device_descs = 10,
                .devices = {
                        {   "Terratec Cinergy HT USB XE",
                                { &dib0700_usb_id_table[27], NULL },
@@ -4417,6 +4418,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                { &dib0700_usb_id_table[54], NULL },
                                { NULL },
                        },
+                       {   "Hama DVB=T Hybrid USB Stick",
+                               { &dib0700_usb_id_table[85], NULL },
+                               { NULL },
+                       },
                },
 
                .rc.core = {
index c60fb54f445f582357ca949b3e4f6775e0822e12..2fa2abd3e726317b848974cae66f941257db430c 100644 (file)
  * but WITHOUT 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
  */
 
 #include "dtv5100.h"
index 93e96e04a82a10714b641bd94053d8ad49546c49..1ab1eafd31879551ba25eb74f2088595b92d992e 100644 (file)
  * but WITHOUT 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 _DVB_USB_DTV5100_H_
index f0023dbb72761641112ac7b0bfcba51cf154eda2..ab9866024ec7983d597efd157476820222ad8134 100644 (file)
@@ -35,28 +35,33 @@ static int usb_cypress_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 le
 
 int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type)
 {
-       struct hexline hx;
+       struct hexline *hx;
        u8 reset;
        int ret,pos=0;
 
+       hx = kmalloc(sizeof(*hx), GFP_KERNEL);
+       if (!hx)
+               return -ENOMEM;
+
        /* stop the CPU */
        reset = 1;
        if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1)
                err("could not stop the USB controller CPU.");
 
-       while ((ret = dvb_usb_get_hexline(fw,&hx,&pos)) > 0) {
-               deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n",hx.addr,hx.len,hx.chk);
-               ret = usb_cypress_writemem(udev,hx.addr,hx.data,hx.len);
+       while ((ret = dvb_usb_get_hexline(fw, hx, &pos)) > 0) {
+               deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n", hx->addr, hx->len, hx->chk);
+               ret = usb_cypress_writemem(udev, hx->addr, hx->data, hx->len);
 
-               if (ret != hx.len) {
+               if (ret != hx->len) {
                        err("error while transferring firmware (transferred size: %d, block size: %d)",
-                               ret,hx.len);
+                               ret, hx->len);
                        ret = -EINVAL;
                        break;
                }
        }
        if (ret < 0) {
                err("firmware download failed at %d with %d",pos,ret);
+               kfree(hx);
                return ret;
        }
 
@@ -70,6 +75,8 @@ int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw
        } else
                ret = -EIO;
 
+       kfree(hx);
+
        return ret;
 }
 EXPORT_SYMBOL(usb_cypress_load_firmware);
index c259f9e43542970d87a32ca2e79806d87d193a8e..059ded59208e8af0275b064efd5c5659130ae228 100644 (file)
@@ -265,7 +265,7 @@ static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d)
        int err, rc_interval;
        struct rc_dev *dev;
 
-       dev = rc_allocate_device();
+       dev = rc_allocate_device(d->props.rc.core.driver_type);
        if (!dev)
                return -ENOMEM;
 
@@ -273,7 +273,6 @@ static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d)
        dev->map_name = d->props.rc.core.rc_codes;
        dev->change_protocol = d->props.rc.core.change_protocol;
        dev->allowed_protocols = d->props.rc.core.allowed_protos;
-       dev->driver_type = d->props.rc.core.driver_type;
        usb_to_input_id(d->udev, &dev->input_id);
        dev->input_name = "IR-receiver inside an USB DVB receiver";
        dev->input_phys = d->rc_phys;
index 2360e7e32b06db333e6c9de0b617191369c64716..37f062225ed213a00f54ed6dc551971a41c8f5c5 100644 (file)
@@ -161,7 +161,7 @@ static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d)
                        goto out_free;
                }
                if (buflen > 64) {
-                       err("firmare chunk size bigger than 64 bytes.");
+                       err("firmware chunk size bigger than 64 bytes.");
                        goto out_free;
                }
 
@@ -278,7 +278,7 @@ static int gp8psk_fe_reload(void *priv)
        return gp8psk_bcm4500_reload(d);
 }
 
-const struct gp8psk_fe_ops gp8psk_fe_ops = {
+static const struct gp8psk_fe_ops gp8psk_fe_ops = {
        .in = gp8psk_fe_in,
        .out = gp8psk_fe_out,
        .reload = gp8psk_fe_reload,
index 02c3bee6f83bdd789af978578254cc85cfe7c62d..9f7dd1afcb15714db883074824d1fe484556b982 100644 (file)
  * License, or (at your option) any later version.
  *
  *
- * 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 PROGRAM IS PROVIDED "AS IS" AND BOTH THE COPYRIGHT HOLDER AND
  * TECHNISAT DIGITAL UK LTD DISCLAIM ALL WARRANTIES WITH REGARD TO
  * THIS PROGRAM INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY OR
@@ -753,7 +749,7 @@ static struct dvb_usb_device_properties technisat_usb2_devices = {
                .rc_codes    = RC_MAP_TECHNISAT_USB2,
                .module_name = "technisat-usb2",
                .rc_query    = technisat_usb2_rc_query,
-               .allowed_protos = RC_BIT_ALL,
+               .allowed_protos = RC_BIT_ALL_IR_DECODER,
                .driver_type    = RC_DRIVER_IR_RAW,
        }
 };
index 7969ddb9e2dd2858909734bf39ed03a07aa66811..ffad7f1af1667cd7ef4a4c95c8239cfd18795e9f 100644 (file)
  *  but WITHOUT 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 "em28xx.h"
index 23c67494762d4d32643bf78446607b3bc24da9b3..5f90d0899a45f5ed8af5b62c5d3e863fcd4ab191 100644 (file)
@@ -509,6 +509,7 @@ static struct em28xx_reg_seq plex_px_bcud[] = {
 
 /*
  * 2040:0265 Hauppauge WinTV-dualHD DVB
+ * 2040:026d Hauppauge WinTV-dualHD ATSC/QAM
  * reg 0x80/0x84:
  * GPIO_0: Yellow LED tuner 1, 0=on, 1=off
  * GPIO_1: Green LED tuner 1, 0=on, 1=off
@@ -2389,6 +2390,21 @@ struct em28xx_board em28xx_boards[] = {
                .ir_codes      = RC_MAP_HAUPPAUGE,
                .leds          = hauppauge_dualhd_leds,
        },
+       /*
+        * 2040:026d Hauppauge WinTV-dualHD (model 01595 - ATSC/QAM).
+        * Empia EM28274, 2x LG LGDT3306A, 2x Silicon Labs Si2157
+        */
+       [EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595] = {
+               .name          = "Hauppauge WinTV-dualHD 01595 ATSC/QAM",
+               .def_i2c_bus   = 1,
+               .i2c_speed     = EM28XX_I2C_CLK_WAIT_ENABLE |
+                                EM28XX_I2C_FREQ_400_KHZ,
+               .tuner_type    = TUNER_ABSENT,
+               .tuner_gpio    = hauppauge_dualhd_dvb,
+               .has_dvb       = 1,
+               .ir_codes      = RC_MAP_HAUPPAUGE,
+               .leds          = hauppauge_dualhd_leds,
+       },
 };
 EXPORT_SYMBOL_GPL(em28xx_boards);
 
@@ -2514,6 +2530,8 @@ 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, 0x026d),
+                       .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),
@@ -2945,6 +2963,7 @@ static void em28xx_card_setup(struct em28xx *dev)
        case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
        case EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C:
        case EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB:
+       case EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595:
        {
                struct tveeprom tv;
 
index 75a75dab2e8ebddef2e8de22f09fa52a76c44418..82edd37f0d733ddc263b5be4883ac314c133eaa3 100644 (file)
@@ -37,6 +37,7 @@
 
 #include "lgdt330x.h"
 #include "lgdt3305.h"
+#include "lgdt3306a.h"
 #include "zl10353.h"
 #include "s5h1409.h"
 #include "mt2060.h"
@@ -920,6 +921,17 @@ static struct tda18271_config pinnacle_80e_dvb_config = {
        .role    = TDA18271_MASTER,
 };
 
+static struct lgdt3306a_config hauppauge_01595_lgdt3306a_config = {
+       .qam_if_khz         = 4000,
+       .vsb_if_khz         = 3250,
+       .spectral_inversion = 0,
+       .deny_i2c_rptr      = 0,
+       .mpeg_mode          = LGDT3306A_MPEG_SERIAL,
+       .tpclk_edge         = LGDT3306A_TPCLK_RISING_EDGE,
+       .tpvalid_polarity   = LGDT3306A_TP_VALID_HIGH,
+       .xtalMHz            = 25,
+};
+
 /* ------------------------------------------------------------------ */
 
 static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev)
@@ -1950,6 +1962,68 @@ static int em28xx_dvb_init(struct em28xx *dev)
 
                }
                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;
+               }
+               break;
        default:
                dev_err(&dev->intf->dev,
                        "The frontend of your DVB/ATSC card isn't supported yet\n");
index 782ce095c8c511a2c99805fe042cef1b2f911697..eba75736e65406a39c547df442ebbb5835836cf6 100644 (file)
@@ -259,18 +259,21 @@ static int em2874_polling_getkey(struct em28xx_IR *ir,
                break;
 
        case RC_BIT_NEC:
-               poll_result->protocol = RC_TYPE_RC5;
                poll_result->scancode = msg[1] << 8 | msg[2];
-               if ((msg[3] ^ msg[4]) != 0xff)          /* 32 bits NEC */
+               if ((msg[3] ^ msg[4]) != 0xff) {        /* 32 bits NEC */
+                       poll_result->protocol = RC_TYPE_NEC32;
                        poll_result->scancode = RC_SCANCODE_NEC32((msg[1] << 24) |
                                                                  (msg[2] << 16) |
                                                                  (msg[3] << 8)  |
                                                                  (msg[4]));
-               else if ((msg[1] ^ msg[2]) != 0xff)     /* 24 bits NEC */
+               } else if ((msg[1] ^ msg[2]) != 0xff) { /* 24 bits NEC */
+                       poll_result->protocol = RC_TYPE_NECX;
                        poll_result->scancode = RC_SCANCODE_NECX(msg[1] << 8 |
                                                                 msg[2], msg[3]);
-               else                                    /* Normal NEC */
+               } else {                                /* Normal NEC */
+                       poll_result->protocol = RC_TYPE_NEC;
                        poll_result->scancode = RC_SCANCODE_NEC(msg[1], msg[3]);
+               }
                break;
 
        case RC_BIT_RC6_0:
@@ -719,7 +722,7 @@ static int em28xx_ir_init(struct em28xx *dev)
        ir = kzalloc(sizeof(*ir), GFP_KERNEL);
        if (!ir)
                return -ENOMEM;
-       rc = rc_allocate_device();
+       rc = rc_allocate_device(RC_DRIVER_SCANCODE);
        if (!rc)
                goto error;
 
@@ -777,7 +780,7 @@ static int em28xx_ir_init(struct em28xx *dev)
                case CHIP_ID_EM28178:
                        ir->get_key = em2874_polling_getkey;
                        rc->allowed_protocols = RC_BIT_RC5 | RC_BIT_NEC |
-                                            RC_BIT_RC6_0;
+                               RC_BIT_NECX | RC_BIT_NEC32 | RC_BIT_RC6_0;
                        break;
                default:
                        err = -ENODEV;
index ca59e2d4fccfa4d1729d94f6f9fd7ac58fc0bded..e9f379959fa5e1bfe570973fa464932792a47776 100644 (file)
 #define EM2884_BOARD_ELGATO_EYETV_HYBRID_2008     97
 #define EM28178_BOARD_PLEX_PX_BCUD                98
 #define EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB  99
+#define EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 100
 
 /* Limits minimum and default number of buffers */
 #define EM28XX_MIN_BUF 4
index 0e9ee8b50bb7f2ed5839b27c5614a5f1b09423ec..427db745e027436b97ec4a878a5442499809a4be 100644 (file)
  * but WITHOUT 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
  */
 #include "gspca.h"
 
index 5fa67b78ad49b1a1da48bb02144b011f6ef34443..60a728203b3bedfeaff36526a9d34e9d6b2483b6 100644 (file)
  * but WITHOUT 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
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 2e15c80d6e3d11b953d210b553cbc6878110427f..bdcdf7999c5644bfa6abe14167c010eff702eee8 100644 (file)
  * but WITHOUT 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
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 52b88e9e656b5f87e3573a7a0afb7e49da8cfb95..23d3285f182a5997c498640ae092c90d4ce7596a 100644 (file)
  * 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
- *
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 26c9ee1f1045a197ca7624b5dd007396964c3c68..8f84292936e98ce592277fd9f3b72d730669b106 100644 (file)
  * but WITHOUT 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
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index ae9a55d7bbbb617aaf94c91477dca6513d8a8a91..7bb469aa61a7363d52ffd18671b784168fa9baec 100644 (file)
  * but WITHOUT 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
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index fa2cbb981905a4908d19dd793a1138bc3bcf7ab4..16bc1dde2c8cd5ed341c8356dc0e48598c4dd43d 100644 (file)
  * WITHOUT 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.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 19736e237b37d6a14e50141c8d24104141783f16..34e043b7d1bc38ec6d7f3a10676c841f1d98e4e7 100644 (file)
  * but WITHOUT 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
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index b12ecb72df4cf4e0e0980ee95c8704805c886c42..17c7a953564ce1dd0e29087730d49320b3883a28 100644 (file)
  * but WITHOUT 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
  */
 
 #define MODULE_NAME "jl2005bcd"
index 0aa2b671faa417120217c9ae960e79013171f213..d5ad7c96d0398ad01f5cdbbc240511d05b449e15 100644 (file)
  * 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
- *
  */
 
 /*
index 3cb30a37d6ac90818521dc646b48b9f9bfcabb95..2f28b38c5479c3c4d414a374ae47f449c221eec1 100644 (file)
  * but WITHOUT 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
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 40aaaa9c5f30ebd0990d5df3fecebfed4faa123a..71f273377f833b3d6fce5a7770a71bcf1c647eac 100644 (file)
  * but WITHOUT 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
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 779a8785f421bbcb67c62840c8a67478ee0a44a2..25df55e840c73026bdffdb76e3fe004942c855b3 100644 (file)
  * but WITHOUT 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
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 6dfb364094ec769937515d7d2d086d4a135a5865..8b0e32a649acffb9f8b60ec96163a0994e6a6fc0 100644 (file)
  * but WITHOUT 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
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 599f755e75b86513c28228468bc19e15278a414a..5d2d0bcb038d3e86eaab89dec368466228f140f9 100644 (file)
  * but WITHOUT 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
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 4dbca54cf2a83de08a743f2c8969ff465b2632ed..f4c41f043cda4da995d1ee52708fc1ffaa57112f 100644 (file)
  * 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
- *
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 9266a5c9abc5db0197b7305530e06dfbbc9dd541..32849ff86b09dfa6b793d94d4435edab776a3f28 100644 (file)
  * but WITHOUT 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
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 47085cf2d72365b5fdac410d5394bbdb8a7407b0..b2a92e518118ff055bdfb086a40a06af91fe2022 100644 (file)
  * but WITHOUT 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
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 51e11248bbb837a60df723f8310f80f4f53a0fcd..01c185d367e5d413d1c957a79d9c3f4bbb7ca6bb 100644 (file)
  * 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
- *
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index be07a24c4518f10cbb97aee99eb9120139ed13cc..595535e143e647c8b5b232b31a8d20ffc9c112b7 100644 (file)
  * but WITHOUT 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
  */
 
 /*
index 25f86b1e74a80b9c9d6f4d856b8156a216d47102..8bac2d9326bf8f9beee707087d15b4953d9e72d0 100644 (file)
  * but WITHOUT 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
  */
 
 /* Some documentation about various registers as determined by trial and error.
index fbc5e226c3e4855436f0ba9781f8f21e91f2420d..4047bcb6c2b552a2d270361cfb6ee855da751ba4 100644 (file)
  * 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
- *
  */
 
 /* We calculate the autogain at the end of the transfer of a frame, at this
index 5102cea504710c5c2aeeba1b0101159f35b0b459..477da0664b7daf1a77537c6314c22bcb7778550d 100644 (file)
  * 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
- *
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 96d8ebf3cf595622d2547344b078586b63c3a19e..7cc0728c1410fce5e375e26c9c5f59d66091be74 100644 (file)
  * 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
- *
  */
 
 #define SE401_REQ_GET_CAMERA_DESCRIPTOR                0x06
index 4f2050a5ec941a036119eba6ad7c6730f6ac713e..5d32dd359d84d49a1ebf63a8f37e8c4d838320d8 100644 (file)
  * but WITHOUT 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
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index f85bc106bc52c7566ff9f7153303f26398a6f960..85761aa7c8b249550476efce59246f695aac04f8 100644 (file)
  * 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
- *
  */
 
 static const unsigned char sn9c2028_sof_marker[] = {
index e7430b06526ae25030e0f960bbbcc021435448c6..c605f78d618673614eb54f7224398c499f960ded 100644 (file)
  * but WITHOUT 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
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 6696b2ec34e969dd631a91ca2dbe6b3ac5fac1fd..5f3f2979540a64b7a868dd2573db3c329a6e08da 100644 (file)
  * but WITHOUT 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
  */
 
 /* Some documentation on known sonixb registers:
index d49d76ec142126c84868dcfd348aaf835ecaaee8..5eeaf16ac5e82a2793d7ca8800d3a5bb28e175da 100644 (file)
  * but WITHOUT 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
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index f38fd8949609fd917cee8568a4cba9bdb5e83cb4..327ec901abe149d8be6a4bdf267a5aa53a9e7728 100644 (file)
  * but WITHOUT 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
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index f011a309dd65f4d0776e82cb55f4e6c3fb4ccf58..da2d9027914c61a9d33c8cd97f20277cdc9f3a35 100644 (file)
  * 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
- *
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index d92fd17d6701423fa254e98d098b76f53f0d353a..ae5a80987553a2567f31890c3f5c3bbbb4045e32 100644 (file)
  * 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
- *
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 232b330d2dd3717c493e1b9aebd218fff9ad9f58..1553cc766c0422fd97040bdbb1039bc6bf394109 100644 (file)
  * 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
- *
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index ee84863d27d473a752e532f6c507cd5a641d8f93..843c93f5acf3acf8a8a4c864542615337c5730eb 100644 (file)
  * but WITHOUT 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
  */
 
 #define MODULE_NAME "spca506"
index 75f2beb2ea5aa9d9d341e40342a7cca8aa7b3c26..1e0ba6b24e2180ddf576d2ec11918904fd1845a9 100644 (file)
  * but WITHOUT 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
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 403d71cd65d93f32e82982cfdff5f89208c3de1c..4ff704cf9ed6cc2c21f36a384fd2fb6da980a969 100644 (file)
  * but WITHOUT 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
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 9424c33f0ddb839023b3bb384374718e0b74e417..f1da34a10ce88af679128cf15dc5f7ea7ed6b413 100644 (file)
  * but WITHOUT 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
  */
 
 /*
index 6c45dcc44eb01fd37fe21a178d20301dfc0e673e..8b4e4948a0cb6d25f1128ede0cd386176d239612 100644 (file)
  * but WITHOUT 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
  */
 
 /*
index e274cf19a3ea22a1448f340f7a779c5a1274d528..aa9a9411b801818f222b668410084a89192981d5 100644 (file)
  * but WITHOUT 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
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index d324d001e1143890fb5ec171f0fad0f608771c06..daf45db6c4047723765279769860a787aa3891ff 100644 (file)
  * but WITHOUT 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
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 48234c9a8b6c3e4b4b927eb654ddb0009aa3d8ba..3ab5ec2ca4bd725f95479c9ff4f1e48880dc09a5 100644 (file)
  * but WITHOUT 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
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index e1dd92ab49bbf60fcad0ec25d3f8f4833f346497..bd144012f73a9f89a64ee44e574f4f9c8de251d3 100644 (file)
  * but WITHOUT 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
  */
 
 #define STK1135_REG_GCTRL      0x000   /* GPIO control */
index 7f94ec74282e3ea42b0c423130419b038a5e3edd..29a65d05cbb22c416ab09397e2ce8b08315bf410 100644 (file)
  * 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
- *
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index fef7a784b8799eae88e99dad70b8bacf2c3b84c6..e72c3e1ab9ff41f0a39d685d4615a8bd3cb06914 100644 (file)
  * 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
- *
  * P/N 861037:      Sensor HDCS1000        ASIC STV0600
  * P/N 861050-0010: Sensor HDCS1000        ASIC STV0600
  * P/N 861050-0020: Sensor Photobit PB100  ASIC STV0600-1 - QuickCam Express
index 34957a4ec1501ec483dcb10167cb2914ea63e956..f9d74e4d7cf95153943c4a94ea683bb7ed881f3a 100644 (file)
  * 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
- *
  * P/N 861037:      Sensor HDCS1000        ASIC STV0600
  * P/N 861050-0010: Sensor HDCS1000        ASIC STV0600
  * P/N 861050-0020: Sensor Photobit PB100  ASIC STV0600-1 - QuickCam Express
index 2220b70d47e6663d6200eec0768c4894fe833ef2..28252f6c4afd837435ad153f2ae6fddf17f225c7 100644 (file)
  * 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
- *
  * P/N 861037:      Sensor HDCS1000        ASIC STV0600
  * P/N 861050-0010: Sensor HDCS1000        ASIC STV0600
  * P/N 861050-0020: Sensor Photobit PB100  ASIC STV0600-1 - QuickCam Express
index 1ba9158d0102196356ff1e069f166aa4b997f4c9..d2da0de05236e54579ef7411a81bb3e00c17e9e6 100644 (file)
  * 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
- *
  * P/N 861037:      Sensor HDCS1000        ASIC STV0600
  * P/N 861050-0010: Sensor HDCS1000        ASIC STV0600
  * P/N 861050-0020: Sensor Photobit PB100  ASIC STV0600-1 - QuickCam Express
index 8d785edcccf2ef040906840f55ea3173e555ecbf..e1ce96e9405f5ed89a23c5c0a59a7b5290b5cd93 100644 (file)
  * 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
- *
  * P/N 861037:      Sensor HDCS1000        ASIC STV0600
  * P/N 861050-0010: Sensor HDCS1000        ASIC STV0600
  * P/N 861050-0020: Sensor Photobit PB100  ASIC STV0600-1 - QuickCam Express
index 5071e5353fd339be30bfd914601e0dacd6b63c15..33572d8bb3689a941574d1129c415d200923a5ac 100644 (file)
  * 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
- *
  * P/N 861037:      Sensor HDCS1000        ASIC STV0600
  * P/N 861050-0010: Sensor HDCS1000        ASIC STV0600
  * P/N 861050-0020: Sensor Photobit PB100  ASIC STV0600-1 - QuickCam Express
index 3a498c2495c606d8c35d74537addc1f3bd1aadf6..747d07c877fe31d0fe6bc3b8235a01fed821bb00 100644 (file)
  * 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
- *
  * P/N 861037:      Sensor HDCS1000        ASIC STV0600
  * P/N 861050-0010: Sensor HDCS1000        ASIC STV0600
  * P/N 861050-0020: Sensor Photobit PB100  ASIC STV0600-1 - QuickCam Express
index 515a9e121653b28bcaf68b0300d955fdcdd7e818..4b76070515b5e8315aed3e11493962e59e1e0e05 100644 (file)
  * 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
- *
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 8f20fbf30f3331d5720249f30794708e57e8de99..87324a69a0bee53da32d733152591ac921da0116 100644 (file)
  * 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 STV06XX_ST6422_H_
index f86cec091bf40f0e5700403152221a945d955d14..d265e6b0099477c6251bc03a17e4a42fc4223be1 100644 (file)
  * 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
- *
  * P/N 861037:      Sensor HDCS1000        ASIC STV0600
  * P/N 861050-0010: Sensor HDCS1000        ASIC STV0600
  * P/N 861050-0020: Sensor Photobit PB100  ASIC STV0600-1 - QuickCam Express
@@ -120,9 +116,6 @@ static int vv6410_init(struct sd *sd)
        for (i = 0; i < ARRAY_SIZE(stv_bridge_init); i++)
                stv06xx_write_bridge(sd, stv_bridge_init[i].addr, stv_bridge_init[i].data);
 
-       if (err < 0)
-               return err;
-
        err = stv06xx_write_sensor_bytes(sd, (u8 *) vv6410_sensor_init,
                                         ARRAY_SIZE(vv6410_sensor_init));
        return (err < 0) ? err : 0;
index 53e67b40ca05f23c0d6492ee95aee1ae189676fe..e8598893791efd4915b7d2dea69f7d082d6b737b 100644 (file)
  * 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
- *
  * P/N 861037:      Sensor HDCS1000        ASIC STV0600
  * P/N 861050-0010: Sensor HDCS1000        ASIC STV0600
  * P/N 861050-0020: Sensor Photobit PB100  ASIC STV0600-1 - QuickCam Express
index 38dc9e7aa313fc028c80f30a0ca68d684937a66f..8c2785aea3cd046a5d60fd824d21579290f3626b 100644 (file)
  * but WITHOUT 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
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index bb52fc1fe598c66982a914cbb351fcb46b24d743..42667710af92279dba54b777b9aa4827237f9340 100644 (file)
  * 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
- *
  *Notes: * t613  + tas5130A
  *     * Focus to light do not balance well as in win.
  *       Quality in win is not good, but its kinda better.
index d497ba38af0da06149ebb95ec91526c21e6a4604..bc2720e9cc4f88065289e27b5b577d7239e92160 100644 (file)
  * 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
- *
  */
 #define MODULE_NAME "tv8532"
 
index b4efb2fb36fa3b875e96e5a668d2f349289e8bad..b935febf7146856c2bf3ef2f9d89d4c2b6558e9f 100644 (file)
  * but WITHOUT 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
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 8860510c2f9c73c7afb00d52cadf5edb934bcf45..554b90ef2200bf928686e83bec938d8d4f6588a1 100644 (file)
  * but WITHOUT 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
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 896f1b2b91793907a62d751f178c30001da683bc..728d2322c433ad25488737f0ecfbe6f2daee8725 100644 (file)
  * 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
- *
  */
 
 /* Note this is not a stand alone driver, it gets included in ov519.c, this
index d5ed9d36ce25855cba5b745b1c605fa4b515bc69..b600ea6460d3bc5012435bbb007b5e261e837867 100644 (file)
  * 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
- *
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index d5d8c7e81762310272caad6b60fe0dc5f0d1dd56..e2d486bd8c2806ae82c59f8d4fa92fdb6d33320d 100644 (file)
  * but WITHOUT 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.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
index 3bac50a248d479c7aefb5d6891dca3cdabcff24b..356afa250cd6e4a3808e05db37143b89550065db 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
  */
 
 #include "pvrusb2-audio.h"
index 27cefb5cb170ebcdaf80dc107269bd995d8ea9d1..4f3898473165f3ec4a0e775cd0358187680682c3 100644 (file)
  *  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 __PVRUSB2_AUDIO_H
index c45f30715dcd019217d9ae51a22f1f8874c96d10..d9e8481e9e286e5f2d6dc7584155e995d7541cc2 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
  */
 
 #include "pvrusb2-context.h"
index 1c1d442d9ea3bba70ea48f451775fa8086895b1f..13e00c529611043a68f925f4faf8ff0a423aee86 100644 (file)
  *  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 __PVRUSB2_CONTEXT_H
 #define __PVRUSB2_CONTEXT_H
index 7f29a0464f36a0062d74998bd63d3a3cf292b393..679f3ff3b0a5c073ff8ab589d59331ffdd92653d 100644 (file)
  *  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
- *
  */
 
 /*
index 86c17bee56f947227b56feb272a20c137f14a020..90dfb8b3f3e515d72bbbd2b0e9c63f8ae2dfa3e4 100644 (file)
  *  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 __PVRUSB2_CS53L32A_H
index 958db170a04832e28361e40dfb0a9d82f9c72f83..5f4ba84e5557788727ba2ca65de50258db982237 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
  */
 
 #include "pvrusb2-ctrl.h"
index c175571868a38a1abf67a6b42b19828ed54ac357..4b9152e36fe4760c85749359dbd5b25d9418fffa 100644 (file)
  *  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 __PVRUSB2_CTRL_H
 #define __PVRUSB2_CTRL_H
index 30eef97ef2efa9dc8bff15b0ba7926c60ea48992..242b213b7599abab0acbad522cb46bef6abea4fb 100644 (file)
  *  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
- *
  */
 
 /*
index 2eed7b7ee25ec4fcf48b86e6764a7712fb5a4868..dfddc88750d9401f9132f65de4f35e85dbab6194 100644 (file)
  *  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 __PVRUSB2_CX2584X_V4L_H
index 4ef2ebcd97a5fd994e1b28765ded57dbd0016846..5cd16292e2fa1ae2de78c6586d24a6c5678f1122 100644 (file)
  *  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 __PVRUSB2_DEBUG_H
 #define __PVRUSB2_DEBUG_H
index 58ec706ebdb3f807528d69aa0b3a3db00b41097c..d3f3bd96885f9637cf0f1e27c66ec3c0ee64fead 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
  */
 
 #include <linux/string.h>
index a8dfc55f136f28dd7488661ee4f367b5fe1b7daa..fcaaa8dd68b87cdc738cb71966519801764fd1de 100644 (file)
  *  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 __PVRUSB2_DEBUGIFC_H
 #define __PVRUSB2_DEBUGIFC_H
index 06c4c3dabcde35cc487637211516dd812e5cdca2..51b3312eaea13421097053e7955e2c1ac5128464 100644 (file)
  *  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
- *
  */
 
 /*
index 5aeefb6a991ff5d441df7047561029a5a3daa345..c1e7d4822cd1d3c398390bf10060be236f17d91c 100644 (file)
  *  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 __PVRUSB2_DEVATTR_H
 #define __PVRUSB2_DEVATTR_H
index 8c95793433e79b8d93470e4b9b757dc7ef656dd6..56c750535ee7e6f11ad455800a29d6be6ed28bdb 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
  */
 
 #include <linux/kthread.h>
index 276b17fb9aadecf6fae0cd4cb8c5676d3f69452b..4af2fb5c85d50d2947692fa499af083633f5b6f5 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
  */
 
 #include <linux/slab.h>
index f1e33c807f4648942d97e6992b0eb6ff38e81fcf..1d81cac30f3d7828f44c2f5d6444514e621f2bf8 100644 (file)
  *  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 __PVRUSB2_EEPROM_H
index f0483621d2a3aedfc4aca1257579a7083e9bdf90..ca637074fa1ff3e74e7491373998a4b679a5ce8a 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
  */
 
 #include <linux/device.h>   // for linux/firmware.h
index a2bfb48f1ecdfb49b033e2856e6b1ec70a2b9edd..10d7f0b48264ba465419f69f6645b0b6e40396dd 100644 (file)
  *  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 __PVRUSB2_ENCODER_H
index 06a15a68bcfdc13ca4ee5d005f0740bf80788950..0a01de4e54db3fa69196eccd853a976981b64439 100644 (file)
  *  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 _PVRUSB2_FX2_CMD_H_
index 23473a21319cd4275a663b77e5fef0850602feb2..7a824196d5fa000f0510d23bb612d92f5f8fa462 100644 (file)
  *  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 __PVRUSB2_HDW_INTERNAL_H
 #define __PVRUSB2_HDW_INTERNAL_H
index e3ed8ffee9f7a0a5b94903bee0ce4c84451ed56a..ad5b25b896990eab69616ad6e454bb2bd2d9601c 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
  */
 
 #include <linux/errno.h>
index a82a00dd732930694dd6815d25d59bed6ffb1546..25648add77e58c841ebf03672433cfb2e35da34d 100644 (file)
  *  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 __PVRUSB2_HDW_H
 #define __PVRUSB2_HDW_H
index cc63e5f4c26c452c214c4f116cf8432bb5fd57fc..f727b54a53c6d94a34476e9d22fca1de544b3ca2 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
  */
 
 #include <linux/i2c.h>
index a10a3e8e9345760f82e0ba0b4ed9aa2bf161e81c..1c44dee7fd69b434aa17a4be3ce9dc2bb03bce58 100644 (file)
  *  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 __PVRUSB2_I2C_CORE_H
 #define __PVRUSB2_I2C_CORE_H
index e3103ecd4828c2f89d1bfeedc3067c91d4b7cc23..6d153fc23ec2e14b98d5e1bbb6f88ff94913f178 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
  */
 
 #include "pvrusb2-io.h"
@@ -37,13 +33,13 @@ static const char *pvr2_buffer_state_decode(enum pvr2_buffer_state);
        if ((bp)->signature != BUFFER_SIG) { \
                pvr2_trace(PVR2_TRACE_ERROR_LEGS, \
                "Buffer %p is bad at %s:%d", \
-               (bp),__FILE__,__LINE__); \
-               pvr2_buffer_describe(bp,"BadSig"); \
+               (bp), __FILE__, __LINE__); \
+               pvr2_buffer_describe(bp, "BadSig"); \
                BUG(); \
        } \
 } while (0)
 #else
-#define BUFFER_CHECK(bp) do {} while(0)
+#define BUFFER_CHECK(bp) do {} while (0)
 #endif
 
 struct pvr2_stream {
@@ -110,7 +106,7 @@ static const char *pvr2_buffer_state_decode(enum pvr2_buffer_state st)
 }
 
 #ifdef SANITY_CHECK_BUFFERS
-static void pvr2_buffer_describe(struct pvr2_buffer *bp,const char *msg)
+static void pvr2_buffer_describe(struct pvr2_buffer *bp, const char *msg)
 {
        pvr2_trace(PVR2_TRACE_INFO,
                   "buffer%s%s %p state=%s id=%d status=%d stream=%p purb=%p sig=0x%x",
@@ -156,7 +152,7 @@ static void pvr2_buffer_remove(struct pvr2_buffer *bp)
        (*bcnt) -= ccnt;
        pvr2_trace(PVR2_TRACE_BUF_FLOW,
                   "/*---TRACE_FLOW---*/ bufferPool     %8s dec cap=%07d cnt=%02d",
-                  pvr2_buffer_state_decode(bp->state),*bcnt,*cnt);
+                  pvr2_buffer_state_decode(bp->state), *bcnt, *cnt);
        bp->state = pvr2_buffer_state_none;
 }
 
@@ -171,9 +167,9 @@ static void pvr2_buffer_set_none(struct pvr2_buffer *bp)
                   bp,
                   pvr2_buffer_state_decode(bp->state),
                   pvr2_buffer_state_decode(pvr2_buffer_state_none));
-       spin_lock_irqsave(&sp->list_lock,irq_flags);
+       spin_lock_irqsave(&sp->list_lock, irq_flags);
        pvr2_buffer_remove(bp);
-       spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+       spin_unlock_irqrestore(&sp->list_lock, irq_flags);
 }
 
 static int pvr2_buffer_set_ready(struct pvr2_buffer *bp)
@@ -188,18 +184,18 @@ static int pvr2_buffer_set_ready(struct pvr2_buffer *bp)
                   bp,
                   pvr2_buffer_state_decode(bp->state),
                   pvr2_buffer_state_decode(pvr2_buffer_state_ready));
-       spin_lock_irqsave(&sp->list_lock,irq_flags);
+       spin_lock_irqsave(&sp->list_lock, irq_flags);
        fl = (sp->r_count == 0);
        pvr2_buffer_remove(bp);
-       list_add_tail(&bp->list_overhead,&sp->ready_list);
+       list_add_tail(&bp->list_overhead, &sp->ready_list);
        bp->state = pvr2_buffer_state_ready;
        (sp->r_count)++;
        sp->r_bcount += bp->used_count;
        pvr2_trace(PVR2_TRACE_BUF_FLOW,
                   "/*---TRACE_FLOW---*/ bufferPool     %8s inc cap=%07d cnt=%02d",
                   pvr2_buffer_state_decode(bp->state),
-                  sp->r_bcount,sp->r_count);
-       spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+                  sp->r_bcount, sp->r_count);
+       spin_unlock_irqrestore(&sp->list_lock, irq_flags);
        return fl;
 }
 
@@ -214,17 +210,17 @@ static void pvr2_buffer_set_idle(struct pvr2_buffer *bp)
                   bp,
                   pvr2_buffer_state_decode(bp->state),
                   pvr2_buffer_state_decode(pvr2_buffer_state_idle));
-       spin_lock_irqsave(&sp->list_lock,irq_flags);
+       spin_lock_irqsave(&sp->list_lock, irq_flags);
        pvr2_buffer_remove(bp);
-       list_add_tail(&bp->list_overhead,&sp->idle_list);
+       list_add_tail(&bp->list_overhead, &sp->idle_list);
        bp->state = pvr2_buffer_state_idle;
        (sp->i_count)++;
        sp->i_bcount += bp->max_count;
        pvr2_trace(PVR2_TRACE_BUF_FLOW,
                   "/*---TRACE_FLOW---*/ bufferPool     %8s inc cap=%07d cnt=%02d",
                   pvr2_buffer_state_decode(bp->state),
-                  sp->i_bcount,sp->i_count);
-       spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+                  sp->i_bcount, sp->i_count);
+       spin_unlock_irqrestore(&sp->list_lock, irq_flags);
 }
 
 static void pvr2_buffer_set_queued(struct pvr2_buffer *bp)
@@ -238,17 +234,17 @@ static void pvr2_buffer_set_queued(struct pvr2_buffer *bp)
                   bp,
                   pvr2_buffer_state_decode(bp->state),
                   pvr2_buffer_state_decode(pvr2_buffer_state_queued));
-       spin_lock_irqsave(&sp->list_lock,irq_flags);
+       spin_lock_irqsave(&sp->list_lock, irq_flags);
        pvr2_buffer_remove(bp);
-       list_add_tail(&bp->list_overhead,&sp->queued_list);
+       list_add_tail(&bp->list_overhead, &sp->queued_list);
        bp->state = pvr2_buffer_state_queued;
        (sp->q_count)++;
        sp->q_bcount += bp->max_count;
        pvr2_trace(PVR2_TRACE_BUF_FLOW,
                   "/*---TRACE_FLOW---*/ bufferPool     %8s inc cap=%07d cnt=%02d",
                   pvr2_buffer_state_decode(bp->state),
-                  sp->q_bcount,sp->q_count);
-       spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+                  sp->q_bcount, sp->q_count);
+       spin_unlock_irqrestore(&sp->list_lock, irq_flags);
 }
 
 static void pvr2_buffer_wipe(struct pvr2_buffer *bp)
@@ -262,18 +258,18 @@ static int pvr2_buffer_init(struct pvr2_buffer *bp,
                            struct pvr2_stream *sp,
                            unsigned int id)
 {
-       memset(bp,0,sizeof(*bp));
+       memset(bp, 0, sizeof(*bp));
        bp->signature = BUFFER_SIG;
        bp->id = id;
        pvr2_trace(PVR2_TRACE_BUF_POOL,
-                  "/*---TRACE_FLOW---*/ bufferInit     %p stream=%p",bp,sp);
+                  "/*---TRACE_FLOW---*/ bufferInit     %p stream=%p", bp, sp);
        bp->stream = sp;
        bp->state = pvr2_buffer_state_none;
        INIT_LIST_HEAD(&bp->list_overhead);
-       bp->purb = usb_alloc_urb(0,GFP_KERNEL);
+       bp->purb = usb_alloc_urb(0, GFP_KERNEL);
        if (! bp->purb) return -ENOMEM;
 #ifdef SANITY_CHECK_BUFFERS
-       pvr2_buffer_describe(bp,"create");
+       pvr2_buffer_describe(bp, "create");
 #endif
        return 0;
 }
@@ -281,7 +277,7 @@ static int pvr2_buffer_init(struct pvr2_buffer *bp,
 static void pvr2_buffer_done(struct pvr2_buffer *bp)
 {
 #ifdef SANITY_CHECK_BUFFERS
-       pvr2_buffer_describe(bp,"delete");
+       pvr2_buffer_describe(bp, "delete");
 #endif
        pvr2_buffer_wipe(bp);
        pvr2_buffer_set_none(bp);
@@ -292,7 +288,7 @@ static void pvr2_buffer_done(struct pvr2_buffer *bp)
                   bp);
 }
 
-static int pvr2_stream_buffer_count(struct pvr2_stream *sp,unsigned int cnt)
+static int pvr2_stream_buffer_count(struct pvr2_stream *sp, unsigned int cnt)
 {
        int ret;
        unsigned int scnt;
@@ -312,10 +308,11 @@ static int pvr2_stream_buffer_count(struct pvr2_stream *sp,unsigned int cnt)
        if (cnt > sp->buffer_total_count) {
                if (scnt > sp->buffer_slot_count) {
                        struct pvr2_buffer **nb;
-                       nb = kmalloc(scnt * sizeof(*nb),GFP_KERNEL);
+
+                       nb = kmalloc_array(scnt, sizeof(*nb), GFP_KERNEL);
                        if (!nb) return -ENOMEM;
                        if (sp->buffer_slot_count) {
-                               memcpy(nb,sp->buffers,
+                               memcpy(nb, sp->buffers,
                                       sp->buffer_slot_count * sizeof(*nb));
                                kfree(sp->buffers);
                        }
@@ -324,9 +321,9 @@ static int pvr2_stream_buffer_count(struct pvr2_stream *sp,unsigned int cnt)
                }
                while (sp->buffer_total_count < cnt) {
                        struct pvr2_buffer *bp;
-                       bp = kmalloc(sizeof(*bp),GFP_KERNEL);
+                       bp = kmalloc(sizeof(*bp), GFP_KERNEL);
                        if (!bp) return -ENOMEM;
-                       ret = pvr2_buffer_init(bp,sp,sp->buffer_total_count);
+                       ret = pvr2_buffer_init(bp, sp, sp->buffer_total_count);
                        if (ret) {
                                kfree(bp);
                                return -ENOMEM;
@@ -369,10 +366,10 @@ static int pvr2_stream_achieve_buffer_count(struct pvr2_stream *sp)
 
        pvr2_trace(PVR2_TRACE_BUF_POOL,
                   "/*---TRACE_FLOW---*/ poolCheck      stream=%p cur=%d tgt=%d",
-                  sp,sp->buffer_total_count,sp->buffer_target_count);
+                  sp, sp->buffer_total_count, sp->buffer_target_count);
 
        if (sp->buffer_total_count < sp->buffer_target_count) {
-               return pvr2_stream_buffer_count(sp,sp->buffer_target_count);
+               return pvr2_stream_buffer_count(sp, sp->buffer_target_count);
        }
 
        cnt = 0;
@@ -382,7 +379,7 @@ static int pvr2_stream_achieve_buffer_count(struct pvr2_stream *sp)
                cnt++;
        }
        if (cnt) {
-               pvr2_stream_buffer_count(sp,sp->buffer_total_count - cnt);
+               pvr2_stream_buffer_count(sp, sp->buffer_total_count - cnt);
        }
 
        return 0;
@@ -393,7 +390,7 @@ static void pvr2_stream_internal_flush(struct pvr2_stream *sp)
        struct list_head *lp;
        struct pvr2_buffer *bp1;
        while ((lp = sp->queued_list.next) != &sp->queued_list) {
-               bp1 = list_entry(lp,struct pvr2_buffer,list_overhead);
+               bp1 = list_entry(lp, struct pvr2_buffer, list_overhead);
                pvr2_buffer_wipe(bp1);
                /* At this point, we should be guaranteed that no
                   completion callback may happen on this buffer.  But it's
@@ -421,7 +418,7 @@ static void pvr2_stream_done(struct pvr2_stream *sp)
 {
        mutex_lock(&sp->mutex); do {
                pvr2_stream_internal_flush(sp);
-               pvr2_stream_buffer_count(sp,0);
+               pvr2_stream_buffer_count(sp, 0);
        } while (0); mutex_unlock(&sp->mutex);
 }
 
@@ -436,8 +433,8 @@ static void buffer_complete(struct urb *urb)
        bp->status = 0;
        pvr2_trace(PVR2_TRACE_BUF_FLOW,
                   "/*---TRACE_FLOW---*/ bufferComplete %p stat=%d cnt=%d",
-                  bp,urb->status,urb->actual_length);
-       spin_lock_irqsave(&sp->list_lock,irq_flags);
+                  bp, urb->status, urb->actual_length);
+       spin_lock_irqsave(&sp->list_lock, irq_flags);
        if ((!(urb->status)) ||
            (urb->status == -ENOENT) ||
            (urb->status == -ECONNRESET) ||
@@ -458,12 +455,12 @@ static void buffer_complete(struct urb *urb)
                (sp->buffers_failed)++;
                pvr2_trace(PVR2_TRACE_TOLERANCE,
                           "stream %p ignoring error %d - fail count increased to %u",
-                          sp,urb->status,sp->fail_count);
+                          sp, urb->status, sp->fail_count);
        } else {
                (sp->buffers_failed)++;
                bp->status = urb->status;
        }
-       spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+       spin_unlock_irqrestore(&sp->list_lock, irq_flags);
        pvr2_buffer_set_ready(bp);
        if (sp->callback_func) {
                sp->callback_func(sp->callback_data);
@@ -473,9 +470,9 @@ static void buffer_complete(struct urb *urb)
 struct pvr2_stream *pvr2_stream_create(void)
 {
        struct pvr2_stream *sp;
-       sp = kzalloc(sizeof(*sp),GFP_KERNEL);
+       sp = kzalloc(sizeof(*sp), GFP_KERNEL);
        if (!sp) return sp;
-       pvr2_trace(PVR2_TRACE_INIT,"pvr2_stream_create: sp=%p",sp);
+       pvr2_trace(PVR2_TRACE_INIT, "pvr2_stream_create: sp=%p", sp);
        pvr2_stream_init(sp);
        return sp;
 }
@@ -483,7 +480,7 @@ struct pvr2_stream *pvr2_stream_create(void)
 void pvr2_stream_destroy(struct pvr2_stream *sp)
 {
        if (!sp) return;
-       pvr2_trace(PVR2_TRACE_INIT,"pvr2_stream_destroy: sp=%p",sp);
+       pvr2_trace(PVR2_TRACE_INIT, "pvr2_stream_destroy: sp=%p", sp);
        pvr2_stream_done(sp);
        kfree(sp);
 }
@@ -498,7 +495,7 @@ void pvr2_stream_setup(struct pvr2_stream *sp,
                sp->dev = dev;
                sp->endpoint = endpoint;
                sp->fail_tolerance = tolerance;
-       } while(0); mutex_unlock(&sp->mutex);
+       } while (0); mutex_unlock(&sp->mutex);
 }
 
 void pvr2_stream_set_callback(struct pvr2_stream *sp,
@@ -508,11 +505,11 @@ void pvr2_stream_set_callback(struct pvr2_stream *sp,
        unsigned long irq_flags;
        mutex_lock(&sp->mutex);
        do {
-               spin_lock_irqsave(&sp->list_lock,irq_flags);
+               spin_lock_irqsave(&sp->list_lock, irq_flags);
                sp->callback_data = data;
                sp->callback_func = func;
-               spin_unlock_irqrestore(&sp->list_lock,irq_flags);
-       } while(0);
+               spin_unlock_irqrestore(&sp->list_lock, irq_flags);
+       } while (0);
        mutex_unlock(&sp->mutex);
 }
 
@@ -521,7 +518,7 @@ void pvr2_stream_get_stats(struct pvr2_stream *sp,
                           int zero_counts)
 {
        unsigned long irq_flags;
-       spin_lock_irqsave(&sp->list_lock,irq_flags);
+       spin_lock_irqsave(&sp->list_lock, irq_flags);
        if (stats) {
                stats->buffers_in_queue = sp->q_count;
                stats->buffers_in_idle = sp->i_count;
@@ -535,7 +532,7 @@ void pvr2_stream_get_stats(struct pvr2_stream *sp,
                sp->buffers_failed = 0;
                sp->bytes_processed = 0;
        }
-       spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+       spin_unlock_irqrestore(&sp->list_lock, irq_flags);
 }
 
 /* Query / set the nominal buffer count */
@@ -544,7 +541,7 @@ int pvr2_stream_get_buffer_count(struct pvr2_stream *sp)
        return sp->buffer_target_count;
 }
 
-int pvr2_stream_set_buffer_count(struct pvr2_stream *sp,unsigned int cnt)
+int pvr2_stream_set_buffer_count(struct pvr2_stream *sp, unsigned int cnt)
 {
        int ret;
        if (sp->buffer_target_count == cnt) return 0;
@@ -552,7 +549,7 @@ int pvr2_stream_set_buffer_count(struct pvr2_stream *sp,unsigned int cnt)
        do {
                sp->buffer_target_count = cnt;
                ret = pvr2_stream_achieve_buffer_count(sp);
-       } while(0);
+       } while (0);
        mutex_unlock(&sp->mutex);
        return ret;
 }
@@ -561,17 +558,17 @@ struct pvr2_buffer *pvr2_stream_get_idle_buffer(struct pvr2_stream *sp)
 {
        struct list_head *lp = sp->idle_list.next;
        if (lp == &sp->idle_list) return NULL;
-       return list_entry(lp,struct pvr2_buffer,list_overhead);
+       return list_entry(lp, struct pvr2_buffer, list_overhead);
 }
 
 struct pvr2_buffer *pvr2_stream_get_ready_buffer(struct pvr2_stream *sp)
 {
        struct list_head *lp = sp->ready_list.next;
        if (lp == &sp->ready_list) return NULL;
-       return list_entry(lp,struct pvr2_buffer,list_overhead);
+       return list_entry(lp, struct pvr2_buffer, list_overhead);
 }
 
-struct pvr2_buffer *pvr2_stream_get_buffer(struct pvr2_stream *sp,int id)
+struct pvr2_buffer *pvr2_stream_get_buffer(struct pvr2_stream *sp, int id)
 {
        if (id < 0) return NULL;
        if (id >= sp->buffer_total_count) return NULL;
@@ -595,7 +592,7 @@ void pvr2_stream_kill(struct pvr2_stream *sp)
                if (sp->buffer_total_count != sp->buffer_target_count) {
                        pvr2_stream_achieve_buffer_count(sp);
                }
-       } while(0);
+       } while (0);
        mutex_unlock(&sp->mutex);
 }
 
@@ -629,18 +626,18 @@ int pvr2_buffer_queue(struct pvr2_buffer *bp)
                usb_fill_bulk_urb(bp->purb,      // struct urb *urb
                                  sp->dev,       // struct usb_device *dev
                                  // endpoint (below)
-                                 usb_rcvbulkpipe(sp->dev,sp->endpoint),
+                                 usb_rcvbulkpipe(sp->dev, sp->endpoint),
                                  bp->ptr,       // void *transfer_buffer
                                  bp->max_count, // int buffer_length
                                  buffer_complete,
                                  bp);
-               usb_submit_urb(bp->purb,GFP_KERNEL);
-       } while(0);
+               usb_submit_urb(bp->purb, GFP_KERNEL);
+       } while (0);
        mutex_unlock(&sp->mutex);
        return ret;
 }
 
-int pvr2_buffer_set_buffer(struct pvr2_buffer *bp,void *ptr,unsigned int cnt)
+int pvr2_buffer_set_buffer(struct pvr2_buffer *bp, void *ptr, unsigned int cnt)
 {
        int ret = 0;
        unsigned long irq_flags;
@@ -649,7 +646,7 @@ int pvr2_buffer_set_buffer(struct pvr2_buffer *bp,void *ptr,unsigned int cnt)
        sp = bp->stream;
        mutex_lock(&sp->mutex);
        do {
-               spin_lock_irqsave(&sp->list_lock,irq_flags);
+               spin_lock_irqsave(&sp->list_lock, irq_flags);
                if (bp->state != pvr2_buffer_state_idle) {
                        ret = -EPERM;
                } else {
@@ -661,10 +658,10 @@ int pvr2_buffer_set_buffer(struct pvr2_buffer *bp,void *ptr,unsigned int cnt)
                                   "/*---TRACE_FLOW---*/ bufferPool     %8s cap cap=%07d cnt=%02d",
                                   pvr2_buffer_state_decode(
                                           pvr2_buffer_state_idle),
-                                  bp->stream->i_bcount,bp->stream->i_count);
+                                  bp->stream->i_bcount, bp->stream->i_count);
                }
-               spin_unlock_irqrestore(&sp->list_lock,irq_flags);
-       } while(0);
+               spin_unlock_irqrestore(&sp->list_lock, irq_flags);
+       } while (0);
        mutex_unlock(&sp->mutex);
        return ret;
 }
index 0c47c6a95ab22651235a42a482d357fc6949bf52..e769aeb9d529595fd8ef5e0f699b6704d4def388 100644 (file)
  *  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 __PVRUSB2_IO_H
 #define __PVRUSB2_IO_H
index 3c7ca2c2c108ed41a23469f22c6169adec424e0d..602097bdcf149dcc18f57cdb92f2215df3e2342c 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
  */
 
 #include "pvrusb2-ioread.h"
index 0b1f0fbc34381799417e699b47cd8b29f2a8c666..5827ea09c5e35a7b8d1e59678155180ade970f07 100644 (file)
  *  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 __PVRUSB2_IOREAD_H
 #define __PVRUSB2_IOREAD_H
index 86be902a00491ebf5d8a94133ae3637db2b9e116..cbe2c3a2245839005aa05f3bd56eedcc9a853270 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
  */
 
 #include <linux/kernel.h>
index cd7bc18a1ba22e9477bd3ceb6e62489d00610899..21bb20dba82c8df5fbc3ccd42c905c220de602eb 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
  */
 
 #include "pvrusb2-std.h"
index ed4ec0474429a3c3034e6e07ac9c6fcd1bc38a79..b48304f414723b9b0e52f5b487afcfd693c1abdf 100644 (file)
  *  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 __PVRUSB2_STD_H
 #define __PVRUSB2_STD_H
index d977976b8d919ab7a15911e89fdd1be2cffbbc25..7bc6d090358ee707173cbb332667a9a2d41f5077 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
  */
 
 #include <linux/string.h>
index 6f0579e1e07ba318ee65202ea1dee4653d7ad90b..431f4fd1901507f49bac5951c347e58ac76cf1bc 100644 (file)
  *  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 __PVRUSB2_SYSFS_H
 #define __PVRUSB2_SYSFS_H
index 5465bf9cd73e692d3616664c20852250daf9e3e5..b03ca3ef1ba03aceaaf686485e396792ac6f1764 100644 (file)
  *  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 __PVRUSB2_UTIL_H
 #define __PVRUSB2_UTIL_H
index bbbe18d5275ac038142fffec3c34539fea10b339..8f13c60198ed64d72dc74ebf56eacb28714aba86 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
  */
 
 #include <linux/kernel.h>
@@ -1054,7 +1050,7 @@ static int pvr2_v4l2_open(struct file *file)
                pvr2_trace(PVR2_TRACE_STRUCT,
                           "Destroying pvr_v4l2_fh id=%p (input mask error)",
                           fhp);
-
+               v4l2_fh_exit(&fhp->fh);
                kfree(fhp);
                return ret;
        }
@@ -1071,6 +1067,7 @@ static int pvr2_v4l2_open(struct file *file)
                pvr2_trace(PVR2_TRACE_STRUCT,
                           "Destroying pvr_v4l2_fh id=%p (input map failure)",
                           fhp);
+               v4l2_fh_exit(&fhp->fh);
                kfree(fhp);
                return -ENOMEM;
        }
index e455c95158414b5453939dd6d8d0ae56bee32274..ec755ee8f86a5d0be82487e689b88435a4e0e4fa 100644 (file)
  *  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 __PVRUSB2_V4L2_H
 #define __PVRUSB2_V4L2_H
index 6fee367139aad54ef963487d9824db3f1ddeb77a..b68aec2124b262dcbea4c23d5a95d38f9e16cb81 100644 (file)
  *  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
- *
  */
 
 /*
index dacf3ec7f9e1b8637b3f495e52cb66892e1aab9e..fa33f20655f4c4d07d510a012a91fda6412ca664 100644 (file)
  *  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 __PVRUSB2_VIDEO_V4L_H
index 7993983de5a68cb2fae869168ec61ca39f5f56e5..8f357f771ba7cb72bbbd8049327436cbbf465693 100644 (file)
  *  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
- *
  */
 
 /*
index a4ee12e28d5c6633c442bfb4552f9a8d495919f8..c4ac7c2701d0dda494e02091fcc787433a35cd26 100644 (file)
  *  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 __PVRUSB2_WM8775_H
index 95f98a87abb3c192f94cbb6641170c2083eb21b6..955290ba2d5439b9d6398e2b15870cdd492bbfe3 100644 (file)
  *  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 __PVRUSB2_H
index f7bb78c1873c915d9db9574ea024cc77a355c413..a9d4484f7626ad4c92692d6e1853461c2efc695a 100644 (file)
  * but WITHOUT 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/module.h>
index 95584c15dc5aa7813444a3d51408142b8032b357..22dff4f3b921c56dbdae5facc486d91c3c8492e6 100644 (file)
@@ -8,17 +8,9 @@ config VIDEO_STK1160_COMMON
          To compile this driver as a module, choose M here: the
          module will be called stk1160
 
-config VIDEO_STK1160_AC97
-       bool "STK1160 AC97 codec support"
-       depends on VIDEO_STK1160_COMMON && SND
-
-       ---help---
-         Enables AC97 codec support for stk1160 driver.
-
 config VIDEO_STK1160
        tristate
-       depends on (!VIDEO_STK1160_AC97 || (SND='n') || SND) && VIDEO_STK1160_COMMON
+       depends on VIDEO_STK1160_COMMON
        default y
        select VIDEOBUF2_VMALLOC
        select VIDEO_SAA711X
-       select SND_AC97_CODEC if SND
index dfe3e90ff392fb3e0e7b17f30dc3bf58180e408e..42d05463b353d5b2b1e3f66dc88bbaa2b00ab0a8 100644 (file)
@@ -1,10 +1,8 @@
-obj-stk1160-ac97-$(CONFIG_VIDEO_STK1160_AC97) := stk1160-ac97.o
-
 stk1160-y :=   stk1160-core.o \
                stk1160-v4l.o \
                stk1160-video.o \
                stk1160-i2c.o \
-               $(obj-stk1160-ac97-y)
+               stk1160-ac97.o
 
 obj-$(CONFIG_VIDEO_STK1160) += stk1160.o
 
index 2dd308f9541f469b719adf7d53f01901f4525b3e..2169be8a71dd29006aed5815213dc4905b3c9deb 100644 (file)
@@ -4,6 +4,9 @@
  * Copyright (C) 2012 Ezequiel Garcia
  * <elezegarcia--a.t--gmail.com>
  *
+ * Copyright (C) 2016 Marcel Hasler
+ * <mahasler--a.t--gmail.com>
+ *
  * Based on Easycap driver by R.M. Thomas
  *     Copyright (C) 2010 R.M. Thomas
  *     <rmthomas--a.t--sciolus.org>
  *
  */
 
-#include <linux/module.h>
-#include <sound/core.h>
-#include <sound/initval.h>
-#include <sound/ac97_codec.h>
+#include <linux/delay.h>
 
 #include "stk1160.h"
 #include "stk1160-reg.h"
 
-static struct snd_ac97 *stk1160_ac97;
-
-static void stk1160_write_ac97(struct snd_ac97 *ac97, u16 reg, u16 value)
+static int stk1160_ac97_wait_transfer_complete(struct stk1160 *dev)
 {
-       struct stk1160 *dev = ac97->private_data;
+       unsigned long timeout = jiffies + msecs_to_jiffies(STK1160_AC97_TIMEOUT);
+       u8 value;
+
+       /* Wait for AC97 transfer to complete */
+       while (time_is_after_jiffies(timeout)) {
+               stk1160_read_reg(dev, STK1160_AC97CTL_0, &value);
+
+               if (!(value & (STK1160_AC97CTL_0_CR | STK1160_AC97CTL_0_CW)))
+                       return 0;
 
+               usleep_range(50, 100);
+       }
+
+       stk1160_err("AC97 transfer took too long, this should never happen!");
+       return -EBUSY;
+}
+
+static void stk1160_write_ac97(struct stk1160 *dev, u16 reg, u16 value)
+{
        /* Set codec register address */
        stk1160_write_reg(dev, STK1160_AC97_ADDR, reg);
 
@@ -41,28 +56,30 @@ static void stk1160_write_ac97(struct snd_ac97 *ac97, u16 reg, u16 value)
        stk1160_write_reg(dev, STK1160_AC97_CMD, value & 0xff);
        stk1160_write_reg(dev, STK1160_AC97_CMD + 1, (value & 0xff00) >> 8);
 
-       /*
-        * Set command write bit to initiate write operation.
-        * The bit will be cleared when transfer is done.
-        */
+       /* Set command write bit to initiate write operation */
        stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x8c);
+
+       /* Wait for command write bit to be cleared */
+       stk1160_ac97_wait_transfer_complete(dev);
 }
 
-static u16 stk1160_read_ac97(struct snd_ac97 *ac97, u16 reg)
+#ifdef DEBUG
+static u16 stk1160_read_ac97(struct stk1160 *dev, u16 reg)
 {
-       struct stk1160 *dev = ac97->private_data;
        u8 vall = 0;
        u8 valh = 0;
 
        /* Set codec register address */
        stk1160_write_reg(dev, STK1160_AC97_ADDR, reg);
 
-       /*
-        * Set command read bit to initiate read operation.
-        * The bit will be cleared when transfer is done.
-        */
+       /* Set command read bit to initiate read operation */
        stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x8b);
 
+       /* Wait for command read bit to be cleared */
+       if (stk1160_ac97_wait_transfer_complete(dev) < 0)
+               return 0;
+
+
        /* Retrieve register value */
        stk1160_read_reg(dev, STK1160_AC97_CMD, &vall);
        stk1160_read_reg(dev, STK1160_AC97_CMD + 1, &valh);
@@ -70,81 +87,79 @@ static u16 stk1160_read_ac97(struct snd_ac97 *ac97, u16 reg)
        return (valh << 8) | vall;
 }
 
-static void stk1160_reset_ac97(struct snd_ac97 *ac97)
+void stk1160_ac97_dump_regs(struct stk1160 *dev)
 {
-       struct stk1160 *dev = ac97->private_data;
-       /* Two-step reset AC97 interface and hardware codec */
-       stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x94);
-       stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x88);
+       u16 value;
 
-       /* Set 16-bit audio data and choose L&R channel*/
-       stk1160_write_reg(dev, STK1160_AC97CTL_1 + 2, 0x01);
+       value = stk1160_read_ac97(dev, 0x12); /* CD volume */
+       stk1160_dbg("0x12 == 0x%04x", value);
+
+       value = stk1160_read_ac97(dev, 0x10); /* Line-in volume */
+       stk1160_dbg("0x10 == 0x%04x", value);
+
+       value = stk1160_read_ac97(dev, 0x0e); /* MIC volume (mono) */
+       stk1160_dbg("0x0e == 0x%04x", value);
+
+       value = stk1160_read_ac97(dev, 0x16); /* Aux volume */
+       stk1160_dbg("0x16 == 0x%04x", value);
+
+       value = stk1160_read_ac97(dev, 0x1a); /* Record select */
+       stk1160_dbg("0x1a == 0x%04x", value);
+
+       value = stk1160_read_ac97(dev, 0x02); /* Master volume */
+       stk1160_dbg("0x02 == 0x%04x", value);
+
+       value = stk1160_read_ac97(dev, 0x1c); /* Record gain */
+       stk1160_dbg("0x1c == 0x%04x", value);
 }
+#endif
+
+static int stk1160_has_audio(struct stk1160 *dev)
+{
+       u8 value;
 
-static struct snd_ac97_bus_ops stk1160_ac97_ops = {
-       .read   = stk1160_read_ac97,
-       .write  = stk1160_write_ac97,
-       .reset  = stk1160_reset_ac97,
-};
+       stk1160_read_reg(dev, STK1160_POSV_L, &value);
+       return !(value & STK1160_POSV_L_ACDOUT);
+}
 
-int stk1160_ac97_register(struct stk1160 *dev)
+static int stk1160_has_ac97(struct stk1160 *dev)
 {
-       struct snd_card *card = NULL;
-       struct snd_ac97_bus *ac97_bus;
-       struct snd_ac97_template ac97_template;
-       int rc;
-
-       /*
-        * Just want a card to access ac96 controls,
-        * the actual capture interface will be handled by snd-usb-audio
-        */
-       rc = snd_card_new(dev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
-                         THIS_MODULE, 0, &card);
-       if (rc < 0)
-               return rc;
-
-       /* TODO: I'm not sure where should I get these names :-( */
-       snprintf(card->shortname, sizeof(card->shortname),
-                "stk1160-mixer");
-       snprintf(card->longname, sizeof(card->longname),
-                "stk1160 ac97 codec mixer control");
-       strlcpy(card->driver, dev->dev->driver->name, sizeof(card->driver));
-
-       rc = snd_ac97_bus(card, 0, &stk1160_ac97_ops, NULL, &ac97_bus);
-       if (rc)
-               goto err;
-
-       /* We must set private_data before calling snd_ac97_mixer */
-       memset(&ac97_template, 0, sizeof(ac97_template));
-       ac97_template.private_data = dev;
-       ac97_template.scaps = AC97_SCAP_SKIP_MODEM;
-       rc = snd_ac97_mixer(ac97_bus, &ac97_template, &stk1160_ac97);
-       if (rc)
-               goto err;
-
-       dev->snd_card = card;
-       rc = snd_card_register(card);
-       if (rc)
-               goto err;
-
-       return 0;
-
-err:
-       dev->snd_card = NULL;
-       snd_card_free(card);
-       return rc;
+       u8 value;
+
+       stk1160_read_reg(dev, STK1160_POSV_L, &value);
+       return !(value & STK1160_POSV_L_ACSYNC);
 }
 
-int stk1160_ac97_unregister(struct stk1160 *dev)
+void stk1160_ac97_setup(struct stk1160 *dev)
 {
-       struct snd_card *card = dev->snd_card;
+       if (!stk1160_has_audio(dev)) {
+               stk1160_info("Device doesn't support audio, skipping AC97 setup.");
+               return;
+       }
 
-       /*
-        * We need to check usb_device,
-        * because ac97 release attempts to communicate with codec
-        */
-       if (card && dev->udev)
-               snd_card_free(card);
+       if (!stk1160_has_ac97(dev)) {
+               stk1160_info("Device uses internal 8-bit ADC, skipping AC97 setup.");
+               return;
+       }
 
-       return 0;
+       /* Two-step reset AC97 interface and hardware codec */
+       stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x94);
+       stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x8c);
+
+       /* Set 16-bit audio data and choose L&R channel*/
+       stk1160_write_reg(dev, STK1160_AC97CTL_1 + 2, 0x01);
+       stk1160_write_reg(dev, STK1160_AC97CTL_1 + 3, 0x00);
+
+       /* Setup channels */
+       stk1160_write_ac97(dev, 0x12, 0x8808); /* CD volume */
+       stk1160_write_ac97(dev, 0x10, 0x0808); /* Line-in volume */
+       stk1160_write_ac97(dev, 0x0e, 0x0008); /* MIC volume (mono) */
+       stk1160_write_ac97(dev, 0x16, 0x0808); /* Aux volume */
+       stk1160_write_ac97(dev, 0x1a, 0x0404); /* Record select */
+       stk1160_write_ac97(dev, 0x02, 0x0000); /* Master volume */
+       stk1160_write_ac97(dev, 0x1c, 0x0808); /* Record gain */
+
+#ifdef DEBUG
+       stk1160_ac97_dump_regs(dev);
+#endif
 }
index bc029478065a0f9c029dd024fca1ef4c0b6788fe..c86eb61647138b394a3c22c7e62b354f1f1df378 100644 (file)
@@ -20,8 +20,7 @@
  *
  * TODO:
  *
- * 1. (Try to) detect if we must register ac97 mixer
- * 2. Support stream at lower speed: lower frame rate or lower frame size.
+ * 1. Support stream at lower speed: lower frame rate or lower frame size.
  *
  */
 
@@ -373,7 +372,7 @@ static int stk1160_probe(struct usb_interface *interface,
        /* select default input */
        stk1160_select_input(dev);
 
-       stk1160_ac97_register(dev);
+       stk1160_ac97_setup(dev);
 
        rc = stk1160_video_register(dev);
        if (rc < 0)
@@ -411,9 +410,6 @@ static void stk1160_disconnect(struct usb_interface *interface)
        /* Here is the only place where isoc get released */
        stk1160_uninit_isoc(dev);
 
-       /* ac97 unregister needs to be done before usb_device is cleared */
-       stk1160_ac97_unregister(dev);
-
        stk1160_clear_queue(dev);
 
        video_unregister_device(&dev->vdev);
index 81ff3a15d96ee413bef207e6cc42325702578a47..7b08a3cc45047c986af1e74d271232b8cd99787e 100644 (file)
 /* Remote Wakup Control */
 #define STK1160_RMCTL                  0x00c
 
+/* Power-on Strapping Data */
+#define STK1160_POSVA                  0x010
+#define STK1160_POSV_L                 0x010
+#define STK1160_POSV_M                 0x011
+#define STK1160_POSV_H                 0x012
+#define  STK1160_POSV_L_ACDOUT         BIT(3)
+#define  STK1160_POSV_L_ACSYNC         BIT(2)
+
 /*
  * Decoder Control Register:
  * This byte controls capture start/stop
 /* AC97 Audio Control */
 #define STK1160_AC97CTL_0              0x500
 #define STK1160_AC97CTL_1              0x504
+#define  STK1160_AC97CTL_0_CR          BIT(1)
+#define  STK1160_AC97CTL_0_CW          BIT(2)
 
 /* Use [0:6] bits of register 0x504 to set codec command address */
 #define STK1160_AC97_ADDR              0x504
index 1ed1cc43cdb268106fee45fdcb61b63fefe02ae0..acd1c811db08a12a9baa9912b8784ea12bae533f 100644 (file)
@@ -50,6 +50,8 @@
 #define STK1160_MAX_INPUT 4
 #define STK1160_SVIDEO_INPUT 4
 
+#define STK1160_AC97_TIMEOUT 50
+
 #define STK1160_I2C_TIMEOUT 100
 
 /* TODO: Print helpers
@@ -197,11 +199,4 @@ int stk1160_read_reg_req_len(struct stk1160 *dev, u8 req, u16 reg,
 void stk1160_select_input(struct stk1160 *dev);
 
 /* Provided by stk1160-ac97.c */
-#ifdef CONFIG_VIDEO_STK1160_AC97
-int stk1160_ac97_register(struct stk1160 *dev);
-int stk1160_ac97_unregister(struct stk1160 *dev);
-#else
-static inline int stk1160_ac97_register(struct stk1160 *dev) { return 0; }
-static inline int stk1160_ac97_unregister(struct stk1160 *dev) { return 0; }
-#endif
-
+void stk1160_ac97_setup(struct stk1160 *dev);
index fbccbb2eed9f4accaf8644c961573542eda2ece2..985af9933c7e093a1d4017d04cb52861b6212992 100644 (file)
  * but WITHOUT 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.
  */
 
 /* Controlling the sensor via the STK1125 vendor specific control interface:
index a212248bc2a3294f8bb915c47b5c12a973587234..6e7fc36b658f9b09786240f98046792c4ebca2a5 100644 (file)
  * but WITHOUT 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
  */
 
 #include <linux/module.h>
index 92bb48e3c74e249a5171938a492eb36aa6b7bf4e..0284120ce246b011cd1d4272091dd9039cc2dbe6 100644 (file)
  * but WITHOUT 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 STKWEBCAM_H
index 8902ee36bc942049d019b545a1c876b674111d79..b293dea6554f568f3f46dd1318987f87c06f18cd 100644 (file)
  *  but WITHOUT 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/init.h>
index 8d104e5c4be3cac6e2095d6a2b76e6577807e579..8c265bd80faa7c7e6f4951ba510cd4924e1cb0e0 100644 (file)
  *  but WITHOUT 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/module.h>
index 70dbaec1219e11e739b08467e575b5d6f6846153..097ac321b7e1e35f1d89bd18456ab1d501a20773 100644 (file)
  *  but WITHOUT 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/kernel.h>
index b01d3ee56e770f8b4d8feca78faf8fa017ca9f88..cbcc1472f1c75d477c4c965f4bdecbadc2e25192 100644 (file)
  *  but WITHOUT 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/module.h>
index 26b2ebb62547d24de91e60452491fc582f476325..4afd4655d562883a58c4e1bc2b7fa0dbe58f0b58 100644 (file)
  *  but WITHOUT 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/module.h>
@@ -39,7 +35,7 @@ MODULE_PARM_DESC(enable_ir, "enable ir (default is enable)");
 
 static unsigned int ir_clock_mhz = 12;
 module_param(ir_clock_mhz, int, 0644);
-MODULE_PARM_DESC(enable_ir, "ir clock, in MHz");
+MODULE_PARM_DESC(ir_clock_mhz, "ir clock, in MHz");
 
 #define URB_SUBMIT_DELAY       100     /* ms - Delay to submit an URB request on retrial and init */
 #define URB_INT_LED_DELAY      100     /* ms - Delay to turn led on again on int mode */
@@ -429,7 +425,7 @@ int tm6000_ir_init(struct tm6000_core *dev)
                return 0;
 
        ir = kzalloc(sizeof(*ir), GFP_ATOMIC);
-       rc = rc_allocate_device();
+       rc = rc_allocate_device(RC_DRIVER_SCANCODE);
        if (!ir || !rc)
                goto out;
 
@@ -456,7 +452,6 @@ int tm6000_ir_init(struct tm6000_core *dev)
                ir->polling = 50;
                INIT_DELAYED_WORK(&ir->work, tm6000_ir_handle_key);
        }
-       rc->driver_type = RC_DRIVER_SCANCODE;
 
        snprintf(ir->name, sizeof(ir->name), "tm5600/60x0 IR (%s)",
                                                dev->name);
index a38c251ed57bbe89443158d851052761cc5eb60e..ab3fb74c476c5d19b8bf5a6cef838ea1e387ad7e 100644 (file)
  *  but WITHOUT 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.
  */
 
 /*
index 4064a5e8fae1bf1526632f070156b06e210072f4..aa43810d17f97b04a48c29d75b011600a6d0797b 100644 (file)
  *  but WITHOUT 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/module.h>
index 99d15a55aa03ae3049320d2b468b14b7dd0a874d..6a13a27c55d7ec785a1673f6b32cb2caf51b8814 100644 (file)
  *  but WITHOUT 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/videodev2.h>
index d9f3fa5db8dd7c1997c570dcd22ed99080e61dad..c4fdc1fa32ef2df170f10339978dba8ea5f288ee 100644 (file)
  *  but WITHOUT 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/module.h>
@@ -1375,8 +1371,11 @@ static int __tm6000_open(struct file *file)
 
        /* initialize hardware on analog mode */
        rc = tm6000_init_analog_mode(dev);
-       if (rc < 0)
+       if (rc < 0) {
+               v4l2_fh_exit(&fh->fh);
+               kfree(fh);
                return rc;
+       }
 
        dev->mode = TM6000_MODE_ANALOG;
 
index f2127944776fb2a4fc91458599d4738d1804c620..7ec478d75f55e57001e1b4100ac9cd32f670c860 100644 (file)
  *  but WITHOUT 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/videodev2.h>
index fc0219f1b7df76ed2307bf1d0bb3ef40136617a2..01c7e6d4481c54567d77bd966f56d2ea87506b66 100644 (file)
  * 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/list.h>
index 2d9444905fdb381061cf5c856521115cef623133..09693caa15e2c3633449f645bd91e6cab170f88f 100644 (file)
  * 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 "dvb_frontend.h"
index 15ccc3d1a20e3bf332005e03a10c4db6655c348a..5aff58c1b075da0584175bbababa78e79df845b0 100644 (file)
  * 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 TTUSBDECFE_H
index d3b6d3dfaa09d2c8a1c76ad7544a6e133b6224e8..8135614f395a93565b21e77a0f9fab46432a00ba 100644 (file)
@@ -757,6 +757,12 @@ static int usbtv_s_ctrl(struct v4l2_ctrl *ctrl)
                        data[1] = -ctrl->val & 0xff;
                }
                break;
+       case V4L2_CID_SHARPNESS:
+               index = USBTV_BASE + 0x0239;
+               data[0] = 0;
+               data[1] = ctrl->val;
+               size = 2;
+               break;
        default:
                kfree(data);
                return -EINVAL;
@@ -825,6 +831,8 @@ int usbtv_video_init(struct usbtv *usbtv)
                        V4L2_CID_SATURATION, 0, 0x3ff, 1, 0x200);
        v4l2_ctrl_new_std(&usbtv->ctrl, &usbtv_ctrl_ops,
                        V4L2_CID_HUE, -0xdff, 0xdff, 1, 0x000);
+       v4l2_ctrl_new_std(&usbtv->ctrl, &usbtv_ctrl_ops,
+                       V4L2_CID_SHARPNESS, 0x0, 0xff, 1, 0x60);
        ret = usbtv->ctrl.error;
        if (ret < 0) {
                dev_warn(usbtv->dev, "Could not initialize controls\n");
index 3103d0d020e814e70a82d38a0f9d1b3fa12341c3..fc2418b9f37cf81a35ba159a085bd5bf399bb6e1 100644 (file)
  * but WITHOUT 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.
  */
 
 
index bf041a9e69dbb65f7149df5050b1c9930fb4cbb4..3f87fbc80be29823e0bae8f9cc9c7107a2c9a49d 100644 (file)
  * but WITHOUT 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/kernel.h>
@@ -1417,8 +1413,6 @@ static void usbvision_ctrl_urb_complete(struct urb *urb)
 
        PDEBUG(DBG_IRQ, "");
        usbvision->ctrl_urb_busy = 0;
-       if (waitqueue_active(&usbvision->ctrl_urb_wq))
-               wake_up_interruptible(&usbvision->ctrl_urb_wq);
 }
 
 
index 120de2e020e1f31ae0b8ef2bf3c50bea1de691dd..5a3f788ad033772f13d641a6357b93639721cdf3 100644 (file)
  * but WITHOUT 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.
  */
 
 
index a7529196c327f8d8ad016ae7b46d68340cba81b4..f5c635a67d74427707e0f44703d6a75f85de9519 100644 (file)
  * 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.
- *
  * Let's call the version 0.... until compression decoding is completely
  * implemented.
  *
@@ -1340,7 +1336,6 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev,
        usbvision->ctrl_urb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL);
        if (usbvision->ctrl_urb == NULL)
                goto err_unreg;
-       init_waitqueue_head(&usbvision->ctrl_urb_wq);
 
        return usbvision;
 
index 4f2e4fde38f24fe2b7b4aec1ba00460b3e658d3a..6ecdcd58248f195cd4a2c7e43b62f93d8857170a 100644 (file)
  * but WITHOUT 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.
  */
 
 
@@ -370,7 +366,6 @@ struct usb_usbvision {
        unsigned char ctrl_urb_buffer[8];
        int ctrl_urb_busy;
        struct usb_ctrlrequest ctrl_urb_setup;
-       wait_queue_head_t ctrl_urb_wq;                                  /* Processes waiting */
 
        /* configuration part */
        int have_tuner;
index 14561a5abb793df434e40bbaa29a5db7d43e5e9c..368f8f8dfcb5c5917e63fbf1cf25bb80f1d4ed50 100644 (file)
@@ -75,14 +75,14 @@ static const struct file_operations uvc_debugfs_stats_fops = {
 
 static struct dentry *uvc_debugfs_root_dir;
 
-int uvc_debugfs_init_stream(struct uvc_streaming *stream)
+void uvc_debugfs_init_stream(struct uvc_streaming *stream)
 {
        struct usb_device *udev = stream->dev->udev;
        struct dentry *dent;
        char dir_name[32];
 
        if (uvc_debugfs_root_dir == NULL)
-               return -ENODEV;
+               return;
 
        sprintf(dir_name, "%u-%u", udev->bus->busnum, udev->devnum);
 
@@ -90,7 +90,7 @@ int uvc_debugfs_init_stream(struct uvc_streaming *stream)
        if (IS_ERR_OR_NULL(dent)) {
                uvc_printk(KERN_INFO, "Unable to create debugfs %s "
                           "directory.\n", dir_name);
-               return -ENODEV;
+               return;
        }
 
        stream->debugfs_dir = dent;
@@ -100,10 +100,8 @@ int uvc_debugfs_init_stream(struct uvc_streaming *stream)
        if (IS_ERR_OR_NULL(dent)) {
                uvc_printk(KERN_INFO, "Unable to create debugfs stats file.\n");
                uvc_debugfs_cleanup_stream(stream);
-               return -ENODEV;
+               return;
        }
-
-       return 0;
 }
 
 void uvc_debugfs_cleanup_stream(struct uvc_streaming *stream)
@@ -115,18 +113,17 @@ void uvc_debugfs_cleanup_stream(struct uvc_streaming *stream)
        stream->debugfs_dir = NULL;
 }
 
-int uvc_debugfs_init(void)
+void uvc_debugfs_init(void)
 {
        struct dentry *dir;
 
        dir = debugfs_create_dir("uvcvideo", usb_debug_root);
        if (IS_ERR_OR_NULL(dir)) {
                uvc_printk(KERN_INFO, "Unable to create debugfs directory\n");
-               return -ENODATA;
+               return;
        }
 
        uvc_debugfs_root_dir = dir;
-       return 0;
 }
 
 void uvc_debugfs_cleanup(void)
index 77edd206d3452b71460326e970a62c10b62708df..aa2199775cb8f37061c021ae0ed3198bfc199f43 100644 (file)
@@ -43,6 +43,11 @@ uvc_queue_to_stream(struct uvc_video_queue *queue)
        return container_of(queue, struct uvc_streaming, queue);
 }
 
+static inline struct uvc_buffer *uvc_vbuf_to_buffer(struct vb2_v4l2_buffer *buf)
+{
+       return container_of(buf, struct uvc_buffer, buf);
+}
+
 /*
  * Return all queued buffers to videobuf2 in the requested state.
  *
@@ -89,7 +94,7 @@ static int uvc_buffer_prepare(struct vb2_buffer *vb)
 {
        struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
        struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
-       struct uvc_buffer *buf = container_of(vbuf, struct uvc_buffer, buf);
+       struct uvc_buffer *buf = uvc_vbuf_to_buffer(vbuf);
 
        if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
            vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) {
@@ -116,7 +121,7 @@ static void uvc_buffer_queue(struct vb2_buffer *vb)
 {
        struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
        struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
-       struct uvc_buffer *buf = container_of(vbuf, struct uvc_buffer, buf);
+       struct uvc_buffer *buf = uvc_vbuf_to_buffer(vbuf);
        unsigned long flags;
 
        spin_lock_irqsave(&queue->irqlock, flags);
@@ -138,7 +143,7 @@ static void uvc_buffer_finish(struct vb2_buffer *vb)
        struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
        struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
        struct uvc_streaming *stream = uvc_queue_to_stream(queue);
-       struct uvc_buffer *buf = container_of(vbuf, struct uvc_buffer, buf);
+       struct uvc_buffer *buf = uvc_vbuf_to_buffer(vbuf);
 
        if (vb->state == VB2_BUF_STATE_DONE)
                uvc_video_clock_update(stream, vbuf, buf);
@@ -412,7 +417,7 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
                nextbuf = NULL;
        spin_unlock_irqrestore(&queue->irqlock, flags);
 
-       buf->state = buf->error ? VB2_BUF_STATE_ERROR : UVC_BUF_STATE_DONE;
+       buf->state = buf->error ? UVC_BUF_STATE_ERROR : UVC_BUF_STATE_DONE;
        vb2_set_plane_payload(&buf->buf.vb2_buf, 0, buf->bytesused);
        vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_DONE);
 
index f3c1c852e401ad3b5e834b971008faa3ed403d69..07a6c833ef7b8bf1920937fb0c508f3a7942b9b9 100644 (file)
@@ -1262,8 +1262,7 @@ static void uvc_video_decode_bulk(struct urb *urb, struct uvc_streaming *stream,
                        uvc_video_decode_end(stream, buf, stream->bulk.header,
                                stream->bulk.payload_size);
                        if (buf->state == UVC_BUF_STATE_READY)
-                               buf = uvc_queue_next_buffer(&stream->queue,
-                                                           buf);
+                               uvc_queue_next_buffer(&stream->queue, buf);
                }
 
                stream->bulk.header_size = 0;
index 3d6cc62f3cd2e6ffbec0f0d7d6e15be65d260a5b..4205e7a423f0fed13473559ea503e35dd1a69771 100644 (file)
@@ -757,9 +757,9 @@ void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream,
                struct uvc_buffer *buf);
 
 /* debugfs and statistics */
-int uvc_debugfs_init(void);
+void uvc_debugfs_init(void);
 void uvc_debugfs_cleanup(void);
-int uvc_debugfs_init_stream(struct uvc_streaming *stream);
+void uvc_debugfs_init_stream(struct uvc_streaming *stream);
 void uvc_debugfs_cleanup_stream(struct uvc_streaming *stream);
 
 size_t uvc_video_stats_dump(struct uvc_streaming *stream, char *buf,
index 3950708cbb328e1adf648c02c1e967aff8ceae5d..f2d6fc03dda03ef000404fc68dba7d40ec20ab48 100644 (file)
  * but WITHOUT 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
  */
 
 
index 5bada202b2d38c264cbcd87022278d699e411a40..96cc733f35ef72b0f8280f8ff30e0beaedf6d222 100644 (file)
@@ -42,7 +42,8 @@ static bool match_devname(struct v4l2_subdev *sd,
 
 static bool match_of(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
 {
-       return sd->of_node == asd->match.of.node;
+       return !of_node_cmp(of_node_full_name(sd->of_node),
+                           of_node_full_name(asd->match.of.node));
 }
 
 static bool match_custom(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
@@ -99,18 +100,11 @@ static int v4l2_async_test_notify(struct v4l2_async_notifier *notifier,
 {
        int ret;
 
-       /* Remove from the waiting list */
-       list_del(&asd->list);
-       sd->asd = asd;
-       sd->notifier = notifier;
-
        if (notifier->bound) {
                ret = notifier->bound(notifier, sd, asd);
                if (ret < 0)
                        return ret;
        }
-       /* Move from the global subdevice list to notifier's done */
-       list_move(&sd->async_list, &notifier->done);
 
        ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
        if (ret < 0) {
@@ -119,6 +113,14 @@ static int v4l2_async_test_notify(struct v4l2_async_notifier *notifier,
                return ret;
        }
 
+       /* Remove from the waiting list */
+       list_del(&asd->list);
+       sd->asd = asd;
+       sd->notifier = notifier;
+
+       /* Move from the global subdevice list to notifier's done */
+       list_move(&sd->async_list, &notifier->done);
+
        if (list_empty(&notifier->waiting) && notifier->complete)
                return notifier->complete(notifier);
 
@@ -168,9 +170,6 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
 
        mutex_lock(&list_lock);
 
-       /* Keep also completed notifiers on the list */
-       list_add(&notifier->list, &notifier_list);
-
        list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
                int ret;
 
@@ -185,6 +184,9 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
                }
        }
 
+       /* Keep also completed notifiers on the list */
+       list_add(&notifier->list, &notifier_list);
+
        mutex_unlock(&list_lock);
 
        return 0;
@@ -202,7 +204,7 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
        if (!notifier->v4l2_dev)
                return;
 
-       dev = kmalloc(n_subdev * sizeof(*dev), GFP_KERNEL);
+       dev = kmalloc_array(n_subdev, sizeof(*dev), GFP_KERNEL);
        if (!dev) {
                dev_err(notifier->v4l2_dev->dev,
                        "Failed to allocate device cache!\n");
index 47001e25fd9eeade8ec028c51f2d2482f633db98..b9e08e3d6e0e7d52deeed2d8d9d2d51f6622659c 100644 (file)
@@ -3367,6 +3367,9 @@ static void v4l2_ctrl_del_event(struct v4l2_subscribed_event *sev)
 {
        struct v4l2_ctrl *ctrl = v4l2_ctrl_find(sev->fh->ctrl_handler, sev->id);
 
+       if (ctrl == NULL)
+               return;
+
        v4l2_ctrl_lock(ctrl);
        list_del(&sev->node);
        v4l2_ctrl_unlock(ctrl);
index 62bbed76dbbc401bda8413ec94cc5cf4d065f5de..f364cc1b521dcd65919cb8a548e3f3d18acf6880 100644 (file)
@@ -253,6 +253,7 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)
                        kfree(vdev);
                        goto clean_up;
                }
+               sd->devnode = vdev;
 #if defined(CONFIG_MEDIA_CONTROLLER)
                sd->entity.info.dev.major = VIDEO_MAJOR;
                sd->entity.info.dev.minor = vdev->minor;
@@ -270,7 +271,6 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)
                        }
                }
 #endif
-               sd->devnode = vdev;
        }
        return 0;
 
index 8d3171c6bee8e5be0d5f06d1e104151b4ee06485..a75df6cb141fdf1466baa323507da29d28e78617 100644 (file)
  * WITHOUT 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 St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #include <media/v4l2-dev.h>
index c183f0996fa1ce3b394b4bd2cb700574842e7e80..3895999bf8805c3c208a4f042cb59b786a6ec44c 100644 (file)
  * WITHOUT 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 St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #include <linux/bitops.h>
index 8bef4331bd511261acacf1b58acbeb56749a90ff..303980b71aae26f2a750c2f1bfe96ebe1046148e 100644 (file)
@@ -198,14 +198,20 @@ EXPORT_SYMBOL_GPL(v4l2_mc_create_media_graph);
 int v4l_enable_media_source(struct video_device *vdev)
 {
        struct media_device *mdev = vdev->entity.graph_obj.mdev;
-       int ret;
+       int ret = 0, err;
 
-       if (!mdev || !mdev->enable_source)
+       if (!mdev)
                return 0;
-       ret = mdev->enable_source(&vdev->entity, &vdev->pipe);
-       if (ret)
-               return -EBUSY;
-       return 0;
+
+       mutex_lock(&mdev->graph_mutex);
+       if (!mdev->enable_source)
+               goto end;
+       err = mdev->enable_source(&vdev->entity, &vdev->pipe);
+       if (err)
+               ret = -EBUSY;
+end:
+       mutex_unlock(&mdev->graph_mutex);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(v4l_enable_media_source);
 
@@ -213,8 +219,12 @@ void v4l_disable_media_source(struct video_device *vdev)
 {
        struct media_device *mdev = vdev->entity.graph_obj.mdev;
 
-       if (mdev && mdev->disable_source)
-               mdev->disable_source(&vdev->entity);
+       if (mdev) {
+               mutex_lock(&mdev->graph_mutex);
+               if (mdev->disable_source)
+                       mdev->disable_source(&vdev->entity);
+               mutex_unlock(&mdev->graph_mutex);
+       }
 }
 EXPORT_SYMBOL_GPL(v4l_disable_media_source);
 
@@ -256,13 +266,13 @@ EXPORT_SYMBOL_GPL(v4l_vb2q_enable_media_source);
  * Return the total number of users of all video device nodes in the pipeline.
  */
 static int pipeline_pm_use_count(struct media_entity *entity,
-       struct media_entity_graph *graph)
+       struct media_graph *graph)
 {
        int use = 0;
 
-       media_entity_graph_walk_start(graph, entity);
+       media_graph_walk_start(graph, entity);
 
-       while ((entity = media_entity_graph_walk_next(graph))) {
+       while ((entity = media_graph_walk_next(graph))) {
                if (is_media_entity_v4l2_video_device(entity))
                        use += entity->use_count;
        }
@@ -315,7 +325,7 @@ static int pipeline_pm_power_one(struct media_entity *entity, int change)
  * Return 0 on success or a negative error code on failure.
  */
 static int pipeline_pm_power(struct media_entity *entity, int change,
-       struct media_entity_graph *graph)
+       struct media_graph *graph)
 {
        struct media_entity *first = entity;
        int ret = 0;
@@ -323,18 +333,18 @@ static int pipeline_pm_power(struct media_entity *entity, int change,
        if (!change)
                return 0;
 
-       media_entity_graph_walk_start(graph, entity);
+       media_graph_walk_start(graph, entity);
 
-       while (!ret && (entity = media_entity_graph_walk_next(graph)))
+       while (!ret && (entity = media_graph_walk_next(graph)))
                if (is_media_entity_v4l2_subdev(entity))
                        ret = pipeline_pm_power_one(entity, change);
 
        if (!ret)
                return ret;
 
-       media_entity_graph_walk_start(graph, first);
+       media_graph_walk_start(graph, first);
 
-       while ((first = media_entity_graph_walk_next(graph))
+       while ((first = media_graph_walk_next(graph))
               && first != entity)
                if (is_media_entity_v4l2_subdev(first))
                        pipeline_pm_power_one(first, -change);
@@ -368,7 +378,7 @@ EXPORT_SYMBOL_GPL(v4l2_pipeline_pm_use);
 int v4l2_pipeline_link_notify(struct media_link *link, u32 flags,
                              unsigned int notification)
 {
-       struct media_entity_graph *graph = &link->graph_obj.mdev->pm_count_walk;
+       struct media_graph *graph = &link->graph_obj.mdev->pm_count_walk;
        struct media_entity *source = link->source->entity;
        struct media_entity *sink = link->sink->entity;
        int source_use;
index 93b33681776ca427703dee8bbf6616cca95d7938..4f59f442dd0a64c9003873f11c0658d2e258eb6b 100644 (file)
@@ -26,7 +26,7 @@ static int v4l2_of_parse_csi_bus(const struct device_node *node,
        struct v4l2_of_bus_mipi_csi2 *bus = &endpoint->bus.mipi_csi2;
        struct property *prop;
        bool have_clk_lane = false;
-       unsigned int flags = 0;
+       unsigned int flags = 0, lanes_used = 0;
        u32 v;
 
        prop = of_find_property(node, "data-lanes", NULL);
@@ -38,6 +38,12 @@ static int v4l2_of_parse_csi_bus(const struct device_node *node,
                        lane = of_prop_next_u32(prop, lane, &v);
                        if (!lane)
                                break;
+
+                       if (lanes_used & BIT(v))
+                               pr_warn("%s: duplicated lane %u in data-lanes\n",
+                                       node->full_name, v);
+                       lanes_used |= BIT(v);
+
                        bus->data_lanes[i] = v;
                }
                bus->num_data_lanes = i;
@@ -63,6 +69,11 @@ static int v4l2_of_parse_csi_bus(const struct device_node *node,
        }
 
        if (!of_property_read_u32(node, "clock-lanes", &v)) {
+               if (lanes_used & BIT(v))
+                       pr_warn("%s: duplicated lane %u in clock-lanes\n",
+                               node->full_name, v);
+               lanes_used |= BIT(v);
+
                bus->clock_lane = v;
                have_clk_lane = true;
        }
index 34a1e7c8b3069e87626dd77db89c659a54c67a56..da78497ae5ed2f0944a20c9992eaa4265917b175 100644 (file)
  * but WITHOUT 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
  */
 
 #include <linux/ioctl.h>
index f3512404bc5282955b383f06e1b9c72bdbf7c1c1..99e651c27fb7add156fad3d53af4c702fe750cc3 100644 (file)
@@ -2000,16 +2000,6 @@ static int msb_bd_getgeo(struct block_device *bdev,
        return 0;
 }
 
-static int msb_prepare_req(struct request_queue *q, struct request *req)
-{
-       if (req->cmd_type != REQ_TYPE_FS) {
-               blk_dump_rq_flags(req, "MS unsupported request");
-               return BLKPREP_KILL;
-       }
-       req->rq_flags |= RQF_DONTPREP;
-       return BLKPREP_OK;
-}
-
 static void msb_submit_req(struct request_queue *q)
 {
        struct memstick_dev *card = q->queuedata;
@@ -2132,7 +2122,6 @@ static int msb_init_disk(struct memstick_dev *card)
        }
 
        msb->queue->queuedata = card;
-       blk_queue_prep_rq(msb->queue, msb_prepare_req);
 
        blk_queue_bounce_limit(msb->queue, limit);
        blk_queue_max_hw_sectors(msb->queue, MS_BLOCK_MAX_PAGES);
index fa0746d182ff50c23189dabd22fe82a2287bd671..c00d8a266878035cafa9bc6570ca73d67b1da372 100644 (file)
@@ -827,18 +827,6 @@ static void mspro_block_start(struct memstick_dev *card)
        spin_unlock_irqrestore(&msb->q_lock, flags);
 }
 
-static int mspro_block_prepare_req(struct request_queue *q, struct request *req)
-{
-       if (req->cmd_type != REQ_TYPE_FS) {
-               blk_dump_rq_flags(req, "MSPro unsupported request");
-               return BLKPREP_KILL;
-       }
-
-       req->rq_flags |= RQF_DONTPREP;
-
-       return BLKPREP_OK;
-}
-
 static void mspro_block_submit_req(struct request_queue *q)
 {
        struct memstick_dev *card = q->queuedata;
@@ -1228,7 +1216,6 @@ static int mspro_block_init_disk(struct memstick_dev *card)
        }
 
        msb->queue->queuedata = card;
-       blk_queue_prep_rq(msb->queue, mspro_block_prepare_req);
 
        blk_queue_bounce_limit(msb->queue, limit);
        blk_queue_max_hw_sectors(msb->queue, MSPRO_BLOCK_MAX_PAGES);
index add6a3a6ef0de994ebf5405dd1c426e6eb1f294e..98eafae785762ea73329f1f794784bc0e1ecbc64 100644 (file)
@@ -119,6 +119,7 @@ static struct scsi_host_template mptfc_driver_template = {
        .target_destroy                 = mptfc_target_destroy,
        .slave_destroy                  = mptscsih_slave_destroy,
        .change_queue_depth             = mptscsih_change_queue_depth,
+       .eh_timed_out                   = fc_eh_timed_out,
        .eh_abort_handler               = mptfc_abort,
        .eh_device_reset_handler        = mptfc_dev_reset,
        .eh_bus_reset_handler           = mptfc_bus_reset,
index 8946e19dbfc82107c958e5f36008d42485ec7e1d..8a24494f8c4dba1d164d4bd8731b4001edc86223 100644 (file)
@@ -65,7 +65,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
-#include <linux/miscdevice.h>
 #include <linux/spinlock.h>
 #include <linux/workqueue.h>
 #include <linux/delay.h>
index 7ee1667acde44b69fd309e5fe9835ed679bd6791..f6308ad35b19774d64fcdd008466ac458a185f61 100644 (file)
@@ -1983,6 +1983,7 @@ static struct scsi_host_template mptsas_driver_template = {
        .target_destroy                 = mptsas_target_destroy,
        .slave_destroy                  = mptscsih_slave_destroy,
        .change_queue_depth             = mptscsih_change_queue_depth,
+       .eh_timed_out                   = mptsas_eh_timed_out,
        .eh_abort_handler               = mptscsih_abort,
        .eh_device_reset_handler        = mptscsih_dev_reset,
        .eh_host_reset_handler          = mptscsih_host_reset,
@@ -2320,10 +2321,10 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
                SmpPassthroughReply_t *smprep;
 
                smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
-               memcpy(req->sense, smprep, sizeof(*smprep));
-               req->sense_len = sizeof(*smprep);
-               req->resid_len = 0;
-               rsp->resid_len -= smprep->ResponseDataLength;
+               memcpy(scsi_req(req)->sense, smprep, sizeof(*smprep));
+               scsi_req(req)->sense_len = sizeof(*smprep);
+               scsi_req(req)->resid_len = 0;
+               scsi_req(rsp)->resid_len -= smprep->ResponseDataLength;
        } else {
                printk(MYIOC_s_ERR_FMT
                    "%s: smp passthru reply failed to be returned\n",
@@ -5398,7 +5399,6 @@ mptsas_init(void)
            sas_attach_transport(&mptsas_transport_functions);
        if (!mptsas_transport_template)
                return -ENODEV;
-       mptsas_transport_template->eh_timed_out = mptsas_eh_timed_out;
 
        mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER,
            "mptscsih_io_done");
index cdfa8520a4b16be2a177294fc5b705755fc21e19..fc1ecdaaa9cac024ee8f006b91cf2a01e1549807 100644 (file)
@@ -12,6 +12,16 @@ config PWRSEQ_EMMC
          This driver can also be built as a module. If so, the module
          will be called pwrseq_emmc.
 
+config PWRSEQ_SD8787
+       tristate "HW reset support for SD8787 BT + Wifi module"
+       depends on OF && (MWIFIEX || BT_MRVL_SDIO)
+       help
+         This selects hardware reset support for the SD8787 BT + Wifi
+         module. By default this option is set to n.
+
+         This driver can also be built as a module. If so, the module
+         will be called pwrseq_sd8787.
+
 config PWRSEQ_SIMPLE
        tristate "Simple HW reset support for MMC"
        default y
index b2a257dc644f4cec9822193271de24bf1ec41b42..7e3ed1aeada2b59d6e3db2b9189d985d9a2cc958 100644 (file)
@@ -7,9 +7,10 @@ mmc_core-y                     := core.o bus.o host.o \
                                   mmc.o mmc_ops.o sd.o sd_ops.o \
                                   sdio.o sdio_ops.o sdio_bus.o \
                                   sdio_cis.o sdio_io.o sdio_irq.o \
-                                  quirks.o slot-gpio.o
+                                  slot-gpio.o
 mmc_core-$(CONFIG_OF)          += pwrseq.o
 obj-$(CONFIG_PWRSEQ_SIMPLE)    += pwrseq_simple.o
+obj-$(CONFIG_PWRSEQ_SD8787)    += pwrseq_sd8787.o
 obj-$(CONFIG_PWRSEQ_EMMC)      += pwrseq_emmc.o
 mmc_core-$(CONFIG_DEBUG_FS)    += debugfs.o
 obj-$(CONFIG_MMC_BLOCK)                += mmc_block.o
index cb1698f268f19023429df520713f20a3de6f6d25..1621fa08e2069298f6a8438c8babdf11ae4a817c 100644 (file)
 
 #include "queue.h"
 #include "block.h"
+#include "core.h"
+#include "card.h"
+#include "host.h"
+#include "bus.h"
+#include "mmc_ops.h"
+#include "quirks.h"
+#include "sd_ops.h"
 
 MODULE_ALIAS("mmc:block");
 #ifdef MODULE_PARAM_PREFIX
@@ -54,12 +61,6 @@ MODULE_ALIAS("mmc:block");
 #endif
 #define MODULE_PARAM_PREFIX "mmcblk."
 
-#define INAND_CMD38_ARG_EXT_CSD  113
-#define INAND_CMD38_ARG_ERASE    0x00
-#define INAND_CMD38_ARG_TRIM     0x01
-#define INAND_CMD38_ARG_SECERASE 0x80
-#define INAND_CMD38_ARG_SECTRIM1 0x81
-#define INAND_CMD38_ARG_SECTRIM2 0x88
 #define MMC_BLK_TIMEOUT_MS  (10 * 60 * 1000)        /* 10 minute timeout */
 #define MMC_SANITIZE_REQ_TIMEOUT 240000
 #define MMC_EXTRACT_INDEX_FROM_ARG(x) ((x & 0x00FF0000) >> 16)
@@ -84,7 +85,6 @@ static int max_devices;
 #define MAX_DEVICES 256
 
 static DEFINE_IDA(mmc_blk_ida);
-static DEFINE_SPINLOCK(mmc_blk_lock);
 
 /*
  * There is one mmc_blk_data per slot.
@@ -157,11 +157,7 @@ static void mmc_blk_put(struct mmc_blk_data *md)
        if (md->usage == 0) {
                int devidx = mmc_get_devidx(md->disk);
                blk_cleanup_queue(md->queue.queue);
-
-               spin_lock(&mmc_blk_lock);
-               ida_remove(&mmc_blk_ida, devidx);
-               spin_unlock(&mmc_blk_lock);
-
+               ida_simple_remove(&mmc_blk_ida, devidx);
                put_disk(md->disk);
                kfree(md);
        }
@@ -442,9 +438,9 @@ out:
 static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
                               struct mmc_blk_ioc_data *idata)
 {
-       struct mmc_command cmd = {0};
-       struct mmc_data data = {0};
-       struct mmc_request mrq = {NULL};
+       struct mmc_command cmd = {};
+       struct mmc_data data = {};
+       struct mmc_request mrq = {};
        struct scatterlist sg;
        int err;
        int is_rpmb = false;
@@ -762,15 +758,15 @@ static inline int mmc_blk_part_switch(struct mmc_card *card,
        return 0;
 }
 
-static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
+static int mmc_sd_num_wr_blocks(struct mmc_card *card, u32 *written_blocks)
 {
        int err;
        u32 result;
        __be32 *blocks;
 
-       struct mmc_request mrq = {NULL};
-       struct mmc_command cmd = {0};
-       struct mmc_data data = {0};
+       struct mmc_request mrq = {};
+       struct mmc_command cmd = {};
+       struct mmc_data data = {};
 
        struct scatterlist sg;
 
@@ -780,9 +776,9 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
 
        err = mmc_wait_for_cmd(card->host, &cmd, 0);
        if (err)
-               return (u32)-1;
+               return err;
        if (!mmc_host_is_spi(card->host) && !(cmd.resp[0] & R1_APP_CMD))
-               return (u32)-1;
+               return -EIO;
 
        memset(&cmd, 0, sizeof(struct mmc_command));
 
@@ -802,7 +798,7 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
 
        blocks = kmalloc(4, GFP_KERNEL);
        if (!blocks)
-               return (u32)-1;
+               return -ENOMEM;
 
        sg_init_one(&sg, blocks, 4);
 
@@ -812,14 +808,16 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
        kfree(blocks);
 
        if (cmd.error || data.error)
-               result = (u32)-1;
+               return -EIO;
+
+       *written_blocks = result;
 
-       return result;
+       return 0;
 }
 
 static int get_card_status(struct mmc_card *card, u32 *status, int retries)
 {
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
        int err;
 
        cmd.opcode = MMC_SEND_STATUS;
@@ -884,7 +882,7 @@ static int send_stop(struct mmc_card *card, unsigned int timeout_ms,
                struct request *req, bool *gen_err, u32 *stop_status)
 {
        struct mmc_host *host = card->host;
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
        int err;
        bool use_r1b_resp = rq_data_dir(req) == WRITE;
 
@@ -1143,7 +1141,7 @@ int mmc_access_rpmb(struct mmc_queue *mq)
        return false;
 }
 
-static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
+static void mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
 {
        struct mmc_blk_data *md = mq->blkdata;
        struct mmc_card *card = md->queue.card;
@@ -1152,7 +1150,7 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
 
        if (!mmc_can_erase(card)) {
                err = -EOPNOTSUPP;
-               goto out;
+               goto fail;
        }
 
        from = blk_rq_pos(req);
@@ -1164,29 +1162,26 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
                arg = MMC_TRIM_ARG;
        else
                arg = MMC_ERASE_ARG;
-retry:
-       if (card->quirks & MMC_QUIRK_INAND_CMD38) {
-               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                                INAND_CMD38_ARG_EXT_CSD,
-                                arg == MMC_TRIM_ARG ?
-                                INAND_CMD38_ARG_TRIM :
-                                INAND_CMD38_ARG_ERASE,
-                                0);
-               if (err)
-                       goto out;
-       }
-       err = mmc_erase(card, from, nr, arg);
-out:
-       if (err == -EIO && !mmc_blk_reset(md, card->host, type))
-               goto retry;
+       do {
+               err = 0;
+               if (card->quirks & MMC_QUIRK_INAND_CMD38) {
+                       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                                        INAND_CMD38_ARG_EXT_CSD,
+                                        arg == MMC_TRIM_ARG ?
+                                        INAND_CMD38_ARG_TRIM :
+                                        INAND_CMD38_ARG_ERASE,
+                                        0);
+               }
+               if (!err)
+                       err = mmc_erase(card, from, nr, arg);
+       } while (err == -EIO && !mmc_blk_reset(md, card->host, type));
        if (!err)
                mmc_blk_reset_success(md, type);
+fail:
        blk_end_request(req, err, blk_rq_bytes(req));
-
-       return err ? 0 : 1;
 }
 
-static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
+static void mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
                                       struct request *req)
 {
        struct mmc_blk_data *md = mq->blkdata;
@@ -1249,11 +1244,9 @@ out_retry:
                mmc_blk_reset_success(md, type);
 out:
        blk_end_request(req, err, blk_rq_bytes(req));
-
-       return err ? 0 : 1;
 }
 
-static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
+static void mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
 {
        struct mmc_blk_data *md = mq->blkdata;
        struct mmc_card *card = md->queue.card;
@@ -1264,8 +1257,6 @@ static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
                ret = -EIO;
 
        blk_end_request_all(req, ret);
-
-       return ret ? 0 : 1;
 }
 
 /*
@@ -1303,7 +1294,7 @@ static enum mmc_blk_status mmc_blk_err_check(struct mmc_card *card,
                                             struct mmc_async_req *areq)
 {
        struct mmc_queue_req *mq_mrq = container_of(areq, struct mmc_queue_req,
-                                                   mmc_active);
+                                                   areq);
        struct mmc_blk_request *brq = &mq_mrq->brq;
        struct request *req = mq_mrq->req;
        int need_retune = card->host->need_retune;
@@ -1559,17 +1550,19 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
                brq->data.sg_len = i;
        }
 
-       mqrq->mmc_active.mrq = &brq->mrq;
-       mqrq->mmc_active.err_check = mmc_blk_err_check;
+       mqrq->areq.mrq = &brq->mrq;
+       mqrq->areq.err_check = mmc_blk_err_check;
 
        mmc_queue_bounce_pre(mqrq);
 }
 
-static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card,
-                          struct mmc_blk_request *brq, struct request *req,
-                          int ret)
+static bool mmc_blk_rw_cmd_err(struct mmc_blk_data *md, struct mmc_card *card,
+                              struct mmc_blk_request *brq, struct request *req,
+                              bool old_req_pending)
 {
        struct mmc_queue_req *mq_rq;
+       bool req_pending;
+
        mq_rq = container_of(brq, struct mmc_queue_req, brq);
 
        /*
@@ -1582,62 +1575,104 @@ static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card,
         */
        if (mmc_card_sd(card)) {
                u32 blocks;
+               int err;
 
-               blocks = mmc_sd_num_wr_blocks(card);
-               if (blocks != (u32)-1) {
-                       ret = blk_end_request(req, 0, blocks << 9);
-               }
+               err = mmc_sd_num_wr_blocks(card, &blocks);
+               if (err)
+                       req_pending = old_req_pending;
+               else
+                       req_pending = blk_end_request(req, 0, blocks << 9);
        } else {
-               ret = blk_end_request(req, 0, brq->data.bytes_xfered);
+               req_pending = blk_end_request(req, 0, brq->data.bytes_xfered);
        }
-       return ret;
+       return req_pending;
+}
+
+static void mmc_blk_rw_cmd_abort(struct mmc_card *card, struct request *req)
+{
+       if (mmc_card_removed(card))
+               req->rq_flags |= RQF_QUIET;
+       while (blk_end_request(req, -EIO, blk_rq_cur_bytes(req)));
+}
+
+/**
+ * mmc_blk_rw_try_restart() - tries to restart the current async request
+ * @mq: the queue with the card and host to restart
+ * @req: a new request that want to be started after the current one
+ */
+static void mmc_blk_rw_try_restart(struct mmc_queue *mq, struct request *req)
+{
+       if (!req)
+               return;
+
+       /*
+        * If the card was removed, just cancel everything and return.
+        */
+       if (mmc_card_removed(mq->card)) {
+               req->rq_flags |= RQF_QUIET;
+               blk_end_request_all(req, -EIO);
+               return;
+       }
+       /* Else proceed and try to restart the current async request */
+       mmc_blk_rw_rq_prep(mq->mqrq_cur, mq->card, 0, mq);
+       mmc_start_areq(mq->card->host, &mq->mqrq_cur->areq, NULL);
 }
 
-static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
+static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req)
 {
        struct mmc_blk_data *md = mq->blkdata;
        struct mmc_card *card = md->queue.card;
        struct mmc_blk_request *brq;
-       int ret = 1, disable_multi = 0, retry = 0, type, retune_retry_done = 0;
+       int disable_multi = 0, retry = 0, type, retune_retry_done = 0;
        enum mmc_blk_status status;
        struct mmc_queue_req *mq_rq;
-       struct request *req;
-       struct mmc_async_req *areq;
+       struct request *old_req;
+       struct mmc_async_req *new_areq;
+       struct mmc_async_req *old_areq;
+       bool req_pending = true;
 
-       if (!rqc && !mq->mqrq_prev->req)
-               return 0;
+       if (!new_req && !mq->mqrq_prev->req)
+               return;
 
        do {
-               if (rqc) {
+               if (new_req) {
                        /*
                         * When 4KB native sector is enabled, only 8 blocks
                         * multiple read or write is allowed
                         */
                        if (mmc_large_sector(card) &&
-                               !IS_ALIGNED(blk_rq_sectors(rqc), 8)) {
+                               !IS_ALIGNED(blk_rq_sectors(new_req), 8)) {
                                pr_err("%s: Transfer size is not 4KB sector size aligned\n",
-                                       rqc->rq_disk->disk_name);
-                               mq_rq = mq->mqrq_cur;
-                               req = rqc;
-                               rqc = NULL;
-                               goto cmd_abort;
+                                       new_req->rq_disk->disk_name);
+                               mmc_blk_rw_cmd_abort(card, new_req);
+                               return;
                        }
 
                        mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
-                       areq = &mq->mqrq_cur->mmc_active;
+                       new_areq = &mq->mqrq_cur->areq;
                } else
-                       areq = NULL;
-               areq = mmc_start_req(card->host, areq, &status);
-               if (!areq) {
+                       new_areq = NULL;
+
+               old_areq = mmc_start_areq(card->host, new_areq, &status);
+               if (!old_areq) {
+                       /*
+                        * We have just put the first request into the pipeline
+                        * and there is nothing more to do until it is
+                        * complete.
+                        */
                        if (status == MMC_BLK_NEW_REQUEST)
-                               mq->flags |= MMC_QUEUE_NEW_REQUEST;
-                       return 0;
+                               mq->new_request = true;
+                       return;
                }
 
-               mq_rq = container_of(areq, struct mmc_queue_req, mmc_active);
+               /*
+                * An asynchronous request has been completed and we proceed
+                * to handle the result of it.
+                */
+               mq_rq = container_of(old_areq, struct mmc_queue_req, areq);
                brq = &mq_rq->brq;
-               req = mq_rq->req;
-               type = rq_data_dir(req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE;
+               old_req = mq_rq->req;
+               type = rq_data_dir(old_req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE;
                mmc_queue_bounce_post(mq_rq);
 
                switch (status) {
@@ -1648,28 +1683,32 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
                         */
                        mmc_blk_reset_success(md, type);
 
-                       ret = blk_end_request(req, 0,
-                                       brq->data.bytes_xfered);
-
+                       req_pending = blk_end_request(old_req, 0,
+                                                     brq->data.bytes_xfered);
                        /*
                         * If the blk_end_request function returns non-zero even
                         * though all data has been transferred and no errors
                         * were returned by the host controller, it's a bug.
                         */
-                       if (status == MMC_BLK_SUCCESS && ret) {
+                       if (status == MMC_BLK_SUCCESS && req_pending) {
                                pr_err("%s BUG rq_tot %d d_xfer %d\n",
-                                      __func__, blk_rq_bytes(req),
+                                      __func__, blk_rq_bytes(old_req),
                                       brq->data.bytes_xfered);
-                               rqc = NULL;
-                               goto cmd_abort;
+                               mmc_blk_rw_cmd_abort(card, old_req);
+                               return;
                        }
                        break;
                case MMC_BLK_CMD_ERR:
-                       ret = mmc_blk_cmd_err(md, card, brq, req, ret);
-                       if (mmc_blk_reset(md, card->host, type))
-                               goto cmd_abort;
-                       if (!ret)
-                               goto start_new_req;
+                       req_pending = mmc_blk_rw_cmd_err(md, card, brq, old_req, req_pending);
+                       if (mmc_blk_reset(md, card->host, type)) {
+                               mmc_blk_rw_cmd_abort(card, old_req);
+                               mmc_blk_rw_try_restart(mq, new_req);
+                               return;
+                       }
+                       if (!req_pending) {
+                               mmc_blk_rw_try_restart(mq, new_req);
+                               return;
+                       }
                        break;
                case MMC_BLK_RETRY:
                        retune_retry_done = brq->retune_retry_done;
@@ -1679,22 +1718,27 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
                case MMC_BLK_ABORT:
                        if (!mmc_blk_reset(md, card->host, type))
                                break;
-                       goto cmd_abort;
+                       mmc_blk_rw_cmd_abort(card, old_req);
+                       mmc_blk_rw_try_restart(mq, new_req);
+                       return;
                case MMC_BLK_DATA_ERR: {
                        int err;
 
                        err = mmc_blk_reset(md, card->host, type);
                        if (!err)
                                break;
-                       if (err == -ENODEV)
-                               goto cmd_abort;
+                       if (err == -ENODEV) {
+                               mmc_blk_rw_cmd_abort(card, old_req);
+                               mmc_blk_rw_try_restart(mq, new_req);
+                               return;
+                       }
                        /* Fall through */
                }
                case MMC_BLK_ECC_ERR:
                        if (brq->data.blocks > 1) {
                                /* Redo read one sector at a time */
                                pr_warn("%s: retrying using single block read\n",
-                                       req->rq_disk->disk_name);
+                                       old_req->rq_disk->disk_name);
                                disable_multi = 1;
                                break;
                        }
@@ -1703,57 +1747,40 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
                         * time, so we only reach here after trying to
                         * read a single sector.
                         */
-                       ret = blk_end_request(req, -EIO,
-                                               brq->data.blksz);
-                       if (!ret)
-                               goto start_new_req;
+                       req_pending = blk_end_request(old_req, -EIO,
+                                                     brq->data.blksz);
+                       if (!req_pending) {
+                               mmc_blk_rw_try_restart(mq, new_req);
+                               return;
+                       }
                        break;
                case MMC_BLK_NOMEDIUM:
-                       goto cmd_abort;
+                       mmc_blk_rw_cmd_abort(card, old_req);
+                       mmc_blk_rw_try_restart(mq, new_req);
+                       return;
                default:
                        pr_err("%s: Unhandled return value (%d)",
-                                       req->rq_disk->disk_name, status);
-                       goto cmd_abort;
+                                       old_req->rq_disk->disk_name, status);
+                       mmc_blk_rw_cmd_abort(card, old_req);
+                       mmc_blk_rw_try_restart(mq, new_req);
+                       return;
                }
 
-               if (ret) {
+               if (req_pending) {
                        /*
                         * In case of a incomplete request
                         * prepare it again and resend.
                         */
                        mmc_blk_rw_rq_prep(mq_rq, card,
                                        disable_multi, mq);
-                       mmc_start_req(card->host,
-                                       &mq_rq->mmc_active, NULL);
+                       mmc_start_areq(card->host,
+                                       &mq_rq->areq, NULL);
                        mq_rq->brq.retune_retry_done = retune_retry_done;
                }
-       } while (ret);
-
-       return 1;
-
- cmd_abort:
-       if (mmc_card_removed(card))
-               req->rq_flags |= RQF_QUIET;
-       while (ret)
-               ret = blk_end_request(req, -EIO,
-                               blk_rq_cur_bytes(req));
-
- start_new_req:
-       if (rqc) {
-               if (mmc_card_removed(card)) {
-                       rqc->rq_flags |= RQF_QUIET;
-                       blk_end_request_all(rqc, -EIO);
-               } else {
-                       mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
-                       mmc_start_req(card->host,
-                                     &mq->mqrq_cur->mmc_active, NULL);
-               }
-       }
-
-       return 0;
+       } while (req_pending);
 }
 
-int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
+void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 {
        int ret;
        struct mmc_blk_data *md = mq->blkdata;
@@ -1769,32 +1796,31 @@ int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
                if (req) {
                        blk_end_request_all(req, -EIO);
                }
-               ret = 0;
                goto out;
        }
 
-       mq->flags &= ~MMC_QUEUE_NEW_REQUEST;
+       mq->new_request = false;
        if (req && req_op(req) == REQ_OP_DISCARD) {
                /* complete ongoing async transfer before issuing discard */
                if (card->host->areq)
                        mmc_blk_issue_rw_rq(mq, NULL);
-               ret = mmc_blk_issue_discard_rq(mq, req);
+               mmc_blk_issue_discard_rq(mq, req);
        } else if (req && req_op(req) == REQ_OP_SECURE_ERASE) {
                /* complete ongoing async transfer before issuing secure erase*/
                if (card->host->areq)
                        mmc_blk_issue_rw_rq(mq, NULL);
-               ret = mmc_blk_issue_secdiscard_rq(mq, req);
+               mmc_blk_issue_secdiscard_rq(mq, req);
        } else if (req && req_op(req) == REQ_OP_FLUSH) {
                /* complete ongoing async transfer before issuing flush */
                if (card->host->areq)
                        mmc_blk_issue_rw_rq(mq, NULL);
-               ret = mmc_blk_issue_flush(mq, req);
+               mmc_blk_issue_flush(mq, req);
        } else {
-               ret = mmc_blk_issue_rw_rq(mq, req);
+               mmc_blk_issue_rw_rq(mq, req);
        }
 
 out:
-       if ((!req && !(mq->flags & MMC_QUEUE_NEW_REQUEST)) || req_is_special)
+       if ((!req && !mq->new_request) || req_is_special)
                /*
                 * Release host when there are no more requests
                 * and after special request(discard, flush) is done.
@@ -1802,7 +1828,6 @@ out:
                 * the 'mmc_blk_issue_rq' with 'mqrq_prev->req'.
                 */
                mmc_put_card(card);
-       return ret;
 }
 
 static inline int mmc_blk_readonly(struct mmc_card *card)
@@ -1821,23 +1846,9 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
        struct mmc_blk_data *md;
        int devidx, ret;
 
-again:
-       if (!ida_pre_get(&mmc_blk_ida, GFP_KERNEL))
-               return ERR_PTR(-ENOMEM);
-
-       spin_lock(&mmc_blk_lock);
-       ret = ida_get_new(&mmc_blk_ida, &devidx);
-       spin_unlock(&mmc_blk_lock);
-
-       if (ret == -EAGAIN)
-               goto again;
-       else if (ret)
-               return ERR_PTR(ret);
-
-       if (devidx >= max_devices) {
-               ret = -ENOSPC;
-               goto out;
-       }
+       devidx = ida_simple_get(&mmc_blk_ida, 0, max_devices, GFP_KERNEL);
+       if (devidx < 0)
+               return ERR_PTR(devidx);
 
        md = kzalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
        if (!md) {
@@ -1926,9 +1937,7 @@ again:
  err_kfree:
        kfree(md);
  out:
-       spin_lock(&mmc_blk_lock);
-       ida_remove(&mmc_blk_ida, devidx);
-       spin_unlock(&mmc_blk_lock);
+       ida_simple_remove(&mmc_blk_ida, devidx);
        return ERR_PTR(ret);
 }
 
@@ -2093,80 +2102,6 @@ force_ro_fail:
        return ret;
 }
 
-static const struct mmc_fixup blk_fixups[] =
-{
-       MMC_FIXUP("SEM02G", CID_MANFID_SANDISK, 0x100, add_quirk,
-                 MMC_QUIRK_INAND_CMD38),
-       MMC_FIXUP("SEM04G", CID_MANFID_SANDISK, 0x100, add_quirk,
-                 MMC_QUIRK_INAND_CMD38),
-       MMC_FIXUP("SEM08G", CID_MANFID_SANDISK, 0x100, add_quirk,
-                 MMC_QUIRK_INAND_CMD38),
-       MMC_FIXUP("SEM16G", CID_MANFID_SANDISK, 0x100, add_quirk,
-                 MMC_QUIRK_INAND_CMD38),
-       MMC_FIXUP("SEM32G", CID_MANFID_SANDISK, 0x100, add_quirk,
-                 MMC_QUIRK_INAND_CMD38),
-
-       /*
-        * Some MMC cards experience performance degradation with CMD23
-        * instead of CMD12-bounded multiblock transfers. For now we'll
-        * black list what's bad...
-        * - Certain Toshiba cards.
-        *
-        * N.B. This doesn't affect SD cards.
-        */
-       MMC_FIXUP("SDMB-32", CID_MANFID_SANDISK, CID_OEMID_ANY, add_quirk_mmc,
-                 MMC_QUIRK_BLK_NO_CMD23),
-       MMC_FIXUP("SDM032", CID_MANFID_SANDISK, CID_OEMID_ANY, add_quirk_mmc,
-                 MMC_QUIRK_BLK_NO_CMD23),
-       MMC_FIXUP("MMC08G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
-                 MMC_QUIRK_BLK_NO_CMD23),
-       MMC_FIXUP("MMC16G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
-                 MMC_QUIRK_BLK_NO_CMD23),
-       MMC_FIXUP("MMC32G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
-                 MMC_QUIRK_BLK_NO_CMD23),
-
-       /*
-        * Some MMC cards need longer data read timeout than indicated in CSD.
-        */
-       MMC_FIXUP(CID_NAME_ANY, CID_MANFID_MICRON, 0x200, add_quirk_mmc,
-                 MMC_QUIRK_LONG_READ_TIME),
-       MMC_FIXUP("008GE0", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
-                 MMC_QUIRK_LONG_READ_TIME),
-
-       /*
-        * On these Samsung MoviNAND parts, performing secure erase or
-        * secure trim can result in unrecoverable corruption due to a
-        * firmware bug.
-        */
-       MMC_FIXUP("M8G2FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
-                 MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
-       MMC_FIXUP("MAG4FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
-                 MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
-       MMC_FIXUP("MBG8FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
-                 MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
-       MMC_FIXUP("MCGAFA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
-                 MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
-       MMC_FIXUP("VAL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
-                 MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
-       MMC_FIXUP("VYL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
-                 MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
-       MMC_FIXUP("KYL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
-                 MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
-       MMC_FIXUP("VZL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
-                 MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
-
-       /*
-        *  On Some Kingston eMMCs, performing trim can result in
-        *  unrecoverable data conrruption occasionally due to a firmware bug.
-        */
-       MMC_FIXUP("V10008", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc,
-                 MMC_QUIRK_TRIM_BROKEN),
-       MMC_FIXUP("V10016", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc,
-                 MMC_QUIRK_TRIM_BROKEN),
-
-       END_FIXUP
-};
-
 static int mmc_blk_probe(struct mmc_card *card)
 {
        struct mmc_blk_data *md, *part_md;
@@ -2178,7 +2113,7 @@ static int mmc_blk_probe(struct mmc_card *card)
        if (!(card->csd.cmdclass & CCC_BLOCK_READ))
                return -ENODEV;
 
-       mmc_fixup_device(card, blk_fixups);
+       mmc_fixup_device(card, mmc_blk_fixups);
 
        md = mmc_blk_alloc(card);
        if (IS_ERR(md))
index cdabb2ee74be9498a30ec04b918fe6197dab9fd8..860ca7c8df8602cefd3daeeaa39026f5644b511a 100644 (file)
@@ -1 +1,9 @@
-int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req);
+#ifndef _MMC_CORE_BLOCK_H
+#define _MMC_CORE_BLOCK_H
+
+struct mmc_queue;
+struct request;
+
+void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req);
+
+#endif
index c64266f5a399b3c6ee2535d2b8539460a75ed5e2..301246513a3709dfa73b9d07d2daab900252e5ba 100644 (file)
@@ -23,6 +23,8 @@
 #include <linux/mmc/host.h>
 
 #include "core.h"
+#include "card.h"
+#include "host.h"
 #include "sdio_cis.h"
 #include "bus.h"
 
index 00a19710b6b449500b613c316c8b167977ba9cb9..72b0ef03f10a2e28a8e88e607a47227aee844186 100644 (file)
 #ifndef _MMC_CORE_BUS_H
 #define _MMC_CORE_BUS_H
 
+#include <linux/device.h>
+
+struct mmc_host;
+struct mmc_card;
+
 #define MMC_DEV_ATTR(name, fmt, args...)                                       \
 static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf)        \
 {                                                                              \
@@ -27,5 +32,14 @@ void mmc_remove_card(struct mmc_card *card);
 int mmc_register_bus(void);
 void mmc_unregister_bus(void);
 
-#endif
+struct mmc_driver {
+       struct device_driver drv;
+       int (*probe)(struct mmc_card *card);
+       void (*remove)(struct mmc_card *card);
+       void (*shutdown)(struct mmc_card *card);
+};
 
+int mmc_register_driver(struct mmc_driver *drv);
+void mmc_unregister_driver(struct mmc_driver *drv);
+
+#endif
diff --git a/drivers/mmc/core/card.h b/drivers/mmc/core/card.h
new file mode 100644 (file)
index 0000000..f06cd91
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Private header for the mmc subsystem
+ *
+ * Copyright (C) 2016 Linaro Ltd
+ *
+ * Author: Ulf Hansson <ulf.hansson@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef _MMC_CORE_CARD_H
+#define _MMC_CORE_CARD_H
+
+#include <linux/mmc/card.h>
+
+#define mmc_card_name(c)       ((c)->cid.prod_name)
+#define mmc_card_id(c)         (dev_name(&(c)->dev))
+#define mmc_dev_to_card(d)     container_of(d, struct mmc_card, dev)
+
+/* Card states */
+#define MMC_STATE_PRESENT      (1<<0)          /* present in sysfs */
+#define MMC_STATE_READONLY     (1<<1)          /* card is read-only */
+#define MMC_STATE_BLOCKADDR    (1<<2)          /* card uses block-addressing */
+#define MMC_CARD_SDXC          (1<<3)          /* card is SDXC */
+#define MMC_CARD_REMOVED       (1<<4)          /* card has been removed */
+#define MMC_STATE_DOING_BKOPS  (1<<5)          /* card is doing BKOPS */
+#define MMC_STATE_SUSPENDED    (1<<6)          /* card is suspended */
+
+#define mmc_card_present(c)    ((c)->state & MMC_STATE_PRESENT)
+#define mmc_card_readonly(c)   ((c)->state & MMC_STATE_READONLY)
+#define mmc_card_blockaddr(c)  ((c)->state & MMC_STATE_BLOCKADDR)
+#define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
+#define mmc_card_removed(c)    ((c) && ((c)->state & MMC_CARD_REMOVED))
+#define mmc_card_doing_bkops(c)        ((c)->state & MMC_STATE_DOING_BKOPS)
+#define mmc_card_suspended(c)  ((c)->state & MMC_STATE_SUSPENDED)
+
+#define mmc_card_set_present(c)        ((c)->state |= MMC_STATE_PRESENT)
+#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
+#define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
+#define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
+#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
+#define mmc_card_set_doing_bkops(c)    ((c)->state |= MMC_STATE_DOING_BKOPS)
+#define mmc_card_clr_doing_bkops(c)    ((c)->state &= ~MMC_STATE_DOING_BKOPS)
+#define mmc_card_set_suspended(c) ((c)->state |= MMC_STATE_SUSPENDED)
+#define mmc_card_clr_suspended(c) ((c)->state &= ~MMC_STATE_SUSPENDED)
+
+/*
+ * The world is not perfect and supplies us with broken mmc/sdio devices.
+ * For at least some of these bugs we need a work-around.
+ */
+struct mmc_fixup {
+       /* CID-specific fields. */
+       const char *name;
+
+       /* Valid revision range */
+       u64 rev_start, rev_end;
+
+       unsigned int manfid;
+       unsigned short oemid;
+
+       /* SDIO-specific fields. You can use SDIO_ANY_ID here of course */
+       u16 cis_vendor, cis_device;
+
+       /* for MMC cards */
+       unsigned int ext_csd_rev;
+
+       void (*vendor_fixup)(struct mmc_card *card, int data);
+       int data;
+};
+
+#define CID_MANFID_ANY (-1u)
+#define CID_OEMID_ANY ((unsigned short) -1)
+#define CID_NAME_ANY (NULL)
+
+#define EXT_CSD_REV_ANY (-1u)
+
+#define CID_MANFID_SANDISK      0x2
+#define CID_MANFID_TOSHIBA      0x11
+#define CID_MANFID_MICRON       0x13
+#define CID_MANFID_SAMSUNG      0x15
+#define CID_MANFID_KINGSTON     0x70
+#define CID_MANFID_HYNIX       0x90
+
+#define END_FIXUP { NULL }
+
+#define _FIXUP_EXT(_name, _manfid, _oemid, _rev_start, _rev_end,       \
+                  _cis_vendor, _cis_device,                            \
+                  _fixup, _data, _ext_csd_rev)                         \
+       {                                               \
+               .name = (_name),                        \
+               .manfid = (_manfid),                    \
+               .oemid = (_oemid),                      \
+               .rev_start = (_rev_start),              \
+               .rev_end = (_rev_end),                  \
+               .cis_vendor = (_cis_vendor),            \
+               .cis_device = (_cis_device),            \
+               .vendor_fixup = (_fixup),               \
+               .data = (_data),                        \
+               .ext_csd_rev = (_ext_csd_rev),          \
+       }
+
+#define MMC_FIXUP_REV(_name, _manfid, _oemid, _rev_start, _rev_end,    \
+                     _fixup, _data, _ext_csd_rev)                      \
+       _FIXUP_EXT(_name, _manfid,                                      \
+                  _oemid, _rev_start, _rev_end,                        \
+                  SDIO_ANY_ID, SDIO_ANY_ID,                            \
+                  _fixup, _data, _ext_csd_rev)                         \
+
+#define MMC_FIXUP(_name, _manfid, _oemid, _fixup, _data) \
+       MMC_FIXUP_REV(_name, _manfid, _oemid, 0, -1ull, _fixup, _data,  \
+                     EXT_CSD_REV_ANY)
+
+#define MMC_FIXUP_EXT_CSD_REV(_name, _manfid, _oemid, _fixup, _data,   \
+                             _ext_csd_rev)                             \
+       MMC_FIXUP_REV(_name, _manfid, _oemid, 0, -1ull, _fixup, _data,  \
+                     _ext_csd_rev)
+
+#define SDIO_FIXUP(_vendor, _device, _fixup, _data)                    \
+       _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_ANY,                        \
+                   CID_OEMID_ANY, 0, -1ull,                            \
+                  _vendor, _device,                                    \
+                  _fixup, _data, EXT_CSD_REV_ANY)                      \
+
+#define cid_rev(hwrev, fwrev, year, month)     \
+       (((u64) hwrev) << 40 |                  \
+        ((u64) fwrev) << 32 |                  \
+        ((u64) year) << 16 |                   \
+        ((u64) month))
+
+#define cid_rev_card(card)                     \
+       cid_rev(card->cid.hwrev,                \
+                   card->cid.fwrev,            \
+                   card->cid.year,             \
+                   card->cid.month)
+
+/*
+ * Unconditionally quirk add/remove.
+ */
+static inline void __maybe_unused add_quirk(struct mmc_card *card, int data)
+{
+       card->quirks |= data;
+}
+
+static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
+{
+       card->quirks &= ~data;
+}
+
+/*
+ * Quirk add/remove for MMC products.
+ */
+static inline void __maybe_unused add_quirk_mmc(struct mmc_card *card, int data)
+{
+       if (mmc_card_mmc(card))
+               card->quirks |= data;
+}
+
+static inline void __maybe_unused remove_quirk_mmc(struct mmc_card *card,
+                                                  int data)
+{
+       if (mmc_card_mmc(card))
+               card->quirks &= ~data;
+}
+
+/*
+ * Quirk add/remove for SD products.
+ */
+static inline void __maybe_unused add_quirk_sd(struct mmc_card *card, int data)
+{
+       if (mmc_card_sd(card))
+               card->quirks |= data;
+}
+
+static inline void __maybe_unused remove_quirk_sd(struct mmc_card *card,
+                                                  int data)
+{
+       if (mmc_card_sd(card))
+               card->quirks &= ~data;
+}
+
+static inline int mmc_card_lenient_fn0(const struct mmc_card *c)
+{
+       return c->quirks & MMC_QUIRK_LENIENT_FN0;
+}
+
+static inline int mmc_blksz_for_byte_mode(const struct mmc_card *c)
+{
+       return c->quirks & MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
+}
+
+static inline int mmc_card_disable_cd(const struct mmc_card *c)
+{
+       return c->quirks & MMC_QUIRK_DISABLE_CD;
+}
+
+static inline int mmc_card_nonstd_func_interface(const struct mmc_card *c)
+{
+       return c->quirks & MMC_QUIRK_NONSTD_FUNC_IF;
+}
+
+static inline int mmc_card_broken_byte_mode_512(const struct mmc_card *c)
+{
+       return c->quirks & MMC_QUIRK_BROKEN_BYTE_MODE_512;
+}
+
+static inline int mmc_card_long_read_time(const struct mmc_card *c)
+{
+       return c->quirks & MMC_QUIRK_LONG_READ_TIME;
+}
+
+static inline int mmc_card_broken_irq_polling(const struct mmc_card *c)
+{
+       return c->quirks & MMC_QUIRK_BROKEN_IRQ_POLLING;
+}
+
+static inline int mmc_card_broken_hpi(const struct mmc_card *c)
+{
+       return c->quirks & MMC_QUIRK_BROKEN_HPI;
+}
+
+#endif
index 1076b9d89df38e26bfb088fae3586a6c577fd70e..926e0fde07d75a441f11ade4c10457bd7dde4ad2 100644 (file)
@@ -40,6 +40,7 @@
 #include <trace/events/mmc.h>
 
 #include "core.h"
+#include "card.h"
 #include "bus.h"
 #include "host.h"
 #include "sdio_bus.h"
@@ -630,10 +631,41 @@ static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
 }
 
 /**
- *     mmc_start_req - start a non-blocking request
+ * mmc_finalize_areq() - finalize an asynchronous request
+ * @host: MMC host to finalize any ongoing request on
+ *
+ * Returns the status of the ongoing asynchronous request, but
+ * MMC_BLK_SUCCESS if no request was going on.
+ */
+static enum mmc_blk_status mmc_finalize_areq(struct mmc_host *host)
+{
+       enum mmc_blk_status status;
+
+       if (!host->areq)
+               return MMC_BLK_SUCCESS;
+
+       status = mmc_wait_for_data_req_done(host, host->areq->mrq);
+       if (status == MMC_BLK_NEW_REQUEST)
+               return status;
+
+       /*
+        * Check BKOPS urgency for each R1 response
+        */
+       if (host->card && mmc_card_mmc(host->card) &&
+           ((mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1) ||
+            (mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1B)) &&
+           (host->areq->mrq->cmd->resp[0] & R1_EXCEPTION_EVENT)) {
+               mmc_start_bkops(host->card, true);
+       }
+
+       return status;
+}
+
+/**
+ *     mmc_start_areq - start an asynchronous request
  *     @host: MMC host to start command
- *     @areq: async request to start
- *     @error: out parameter returns 0 for success, otherwise non zero
+ *     @areq: asynchronous request to start
+ *     @ret_stat: out parameter for status
  *
  *     Start a new MMC custom command request for a host.
  *     If there is on ongoing async request wait for completion
@@ -645,11 +677,11 @@ static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
  *     return the completed request. If there is no ongoing request, NULL
  *     is returned without waiting. NULL is not an error condition.
  */
-struct mmc_async_req *mmc_start_req(struct mmc_host *host,
-                                   struct mmc_async_req *areq,
-                                   enum mmc_blk_status *ret_stat)
+struct mmc_async_req *mmc_start_areq(struct mmc_host *host,
+                                    struct mmc_async_req *areq,
+                                    enum mmc_blk_status *ret_stat)
 {
-       enum mmc_blk_status status = MMC_BLK_SUCCESS;
+       enum mmc_blk_status status;
        int start_err = 0;
        struct mmc_async_req *data = host->areq;
 
@@ -657,44 +689,25 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
        if (areq)
                mmc_pre_req(host, areq->mrq);
 
-       if (host->areq) {
-               status = mmc_wait_for_data_req_done(host, host->areq->mrq);
-               if (status == MMC_BLK_NEW_REQUEST) {
-                       if (ret_stat)
-                               *ret_stat = status;
-                       /*
-                        * The previous request was not completed,
-                        * nothing to return
-                        */
-                       return NULL;
-               }
-               /*
-                * Check BKOPS urgency for each R1 response
-                */
-               if (host->card && mmc_card_mmc(host->card) &&
-                   ((mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1) ||
-                    (mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1B)) &&
-                   (host->areq->mrq->cmd->resp[0] & R1_EXCEPTION_EVENT)) {
-
-                       /* Cancel the prepared request */
-                       if (areq)
-                               mmc_post_req(host, areq->mrq, -EINVAL);
-
-                       mmc_start_bkops(host->card, true);
+       /* Finalize previous request */
+       status = mmc_finalize_areq(host);
 
-                       /* prepare the request again */
-                       if (areq)
-                               mmc_pre_req(host, areq->mrq);
-               }
+       /* The previous request is still going on... */
+       if (status == MMC_BLK_NEW_REQUEST) {
+               if (ret_stat)
+                       *ret_stat = status;
+               return NULL;
        }
 
+       /* Fine so far, start the new request! */
        if (status == MMC_BLK_SUCCESS && areq)
                start_err = __mmc_start_data_req(host, areq->mrq);
 
+       /* Postprocess the old request at this point */
        if (host->areq)
                mmc_post_req(host, host->areq->mrq, 0);
 
-        /* Cancel a prepared request if it was not started. */
+       /* Cancel a prepared request if it was not started. */
        if ((status != MMC_BLK_SUCCESS || start_err) && areq)
                mmc_post_req(host, areq->mrq, -EINVAL);
 
@@ -707,7 +720,7 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
                *ret_stat = status;
        return data;
 }
-EXPORT_SYMBOL(mmc_start_req);
+EXPORT_SYMBOL(mmc_start_areq);
 
 /**
  *     mmc_wait_for_req - start a request and wait for completion
@@ -807,7 +820,7 @@ EXPORT_SYMBOL(mmc_interrupt_hpi);
  */
 int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)
 {
-       struct mmc_request mrq = {NULL};
+       struct mmc_request mrq = {};
 
        WARN_ON(!host->claimed);
 
@@ -1630,7 +1643,7 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
        return ocr;
 }
 
-int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
+int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
 {
        int err = 0;
        int old_signal_voltage = host->ios.signal_voltage;
@@ -1646,19 +1659,12 @@ int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
 
 }
 
-int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr)
+int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr)
 {
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
        int err = 0;
        u32 clock;
 
-       /*
-        * Send CMD11 only if the request is to switch the card to
-        * 1.8V signalling.
-        */
-       if (signal_voltage == MMC_SIGNAL_VOLTAGE_330)
-               return __mmc_set_signal_voltage(host, signal_voltage);
-
        /*
         * If we cannot switch voltages, return failure so the caller
         * can continue without UHS mode
@@ -1697,7 +1703,7 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr)
        host->ios.clock = 0;
        mmc_set_ios(host);
 
-       if (__mmc_set_signal_voltage(host, signal_voltage)) {
+       if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180)) {
                /*
                 * Voltages may not have been switched, but we've already
                 * sent CMD11, so a power cycle is required anyway
@@ -1806,11 +1812,11 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
        mmc_set_initial_state(host);
 
        /* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */
-       if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330) == 0)
+       if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330))
                dev_dbg(mmc_dev(host), "Initial signal voltage of 3.3v\n");
-       else if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180) == 0)
+       else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180))
                dev_dbg(mmc_dev(host), "Initial signal voltage of 1.8v\n");
-       else if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120) == 0)
+       else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120))
                dev_dbg(mmc_dev(host), "Initial signal voltage of 1.2v\n");
 
        /*
@@ -2129,7 +2135,7 @@ static unsigned int mmc_erase_timeout(struct mmc_card *card,
 static int mmc_do_erase(struct mmc_card *card, unsigned int from,
                        unsigned int to, unsigned int arg)
 {
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
        unsigned int qty = 0, busy_timeout = 0;
        bool use_r1b_resp = false;
        unsigned long timeout;
@@ -2551,7 +2557,7 @@ EXPORT_SYMBOL(mmc_calc_max_discard);
 
 int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
 {
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
 
        if (mmc_card_blockaddr(card) || mmc_card_ddr52(card) ||
            mmc_card_hs400(card) || mmc_card_hs400es(card))
@@ -2567,7 +2573,7 @@ EXPORT_SYMBOL(mmc_set_blocklen);
 int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount,
                        bool is_rel_write)
 {
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
 
        cmd.opcode = MMC_SET_BLOCK_COUNT;
        cmd.arg = blockcount & 0x0000FFFF;
index 0fa86a2afc265e7224520f22892e12cfc652a2e2..55f543fd37c42dda62e8f9fce78e2e642f282d17 100644 (file)
 #define _MMC_CORE_CORE_H
 
 #include <linux/delay.h>
+#include <linux/sched.h>
+
+struct mmc_host;
+struct mmc_card;
+struct mmc_request;
 
 #define MMC_CMD_RETRIES        3
 
@@ -43,8 +48,8 @@ void mmc_set_clock(struct mmc_host *host, unsigned int hz);
 void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
 void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
 u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
-int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr);
-int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
+int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr);
+int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
 void mmc_set_timing(struct mmc_host *host, unsigned int timing);
 void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
 int mmc_select_drive_strength(struct mmc_card *card, unsigned int max_dtr,
@@ -69,6 +74,7 @@ void mmc_start_host(struct mmc_host *host);
 void mmc_stop_host(struct mmc_host *host);
 
 int _mmc_detect_card_removed(struct mmc_host *host);
+int mmc_detect_card_removed(struct mmc_host *host);
 
 int mmc_attach_mmc(struct mmc_host *host);
 int mmc_attach_sd(struct mmc_host *host);
@@ -98,5 +104,38 @@ static inline void mmc_register_pm_notifier(struct mmc_host *host) { }
 static inline void mmc_unregister_pm_notifier(struct mmc_host *host) { }
 #endif
 
-#endif
+void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq);
+bool mmc_is_req_done(struct mmc_host *host, struct mmc_request *mrq);
+
+int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
+               unsigned int arg);
+int mmc_can_erase(struct mmc_card *card);
+int mmc_can_trim(struct mmc_card *card);
+int mmc_can_discard(struct mmc_card *card);
+int mmc_can_sanitize(struct mmc_card *card);
+int mmc_can_secure_erase_trim(struct mmc_card *card);
+int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
+                       unsigned int nr);
+unsigned int mmc_calc_max_discard(struct mmc_card *card);
+
+int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen);
+int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount,
+                       bool is_rel_write);
+
+int __mmc_claim_host(struct mmc_host *host, atomic_t *abort);
+void mmc_release_host(struct mmc_host *host);
+void mmc_get_card(struct mmc_card *card);
+void mmc_put_card(struct mmc_card *card);
+
+/**
+ *     mmc_claim_host - exclusively claim a host
+ *     @host: mmc host to claim
+ *
+ *     Claim a host for a set of operations.
+ */
+static inline void mmc_claim_host(struct mmc_host *host)
+{
+       __mmc_claim_host(host, NULL);
+}
 
+#endif
index 30623b8b86a42589ed462b5625fd99d546a43b7d..a1fba5732d66b5de5d75035f72dd12dd86463b38 100644 (file)
@@ -20,6 +20,8 @@
 #include <linux/mmc/host.h>
 
 #include "core.h"
+#include "card.h"
+#include "host.h"
 #include "mmc_ops.h"
 
 #ifdef CONFIG_FAIL_MMC_REQUEST
index 98f25ffb42583a1f5c70258fd2f4bd9c55d6f00e..3f8c85d5aa094b43666904c7dbbe5e62c9763c19 100644 (file)
 #define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev)
 
 static DEFINE_IDA(mmc_host_ida);
-static DEFINE_SPINLOCK(mmc_host_lock);
 
 static void mmc_host_classdev_release(struct device *dev)
 {
        struct mmc_host *host = cls_dev_to_mmc_host(dev);
-       spin_lock(&mmc_host_lock);
-       ida_remove(&mmc_host_ida, host->index);
-       spin_unlock(&mmc_host_lock);
+       ida_simple_remove(&mmc_host_ida, host->index);
        kfree(host);
 }
 
@@ -301,6 +298,8 @@ int mmc_of_parse(struct mmc_host *host)
        if (of_property_read_bool(np, "wakeup-source") ||
            of_property_read_bool(np, "enable-sdio-wakeup")) /* legacy */
                host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
+       if (of_property_read_bool(np, "mmc-ddr-3_3v"))
+               host->caps |= MMC_CAP_3_3V_DDR;
        if (of_property_read_bool(np, "mmc-ddr-1_8v"))
                host->caps |= MMC_CAP_1_8V_DDR;
        if (of_property_read_bool(np, "mmc-ddr-1_2v"))
@@ -354,22 +353,13 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
        /* scanning will be enabled when we're ready */
        host->rescan_disable = 1;
 
-again:
-       if (!ida_pre_get(&mmc_host_ida, GFP_KERNEL)) {
+       err = ida_simple_get(&mmc_host_ida, 0, 0, GFP_KERNEL);
+       if (err < 0) {
                kfree(host);
                return NULL;
        }
 
-       spin_lock(&mmc_host_lock);
-       err = ida_get_new(&mmc_host_ida, &host->index);
-       spin_unlock(&mmc_host_lock);
-
-       if (err == -EAGAIN) {
-               goto again;
-       } else if (err) {
-               kfree(host);
-               return NULL;
-       }
+       host->index = err;
 
        dev_set_name(&host->class_dev, "mmc%d", host->index);
 
@@ -381,6 +371,8 @@ again:
 
        if (mmc_gpio_alloc(host)) {
                put_device(&host->class_dev);
+               ida_simple_remove(&mmc_host_ida, host->index);
+               kfree(host);
                return NULL;
        }
 
index 992bf53976337f0edf3f64fe4f9a007f4693b3a6..fb6a76a038330fc9234b062d67854a27e27e9f83 100644 (file)
@@ -10,6 +10,7 @@
  */
 #ifndef _MMC_CORE_HOST_H
 #define _MMC_CORE_HOST_H
+
 #include <linux/mmc/host.h>
 
 int mmc_register_host_class(void);
@@ -20,6 +21,53 @@ void mmc_retune_disable(struct mmc_host *host);
 void mmc_retune_hold(struct mmc_host *host);
 void mmc_retune_release(struct mmc_host *host);
 int mmc_retune(struct mmc_host *host);
+void mmc_retune_pause(struct mmc_host *host);
+void mmc_retune_unpause(struct mmc_host *host);
+
+static inline void mmc_retune_recheck(struct mmc_host *host)
+{
+       if (host->hold_retune <= 1)
+               host->retune_now = 1;
+}
+
+static inline int mmc_host_cmd23(struct mmc_host *host)
+{
+       return host->caps & MMC_CAP_CMD23;
+}
+
+static inline int mmc_boot_partition_access(struct mmc_host *host)
+{
+       return !(host->caps2 & MMC_CAP2_BOOTPART_NOACC);
+}
+
+static inline int mmc_host_uhs(struct mmc_host *host)
+{
+       return host->caps &
+               (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+                MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
+                MMC_CAP_UHS_DDR50);
+}
+
+static inline bool mmc_card_hs200(struct mmc_card *card)
+{
+       return card->host->ios.timing == MMC_TIMING_MMC_HS200;
+}
+
+static inline bool mmc_card_ddr52(struct mmc_card *card)
+{
+       return card->host->ios.timing == MMC_TIMING_MMC_DDR52;
+}
+
+static inline bool mmc_card_hs400(struct mmc_card *card)
+{
+       return card->host->ios.timing == MMC_TIMING_MMC_HS400;
+}
+
+static inline bool mmc_card_hs400es(struct mmc_card *card)
+{
+       return card->host->ios.enhanced_strobe;
+}
+
 
 #endif
 
index 0fccca075e2947337cc999e04438b1c1e2cc056d..7fd722868875f396e3e4e8147774913ab860b0e2 100644 (file)
 #include <linux/mmc/mmc.h>
 
 #include "core.h"
+#include "card.h"
 #include "host.h"
 #include "bus.h"
 #include "mmc_ops.h"
+#include "quirks.h"
 #include "sd_ops.h"
 
 #define DEFAULT_CMD6_TIMEOUT_MS        500
@@ -47,17 +49,6 @@ static const unsigned int tacc_mant[] = {
        35,     40,     45,     50,     55,     60,     70,     80,
 };
 
-static const struct mmc_fixup mmc_ext_csd_fixups[] = {
-       /*
-        * Certain Hynix eMMC 4.41 cards might get broken when HPI feature
-        * is used so disable the HPI feature for such buggy cards.
-        */
-       MMC_FIXUP_EXT_CSD_REV(CID_NAME_ANY, CID_MANFID_HYNIX,
-                             0x014a, add_quirk, MMC_QUIRK_BROKEN_HPI, 5),
-
-       END_FIXUP
-};
-
 #define UNSTUFF_BITS(resp,start,size)                                  \
        ({                                                              \
                const int __size = size;                                \
@@ -212,7 +203,7 @@ static void mmc_select_card_type(struct mmc_card *card)
                avail_type |= EXT_CSD_CARD_TYPE_HS_52;
        }
 
-       if (caps & MMC_CAP_1_8V_DDR &&
+       if (caps & (MMC_CAP_1_8V_DDR | MMC_CAP_3_3V_DDR) &&
            card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) {
                hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
                avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
@@ -307,6 +298,18 @@ static void mmc_manage_enhanced_area(struct mmc_card *card, u8 *ext_csd)
        }
 }
 
+static void mmc_part_add(struct mmc_card *card, unsigned int size,
+                        unsigned int part_cfg, char *name, int idx, bool ro,
+                        int area_type)
+{
+       card->part[card->nr_parts].size = size;
+       card->part[card->nr_parts].part_cfg = part_cfg;
+       sprintf(card->part[card->nr_parts].name, name, idx);
+       card->part[card->nr_parts].force_ro = ro;
+       card->part[card->nr_parts].area_type = area_type;
+       card->nr_parts++;
+}
+
 static void mmc_manage_gp_partitions(struct mmc_card *card, u8 *ext_csd)
 {
        int idx;
@@ -530,8 +533,14 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
                                                EXT_CSD_MANUAL_BKOPS_MASK);
                        card->ext_csd.raw_bkops_status =
                                ext_csd[EXT_CSD_BKOPS_STATUS];
-                       if (!card->ext_csd.man_bkops_en)
-                               pr_debug("%s: MAN_BKOPS_EN bit is not set\n",
+                       if (card->ext_csd.man_bkops_en)
+                               pr_debug("%s: MAN_BKOPS_EN bit is set\n",
+                                       mmc_hostname(card->host));
+                       card->ext_csd.auto_bkops_en =
+                                       (ext_csd[EXT_CSD_BKOPS_EN] &
+                                               EXT_CSD_AUTO_BKOPS_MASK);
+                       if (card->ext_csd.auto_bkops_en)
+                               pr_debug("%s: AUTO_BKOPS_EN bit is set\n",
                                        mmc_hostname(card->host));
                }
 
@@ -617,6 +626,12 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
                card->ext_csd.ffu_capable =
                        (ext_csd[EXT_CSD_SUPPORTED_MODE] & 0x1) &&
                        !(ext_csd[EXT_CSD_FW_CONFIG] & 0x1);
+
+               card->ext_csd.pre_eol_info = ext_csd[EXT_CSD_PRE_EOL_INFO];
+               card->ext_csd.device_life_time_est_typ_a =
+                       ext_csd[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A];
+               card->ext_csd.device_life_time_est_typ_b =
+                       ext_csd[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B];
        }
 
        /* eMMC v5.1 or later */
@@ -764,6 +779,10 @@ MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
 MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name);
 MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid);
 MMC_DEV_ATTR(prv, "0x%x\n", card->cid.prv);
+MMC_DEV_ATTR(pre_eol_info, "%02x\n", card->ext_csd.pre_eol_info);
+MMC_DEV_ATTR(life_time, "0x%02x 0x%02x\n",
+       card->ext_csd.device_life_time_est_typ_a,
+       card->ext_csd.device_life_time_est_typ_b);
 MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial);
 MMC_DEV_ATTR(enhanced_area_offset, "%llu\n",
                card->ext_csd.enhanced_area_offset);
@@ -817,6 +836,8 @@ static struct attribute *mmc_std_attrs[] = {
        &dev_attr_name.attr,
        &dev_attr_oemid.attr,
        &dev_attr_prv.attr,
+       &dev_attr_pre_eol_info.attr,
+       &dev_attr_life_time.attr,
        &dev_attr_serial.attr,
        &dev_attr_enhanced_area_offset.attr,
        &dev_attr_enhanced_area_size.attr,
@@ -1095,16 +1116,19 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
         *
         * WARNING: eMMC rules are NOT the same as SD DDR
         */
-       err = -EINVAL;
-       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
-               err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
+       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
+               err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
+               if (!err)
+                       return 0;
+       }
 
-       if (err && (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_8V))
-               err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
+       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_8V &&
+           host->caps & MMC_CAP_1_8V_DDR)
+               err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
 
        /* make sure vccq is 3.3v after switching disaster */
        if (err)
-               err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330);
+               err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330);
 
        return err;
 }
@@ -1271,10 +1295,10 @@ static int mmc_select_hs400es(struct mmc_card *card)
        }
 
        if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400_1_2V)
-               err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
+               err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
 
        if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400_1_8V)
-               err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
+               err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
 
        /* If fails try again during next card power cycle */
        if (err)
@@ -1380,10 +1404,10 @@ static int mmc_select_hs200(struct mmc_card *card)
 
        old_signal_voltage = host->ios.signal_voltage;
        if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
-               err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
+               err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
 
        if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
-               err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
+               err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
 
        /* If fails try again during next card power cycle */
        if (err)
@@ -1425,7 +1449,7 @@ static int mmc_select_hs200(struct mmc_card *card)
 err:
        if (err) {
                /* fall back to the old signal voltage, if fails report error */
-               if (__mmc_set_signal_voltage(host, old_signal_voltage))
+               if (mmc_set_signal_voltage(host, old_signal_voltage))
                        err = -EIO;
 
                pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
@@ -1805,7 +1829,7 @@ static int mmc_can_sleep(struct mmc_card *card)
 
 static int mmc_sleep(struct mmc_host *host)
 {
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
        struct mmc_card *card = host->card;
        unsigned int timeout_ms = DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000);
        int err;
index e6ea8503f40c8466643db34f6ee36ff19345aa89..fe80f26d69717dd14d357e5563bd6b788e5a5069 100644 (file)
@@ -57,7 +57,7 @@ static const u8 tuning_blk_pattern_8bit[] = {
 int mmc_send_status(struct mmc_card *card, u32 *status)
 {
        int err;
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
 
        cmd.opcode = MMC_SEND_STATUS;
        if (!mmc_host_is_spi(card->host))
@@ -79,7 +79,7 @@ int mmc_send_status(struct mmc_card *card, u32 *status)
 
 static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
 {
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
 
        cmd.opcode = MMC_SELECT_CARD;
 
@@ -115,7 +115,7 @@ int mmc_deselect_cards(struct mmc_host *host)
  */
 int mmc_set_dsr(struct mmc_host *host)
 {
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
 
        cmd.opcode = MMC_SET_DSR;
 
@@ -128,7 +128,7 @@ int mmc_set_dsr(struct mmc_host *host)
 int mmc_go_idle(struct mmc_host *host)
 {
        int err;
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
 
        /*
         * Non-SPI hosts need to prevent chipselect going active during
@@ -164,7 +164,7 @@ int mmc_go_idle(struct mmc_host *host)
 
 int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
 {
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
        int i, err = 0;
 
        cmd.opcode = MMC_SEND_OP_COND;
@@ -203,7 +203,7 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
 int mmc_all_send_cid(struct mmc_host *host, u32 *cid)
 {
        int err;
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
 
        cmd.opcode = MMC_ALL_SEND_CID;
        cmd.arg = 0;
@@ -220,7 +220,7 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid)
 
 int mmc_set_relative_addr(struct mmc_card *card)
 {
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
 
        cmd.opcode = MMC_SET_RELATIVE_ADDR;
        cmd.arg = card->rca << 16;
@@ -233,7 +233,7 @@ static int
 mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode)
 {
        int err;
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
 
        cmd.opcode = opcode;
        cmd.arg = arg;
@@ -256,9 +256,9 @@ static int
 mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
                u32 opcode, void *buf, unsigned len)
 {
-       struct mmc_request mrq = {NULL};
-       struct mmc_command cmd = {0};
-       struct mmc_data data = {0};
+       struct mmc_request mrq = {};
+       struct mmc_command cmd = {};
+       struct mmc_data data = {};
        struct scatterlist sg;
 
        mrq.cmd = &cmd;
@@ -387,7 +387,7 @@ EXPORT_SYMBOL_GPL(mmc_get_ext_csd);
 
 int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp)
 {
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
        int err;
 
        cmd.opcode = MMC_SPI_READ_OCR;
@@ -402,7 +402,7 @@ int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp)
 
 int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
 {
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
        int err;
 
        cmd.opcode = MMC_SPI_CRC_ON_OFF;
@@ -530,7 +530,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
 {
        struct mmc_host *host = card->host;
        int err;
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
        bool use_r1b_resp = use_busy_signal;
        unsigned char old_timing = host->ios.timing;
 
@@ -610,9 +610,9 @@ EXPORT_SYMBOL_GPL(mmc_switch);
 
 int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error)
 {
-       struct mmc_request mrq = {NULL};
-       struct mmc_command cmd = {0};
-       struct mmc_data data = {0};
+       struct mmc_request mrq = {};
+       struct mmc_command cmd = {};
+       struct mmc_data data = {};
        struct scatterlist sg;
        struct mmc_ios *ios = &host->ios;
        const u8 *tuning_block_pattern;
@@ -679,7 +679,7 @@ EXPORT_SYMBOL_GPL(mmc_send_tuning);
 
 int mmc_abort_tuning(struct mmc_host *host, u32 opcode)
 {
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
 
        /*
         * eMMC specification specifies that CMD12 can be used to stop a tuning
@@ -706,9 +706,9 @@ static int
 mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
                  u8 len)
 {
-       struct mmc_request mrq = {NULL};
-       struct mmc_command cmd = {0};
-       struct mmc_data data = {0};
+       struct mmc_request mrq = {};
+       struct mmc_command cmd = {};
+       struct mmc_data data = {};
        struct scatterlist sg;
        u8 *data_buf;
        u8 *test_buf;
@@ -802,7 +802,7 @@ int mmc_bus_test(struct mmc_card *card, u8 bus_width)
 
 int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
 {
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
        unsigned int opcode;
        int err;
 
index abd525ed74be37b4fb3d1a4bdfeb770f835061f4..74beea8a9c7e52e487b40923036cb612bf4322f8 100644 (file)
 #ifndef _MMC_MMC_OPS_H
 #define _MMC_MMC_OPS_H
 
+#include <linux/types.h>
+
+struct mmc_host;
+struct mmc_card;
+
 int mmc_select_card(struct mmc_card *card);
 int mmc_deselect_cards(struct mmc_host *host);
 int mmc_set_dsr(struct mmc_host *host);
@@ -26,12 +31,21 @@ int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
 int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
 int mmc_bus_test(struct mmc_card *card, u8 bus_width);
 int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status);
+int mmc_interrupt_hpi(struct mmc_card *card);
 int mmc_can_ext_csd(struct mmc_card *card);
+int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
 int mmc_switch_status(struct mmc_card *card);
 int __mmc_switch_status(struct mmc_card *card, bool crc_err_fatal);
 int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
                unsigned int timeout_ms, unsigned char timing,
                bool use_busy_signal, bool send_status, bool retry_crc_err);
+int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
+               unsigned int timeout_ms);
+int mmc_stop_bkops(struct mmc_card *card);
+int mmc_read_bkops_status(struct mmc_card *card);
+void mmc_start_bkops(struct mmc_card *card, bool from_exception);
+int mmc_can_reset(struct mmc_card *card);
+int mmc_flush_cache(struct mmc_card *card);
 
 #endif
 
index 3ab6e52d106c6c20b2de00a97badd1a1f0f99b66..f99ac3123fd26dc68fb0a03be8babe7637a39d62 100644 (file)
 #include <linux/seq_file.h>
 #include <linux/module.h>
 
+#include "core.h"
+#include "card.h"
+#include "host.h"
+#include "bus.h"
+
 #define RESULT_OK              0
 #define RESULT_FAIL            1
 #define RESULT_UNSUP_HOST      2
@@ -260,7 +265,7 @@ static int mmc_test_busy(struct mmc_command *cmd)
 static int mmc_test_wait_busy(struct mmc_test_card *test)
 {
        int ret, busy;
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
 
        busy = 0;
        do {
@@ -277,8 +282,7 @@ static int mmc_test_wait_busy(struct mmc_test_card *test)
                if (!busy && mmc_test_busy(&cmd)) {
                        busy = 1;
                        if (test->card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)
-                               pr_info("%s: Warning: Host did not "
-                                       "wait for busy state to end.\n",
+                               pr_info("%s: Warning: Host did not wait for busy state to end.\n",
                                        mmc_hostname(test->card->host));
                }
        } while (mmc_test_busy(&cmd));
@@ -292,10 +296,10 @@ static int mmc_test_wait_busy(struct mmc_test_card *test)
 static int mmc_test_buffer_transfer(struct mmc_test_card *test,
        u8 *buffer, unsigned addr, unsigned blksz, int write)
 {
-       struct mmc_request mrq = {0};
-       struct mmc_command cmd = {0};
-       struct mmc_command stop = {0};
-       struct mmc_data data = {0};
+       struct mmc_request mrq = {};
+       struct mmc_command cmd = {};
+       struct mmc_command stop = {};
+       struct mmc_data data = {};
 
        struct scatterlist sg;
 
@@ -357,12 +361,11 @@ static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz,
        if (max_segs > max_page_cnt)
                max_segs = max_page_cnt;
 
-       mem = kzalloc(sizeof(struct mmc_test_mem), GFP_KERNEL);
+       mem = kzalloc(sizeof(*mem), GFP_KERNEL);
        if (!mem)
                return NULL;
 
-       mem->arr = kzalloc(sizeof(struct mmc_test_pages) * max_segs,
-                          GFP_KERNEL);
+       mem->arr = kcalloc(max_segs, sizeof(*mem->arr), GFP_KERNEL);
        if (!mem->arr)
                goto out_free;
 
@@ -546,7 +549,7 @@ static void mmc_test_save_transfer_result(struct mmc_test_card *test,
        if (!test->gr)
                return;
 
-       tr = kmalloc(sizeof(struct mmc_test_transfer_result), GFP_KERNEL);
+       tr = kmalloc(sizeof(*tr), GFP_KERNEL);
        if (!tr)
                return;
 
@@ -641,11 +644,11 @@ static int __mmc_test_prepare(struct mmc_test_card *test, int write)
        if (write)
                memset(test->buffer, 0xDF, 512);
        else {
-               for (i = 0;i < 512;i++)
+               for (i = 0; i < 512; i++)
                        test->buffer[i] = i;
        }
 
-       for (i = 0;i < BUFFER_SIZE / 512;i++) {
+       for (i = 0; i < BUFFER_SIZE / 512; i++) {
                ret = mmc_test_buffer_transfer(test, test->buffer, i, 512, 1);
                if (ret)
                        return ret;
@@ -674,7 +677,7 @@ static int mmc_test_cleanup(struct mmc_test_card *test)
 
        memset(test->buffer, 0, 512);
 
-       for (i = 0;i < BUFFER_SIZE / 512;i++) {
+       for (i = 0; i < BUFFER_SIZE / 512; i++) {
                ret = mmc_test_buffer_transfer(test, test->buffer, i, 512, 1);
                if (ret)
                        return ret;
@@ -850,7 +853,7 @@ static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
        for (i = 0; i < count; i++) {
                mmc_test_prepare_mrq(test, cur_areq->mrq, sg, sg_len, dev_addr,
                                     blocks, blksz, write);
-               done_areq = mmc_start_req(test->card->host, cur_areq, &status);
+               done_areq = mmc_start_areq(test->card->host, cur_areq, &status);
 
                if (status != MMC_BLK_SUCCESS || (!done_areq && i > 0)) {
                        ret = RESULT_FAIL;
@@ -869,7 +872,7 @@ static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
                dev_addr += blocks;
        }
 
-       done_areq = mmc_start_req(test->card->host, NULL, &status);
+       done_areq = mmc_start_areq(test->card->host, NULL, &status);
        if (status != MMC_BLK_SUCCESS)
                ret = RESULT_FAIL;
 
@@ -885,10 +888,10 @@ static int mmc_test_simple_transfer(struct mmc_test_card *test,
        struct scatterlist *sg, unsigned sg_len, unsigned dev_addr,
        unsigned blocks, unsigned blksz, int write)
 {
-       struct mmc_request mrq = {0};
-       struct mmc_command cmd = {0};
-       struct mmc_command stop = {0};
-       struct mmc_data data = {0};
+       struct mmc_request mrq = {};
+       struct mmc_command cmd = {};
+       struct mmc_command stop = {};
+       struct mmc_data data = {};
 
        mrq.cmd = &cmd;
        mrq.data = &data;
@@ -910,10 +913,10 @@ static int mmc_test_simple_transfer(struct mmc_test_card *test,
 static int mmc_test_broken_transfer(struct mmc_test_card *test,
        unsigned blocks, unsigned blksz, int write)
 {
-       struct mmc_request mrq = {0};
-       struct mmc_command cmd = {0};
-       struct mmc_command stop = {0};
-       struct mmc_data data = {0};
+       struct mmc_request mrq = {};
+       struct mmc_command cmd = {};
+       struct mmc_command stop = {};
+       struct mmc_data data = {};
 
        struct scatterlist sg;
 
@@ -946,7 +949,7 @@ static int mmc_test_transfer(struct mmc_test_card *test,
        unsigned long flags;
 
        if (write) {
-               for (i = 0;i < blocks * blksz;i++)
+               for (i = 0; i < blocks * blksz; i++)
                        test->scratch[i] = i;
        } else {
                memset(test->scratch, 0, BUFFER_SIZE);
@@ -980,7 +983,7 @@ static int mmc_test_transfer(struct mmc_test_card *test,
 
                memset(test->buffer, 0, sectors * 512);
 
-               for (i = 0;i < sectors;i++) {
+               for (i = 0; i < sectors; i++) {
                        ret = mmc_test_buffer_transfer(test,
                                test->buffer + i * 512,
                                dev_addr + i, 512, 0);
@@ -988,12 +991,12 @@ static int mmc_test_transfer(struct mmc_test_card *test,
                                return ret;
                }
 
-               for (i = 0;i < blocks * blksz;i++) {
+               for (i = 0; i < blocks * blksz; i++) {
                        if (test->buffer[i] != (u8)i)
                                return RESULT_FAIL;
                }
 
-               for (;i < sectors * 512;i++) {
+               for (; i < sectors * 512; i++) {
                        if (test->buffer[i] != 0xDF)
                                return RESULT_FAIL;
                }
@@ -1001,7 +1004,7 @@ static int mmc_test_transfer(struct mmc_test_card *test,
                local_irq_save(flags);
                sg_copy_to_buffer(sg, sg_len, test->scratch, BUFFER_SIZE);
                local_irq_restore(flags);
-               for (i = 0;i < blocks * blksz;i++) {
+               for (i = 0; i < blocks * blksz; i++) {
                        if (test->scratch[i] != (u8)i)
                                return RESULT_FAIL;
                }
@@ -1086,7 +1089,7 @@ static int mmc_test_multi_write(struct mmc_test_card *test)
 
        sg_init_one(&sg, test->buffer, size);
 
-       return mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1);
+       return mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 1);
 }
 
 static int mmc_test_multi_read(struct mmc_test_card *test)
@@ -1107,7 +1110,7 @@ static int mmc_test_multi_read(struct mmc_test_card *test)
 
        sg_init_one(&sg, test->buffer, size);
 
-       return mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0);
+       return mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 0);
 }
 
 static int mmc_test_pow2_write(struct mmc_test_card *test)
@@ -1118,7 +1121,7 @@ static int mmc_test_pow2_write(struct mmc_test_card *test)
        if (!test->card->csd.write_partial)
                return RESULT_UNSUP_CARD;
 
-       for (i = 1; i < 512;i <<= 1) {
+       for (i = 1; i < 512; i <<= 1) {
                sg_init_one(&sg, test->buffer, i);
                ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 1);
                if (ret)
@@ -1136,7 +1139,7 @@ static int mmc_test_pow2_read(struct mmc_test_card *test)
        if (!test->card->csd.read_partial)
                return RESULT_UNSUP_CARD;
 
-       for (i = 1; i < 512;i <<= 1) {
+       for (i = 1; i < 512; i <<= 1) {
                sg_init_one(&sg, test->buffer, i);
                ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 0);
                if (ret)
@@ -1154,7 +1157,7 @@ static int mmc_test_weird_write(struct mmc_test_card *test)
        if (!test->card->csd.write_partial)
                return RESULT_UNSUP_CARD;
 
-       for (i = 3; i < 512;i += 7) {
+       for (i = 3; i < 512; i += 7) {
                sg_init_one(&sg, test->buffer, i);
                ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 1);
                if (ret)
@@ -1172,7 +1175,7 @@ static int mmc_test_weird_read(struct mmc_test_card *test)
        if (!test->card->csd.read_partial)
                return RESULT_UNSUP_CARD;
 
-       for (i = 3; i < 512;i += 7) {
+       for (i = 3; i < 512; i += 7) {
                sg_init_one(&sg, test->buffer, i);
                ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 0);
                if (ret)
@@ -1231,7 +1234,7 @@ static int mmc_test_align_multi_write(struct mmc_test_card *test)
 
        for (i = 1; i < TEST_ALIGN_END; i++) {
                sg_init_one(&sg, test->buffer + i, size);
-               ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1);
+               ret = mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 1);
                if (ret)
                        return ret;
        }
@@ -1258,7 +1261,7 @@ static int mmc_test_align_multi_read(struct mmc_test_card *test)
 
        for (i = 1; i < TEST_ALIGN_END; i++) {
                sg_init_one(&sg, test->buffer + i, size);
-               ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0);
+               ret = mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 0);
                if (ret)
                        return ret;
        }
@@ -1357,7 +1360,7 @@ static int mmc_test_multi_write_high(struct mmc_test_card *test)
        sg_init_table(&sg, 1);
        sg_set_page(&sg, test->highmem, size, 0);
 
-       return mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1);
+       return mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 1);
 }
 
 static int mmc_test_multi_read_high(struct mmc_test_card *test)
@@ -1379,7 +1382,7 @@ static int mmc_test_multi_read_high(struct mmc_test_card *test)
        sg_init_table(&sg, 1);
        sg_set_page(&sg, test->highmem, size, 0);
 
-       return mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0);
+       return mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 0);
 }
 
 #else
@@ -1533,7 +1536,7 @@ static int mmc_test_area_cleanup(struct mmc_test_card *test)
 
 /*
  * Initialize an area for testing large transfers.  The test area is set to the
- * middle of the card because cards may have different charateristics at the
+ * middle of the card because cards may have different characteristics at the
  * front (for FAT file system optimization).  Optionally, the area is erased
  * (if the card supports it) which may improve write performance.  Optionally,
  * the area is filled with data for subsequent read tests.
@@ -1579,7 +1582,7 @@ static int mmc_test_area_init(struct mmc_test_card *test, int erase, int fill)
        if (!t->mem)
                return -ENOMEM;
 
-       t->sg = kmalloc(sizeof(struct scatterlist) * t->max_segs, GFP_KERNEL);
+       t->sg = kmalloc_array(t->max_segs, sizeof(*t->sg), GFP_KERNEL);
        if (!t->sg) {
                ret = -ENOMEM;
                goto out_free;
@@ -2147,7 +2150,7 @@ static int mmc_test_rw_multiple_sg_len(struct mmc_test_card *test,
        int i;
 
        for (i = 0 ; i < rw->len && ret == 0; i++) {
-               ret = mmc_test_rw_multiple(test, rw, 512*1024, rw->size,
+               ret = mmc_test_rw_multiple(test, rw, 512 * 1024, rw->size,
                                           rw->sg_len[i]);
                if (ret)
                        break;
@@ -2399,7 +2402,7 @@ static int mmc_test_ongoing_transfer(struct mmc_test_card *test,
 
        /* Start ongoing data request */
        if (use_areq) {
-               mmc_start_req(host, &test_areq.areq, &blkstat);
+               mmc_start_areq(host, &test_areq.areq, &blkstat);
                if (blkstat != MMC_BLK_SUCCESS) {
                        ret = RESULT_FAIL;
                        goto out_free;
@@ -2437,7 +2440,7 @@ static int mmc_test_ongoing_transfer(struct mmc_test_card *test,
 
        /* Wait for data request to complete */
        if (use_areq) {
-               mmc_start_req(host, NULL, &blkstat);
+               mmc_start_areq(host, NULL, &blkstat);
                if (blkstat != MMC_BLK_SUCCESS)
                        ret = RESULT_FAIL;
        } else {
@@ -2954,7 +2957,7 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
 
        mmc_claim_host(test->card->host);
 
-       for (i = 0;i < ARRAY_SIZE(mmc_test_cases);i++) {
+       for (i = 0; i < ARRAY_SIZE(mmc_test_cases); i++) {
                struct mmc_test_general_result *gr;
 
                if (testcase && ((i + 1) != testcase))
@@ -2967,16 +2970,14 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
                if (mmc_test_cases[i].prepare) {
                        ret = mmc_test_cases[i].prepare(test);
                        if (ret) {
-                               pr_info("%s: Result: Prepare "
-                                       "stage failed! (%d)\n",
+                               pr_info("%s: Result: Prepare stage failed! (%d)\n",
                                        mmc_hostname(test->card->host),
                                        ret);
                                continue;
                        }
                }
 
-               gr = kzalloc(sizeof(struct mmc_test_general_result),
-                       GFP_KERNEL);
+               gr = kzalloc(sizeof(*gr), GFP_KERNEL);
                if (gr) {
                        INIT_LIST_HEAD(&gr->tr_lst);
 
@@ -3005,13 +3006,11 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
                                mmc_hostname(test->card->host));
                        break;
                case RESULT_UNSUP_HOST:
-                       pr_info("%s: Result: UNSUPPORTED "
-                               "(by host)\n",
+                       pr_info("%s: Result: UNSUPPORTED (by host)\n",
                                mmc_hostname(test->card->host));
                        break;
                case RESULT_UNSUP_CARD:
-                       pr_info("%s: Result: UNSUPPORTED "
-                               "(by card)\n",
+                       pr_info("%s: Result: UNSUPPORTED (by card)\n",
                                mmc_hostname(test->card->host));
                        break;
                default:
@@ -3026,8 +3025,7 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
                if (mmc_test_cases[i].cleanup) {
                        ret = mmc_test_cases[i].cleanup(test);
                        if (ret) {
-                               pr_info("%s: Warning: Cleanup "
-                                       "stage failed! (%d)\n",
+                               pr_info("%s: Warning: Cleanup stage failed! (%d)\n",
                                        mmc_hostname(test->card->host),
                                        ret);
                        }
@@ -3113,7 +3111,7 @@ static ssize_t mtf_test_write(struct file *file, const char __user *buf,
        if (ret)
                return ret;
 
-       test = kzalloc(sizeof(struct mmc_test_card), GFP_KERNEL);
+       test = kzalloc(sizeof(*test), GFP_KERNEL);
        if (!test)
                return -ENOMEM;
 
@@ -3163,9 +3161,9 @@ static int mtf_testlist_show(struct seq_file *sf, void *data)
 
        mutex_lock(&mmc_test_lock);
 
-       seq_printf(sf, "0:\tRun all tests\n");
+       seq_puts(sf, "0:\tRun all tests\n");
        for (i = 0; i < ARRAY_SIZE(mmc_test_cases); i++)
-               seq_printf(sf, "%d:\t%s\n", i+1, mmc_test_cases[i].name);
+               seq_printf(sf, "%d:\t%s\n", i + 1, mmc_test_cases[i].name);
 
        mutex_unlock(&mmc_test_lock);
 
@@ -3218,7 +3216,7 @@ static int __mmc_test_register_dbgfs_file(struct mmc_card *card,
                return -ENODEV;
        }
 
-       df = kmalloc(sizeof(struct mmc_test_dbgfs_file), GFP_KERNEL);
+       df = kmalloc(sizeof(*df), GFP_KERNEL);
        if (!df) {
                debugfs_remove(file);
                dev_err(&card->dev,
index d69e751f148b85f26d89e748a51c0486d215695c..39c911aa6ebba3204b52c93f857cfe2e9c9bdaf9 100644 (file)
@@ -8,7 +8,11 @@
 #ifndef _MMC_CORE_PWRSEQ_H
 #define _MMC_CORE_PWRSEQ_H
 
-#include <linux/mmc/host.h>
+#include <linux/types.h>
+
+struct mmc_host;
+struct device;
+struct module;
 
 struct mmc_pwrseq_ops {
        void (*pre_power_on)(struct mmc_host *host);
diff --git a/drivers/mmc/core/pwrseq_sd8787.c b/drivers/mmc/core/pwrseq_sd8787.c
new file mode 100644 (file)
index 0000000..1a21e14
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * pwrseq_sd8787.c - power sequence support for Marvell SD8787 BT + Wifi chip
+ *
+ * Copyright (C) 2016 Matt Ranostay <matt@ranostay.consulting>
+ *
+ * Based on the original work pwrseq_simple.c
+ *  Copyright (C) 2014 Linaro Ltd
+ *  Author: Ulf Hansson <ulf.hansson@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+
+#include <linux/mmc/host.h>
+
+#include "pwrseq.h"
+
+struct mmc_pwrseq_sd8787 {
+       struct mmc_pwrseq pwrseq;
+       struct gpio_desc *reset_gpio;
+       struct gpio_desc *pwrdn_gpio;
+};
+
+#define to_pwrseq_sd8787(p) container_of(p, struct mmc_pwrseq_sd8787, pwrseq)
+
+static void mmc_pwrseq_sd8787_pre_power_on(struct mmc_host *host)
+{
+       struct mmc_pwrseq_sd8787 *pwrseq = to_pwrseq_sd8787(host->pwrseq);
+
+       gpiod_set_value_cansleep(pwrseq->reset_gpio, 1);
+
+       msleep(300);
+       gpiod_set_value_cansleep(pwrseq->pwrdn_gpio, 1);
+}
+
+static void mmc_pwrseq_sd8787_power_off(struct mmc_host *host)
+{
+       struct mmc_pwrseq_sd8787 *pwrseq = to_pwrseq_sd8787(host->pwrseq);
+
+       gpiod_set_value_cansleep(pwrseq->pwrdn_gpio, 0);
+       gpiod_set_value_cansleep(pwrseq->reset_gpio, 0);
+}
+
+static const struct mmc_pwrseq_ops mmc_pwrseq_sd8787_ops = {
+       .pre_power_on = mmc_pwrseq_sd8787_pre_power_on,
+       .power_off = mmc_pwrseq_sd8787_power_off,
+};
+
+static const struct of_device_id mmc_pwrseq_sd8787_of_match[] = {
+       { .compatible = "mmc-pwrseq-sd8787",},
+       {/* sentinel */},
+};
+MODULE_DEVICE_TABLE(of, mmc_pwrseq_sd8787_of_match);
+
+static int mmc_pwrseq_sd8787_probe(struct platform_device *pdev)
+{
+       struct mmc_pwrseq_sd8787 *pwrseq;
+       struct device *dev = &pdev->dev;
+
+       pwrseq = devm_kzalloc(dev, sizeof(*pwrseq), GFP_KERNEL);
+       if (!pwrseq)
+               return -ENOMEM;
+
+       pwrseq->pwrdn_gpio = devm_gpiod_get(dev, "powerdown", GPIOD_OUT_LOW);
+       if (IS_ERR(pwrseq->pwrdn_gpio))
+               return PTR_ERR(pwrseq->pwrdn_gpio);
+
+       pwrseq->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+       if (IS_ERR(pwrseq->reset_gpio))
+               return PTR_ERR(pwrseq->reset_gpio);
+
+       pwrseq->pwrseq.dev = dev;
+       pwrseq->pwrseq.ops = &mmc_pwrseq_sd8787_ops;
+       pwrseq->pwrseq.owner = THIS_MODULE;
+       platform_set_drvdata(pdev, pwrseq);
+
+       return mmc_pwrseq_register(&pwrseq->pwrseq);
+}
+
+static int mmc_pwrseq_sd8787_remove(struct platform_device *pdev)
+{
+       struct mmc_pwrseq_sd8787 *pwrseq = platform_get_drvdata(pdev);
+
+       mmc_pwrseq_unregister(&pwrseq->pwrseq);
+
+       return 0;
+}
+
+static struct platform_driver mmc_pwrseq_sd8787_driver = {
+       .probe = mmc_pwrseq_sd8787_probe,
+       .remove = mmc_pwrseq_sd8787_remove,
+       .driver = {
+               .name = "pwrseq_sd8787",
+               .of_match_table = mmc_pwrseq_sd8787_of_match,
+       },
+};
+
+module_platform_driver(mmc_pwrseq_sd8787_driver);
+MODULE_LICENSE("GPL v2");
index a6496d8027bce0b4914c2ced3cf6bada3c540b8c..493eb10ce58045851fc1064426acc08b842f4811 100644 (file)
@@ -20,6 +20,8 @@
 
 #include "queue.h"
 #include "block.h"
+#include "core.h"
+#include "card.h"
 
 #define MMC_QUEUE_BOUNCESZ     65536
 
@@ -30,15 +32,6 @@ static int mmc_prep_request(struct request_queue *q, struct request *req)
 {
        struct mmc_queue *mq = q->queuedata;
 
-       /*
-        * We only like normal block requests and discards.
-        */
-       if (req->cmd_type != REQ_TYPE_FS && req_op(req) != REQ_OP_DISCARD &&
-           req_op(req) != REQ_OP_SECURE_ERASE) {
-               blk_dump_rq_flags(req, "MMC bad request");
-               return BLKPREP_KILL;
-       }
-
        if (mq && (mmc_card_removed(mq->card) || mmc_access_rpmb(mq)))
                return BLKPREP_KILL;
 
@@ -84,8 +77,8 @@ static int mmc_queue_thread(void *d)
                        set_current_state(TASK_RUNNING);
                        mmc_blk_issue_rq(mq, req);
                        cond_resched();
-                       if (mq->flags & MMC_QUEUE_NEW_REQUEST) {
-                               mq->flags &= ~MMC_QUEUE_NEW_REQUEST;
+                       if (mq->new_request) {
+                               mq->new_request = false;
                                continue; /* fetch again */
                        }
 
@@ -152,7 +145,7 @@ static struct scatterlist *mmc_alloc_sg(int sg_len, int *err)
 {
        struct scatterlist *sg;
 
-       sg = kmalloc(sizeof(struct scatterlist)*sg_len, GFP_KERNEL);
+       sg = kmalloc_array(sg_len, sizeof(*sg), GFP_KERNEL);
        if (!sg)
                *err = -ENOMEM;
        else {
@@ -399,8 +392,8 @@ void mmc_queue_suspend(struct mmc_queue *mq)
        struct request_queue *q = mq->queue;
        unsigned long flags;
 
-       if (!(mq->flags & MMC_QUEUE_SUSPENDED)) {
-               mq->flags |= MMC_QUEUE_SUSPENDED;
+       if (!mq->suspended) {
+               mq->suspended |= true;
 
                spin_lock_irqsave(q->queue_lock, flags);
                blk_stop_queue(q);
@@ -419,8 +412,8 @@ void mmc_queue_resume(struct mmc_queue *mq)
        struct request_queue *q = mq->queue;
        unsigned long flags;
 
-       if (mq->flags & MMC_QUEUE_SUSPENDED) {
-               mq->flags &= ~MMC_QUEUE_SUSPENDED;
+       if (mq->suspended) {
+               mq->suspended = false;
 
                up(&mq->thread_sem);
 
index dac8c3d010dd9615a576256ec45b2dd7cef5a6f2..e298f100101b9c3807dc0249bc2412b0f64bb77e 100644 (file)
@@ -1,6 +1,11 @@
 #ifndef MMC_QUEUE_H
 #define MMC_QUEUE_H
 
+#include <linux/types.h>
+#include <linux/blkdev.h>
+#include <linux/mmc/core.h>
+#include <linux/mmc/host.h>
+
 static inline bool mmc_req_is_special(struct request *req)
 {
        return req &&
@@ -9,7 +14,6 @@ static inline bool mmc_req_is_special(struct request *req)
                 req_op(req) == REQ_OP_SECURE_ERASE);
 }
 
-struct request;
 struct task_struct;
 struct mmc_blk_data;
 
@@ -29,16 +33,15 @@ struct mmc_queue_req {
        char                    *bounce_buf;
        struct scatterlist      *bounce_sg;
        unsigned int            bounce_sg_len;
-       struct mmc_async_req    mmc_active;
+       struct mmc_async_req    areq;
 };
 
 struct mmc_queue {
        struct mmc_card         *card;
        struct task_struct      *thread;
        struct semaphore        thread_sem;
-       unsigned int            flags;
-#define MMC_QUEUE_SUSPENDED    (1 << 0)
-#define MMC_QUEUE_NEW_REQUEST  (1 << 1)
+       bool                    new_request;
+       bool                    suspended;
        bool                    asleep;
        struct mmc_blk_data     *blkdata;
        struct request_queue    *queue;
diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c
deleted file mode 100644 (file)
index ca9cade..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- *  This file contains work-arounds for many known SD/MMC
- *  and SDIO hardware bugs.
- *
- *  Copyright (c) 2011 Andrei Warkentin <andreiw@motorola.com>
- *  Copyright (c) 2011 Pierre Tardy <tardyp@gmail.com>
- *  Inspired from pci fixup code:
- *  Copyright (c) 1999 Martin Mares <mj@ucw.cz>
- *
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/sdio_ids.h>
-
-#ifndef SDIO_VENDOR_ID_TI
-#define SDIO_VENDOR_ID_TI              0x0097
-#endif
-
-#ifndef SDIO_DEVICE_ID_TI_WL1271
-#define SDIO_DEVICE_ID_TI_WL1271       0x4076
-#endif
-
-#ifndef SDIO_VENDOR_ID_STE
-#define SDIO_VENDOR_ID_STE             0x0020
-#endif
-
-#ifndef SDIO_DEVICE_ID_STE_CW1200
-#define SDIO_DEVICE_ID_STE_CW1200      0x2280
-#endif
-
-#ifndef SDIO_DEVICE_ID_MARVELL_8797_F0
-#define SDIO_DEVICE_ID_MARVELL_8797_F0 0x9128
-#endif
-
-static const struct mmc_fixup mmc_fixup_methods[] = {
-       SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
-                  add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
-
-       SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
-                  add_quirk, MMC_QUIRK_DISABLE_CD),
-
-       SDIO_FIXUP(SDIO_VENDOR_ID_STE, SDIO_DEVICE_ID_STE_CW1200,
-                  add_quirk, MMC_QUIRK_BROKEN_BYTE_MODE_512),
-
-       SDIO_FIXUP(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8797_F0,
-                  add_quirk, MMC_QUIRK_BROKEN_IRQ_POLLING),
-
-       END_FIXUP
-};
-
-void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table)
-{
-       const struct mmc_fixup *f;
-       u64 rev = cid_rev_card(card);
-
-       /* Non-core specific workarounds. */
-       if (!table)
-               table = mmc_fixup_methods;
-
-       for (f = table; f->vendor_fixup; f++) {
-               if ((f->manfid == CID_MANFID_ANY ||
-                    f->manfid == card->cid.manfid) &&
-                   (f->oemid == CID_OEMID_ANY ||
-                    f->oemid == card->cid.oemid) &&
-                   (f->name == CID_NAME_ANY ||
-                    !strncmp(f->name, card->cid.prod_name,
-                             sizeof(card->cid.prod_name))) &&
-                   (f->cis_vendor == card->cis.vendor ||
-                    f->cis_vendor == (u16) SDIO_ANY_ID) &&
-                   (f->cis_device == card->cis.device ||
-                    f->cis_device == (u16) SDIO_ANY_ID) &&
-                   (f->ext_csd_rev == EXT_CSD_REV_ANY ||
-                    f->ext_csd_rev == card->ext_csd.rev) &&
-                   rev >= f->rev_start && rev <= f->rev_end) {
-                       dev_dbg(&card->dev, "calling %pf\n", f->vendor_fixup);
-                       f->vendor_fixup(card, f->data);
-               }
-       }
-}
-EXPORT_SYMBOL(mmc_fixup_device);
diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h
new file mode 100644 (file)
index 0000000..fb72593
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ *  This file contains work-arounds for many known SD/MMC
+ *  and SDIO hardware bugs.
+ *
+ *  Copyright (c) 2011 Andrei Warkentin <andreiw@motorola.com>
+ *  Copyright (c) 2011 Pierre Tardy <tardyp@gmail.com>
+ *  Inspired from pci fixup code:
+ *  Copyright (c) 1999 Martin Mares <mj@ucw.cz>
+ *
+ */
+
+#include <linux/mmc/sdio_ids.h>
+
+#include "card.h"
+
+static const struct mmc_fixup mmc_blk_fixups[] = {
+#define INAND_CMD38_ARG_EXT_CSD  113
+#define INAND_CMD38_ARG_ERASE    0x00
+#define INAND_CMD38_ARG_TRIM     0x01
+#define INAND_CMD38_ARG_SECERASE 0x80
+#define INAND_CMD38_ARG_SECTRIM1 0x81
+#define INAND_CMD38_ARG_SECTRIM2 0x88
+       /* CMD38 argument is passed through EXT_CSD[113] */
+       MMC_FIXUP("SEM02G", CID_MANFID_SANDISK, 0x100, add_quirk,
+                 MMC_QUIRK_INAND_CMD38),
+       MMC_FIXUP("SEM04G", CID_MANFID_SANDISK, 0x100, add_quirk,
+                 MMC_QUIRK_INAND_CMD38),
+       MMC_FIXUP("SEM08G", CID_MANFID_SANDISK, 0x100, add_quirk,
+                 MMC_QUIRK_INAND_CMD38),
+       MMC_FIXUP("SEM16G", CID_MANFID_SANDISK, 0x100, add_quirk,
+                 MMC_QUIRK_INAND_CMD38),
+       MMC_FIXUP("SEM32G", CID_MANFID_SANDISK, 0x100, add_quirk,
+                 MMC_QUIRK_INAND_CMD38),
+
+       /*
+        * Some MMC cards experience performance degradation with CMD23
+        * instead of CMD12-bounded multiblock transfers. For now we'll
+        * black list what's bad...
+        * - Certain Toshiba cards.
+        *
+        * N.B. This doesn't affect SD cards.
+        */
+       MMC_FIXUP("SDMB-32", CID_MANFID_SANDISK, CID_OEMID_ANY, add_quirk_mmc,
+                 MMC_QUIRK_BLK_NO_CMD23),
+       MMC_FIXUP("SDM032", CID_MANFID_SANDISK, CID_OEMID_ANY, add_quirk_mmc,
+                 MMC_QUIRK_BLK_NO_CMD23),
+       MMC_FIXUP("MMC08G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
+                 MMC_QUIRK_BLK_NO_CMD23),
+       MMC_FIXUP("MMC16G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
+                 MMC_QUIRK_BLK_NO_CMD23),
+       MMC_FIXUP("MMC32G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
+                 MMC_QUIRK_BLK_NO_CMD23),
+
+       /*
+        * Some MMC cards need longer data read timeout than indicated in CSD.
+        */
+       MMC_FIXUP(CID_NAME_ANY, CID_MANFID_MICRON, 0x200, add_quirk_mmc,
+                 MMC_QUIRK_LONG_READ_TIME),
+       MMC_FIXUP("008GE0", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
+                 MMC_QUIRK_LONG_READ_TIME),
+
+       /*
+        * On these Samsung MoviNAND parts, performing secure erase or
+        * secure trim can result in unrecoverable corruption due to a
+        * firmware bug.
+        */
+       MMC_FIXUP("M8G2FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+                 MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
+       MMC_FIXUP("MAG4FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+                 MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
+       MMC_FIXUP("MBG8FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+                 MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
+       MMC_FIXUP("MCGAFA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+                 MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
+       MMC_FIXUP("VAL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+                 MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
+       MMC_FIXUP("VYL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+                 MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
+       MMC_FIXUP("KYL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+                 MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
+       MMC_FIXUP("VZL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+                 MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
+
+       /*
+        *  On Some Kingston eMMCs, performing trim can result in
+        *  unrecoverable data conrruption occasionally due to a firmware bug.
+        */
+       MMC_FIXUP("V10008", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc,
+                 MMC_QUIRK_TRIM_BROKEN),
+       MMC_FIXUP("V10016", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc,
+                 MMC_QUIRK_TRIM_BROKEN),
+
+       END_FIXUP
+};
+
+static const struct mmc_fixup mmc_ext_csd_fixups[] = {
+       /*
+        * Certain Hynix eMMC 4.41 cards might get broken when HPI feature
+        * is used so disable the HPI feature for such buggy cards.
+        */
+       MMC_FIXUP_EXT_CSD_REV(CID_NAME_ANY, CID_MANFID_HYNIX,
+                             0x014a, add_quirk, MMC_QUIRK_BROKEN_HPI, 5),
+
+       END_FIXUP
+};
+
+static const struct mmc_fixup sdio_fixup_methods[] = {
+       SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
+                  add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
+
+       SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
+                  add_quirk, MMC_QUIRK_DISABLE_CD),
+
+       SDIO_FIXUP(SDIO_VENDOR_ID_STE, SDIO_DEVICE_ID_STE_CW1200,
+                  add_quirk, MMC_QUIRK_BROKEN_BYTE_MODE_512),
+
+       SDIO_FIXUP(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8797_F0,
+                  add_quirk, MMC_QUIRK_BROKEN_IRQ_POLLING),
+
+       END_FIXUP
+};
+
+static inline void mmc_fixup_device(struct mmc_card *card,
+                                   const struct mmc_fixup *table)
+{
+       const struct mmc_fixup *f;
+       u64 rev = cid_rev_card(card);
+
+       for (f = table; f->vendor_fixup; f++) {
+               if ((f->manfid == CID_MANFID_ANY ||
+                    f->manfid == card->cid.manfid) &&
+                   (f->oemid == CID_OEMID_ANY ||
+                    f->oemid == card->cid.oemid) &&
+                   (f->name == CID_NAME_ANY ||
+                    !strncmp(f->name, card->cid.prod_name,
+                             sizeof(card->cid.prod_name))) &&
+                   (f->cis_vendor == card->cis.vendor ||
+                    f->cis_vendor == (u16) SDIO_ANY_ID) &&
+                   (f->cis_device == card->cis.device ||
+                    f->cis_device == (u16) SDIO_ANY_ID) &&
+                   (f->ext_csd_rev == EXT_CSD_REV_ANY ||
+                    f->ext_csd_rev == card->ext_csd.rev) &&
+                   rev >= f->rev_start && rev <= f->rev_end) {
+                       dev_dbg(&card->dev, "calling %pf\n", f->vendor_fixup);
+                       f->vendor_fixup(card, f->data);
+               }
+       }
+}
index a614f37faf27e05e52d851353024384e5cbc3f41..89531b48ae841a405400c943138c5a82297a0791 100644 (file)
@@ -22,6 +22,8 @@
 #include <linux/mmc/sd.h>
 
 #include "core.h"
+#include "card.h"
+#include "host.h"
 #include "bus.h"
 #include "mmc_ops.h"
 #include "sd.h"
@@ -786,8 +788,7 @@ try_again:
         */
        if (!mmc_host_is_spi(host) && rocr &&
           ((*rocr & 0x41000000) == 0x41000000)) {
-               err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180,
-                                       pocr);
+               err = mmc_set_uhs_voltage(host, pocr);
                if (err == -EAGAIN) {
                        retries--;
                        goto try_again;
index aab824a9a7f369b858b663797807c07088b29142..1ada9808c3296921c4b3dff5424482a3ad86327d 100644 (file)
@@ -1,10 +1,13 @@
 #ifndef _MMC_CORE_SD_H
 #define _MMC_CORE_SD_H
 
-#include <linux/mmc/card.h>
+#include <linux/types.h>
 
 extern struct device_type sd_type;
 
+struct mmc_host;
+struct mmc_card;
+
 int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr);
 int mmc_sd_get_csd(struct mmc_host *host, struct mmc_card *card);
 void mmc_decode_cid(struct mmc_card *card);
index de125a41aa7ae31960fab8f5c8d8b5651bccdc31..9d5824a3758673d50e03ba21cfb3283da432728f 100644 (file)
@@ -25,7 +25,7 @@
 int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
 {
        int err;
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
 
        if (WARN_ON(card && card->host != host))
                return -EINVAL;
@@ -68,7 +68,7 @@ EXPORT_SYMBOL_GPL(mmc_app_cmd);
 int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
        struct mmc_command *cmd, int retries)
 {
-       struct mmc_request mrq = {NULL};
+       struct mmc_request mrq = {};
 
        int i, err;
 
@@ -120,7 +120,7 @@ EXPORT_SYMBOL(mmc_wait_for_app_cmd);
 
 int mmc_app_set_bus_width(struct mmc_card *card, int width)
 {
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
 
        cmd.opcode = SD_APP_SET_BUS_WIDTH;
        cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
@@ -141,7 +141,7 @@ int mmc_app_set_bus_width(struct mmc_card *card, int width)
 
 int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
 {
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
        int i, err = 0;
 
        cmd.opcode = SD_APP_OP_COND;
@@ -185,7 +185,7 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
 
 int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
 {
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
        int err;
        static const u8 test_pattern = 0xAA;
        u8 result_pattern;
@@ -217,7 +217,7 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
 int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca)
 {
        int err;
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
 
        cmd.opcode = SD_SEND_RELATIVE_ADDR;
        cmd.arg = 0;
@@ -235,9 +235,9 @@ int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca)
 int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
 {
        int err;
-       struct mmc_request mrq = {NULL};
-       struct mmc_command cmd = {0};
-       struct mmc_data data = {0};
+       struct mmc_request mrq = {};
+       struct mmc_command cmd = {};
+       struct mmc_data data = {};
        struct scatterlist sg;
        void *data_buf;
 
@@ -290,9 +290,9 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
 int mmc_sd_switch(struct mmc_card *card, int mode, int group,
        u8 value, u8 *resp)
 {
-       struct mmc_request mrq = {NULL};
-       struct mmc_command cmd = {0};
-       struct mmc_data data = {0};
+       struct mmc_request mrq = {};
+       struct mmc_command cmd = {};
+       struct mmc_data data = {};
        struct scatterlist sg;
 
        /* NOTE: caller guarantees resp is heap-allocated */
@@ -332,9 +332,9 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group,
 int mmc_app_sd_status(struct mmc_card *card, void *ssr)
 {
        int err;
-       struct mmc_request mrq = {NULL};
-       struct mmc_command cmd = {0};
-       struct mmc_data data = {0};
+       struct mmc_request mrq = {};
+       struct mmc_command cmd = {};
+       struct mmc_data data = {};
        struct scatterlist sg;
 
        /* NOTE: caller guarantees ssr is heap-allocated */
index ffc2305d905fcc2c121a0d32a171846d835ec41b..784f8e6b6baa35c46920046bf1074083fdf86e41 100644 (file)
 #ifndef _MMC_SD_OPS_H
 #define _MMC_SD_OPS_H
 
+#include <linux/types.h>
+
+struct mmc_card;
+struct mmc_host;
+struct mmc_command;
+
 int mmc_app_set_bus_width(struct mmc_card *card, int width);
 int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
 int mmc_send_if_cond(struct mmc_host *host, u32 ocr);
@@ -20,6 +26,9 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr);
 int mmc_sd_switch(struct mmc_card *card, int mode, int group,
        u8 value, u8 *resp);
 int mmc_app_sd_status(struct mmc_card *card, void *ssr);
+int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card);
+int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
+       struct mmc_command *cmd, int retries);
 
 #endif
 
index ecbc52981ba5c810463c5fb046bd3ab4b517e442..fae732c870a961ffd001627307ac37433cd23215 100644 (file)
 #include <linux/mmc/sdio_ids.h>
 
 #include "core.h"
+#include "card.h"
+#include "host.h"
 #include "bus.h"
+#include "quirks.h"
 #include "sd.h"
 #include "sdio_bus.h"
 #include "mmc_ops.h"
@@ -541,6 +544,15 @@ out:
        return err;
 }
 
+static void mmc_sdio_resend_if_cond(struct mmc_host *host,
+                                   struct mmc_card *card)
+{
+       sdio_reset(host);
+       mmc_go_idle(host);
+       mmc_send_if_cond(host, host->ocr_avail);
+       mmc_remove_card(card);
+}
+
 /*
  * Handle the detection and initialisation of a card.
  *
@@ -624,24 +636,21 @@ try_again:
         * to switch to 1.8V signaling level.  No 1.8v signalling if
         * UHS mode is not enabled to maintain compatibility and some
         * systems that claim 1.8v signalling in fact do not support
-        * it.
+        * it. Per SDIO spec v3, section 3.1.2, if the voltage is already
+        * 1.8v, the card sets S18A to 0 in the R4 response. So it will
+        * fails to check rocr & R4_18V_PRESENT,  but we still need to
+        * try to init uhs card. sdio_read_cccr will take over this task
+        * to make sure which speed mode should work.
         */
        if (!powered_resume && (rocr & ocr & R4_18V_PRESENT)) {
-               err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180,
-                                       ocr_card);
+               err = mmc_set_uhs_voltage(host, ocr_card);
                if (err == -EAGAIN) {
-                       sdio_reset(host);
-                       mmc_go_idle(host);
-                       mmc_send_if_cond(host, host->ocr_avail);
-                       mmc_remove_card(card);
+                       mmc_sdio_resend_if_cond(host, card);
                        retries--;
                        goto try_again;
                } else if (err) {
                        ocr &= ~R4_18V_PRESENT;
                }
-               err = 0;
-       } else {
-               ocr &= ~R4_18V_PRESENT;
        }
 
        /*
@@ -698,11 +707,20 @@ try_again:
        }
 
        /*
-        * Read the common registers.
+        * Read the common registers. Note that we should try to
+        * validate whether UHS would work or not.
         */
        err = sdio_read_cccr(card, ocr);
-       if (err)
-               goto remove;
+       if (err) {
+               mmc_sdio_resend_if_cond(host, card);
+               if (ocr & R4_18V_PRESENT) {
+                       /* Retry init sequence, but without R4_18V_PRESENT. */
+                       retries = 0;
+                       goto try_again;
+               } else {
+                       goto remove;
+               }
+       }
 
        /*
         * Read the common CIS tuples.
@@ -721,7 +739,7 @@ try_again:
                card = oldcard;
        }
        card->ocr = ocr_card;
-       mmc_fixup_device(card, NULL);
+       mmc_fixup_device(card, sdio_fixup_methods);
 
        if (card->type == MMC_TYPE_SD_COMBO) {
                err = mmc_sd_setup_card(host, card, oldcard != NULL);
index 86f5b3223aaeec29a110fa0b2851b652b66d0dc5..e992a7f8a16fc3019016aa1f2844cfbfb437ad97 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/of.h>
 
 #include "core.h"
+#include "card.h"
 #include "sdio_cis.h"
 #include "sdio_bus.h"
 
index 567a76821ba77d6ef4b5a9df3333c9becb265994..b69a2540a076f6dac50233f83a686bb93371d7b3 100644 (file)
@@ -11,6 +11,9 @@
 #ifndef _MMC_CORE_SDIO_BUS_H
 #define _MMC_CORE_SDIO_BUS_H
 
+struct mmc_card;
+struct sdio_func;
+
 struct sdio_func *sdio_alloc_func(struct mmc_card *card);
 int sdio_add_func(struct sdio_func *func);
 void sdio_remove_func(struct sdio_func *func);
index 4d903c2e425e029ddea616dbfacc8d6dc7c90393..16aa563faa00733f2568acabac6aeb7e85973b18 100644 (file)
@@ -14,6 +14,9 @@
 #ifndef _MMC_SDIO_CIS_H
 #define _MMC_SDIO_CIS_H
 
+struct mmc_card;
+struct sdio_func;
+
 int sdio_read_common_cis(struct mmc_card *card);
 void sdio_free_common_cis(struct mmc_card *card);
 
index 406e5f037e3203618e2997498df58110563e19d6..74195d772f5a7a159f61ccfabf7799e0f4130510 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/mmc/sdio_func.h>
 
 #include "sdio_ops.h"
+#include "core.h"
+#include "card.h"
 
 /**
  *     sdio_claim_host - exclusively claim a bus for a certain SDIO function
index f1faf9acc007d5b3bbf9423ce306203523acc5fa..d29faf2addfe51a0dd82a1ca3ef09425a242bcb1 100644 (file)
@@ -27,6 +27,8 @@
 #include <linux/mmc/sdio_func.h>
 
 #include "sdio_ops.h"
+#include "core.h"
+#include "card.h"
 
 static int process_sdio_pending_irqs(struct mmc_host *host)
 {
index 90fe5545c67713b772da886f49b566a2c1cb59d9..3c0d3ab4324cc91a2611151e9a6aaf176b7c98a0 100644 (file)
@@ -21,7 +21,7 @@
 
 int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
 {
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
        int i, err = 0;
 
        cmd.opcode = SD_IO_SEND_OP_COND;
@@ -66,7 +66,7 @@ int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
 static int mmc_io_rw_direct_host(struct mmc_host *host, int write, unsigned fn,
        unsigned addr, u8 in, u8 *out)
 {
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
        int err;
 
        if (fn > 7)
@@ -118,9 +118,9 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
 int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
        unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz)
 {
-       struct mmc_request mrq = {NULL};
-       struct mmc_command cmd = {0};
-       struct mmc_data data = {0};
+       struct mmc_request mrq = {};
+       struct mmc_command cmd = {};
+       struct mmc_data data = {};
        struct scatterlist sg, *sg_ptr;
        struct sg_table sgtable;
        unsigned int nents, left_size, i;
index 5660c7f459e94731b14a5055e9aab3fbb79ec3b1..bed8a8377fecd5b000d4134b4846d9b1eb95036e 100644 (file)
 #ifndef _MMC_SDIO_OPS_H
 #define _MMC_SDIO_OPS_H
 
+#include <linux/types.h>
 #include <linux/mmc/sdio.h>
 
+struct mmc_host;
+struct mmc_card;
+
 int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
 int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
        unsigned addr, u8 in, u8* out);
 int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
        unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz);
 int sdio_reset(struct mmc_host *host);
+unsigned int mmc_align_data_size(struct mmc_card *card, unsigned int sz);
 
 static inline bool mmc_is_io_op(u32 opcode)
 {
index babe591aea969204bb9500e6c30ff1e64bdafd81..a8450a8701e435c8ae0878896fc6e5321626911e 100644 (file)
@@ -235,9 +235,6 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
        struct gpio_desc *desc;
        int ret;
 
-       if (!con_id)
-               con_id = ctx->cd_label;
-
        desc = devm_gpiod_get_index(host->parent, con_id, idx, GPIOD_IN);
        if (IS_ERR(desc))
                return PTR_ERR(desc);
@@ -289,9 +286,6 @@ int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id,
        struct gpio_desc *desc;
        int ret;
 
-       if (!con_id)
-               con_id = ctx->ro_label;
-
        desc = devm_gpiod_get_index(host->parent, con_id, idx, GPIOD_IN);
        if (IS_ERR(desc))
                return PTR_ERR(desc);
index 8c1854dc5d588d44b0b506040728bda07f55e628..a06fd843f0256624dac7a20203477a383415b0f2 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef _MMC_CORE_SLOTGPIO_H
 #define _MMC_CORE_SLOTGPIO_H
 
+struct mmc_host;
+
 int mmc_gpio_alloc(struct mmc_host *host);
 
 #endif
index 2eb97014dc3f2073c3b471688ba31598d023bc9e..f08691a58d7e02220e8a3ef7d6c552eef7c2a79d 100644 (file)
@@ -683,6 +683,15 @@ config MMC_DW_ROCKCHIP
          Synopsys DesignWare Memory Card Interface driver. Select this option
          for platforms based on RK3066, RK3188 and RK3288 SoC's.
 
+config MMC_DW_ZX
+       tristate "ZTE specific extensions for Synopsys DW Memory Card Interface"
+       depends on MMC_DW && ARCH_ZX
+       select MMC_DW_PLTFM
+       help
+         This selects support for ZTE SoC specific extensions to the
+         Synopsys DesignWare Memory Card Interface driver. Select this option
+         for platforms based on ZX296718 SoC's.
+
 config MMC_SH_MMCIF
        tristate "SuperH Internal MMCIF support"
        depends on HAS_DMA
index ccc9c4cba154c6ba1849151353526e555d63c8a6..6d548c4ee2fa311ce75b02bbbdd3ca53e9d68788 100644 (file)
@@ -48,6 +48,7 @@ obj-$(CONFIG_MMC_DW_EXYNOS)   += dw_mmc-exynos.o
 obj-$(CONFIG_MMC_DW_K3)                += dw_mmc-k3.o
 obj-$(CONFIG_MMC_DW_PCI)       += dw_mmc-pci.o
 obj-$(CONFIG_MMC_DW_ROCKCHIP)  += dw_mmc-rockchip.o
+obj-$(CONFIG_MMC_DW_ZX)                += dw_mmc-zx.o
 obj-$(CONFIG_MMC_SH_MMCIF)     += sh_mmcif.o
 obj-$(CONFIG_MMC_JZ4740)       += jz4740_mmc.o
 obj-$(CONFIG_MMC_VUB300)       += vub300.o
index 36b5af8eadb88eae79e74cad782259ba100b9910..1e2600da105f4656e3b65e8e45295e43f05fe2ea 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/mmc/slot-gpio.h>
+#include <linux/interrupt.h>
 
 #include <linux/platform_data/mmc-davinci.h>
 
index e1335289316c84839acc46a1a298984a0ace9a93..25691cca1881b393a1e7f09e00c1b561b7dab440 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/mmc/host.h>
-#include <linux/mmc/dw_mmc.h>
 #include <linux/mmc/mmc.h>
 #include <linux/of.h>
 #include <linux/of_gpio.h>
index 9821e6bd5d5ecf30ba045ea81f5ee397f3cd8a90..e38fb0020bb17e41f8e2dba3a1b71749d8b6e0e6 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/clk.h>
 #include <linux/mfd/syscon.h>
 #include <linux/mmc/host.h>
-#include <linux/mmc/dw_mmc.h>
 #include <linux/module.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
index ab82796b01e2665eca6c82645f7938981f1b469a..ab8713297edbeeaaf69a3cfbad0fa7f9c3e2ebb2 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/slab.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
-#include <linux/mmc/dw_mmc.h>
 #include "dw_mmc.h"
 
 #define PCI_BAR_NO 2
index 1236d49ba36e201f51c12b8da0f12b8eec8da093..58c13e21bd5a72fc133c1ae357c337ea4f1bfd44 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/slab.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
-#include <linux/mmc/dw_mmc.h>
 #include <linux/of.h>
 #include <linux/clk.h>
 
index 9a46e4694227b67148d88fd7d24d8e9bc8ea11ce..372fb6e948c1aca62f33e73a15d6bc195e9335d4 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/mmc/host.h>
-#include <linux/mmc/dw_mmc.h>
 #include <linux/of_address.h>
 #include <linux/mmc/slot-gpio.h>
 #include <linux/pm_runtime.h>
diff --git a/drivers/mmc/host/dw_mmc-zx.c b/drivers/mmc/host/dw_mmc-zx.c
new file mode 100644 (file)
index 0000000..d38e94a
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * ZX Specific Extensions for Synopsys DW Multimedia Card Interface driver
+ *
+ * Copyright (C) 2016, Linaro Ltd.
+ * Copyright (C) 2016, ZTE Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include "dw_mmc.h"
+#include "dw_mmc-pltfm.h"
+#include "dw_mmc-zx.h"
+
+struct dw_mci_zx_priv_data {
+       struct regmap   *sysc_base;
+};
+
+enum delay_type {
+       DELAY_TYPE_READ,        /* read dqs delay */
+       DELAY_TYPE_CLK,         /* clk sample delay */
+};
+
+static int dw_mci_zx_emmc_set_delay(struct dw_mci *host, unsigned int delay,
+                                   enum delay_type dflag)
+{
+       struct dw_mci_zx_priv_data *priv = host->priv;
+       struct regmap *sysc_base = priv->sysc_base;
+       unsigned int clksel;
+       unsigned int loop = 1000;
+       int ret;
+
+       if (!sysc_base)
+               return -EINVAL;
+
+       ret = regmap_update_bits(sysc_base, LB_AON_EMMC_CFG_REG0,
+                                PARA_HALF_CLK_MODE | PARA_DLL_BYPASS_MODE |
+                                PARA_PHASE_DET_SEL_MASK |
+                                PARA_DLL_LOCK_NUM_MASK |
+                                DLL_REG_SET | PARA_DLL_START_MASK,
+                                PARA_DLL_START(4) | PARA_DLL_LOCK_NUM(4));
+       if (ret)
+               return ret;
+
+       ret = regmap_read(sysc_base, LB_AON_EMMC_CFG_REG1, &clksel);
+       if (ret)
+               return ret;
+
+       if (dflag == DELAY_TYPE_CLK) {
+               clksel &= ~CLK_SAMP_DELAY_MASK;
+               clksel |= CLK_SAMP_DELAY(delay);
+       } else {
+               clksel &= ~READ_DQS_DELAY_MASK;
+               clksel |= READ_DQS_DELAY(delay);
+       }
+
+       regmap_write(sysc_base, LB_AON_EMMC_CFG_REG1, clksel);
+       regmap_update_bits(sysc_base, LB_AON_EMMC_CFG_REG0,
+                          PARA_DLL_START_MASK | PARA_DLL_LOCK_NUM_MASK |
+                          DLL_REG_SET,
+                          PARA_DLL_START(4) | PARA_DLL_LOCK_NUM(4) |
+                          DLL_REG_SET);
+
+       do {
+               ret = regmap_read(sysc_base, LB_AON_EMMC_CFG_REG2, &clksel);
+               if (ret)
+                       return ret;
+
+       } while (--loop && !(clksel & ZX_DLL_LOCKED));
+
+       if (!loop) {
+               dev_err(host->dev, "Error: %s dll lock fail\n", __func__);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int dw_mci_zx_emmc_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
+{
+       struct dw_mci *host = slot->host;
+       struct mmc_host *mmc = slot->mmc;
+       int ret, len = 0, start = 0, end = 0, delay, best = 0;
+
+       for (delay = 1; delay < 128; delay++) {
+               ret = dw_mci_zx_emmc_set_delay(host, delay, DELAY_TYPE_CLK);
+               if (!ret && mmc_send_tuning(mmc, opcode, NULL)) {
+                       if (start >= 0) {
+                               end = delay - 1;
+                               /* check and update longest good range */
+                               if ((end - start) > len) {
+                                       best = (start + end) >> 1;
+                                       len = end - start;
+                               }
+                       }
+                       start = -1;
+                       end = 0;
+                       continue;
+               }
+               if (start < 0)
+                       start = delay;
+       }
+
+       if (start >= 0) {
+               end = delay - 1;
+               if ((end - start) > len) {
+                       best = (start + end) >> 1;
+                       len = end - start;
+               }
+       }
+       if (best < 0)
+               return -EIO;
+
+       dev_info(host->dev, "%s best range: start %d end %d\n", __func__,
+                start, end);
+       return dw_mci_zx_emmc_set_delay(host, best, DELAY_TYPE_CLK);
+}
+
+static int dw_mci_zx_prepare_hs400_tuning(struct dw_mci *host,
+                                         struct mmc_ios *ios)
+{
+       int ret;
+
+       /* config phase shift as 90 degree */
+       ret = dw_mci_zx_emmc_set_delay(host, 32, DELAY_TYPE_READ);
+       if (ret < 0)
+               return -EIO;
+
+       return 0;
+}
+
+static int dw_mci_zx_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
+{
+       struct dw_mci *host = slot->host;
+
+       if (host->verid == 0x290a) /* only for emmc */
+               return dw_mci_zx_emmc_execute_tuning(slot, opcode);
+       /* TODO: Add 0x210a dedicated tuning for sd/sdio */
+
+       return 0;
+}
+
+static int dw_mci_zx_parse_dt(struct dw_mci *host)
+{
+       struct device_node *np = host->dev->of_node;
+       struct device_node *node;
+       struct dw_mci_zx_priv_data *priv;
+       struct regmap *sysc_base;
+       int ret;
+
+       /* syscon is needed only by emmc */
+       node = of_parse_phandle(np, "zte,aon-syscon", 0);
+       if (node) {
+               sysc_base = syscon_node_to_regmap(node);
+               of_node_put(node);
+
+               if (IS_ERR(sysc_base)) {
+                       ret = PTR_ERR(sysc_base);
+                       if (ret != -EPROBE_DEFER)
+                               dev_err(host->dev, "Can't get syscon: %d\n",
+                                       ret);
+                       return ret;
+               }
+       } else {
+               return 0;
+       }
+
+       priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+       priv->sysc_base = sysc_base;
+       host->priv = priv;
+
+       return 0;
+}
+
+static unsigned long zx_dwmmc_caps[3] = {
+       MMC_CAP_CMD23,
+       MMC_CAP_CMD23,
+       MMC_CAP_CMD23,
+};
+
+static const struct dw_mci_drv_data zx_drv_data = {
+       .caps                   = zx_dwmmc_caps,
+       .execute_tuning         = dw_mci_zx_execute_tuning,
+       .prepare_hs400_tuning   = dw_mci_zx_prepare_hs400_tuning,
+       .parse_dt               = dw_mci_zx_parse_dt,
+};
+
+static const struct of_device_id dw_mci_zx_match[] = {
+       { .compatible = "zte,zx296718-dw-mshc", .data = &zx_drv_data},
+       {},
+};
+MODULE_DEVICE_TABLE(of, dw_mci_zx_match);
+
+static int dw_mci_zx_probe(struct platform_device *pdev)
+{
+       const struct dw_mci_drv_data *drv_data;
+       const struct of_device_id *match;
+
+       match = of_match_node(dw_mci_zx_match, pdev->dev.of_node);
+       drv_data = match->data;
+
+       return dw_mci_pltfm_register(pdev, drv_data);
+}
+
+static const struct dev_pm_ops dw_mci_zx_dev_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
+       SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend,
+                          dw_mci_runtime_resume,
+                          NULL)
+};
+
+static struct platform_driver dw_mci_zx_pltfm_driver = {
+       .probe          = dw_mci_zx_probe,
+       .remove         = dw_mci_pltfm_remove,
+       .driver         = {
+               .name           = "dwmmc_zx",
+               .of_match_table = dw_mci_zx_match,
+               .pm             = &dw_mci_zx_dev_pm_ops,
+       },
+};
+
+module_platform_driver(dw_mci_zx_pltfm_driver);
+
+MODULE_DESCRIPTION("ZTE emmc/sd driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/dw_mmc-zx.h b/drivers/mmc/host/dw_mmc-zx.h
new file mode 100644 (file)
index 0000000..f369997
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef _DW_MMC_ZX_H_
+#define _DW_MMC_ZX_H_
+
+/* ZX296718 SoC specific DLL register offset. */
+#define LB_AON_EMMC_CFG_REG0  0x1B0
+#define LB_AON_EMMC_CFG_REG1  0x1B4
+#define LB_AON_EMMC_CFG_REG2  0x1B8
+
+/* LB_AON_EMMC_CFG_REG0 register defines */
+#define PARA_DLL_START(x)      ((x) & 0xFF)
+#define PARA_DLL_START_MASK    0xFF
+#define DLL_REG_SET            BIT(8)
+#define PARA_DLL_LOCK_NUM(x)   (((x) & 7) << 16)
+#define PARA_DLL_LOCK_NUM_MASK  (7 << 16)
+#define PARA_PHASE_DET_SEL(x)  (((x) & 7) << 20)
+#define PARA_PHASE_DET_SEL_MASK        (7 << 20)
+#define PARA_DLL_BYPASS_MODE   BIT(23)
+#define PARA_HALF_CLK_MODE     BIT(24)
+
+/* LB_AON_EMMC_CFG_REG1 register defines */
+#define READ_DQS_DELAY(x)      ((x) & 0x7F)
+#define READ_DQS_DELAY_MASK    (0x7F)
+#define READ_DQS_BYPASS_MODE   BIT(7)
+#define CLK_SAMP_DELAY(x)      (((x) & 0x7F) << 8)
+#define CLK_SAMP_DELAY_MASK    (0x7F << 8)
+#define CLK_SAMP_BYPASS_MODE   BIT(15)
+
+/* LB_AON_EMMC_CFG_REG2 register defines */
+#define ZX_DLL_LOCKED          BIT(2)
+
+#endif /* _DW_MMC_ZX_H_ */
index 73db08558e4dd6d100d44e04cd58649e63ee94e8..a9ac0b4573131f48cad46044e018b5de479cf695 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/sd.h>
 #include <linux/mmc/sdio.h>
-#include <linux/mmc/dw_mmc.h>
 #include <linux/bitops.h>
 #include <linux/regulator/consumer.h>
 #include <linux/of.h>
@@ -1113,11 +1112,15 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
                mci_writel(host, CTRL, temp);
 
                /*
-                * Use the initial fifoth_val for PIO mode.
+                * Use the initial fifoth_val for PIO mode. If wm_algined
+                * is set, we set watermark same as data size.
                 * If next issued data may be transfered by DMA mode,
                 * prev_blksz should be invalidated.
                 */
-               mci_writel(host, FIFOTH, host->fifoth_val);
+               if (host->wm_aligned)
+                       dw_mci_adjust_fifoth(host, data);
+               else
+                       mci_writel(host, FIFOTH, host->fifoth_val);
                host->prev_blksz = 0;
        } else {
                /*
@@ -1179,11 +1182,13 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
                if ((clock != slot->__clk_old &&
                        !test_bit(DW_MMC_CARD_NEEDS_POLL, &slot->flags)) ||
                        force_clkinit) {
-                       dev_info(&slot->mmc->class_dev,
-                                "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ div = %d)\n",
-                                slot->id, host->bus_hz, clock,
-                                div ? ((host->bus_hz / div) >> 1) :
-                                host->bus_hz, div);
+                       /* Silent the verbose log if calling from PM context */
+                       if (!force_clkinit)
+                               dev_info(&slot->mmc->class_dev,
+                                        "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ div = %d)\n",
+                                        slot->id, host->bus_hz, clock,
+                                        div ? ((host->bus_hz / div) >> 1) :
+                                        host->bus_hz, div);
 
                        /*
                         * If card is polling, display the message only
@@ -2977,6 +2982,11 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
 
        of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
 
+       of_property_read_u32(np, "data-addr", &host->data_addr_override);
+
+       if (of_get_property(np, "fifo-watermark-aligned", NULL))
+               host->wm_aligned = true;
+
        if (!of_property_read_u32(np, "clock-frequency", &clock_frequency))
                pdata->bus_hz = clock_frequency;
 
@@ -3180,7 +3190,9 @@ int dw_mci_probe(struct dw_mci *host)
        host->verid = SDMMC_GET_VERID(mci_readl(host, VERID));
        dev_info(host->dev, "Version ID is %04x\n", host->verid);
 
-       if (host->verid < DW_MMC_240A)
+       if (host->data_addr_override)
+               host->fifo_reg = host->regs + host->data_addr_override;
+       else if (host->verid < DW_MMC_240A)
                host->fifo_reg = host->regs + DATA_OFFSET;
        else
                host->fifo_reg = host->regs + DATA_240A_OFFSET;
index c59465829387757ddd3d8257c409b400534f048c..ce347361f3dcb435e7bd5b9dccf06319b4a8d18a 100644 (file)
 #ifndef _DW_MMC_H_
 #define _DW_MMC_H_
 
+#include <linux/scatterlist.h>
+#include <linux/mmc/core.h>
+#include <linux/dmaengine.h>
+#include <linux/reset.h>
+#include <linux/interrupt.h>
+
+#define MAX_MCI_SLOTS  2
+
+enum dw_mci_state {
+       STATE_IDLE = 0,
+       STATE_SENDING_CMD,
+       STATE_SENDING_DATA,
+       STATE_DATA_BUSY,
+       STATE_SENDING_STOP,
+       STATE_DATA_ERROR,
+       STATE_SENDING_CMD11,
+       STATE_WAITING_CMD11_DONE,
+};
+
+enum {
+       EVENT_CMD_COMPLETE = 0,
+       EVENT_XFER_COMPLETE,
+       EVENT_DATA_COMPLETE,
+       EVENT_DATA_ERROR,
+};
+
+enum dw_mci_cookie {
+       COOKIE_UNMAPPED,
+       COOKIE_PRE_MAPPED,      /* mapped by pre_req() of dwmmc */
+       COOKIE_MAPPED,          /* mapped by prepare_data() of dwmmc */
+};
+
+struct mmc_data;
+
+enum {
+       TRANS_MODE_PIO = 0,
+       TRANS_MODE_IDMAC,
+       TRANS_MODE_EDMAC
+};
+
+struct dw_mci_dma_slave {
+       struct dma_chan *ch;
+       enum dma_transfer_direction direction;
+};
+
+/**
+ * struct dw_mci - MMC controller state shared between all slots
+ * @lock: Spinlock protecting the queue and associated data.
+ * @irq_lock: Spinlock protecting the INTMASK setting.
+ * @regs: Pointer to MMIO registers.
+ * @fifo_reg: Pointer to MMIO registers for data FIFO
+ * @sg: Scatterlist entry currently being processed by PIO code, if any.
+ * @sg_miter: PIO mapping scatterlist iterator.
+ * @cur_slot: The slot which is currently using the controller.
+ * @mrq: The request currently being processed on @cur_slot,
+ *     or NULL if the controller is idle.
+ * @cmd: The command currently being sent to the card, or NULL.
+ * @data: The data currently being transferred, or NULL if no data
+ *     transfer is in progress.
+ * @stop_abort: The command currently prepared for stoping transfer.
+ * @prev_blksz: The former transfer blksz record.
+ * @timing: Record of current ios timing.
+ * @use_dma: Whether DMA channel is initialized or not.
+ * @using_dma: Whether DMA is in use for the current transfer.
+ * @dma_64bit_address: Whether DMA supports 64-bit address mode or not.
+ * @sg_dma: Bus address of DMA buffer.
+ * @sg_cpu: Virtual address of DMA buffer.
+ * @dma_ops: Pointer to platform-specific DMA callbacks.
+ * @cmd_status: Snapshot of SR taken upon completion of the current
+ * @ring_size: Buffer size for idma descriptors.
+ *     command. Only valid when EVENT_CMD_COMPLETE is pending.
+ * @dms: structure of slave-dma private data.
+ * @phy_regs: physical address of controller's register map
+ * @data_status: Snapshot of SR taken upon completion of the current
+ *     data transfer. Only valid when EVENT_DATA_COMPLETE or
+ *     EVENT_DATA_ERROR is pending.
+ * @stop_cmdr: Value to be loaded into CMDR when the stop command is
+ *     to be sent.
+ * @dir_status: Direction of current transfer.
+ * @tasklet: Tasklet running the request state machine.
+ * @pending_events: Bitmask of events flagged by the interrupt handler
+ *     to be processed by the tasklet.
+ * @completed_events: Bitmask of events which the state machine has
+ *     processed.
+ * @state: Tasklet state.
+ * @queue: List of slots waiting for access to the controller.
+ * @bus_hz: The rate of @mck in Hz. This forms the basis for MMC bus
+ *     rate and timeout calculations.
+ * @current_speed: Configured rate of the controller.
+ * @num_slots: Number of slots available.
+ * @fifoth_val: The value of FIFOTH register.
+ * @verid: Denote Version ID.
+ * @dev: Device associated with the MMC controller.
+ * @pdata: Platform data associated with the MMC controller.
+ * @drv_data: Driver specific data for identified variant of the controller
+ * @priv: Implementation defined private data.
+ * @biu_clk: Pointer to bus interface unit clock instance.
+ * @ciu_clk: Pointer to card interface unit clock instance.
+ * @slot: Slots sharing this MMC controller.
+ * @fifo_depth: depth of FIFO.
+ * @data_addr_override: override fifo reg offset with this value.
+ * @wm_aligned: force fifo watermark equal with data length in PIO mode.
+ *     Set as true if alignment is needed.
+ * @data_shift: log2 of FIFO item size.
+ * @part_buf_start: Start index in part_buf.
+ * @part_buf_count: Bytes of partial data in part_buf.
+ * @part_buf: Simple buffer for partial fifo reads/writes.
+ * @push_data: Pointer to FIFO push function.
+ * @pull_data: Pointer to FIFO pull function.
+ * @vqmmc_enabled: Status of vqmmc, should be true or false.
+ * @irq_flags: The flags to be passed to request_irq.
+ * @irq: The irq value to be passed to request_irq.
+ * @sdio_id0: Number of slot0 in the SDIO interrupt registers.
+ * @cmd11_timer: Timer for SD3.0 voltage switch over scheme.
+ * @dto_timer: Timer for broken data transfer over scheme.
+ *
+ * Locking
+ * =======
+ *
+ * @lock is a softirq-safe spinlock protecting @queue as well as
+ * @cur_slot, @mrq and @state. These must always be updated
+ * at the same time while holding @lock.
+ *
+ * @irq_lock is an irq-safe spinlock protecting the INTMASK register
+ * to allow the interrupt handler to modify it directly.  Held for only long
+ * enough to read-modify-write INTMASK and no other locks are grabbed when
+ * holding this one.
+ *
+ * The @mrq field of struct dw_mci_slot is also protected by @lock,
+ * and must always be written at the same time as the slot is added to
+ * @queue.
+ *
+ * @pending_events and @completed_events are accessed using atomic bit
+ * operations, so they don't need any locking.
+ *
+ * None of the fields touched by the interrupt handler need any
+ * locking. However, ordering is important: Before EVENT_DATA_ERROR or
+ * EVENT_DATA_COMPLETE is set in @pending_events, all data-related
+ * interrupts must be disabled and @data_status updated with a
+ * snapshot of SR. Similarly, before EVENT_CMD_COMPLETE is set, the
+ * CMDRDY interrupt must be disabled and @cmd_status updated with a
+ * snapshot of SR, and before EVENT_XFER_COMPLETE can be set, the
+ * bytes_xfered field of @data must be written. This is ensured by
+ * using barriers.
+ */
+struct dw_mci {
+       spinlock_t              lock;
+       spinlock_t              irq_lock;
+       void __iomem            *regs;
+       void __iomem            *fifo_reg;
+       u32                     data_addr_override;
+       bool                    wm_aligned;
+
+       struct scatterlist      *sg;
+       struct sg_mapping_iter  sg_miter;
+
+       struct dw_mci_slot      *cur_slot;
+       struct mmc_request      *mrq;
+       struct mmc_command      *cmd;
+       struct mmc_data         *data;
+       struct mmc_command      stop_abort;
+       unsigned int            prev_blksz;
+       unsigned char           timing;
+
+       /* DMA interface members*/
+       int                     use_dma;
+       int                     using_dma;
+       int                     dma_64bit_address;
+
+       dma_addr_t              sg_dma;
+       void                    *sg_cpu;
+       const struct dw_mci_dma_ops     *dma_ops;
+       /* For idmac */
+       unsigned int            ring_size;
+
+       /* For edmac */
+       struct dw_mci_dma_slave *dms;
+       /* Registers's physical base address */
+       resource_size_t         phy_regs;
+
+       u32                     cmd_status;
+       u32                     data_status;
+       u32                     stop_cmdr;
+       u32                     dir_status;
+       struct tasklet_struct   tasklet;
+       unsigned long           pending_events;
+       unsigned long           completed_events;
+       enum dw_mci_state       state;
+       struct list_head        queue;
+
+       u32                     bus_hz;
+       u32                     current_speed;
+       u32                     num_slots;
+       u32                     fifoth_val;
+       u16                     verid;
+       struct device           *dev;
+       struct dw_mci_board     *pdata;
+       const struct dw_mci_drv_data    *drv_data;
+       void                    *priv;
+       struct clk              *biu_clk;
+       struct clk              *ciu_clk;
+       struct dw_mci_slot      *slot[MAX_MCI_SLOTS];
+
+       /* FIFO push and pull */
+       int                     fifo_depth;
+       int                     data_shift;
+       u8                      part_buf_start;
+       u8                      part_buf_count;
+       union {
+               u16             part_buf16;
+               u32             part_buf32;
+               u64             part_buf;
+       };
+       void (*push_data)(struct dw_mci *host, void *buf, int cnt);
+       void (*pull_data)(struct dw_mci *host, void *buf, int cnt);
+
+       bool                    vqmmc_enabled;
+       unsigned long           irq_flags; /* IRQ flags */
+       int                     irq;
+
+       int                     sdio_id0;
+
+       struct timer_list       cmd11_timer;
+       struct timer_list       dto_timer;
+};
+
+/* DMA ops for Internal/External DMAC interface */
+struct dw_mci_dma_ops {
+       /* DMA Ops */
+       int (*init)(struct dw_mci *host);
+       int (*start)(struct dw_mci *host, unsigned int sg_len);
+       void (*complete)(void *host);
+       void (*stop)(struct dw_mci *host);
+       void (*cleanup)(struct dw_mci *host);
+       void (*exit)(struct dw_mci *host);
+};
+
+struct dma_pdata;
+
+/* Board platform data */
+struct dw_mci_board {
+       u32 num_slots;
+
+       unsigned int bus_hz; /* Clock speed at the cclk_in pad */
+
+       u32 caps;       /* Capabilities */
+       u32 caps2;      /* More capabilities */
+       u32 pm_caps;    /* PM capabilities */
+       /*
+        * Override fifo depth. If 0, autodetect it from the FIFOTH register,
+        * but note that this may not be reliable after a bootloader has used
+        * it.
+        */
+       unsigned int fifo_depth;
+
+       /* delay in mS before detecting cards after interrupt */
+       u32 detect_delay_ms;
+
+       struct reset_control *rstc;
+       struct dw_mci_dma_ops *dma_ops;
+       struct dma_pdata *data;
+};
+
 #define DW_MMC_240A            0x240a
 #define DW_MMC_280A            0x280a
 
index 09739352834c8253eedac3000b703e42c37eacfc..5a959783304bc6fd97cd8edf9cdca6614413cc18 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/regulator/consumer.h>
+#include <linux/interrupt.h>
 
 #define DRIVER_NAME "meson-gx-mmc"
 
@@ -82,6 +83,7 @@
 #define   CFG_RC_CC_MASK 0xf
 #define   CFG_STOP_CLOCK BIT(22)
 #define   CFG_CLK_ALWAYS_ON BIT(18)
+#define   CFG_CHK_DS BIT(20)
 #define   CFG_AUTO_CLK BIT(23)
 
 #define SD_EMMC_STATUS 0x48
@@ -131,7 +133,7 @@ struct meson_host {
        struct clk_mux mux;
        struct clk *mux_clk;
        struct clk *mux_parent[MUX_CLK_NUM_PARENTS];
-       unsigned long mux_parent_rate[MUX_CLK_NUM_PARENTS];
+       unsigned long current_clock;
 
        struct clk_divider cfg_div;
        struct clk *cfg_div_clk;
@@ -178,7 +180,7 @@ struct sd_emmc_desc {
 static int meson_mmc_clk_set(struct meson_host *host, unsigned long clk_rate)
 {
        struct mmc_host *mmc = host->mmc;
-       int ret = 0;
+       int ret;
        u32 cfg;
 
        if (clk_rate) {
@@ -188,7 +190,7 @@ static int meson_mmc_clk_set(struct meson_host *host, unsigned long clk_rate)
                        clk_rate = mmc->f_min;
        }
 
-       if (clk_rate == mmc->actual_clock)
+       if (clk_rate == host->current_clock)
                return 0;
 
        /* stop clock */
@@ -201,29 +203,34 @@ static int meson_mmc_clk_set(struct meson_host *host, unsigned long clk_rate)
        dev_dbg(host->dev, "change clock rate %u -> %lu\n",
                mmc->actual_clock, clk_rate);
 
-       if (clk_rate == 0) {
+       if (!clk_rate) {
                mmc->actual_clock = 0;
+               host->current_clock = 0;
+               /* return with clock being stopped */
                return 0;
        }
 
        ret = clk_set_rate(host->cfg_div_clk, clk_rate);
-       if (ret)
-               dev_warn(host->dev, "Unable to set cfg_div_clk to %lu. ret=%d\n",
-                        clk_rate, ret);
-       else if (clk_rate && clk_rate != clk_get_rate(host->cfg_div_clk))
-               dev_warn(host->dev, "divider requested rate %lu != actual rate %lu: ret=%d\n",
-                        clk_rate, clk_get_rate(host->cfg_div_clk), ret);
-       else
-               mmc->actual_clock = clk_rate;
-
-       /* (re)start clock, if non-zero */
-       if (!ret && clk_rate) {
-               cfg = readl(host->regs + SD_EMMC_CFG);
-               cfg &= ~CFG_STOP_CLOCK;
-               writel(cfg, host->regs + SD_EMMC_CFG);
+       if (ret) {
+               dev_err(host->dev, "Unable to set cfg_div_clk to %lu. ret=%d\n",
+                       clk_rate, ret);
+               return ret;
        }
 
-       return ret;
+       mmc->actual_clock = clk_get_rate(host->cfg_div_clk);
+       host->current_clock = clk_rate;
+
+       if (clk_rate != mmc->actual_clock)
+               dev_dbg(host->dev,
+                       "divider requested rate %lu != actual rate %u\n",
+                       clk_rate, mmc->actual_clock);
+
+       /* (re)start clock */
+       cfg = readl(host->regs + SD_EMMC_CFG);
+       cfg &= ~CFG_STOP_CLOCK;
+       writel(cfg, host->regs + SD_EMMC_CFG);
+
+       return 0;
 }
 
 /*
@@ -239,7 +246,6 @@ static int meson_mmc_clk_init(struct meson_host *host)
        const char *mux_parent_names[MUX_CLK_NUM_PARENTS];
        unsigned int mux_parent_count = 0;
        const char *clk_div_parents[1];
-       unsigned int f_min = UINT_MAX;
        u32 clk_reg, cfg;
 
        /* get the mux parents */
@@ -256,20 +262,10 @@ static int meson_mmc_clk_init(struct meson_host *host)
                        return ret;
                }
 
-               host->mux_parent_rate[i] = clk_get_rate(host->mux_parent[i]);
                mux_parent_names[i] = __clk_get_name(host->mux_parent[i]);
                mux_parent_count++;
-               if (host->mux_parent_rate[i] < f_min)
-                       f_min = host->mux_parent_rate[i];
        }
 
-       /* cacluate f_min based on input clocks, and max divider value */
-       if (f_min != UINT_MAX)
-               f_min = DIV_ROUND_UP(CLK_SRC_XTAL_RATE, CLK_DIV_MAX);
-       else
-               f_min = 4000000;  /* default min: 400 MHz */
-       host->mmc->f_min = f_min;
-
        /* create the mux */
        snprintf(clk_name, sizeof(clk_name), "%s#mux", dev_name(host->dev));
        init.name = clk_name;
@@ -324,9 +320,13 @@ static int meson_mmc_clk_init(struct meson_host *host)
        writel(cfg, host->regs + SD_EMMC_CFG);
 
        ret = clk_prepare_enable(host->cfg_div_clk);
-       if (!ret)
-               ret = meson_mmc_clk_set(host, f_min);
+       if (ret)
+               return ret;
 
+       /* Get the nearest minimum clock to 400KHz */
+       host->mmc->f_min = clk_round_rate(host->cfg_div_clk, 400000);
+
+       ret = meson_mmc_clk_set(host, host->mmc->f_min);
        if (!ret)
                clk_disable_unprepare(host->cfg_div_clk);
 
@@ -378,7 +378,6 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        meson_mmc_clk_set(host, ios->clock);
 
        /* Bus width */
-       val = readl(host->regs + SD_EMMC_CFG);
        switch (ios->bus_width) {
        case MMC_BUS_WIDTH_1:
                bus_width = CFG_BUS_WIDTH_1;
@@ -393,7 +392,6 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                dev_err(host->dev, "Invalid ios->bus_width: %u.  Setting to 4.\n",
                        ios->bus_width);
                bus_width = CFG_BUS_WIDTH_4;
-               return;
        }
 
        val = readl(host->regs + SD_EMMC_CFG);
@@ -411,6 +409,16 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        val &= ~(CFG_RC_CC_MASK << CFG_RC_CC_SHIFT);
        val |= ilog2(SD_EMMC_CFG_CMD_GAP) << CFG_RC_CC_SHIFT;
 
+       val &= ~CFG_DDR;
+       if (ios->timing == MMC_TIMING_UHS_DDR50 ||
+           ios->timing == MMC_TIMING_MMC_DDR52 ||
+           ios->timing == MMC_TIMING_MMC_HS400)
+               val |= CFG_DDR;
+
+       val &= ~CFG_CHK_DS;
+       if (ios->timing == MMC_TIMING_MMC_HS400)
+               val |= CFG_CHK_DS;
+
        writel(val, host->regs + SD_EMMC_CFG);
 
        if (val != orig)
@@ -480,9 +488,9 @@ static void meson_mmc_start_cmd(struct mmc_host *mmc, struct mmc_command *cmd)
                        blk_len = cfg & (CFG_BLK_LEN_MASK << CFG_BLK_LEN_SHIFT);
                        blk_len >>= CFG_BLK_LEN_SHIFT;
                        if (blk_len != ilog2(cmd->data->blksz)) {
-                               dev_warn(host->dev, "%s: update blk_len %d -> %d\n",
+                               dev_dbg(host->dev, "%s: update blk_len %d -> %d\n",
                                        __func__, blk_len,
-                                        ilog2(cmd->data->blksz));
+                                       ilog2(cmd->data->blksz));
                                blk_len = ilog2(cmd->data->blksz);
                                cfg &= ~(CFG_BLK_LEN_MASK << CFG_BLK_LEN_SHIFT);
                                cfg |= blk_len << CFG_BLK_LEN_SHIFT;
@@ -545,11 +553,6 @@ static void meson_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
        /* Stop execution */
        writel(0, host->regs + SD_EMMC_START);
 
-       /* clear, ack, enable all interrupts */
-       writel(0, host->regs + SD_EMMC_IRQ_EN);
-       writel(IRQ_EN_MASK, host->regs + SD_EMMC_STATUS);
-       writel(IRQ_EN_MASK, host->regs + SD_EMMC_IRQ_EN);
-
        host->mrq = mrq;
 
        if (mrq->sbc)
@@ -669,7 +672,6 @@ static irqreturn_t meson_mmc_irq_thread(int irq, void *dev_id)
        struct mmc_command *cmd = host->cmd;
        struct mmc_data *data;
        unsigned int xfer_bytes;
-       int ret = IRQ_HANDLED;
 
        if (WARN_ON(!mrq))
                return IRQ_NONE;
@@ -678,14 +680,12 @@ static irqreturn_t meson_mmc_irq_thread(int irq, void *dev_id)
                return IRQ_NONE;
 
        data = cmd->data;
-       if (data) {
+       if (data && data->flags & MMC_DATA_READ) {
                xfer_bytes = data->blksz * data->blocks;
-               if (data->flags & MMC_DATA_READ) {
-                       WARN_ON(xfer_bytes > host->bounce_buf_size);
-                       sg_copy_from_buffer(data->sg, data->sg_len,
-                                           host->bounce_buf, xfer_bytes);
-                       data->bytes_xfered = xfer_bytes;
-               }
+               WARN_ON(xfer_bytes > host->bounce_buf_size);
+               sg_copy_from_buffer(data->sg, data->sg_len,
+                                   host->bounce_buf, xfer_bytes);
+               data->bytes_xfered = xfer_bytes;
        }
 
        meson_mmc_read_resp(host->mmc, cmd);
@@ -694,7 +694,7 @@ static irqreturn_t meson_mmc_irq_thread(int irq, void *dev_id)
        else
                meson_mmc_start_cmd(host->mmc, data->stop);
 
-       return ret;
+       return IRQ_HANDLED;
 }
 
 /*
@@ -742,7 +742,8 @@ static int meson_mmc_probe(struct platform_device *pdev)
 
        ret = mmc_of_parse(mmc);
        if (ret) {
-               dev_warn(&pdev->dev, "error parsing DT: %d\n", ret);
+               if (ret != -EPROBE_DEFER)
+                       dev_warn(&pdev->dev, "error parsing DT: %d\n", ret);
                goto free_host;
        }
 
@@ -780,6 +781,7 @@ static int meson_mmc_probe(struct platform_device *pdev)
        /* clear, ack, enable all interrupts */
        writel(0, host->regs + SD_EMMC_IRQ_EN);
        writel(IRQ_EN_MASK, host->regs + SD_EMMC_STATUS);
+       writel(IRQ_EN_MASK, host->regs + SD_EMMC_IRQ_EN);
 
        ret = devm_request_threaded_irq(&pdev->dev, host->irq,
                                        meson_mmc_irq, meson_mmc_irq_thread,
@@ -787,8 +789,11 @@ static int meson_mmc_probe(struct platform_device *pdev)
        if (ret)
                goto free_host;
 
+       mmc->max_blk_count = CMD_CFG_LENGTH_MASK;
+       mmc->max_req_size = mmc->max_blk_count * mmc->max_blk_size;
+
        /* data bounce buffer */
-       host->bounce_buf_size = SZ_512K;
+       host->bounce_buf_size = mmc->max_req_size;
        host->bounce_buf =
                dma_alloc_coherent(host->dev, host->bounce_buf_size,
                                   &host->bounce_dma_addr, GFP_KERNEL);
@@ -814,12 +819,11 @@ static int meson_mmc_remove(struct platform_device *pdev)
 {
        struct meson_host *host = dev_get_drvdata(&pdev->dev);
 
-       if (WARN_ON(!host))
-               return 0;
+       /* disable interrupts */
+       writel(0, host->regs + SD_EMMC_IRQ_EN);
 
-       if (host->bounce_buf)
-               dma_free_coherent(host->dev, host->bounce_buf_size,
-                                 host->bounce_buf, host->bounce_dma_addr);
+       dma_free_coherent(host->dev, host->bounce_buf_size,
+                         host->bounce_buf, host->bounce_dma_addr);
 
        clk_disable_unprepare(host->cfg_div_clk);
        clk_disable_unprepare(host->core_clk);
index b5972440c1bf606e677ad312a9a391576f859f70..0c6420bb2f00fe9f9433000ec27e51af2c5cd4ca 100644 (file)
@@ -507,6 +507,7 @@ static void mmci_dma_data_error(struct mmci_host *host)
 {
        dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n");
        dmaengine_terminate_all(host->dma_current);
+       host->dma_in_progress = false;
        host->dma_current = NULL;
        host->dma_desc_current = NULL;
        host->data->host_cookie = 0;
@@ -565,6 +566,7 @@ static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data)
                mmci_dma_release(host);
        }
 
+       host->dma_in_progress = false;
        host->dma_current = NULL;
        host->dma_desc_current = NULL;
 }
@@ -665,6 +667,7 @@ static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
        dev_vdbg(mmc_dev(host->mmc),
                 "Submit MMCI DMA job, sglen %d blksz %04x blks %04x flags %08x\n",
                 data->sg_len, data->blksz, data->blocks, data->flags);
+       host->dma_in_progress = true;
        dmaengine_submit(host->dma_desc_current);
        dma_async_issue_pending(host->dma_current);
 
@@ -740,8 +743,10 @@ static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq,
                if (host->dma_desc_current == next->dma_desc)
                        host->dma_desc_current = NULL;
 
-               if (host->dma_current == next->dma_chan)
+               if (host->dma_current == next->dma_chan) {
+                       host->dma_in_progress = false;
                        host->dma_current = NULL;
+               }
 
                next->dma_desc = NULL;
                next->dma_chan = NULL;
index 56322c6afba4c9a32e4f54c2386aa192ead02bdf..4a8bef1aac8f7b73b215f42ba962bcbd004ba642 100644 (file)
@@ -245,8 +245,9 @@ struct mmci_host {
        struct dma_chan         *dma_tx_channel;
        struct dma_async_tx_descriptor  *dma_desc_current;
        struct mmci_host_next   next_data;
+       bool                    dma_in_progress;
 
-#define dma_inprogress(host)   ((host)->dma_current)
+#define dma_inprogress(host)   ((host)->dma_in_progress)
 #else
 #define dma_inprogress(host)   (0)
 #endif
index 10ef2ae1d2f6d80e1f563265263eb25cc7cd7ed4..8e32580c12b520017eb73af884f1b04607c3a78b 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/interrupt.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/core.h>
@@ -1074,11 +1075,8 @@ static int msdc_card_busy(struct mmc_host *mmc)
        struct msdc_host *host = mmc_priv(mmc);
        u32 status = readl(host->base + MSDC_PS);
 
-       /* check if any pin between dat[0:3] is low */
-       if (((status >> 16) & 0xf) != 0xf)
-               return 1;
-
-       return 0;
+       /* only check if data0 is low */
+       return !(status & BIT(16));
 }
 
 static void msdc_request_timeout(struct work_struct *work)
index c8b8ac66ff7e3a4839ba4943c9069e540846c87e..add1e70195ea6a2c7111f768c5865d15b17f085e 100644 (file)
@@ -153,7 +153,11 @@ static void mxs_mmc_request_done(struct mxs_mmc_host *host)
                }
        }
 
-       if (data) {
+       if (cmd == mrq->sbc) {
+               /* Finished CMD23, now send actual command. */
+               mxs_mmc_start_cmd(host, mrq->cmd);
+               return;
+       } else if (data) {
                dma_unmap_sg(mmc_dev(host->mmc), data->sg,
                             data->sg_len, ssp->dma_dir);
                /*
@@ -166,7 +170,7 @@ static void mxs_mmc_request_done(struct mxs_mmc_host *host)
                        data->bytes_xfered = 0;
 
                host->data = NULL;
-               if (mrq->stop) {
+               if (data->stop && (data->error || !mrq->sbc)) {
                        mxs_mmc_start_cmd(host, mrq->stop);
                        return;
                }
@@ -495,7 +499,11 @@ static void mxs_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
 
        WARN_ON(host->mrq != NULL);
        host->mrq = mrq;
-       mxs_mmc_start_cmd(host, mrq->cmd);
+
+       if (mrq->sbc)
+               mxs_mmc_start_cmd(host, mrq->sbc);
+       else
+               mxs_mmc_start_cmd(host, mrq->cmd);
 }
 
 static void mxs_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
@@ -642,7 +650,7 @@ static int mxs_mmc_probe(struct platform_device *pdev)
        /* set mmc core parameters */
        mmc->ops = &mxs_mmc_ops;
        mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED |
-                   MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL;
+                   MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL | MMC_CAP_CMD23;
 
        host->broken_cd = of_property_read_bool(np, "broken-cd");
 
index be3c49fa7382f31bde9b671834e74dc9f41c9874..bd49f34d765460283e13649a6030fa358e1eaaaf 100644 (file)
@@ -893,7 +893,7 @@ static void mmc_omap_cover_handler(unsigned long param)
         * If no card is inserted, we postpone polling until
         * the cover has been closed.
         */
-       if (slot->mmc->card == NULL || !mmc_card_present(slot->mmc->card))
+       if (slot->mmc->card == NULL)
                return;
 
        mod_timer(&slot->cover_timer,
index ad11c4cc12eddc65c04908597ccfa6f162cc4cd4..a58bd653ed8b33a867eb777614a25349b48bb8ed 100644 (file)
@@ -1162,7 +1162,7 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
        if (status & ERR_EN) {
                omap_hsmmc_dbg_report_irq(host, status);
 
-               if (status & (CTO_EN | CCRC_EN))
+               if (status & (CTO_EN | CCRC_EN | CEB_EN))
                        end_cmd = 1;
                if (host->data || host->response_busy) {
                        end_trans = !end_cmd;
@@ -1469,10 +1469,11 @@ static int omap_hsmmc_setup_dma_transfer(struct omap_hsmmc_host *host,
 }
 
 static void set_data_timeout(struct omap_hsmmc_host *host,
-                            unsigned int timeout_ns,
+                            unsigned long long timeout_ns,
                             unsigned int timeout_clks)
 {
-       unsigned int timeout, cycle_ns;
+       unsigned long long timeout = timeout_ns;
+       unsigned int cycle_ns;
        uint32_t reg, clkd, dto = 0;
 
        reg = OMAP_HSMMC_READ(host->base, SYSCTL);
@@ -1481,7 +1482,7 @@ static void set_data_timeout(struct omap_hsmmc_host *host,
                clkd = 1;
 
        cycle_ns = 1000000000 / (host->clk_rate / clkd);
-       timeout = timeout_ns / cycle_ns;
+       do_div(timeout, cycle_ns);
        timeout += timeout_clks;
        if (timeout) {
                while ((timeout & 0x80000000) == 0) {
@@ -1527,16 +1528,24 @@ static int
 omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req)
 {
        int ret;
+       unsigned long long timeout;
+
        host->data = req->data;
 
        if (req->data == NULL) {
                OMAP_HSMMC_WRITE(host->base, BLK, 0);
-               /*
-                * Set an arbitrary 100ms data timeout for commands with
-                * busy signal.
-                */
-               if (req->cmd->flags & MMC_RSP_BUSY)
-                       set_data_timeout(host, 100000000U, 0);
+               if (req->cmd->flags & MMC_RSP_BUSY) {
+                       timeout = req->cmd->busy_timeout * NSEC_PER_MSEC;
+
+                       /*
+                        * Set an arbitrary 100ms data timeout for commands with
+                        * busy signal and no indication of busy_timeout.
+                        */
+                       if (!timeout)
+                               timeout = 100000000U;
+
+                       set_data_timeout(host, timeout, 0);
+               }
                return 0;
        }
 
index ecb99a8d2fa21fe036c8973abc4ed00d5956e440..41b57713b620aecdb2e3a3348c0a9d8949e7ce49 100644 (file)
@@ -707,7 +707,7 @@ static int sd_tuning_rx_cmd(struct realtek_pci_sdmmc *host,
                u8 opcode, u8 sample_point)
 {
        int err;
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
 
        err = sd_change_phase(host, sample_point, true);
        if (err < 0)
index dc1abd14acbc76301746cec3182f453cd8980278..12d2fbe9c520a69741f587d24888b13773bcc74d 100644 (file)
@@ -682,7 +682,7 @@ static int sd_tuning_rx_cmd(struct rtsx_usb_sdmmc *host,
                u8 opcode, u8 sample_point)
 {
        int err;
-       struct mmc_command cmd = {0};
+       struct mmc_command cmd = {};
 
        err = sd_change_phase(host, sample_point, 0);
        if (err)
index 932a4b1fed33ffafb9a9c219e79976b6e23d8bfa..7a173f8c455b4b23cdda62e7f1b93e3f704aed99 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <linux/gpio.h>
+#include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/io.h>
 
index 278a5a435ab76bc422dd748617c96611fe09b105..9dcb7048e3b15b6a1c0e1f321e7f267a9319fb20 100644 (file)
@@ -467,7 +467,10 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
        if (sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD)) {
                bool v = sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL);
 
-               if (mmc_gpiod_request_cd(host->mmc, NULL, 0, v, 0, NULL)) {
+               err = mmc_gpiod_request_cd(host->mmc, NULL, 0, v, 0, NULL);
+               if (err) {
+                       if (err == -EPROBE_DEFER)
+                               goto err_free;
                        dev_warn(dev, "failed to setup card detect gpio\n");
                        c->use_runtime_pm = false;
                }
index 4b0ecb981842248b1cc4ea8edaf35dc4bac753e1..316cfec3f0050a988e42d50129479b58bca233ae 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/iopoll.h>
 #include <linux/module.h>
 #include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
 
 #include "sdhci-pltfm.h"
 
@@ -25,7 +26,7 @@
 #define   SDHCI_CDNS_HRS04_ACK                 BIT(26)
 #define   SDHCI_CDNS_HRS04_RD                  BIT(25)
 #define   SDHCI_CDNS_HRS04_WR                  BIT(24)
-#define   SDHCI_CDNS_HRS04_RDATA_SHIFT         12
+#define   SDHCI_CDNS_HRS04_RDATA_SHIFT         16
 #define   SDHCI_CDNS_HRS04_WDATA_SHIFT         8
 #define   SDHCI_CDNS_HRS04_ADDR_SHIFT          0
 
index de132e28175342ea5869f1da1c003a0d16c2b6a7..ece8b37e51ddde167b44069e80bdfb5c3105fa19 100644 (file)
                                SDHCI_QUIRK_PIO_NEEDS_DELAY | \
                                SDHCI_QUIRK_NO_HISPD_BIT)
 
-#define ESDHC_PROCTL           0x28
-
-#define ESDHC_SYSTEM_CONTROL   0x2c
-#define ESDHC_CLOCK_MASK       0x0000fff0
-#define ESDHC_PREDIV_SHIFT     8
-#define ESDHC_DIVIDER_SHIFT    4
-#define ESDHC_CLOCK_PEREN      0x00000004
-#define ESDHC_CLOCK_HCKEN      0x00000002
-#define ESDHC_CLOCK_IPGEN      0x00000001
-
 /* pltfm-specific */
 #define ESDHC_HOST_CONTROL_LE  0x20
 
 /*
- * P2020 interpretation of the SDHCI_HOST_CONTROL register
+ * eSDHC register definition
  */
-#define ESDHC_CTRL_4BITBUS          (0x1 << 1)
-#define ESDHC_CTRL_8BITBUS          (0x2 << 1)
-#define ESDHC_CTRL_BUSWIDTH_MASK    (0x3 << 1)
-
-/* OF-specific */
-#define ESDHC_DMA_SYSCTL       0x40c
-#define ESDHC_DMA_SNOOP                0x00000040
 
-#define ESDHC_HOST_CONTROL_RES 0x01
+/* Present State Register */
+#define ESDHC_PRSSTAT                  0x24
+#define ESDHC_CLOCK_STABLE             0x00000008
+
+/* Protocol Control Register */
+#define ESDHC_PROCTL                   0x28
+#define ESDHC_CTRL_4BITBUS             (0x1 << 1)
+#define ESDHC_CTRL_8BITBUS             (0x2 << 1)
+#define ESDHC_CTRL_BUSWIDTH_MASK       (0x3 << 1)
+#define ESDHC_HOST_CONTROL_RES         0x01
+
+/* System Control Register */
+#define ESDHC_SYSTEM_CONTROL           0x2c
+#define ESDHC_CLOCK_MASK               0x0000fff0
+#define ESDHC_PREDIV_SHIFT             8
+#define ESDHC_DIVIDER_SHIFT            4
+#define ESDHC_CLOCK_SDCLKEN            0x00000008
+#define ESDHC_CLOCK_PEREN              0x00000004
+#define ESDHC_CLOCK_HCKEN              0x00000002
+#define ESDHC_CLOCK_IPGEN              0x00000001
+
+/* Control Register for DMA transfer */
+#define ESDHC_DMA_SYSCTL               0x40c
+#define ESDHC_DMA_SNOOP                        0x00000040
 
 #endif /* _DRIVERS_MMC_SDHCI_ESDHC_H */
index d7046d67415a429a16502ffc5bcc14c515720b3e..3275d49958120857d899384237bc905ad5fd17a5 100644 (file)
@@ -211,14 +211,19 @@ static const struct sdhci_iproc_data iproc_data = {
 static const struct sdhci_pltfm_data sdhci_bcm2835_pltfm_data = {
        .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
                  SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
-                 SDHCI_QUIRK_MISSING_CAPS,
+                 SDHCI_QUIRK_MISSING_CAPS |
+                 SDHCI_QUIRK_NO_HISPD_BIT,
        .ops = &sdhci_iproc_32only_ops,
 };
 
 static const struct sdhci_iproc_data bcm2835_data = {
        .pdata = &sdhci_bcm2835_pltfm_data,
-       .caps = SDHCI_CAN_VDD_330,
-       .caps1 = 0x00000000,
+       .caps = ((0x1 << SDHCI_MAX_BLOCK_SHIFT)
+                       & SDHCI_MAX_BLOCK_MASK) |
+               SDHCI_CAN_VDD_330 |
+               SDHCI_CAN_DO_HISPD,
+       .caps1 = SDHCI_DRIVER_TYPE_A |
+                SDHCI_DRIVER_TYPE_C,
        .mmc_caps = 0x00000000,
 };
 
index 32879b845b7548ef299add09d84d24e445296f2c..10cdc84d51136694d8e95413b754d5f6d26ace48 100644 (file)
@@ -69,6 +69,7 @@
 #define CORE_DLL_CLOCK_DISABLE BIT(21)
 
 #define CORE_VENDOR_SPEC       0x10c
+#define CORE_VENDOR_SPEC_POR_VAL       0xa1c
 #define CORE_CLK_PWRSAVE       BIT(1)
 #define CORE_HC_MCLK_SEL_DFLT  (2 << 8)
 #define CORE_HC_MCLK_SEL_HS400 (3 << 8)
 
 #define CORE_DDR_200_CFG               0x184
 #define CORE_CDC_T4_DLY_SEL            BIT(0)
+#define CORE_CMDIN_RCLK_EN             BIT(1)
 #define CORE_START_CDC_TRAFFIC         BIT(6)
 #define CORE_VENDOR_SPEC3      0x1b0
 #define CORE_PWRSAVE_DLL       BIT(3)
@@ -138,6 +140,46 @@ struct sdhci_msm_host {
        bool use_cdclp533;
 };
 
+static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host,
+                                                   unsigned int clock)
+{
+       struct mmc_ios ios = host->mmc->ios;
+       /*
+        * The SDHC requires internal clock frequency to be double the
+        * actual clock that will be set for DDR mode. The controller
+        * uses the faster clock(100/400MHz) for some of its parts and
+        * send the actual required clock (50/200MHz) to the card.
+        */
+       if (ios.timing == MMC_TIMING_UHS_DDR50 ||
+           ios.timing == MMC_TIMING_MMC_DDR52 ||
+           ios.timing == MMC_TIMING_MMC_HS400 ||
+           host->flags & SDHCI_HS400_TUNING)
+               clock *= 2;
+       return clock;
+}
+
+static void msm_set_clock_rate_for_bus_mode(struct sdhci_host *host,
+                                           unsigned int clock)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+       struct mmc_ios curr_ios = host->mmc->ios;
+       int rc;
+
+       clock = msm_get_clock_rate_for_bus_mode(host, clock);
+       rc = clk_set_rate(msm_host->clk, clock);
+       if (rc) {
+               pr_err("%s: Failed to set clock at rate %u at timing %d\n",
+                      mmc_hostname(host->mmc), clock,
+                      curr_ios.timing);
+               return;
+       }
+       msm_host->clk_rate = clock;
+       pr_debug("%s: Setting clock at rate %lu at timing %d\n",
+                mmc_hostname(host->mmc), clk_get_rate(msm_host->clk),
+                curr_ios.timing);
+}
+
 /* Platform specific tuning */
 static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host, u8 poll)
 {
@@ -464,6 +506,122 @@ static int msm_init_cm_dll(struct sdhci_host *host)
        return 0;
 }
 
+static void msm_hc_select_default(struct sdhci_host *host)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+       u32 config;
+
+       if (!msm_host->use_cdclp533) {
+               config = readl_relaxed(host->ioaddr +
+                               CORE_VENDOR_SPEC3);
+               config &= ~CORE_PWRSAVE_DLL;
+               writel_relaxed(config, host->ioaddr +
+                               CORE_VENDOR_SPEC3);
+       }
+
+       config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC);
+       config &= ~CORE_HC_MCLK_SEL_MASK;
+       config |= CORE_HC_MCLK_SEL_DFLT;
+       writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC);
+
+       /*
+        * Disable HC_SELECT_IN to be able to use the UHS mode select
+        * configuration from Host Control2 register for all other
+        * modes.
+        * Write 0 to HC_SELECT_IN and HC_SELECT_IN_EN field
+        * in VENDOR_SPEC_FUNC
+        */
+       config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC);
+       config &= ~CORE_HC_SELECT_IN_EN;
+       config &= ~CORE_HC_SELECT_IN_MASK;
+       writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC);
+
+       /*
+        * Make sure above writes impacting free running MCLK are completed
+        * before changing the clk_rate at GCC.
+        */
+       wmb();
+}
+
+static void msm_hc_select_hs400(struct sdhci_host *host)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+       struct mmc_ios ios = host->mmc->ios;
+       u32 config, dll_lock;
+       int rc;
+
+       /* Select the divided clock (free running MCLK/2) */
+       config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC);
+       config &= ~CORE_HC_MCLK_SEL_MASK;
+       config |= CORE_HC_MCLK_SEL_HS400;
+
+       writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC);
+       /*
+        * Select HS400 mode using the HC_SELECT_IN from VENDOR SPEC
+        * register
+        */
+       if ((msm_host->tuning_done || ios.enhanced_strobe) &&
+           !msm_host->calibration_done) {
+               config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC);
+               config |= CORE_HC_SELECT_IN_HS400;
+               config |= CORE_HC_SELECT_IN_EN;
+               writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC);
+       }
+       if (!msm_host->clk_rate && !msm_host->use_cdclp533) {
+               /*
+                * Poll on DLL_LOCK or DDR_DLL_LOCK bits in
+                * CORE_DLL_STATUS to be set.  This should get set
+                * within 15 us at 200 MHz.
+                */
+               rc = readl_relaxed_poll_timeout(host->ioaddr +
+                                               CORE_DLL_STATUS,
+                                               dll_lock,
+                                               (dll_lock &
+                                               (CORE_DLL_LOCK |
+                                               CORE_DDR_DLL_LOCK)), 10,
+                                               1000);
+               if (rc == -ETIMEDOUT)
+                       pr_err("%s: Unable to get DLL_LOCK/DDR_DLL_LOCK, dll_status: 0x%08x\n",
+                              mmc_hostname(host->mmc), dll_lock);
+       }
+       /*
+        * Make sure above writes impacting free running MCLK are completed
+        * before changing the clk_rate at GCC.
+        */
+       wmb();
+}
+
+/*
+ * sdhci_msm_hc_select_mode :- In general all timing modes are
+ * controlled via UHS mode select in Host Control2 register.
+ * eMMC specific HS200/HS400 doesn't have their respective modes
+ * defined here, hence we use these values.
+ *
+ * HS200 - SDR104 (Since they both are equivalent in functionality)
+ * HS400 - This involves multiple configurations
+ *             Initially SDR104 - when tuning is required as HS200
+ *             Then when switching to DDR @ 400MHz (HS400) we use
+ *             the vendor specific HC_SELECT_IN to control the mode.
+ *
+ * In addition to controlling the modes we also need to select the
+ * correct input clock for DLL depending on the mode.
+ *
+ * HS400 - divided clock (free running MCLK/2)
+ * All other modes - default (free running MCLK)
+ */
+void sdhci_msm_hc_select_mode(struct sdhci_host *host)
+{
+       struct mmc_ios ios = host->mmc->ios;
+
+       if (ios.timing == MMC_TIMING_MMC_HS400 ||
+           host->flags & SDHCI_HS400_TUNING)
+               msm_hc_select_hs400(host);
+       else
+               msm_hc_select_default(host);
+}
+
 static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -506,19 +664,7 @@ static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host)
        config &= ~CORE_START_CDC_TRAFFIC;
        writel_relaxed(config, host->ioaddr + CORE_DDR_200_CFG);
 
-       /*
-        * Perform CDC Register Initialization Sequence
-        *
-        * CORE_CSR_CDC_CTLR_CFG0       0x11800EC
-        * CORE_CSR_CDC_CTLR_CFG1       0x3011111
-        * CORE_CSR_CDC_CAL_TIMER_CFG0  0x1201000
-        * CORE_CSR_CDC_CAL_TIMER_CFG1  0x4
-        * CORE_CSR_CDC_REFCOUNT_CFG    0xCB732020
-        * CORE_CSR_CDC_COARSE_CAL_CFG  0xB19
-        * CORE_CSR_CDC_DELAY_CFG       0x3AC
-        * CORE_CDC_OFFSET_CFG          0x0
-        * CORE_CDC_SLAVE_DDA_CFG       0x16334
-        */
+       /* Perform CDC Register Initialization Sequence */
 
        writel_relaxed(0x11800EC, host->ioaddr + CORE_CSR_CDC_CTLR_CFG0);
        writel_relaxed(0x3011111, host->ioaddr + CORE_CSR_CDC_CTLR_CFG1);
@@ -526,7 +672,7 @@ static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host)
        writel_relaxed(0x4, host->ioaddr + CORE_CSR_CDC_CAL_TIMER_CFG1);
        writel_relaxed(0xCB732020, host->ioaddr + CORE_CSR_CDC_REFCOUNT_CFG);
        writel_relaxed(0xB19, host->ioaddr + CORE_CSR_CDC_COARSE_CAL_CFG);
-       writel_relaxed(0x3AC, host->ioaddr + CORE_CSR_CDC_DELAY_CFG);
+       writel_relaxed(0x4E2, host->ioaddr + CORE_CSR_CDC_DELAY_CFG);
        writel_relaxed(0x0, host->ioaddr + CORE_CDC_OFFSET_CFG);
        writel_relaxed(0x16334, host->ioaddr + CORE_CDC_SLAVE_DDA_CFG);
 
@@ -579,6 +725,7 @@ out:
 
 static int sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host)
 {
+       struct mmc_host *mmc = host->mmc;
        u32 dll_status, config;
        int ret;
 
@@ -593,6 +740,12 @@ static int sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host)
         */
        writel_relaxed(DDR_CONFIG_POR_VAL, host->ioaddr + CORE_DDR_CONFIG);
 
+       if (mmc->ios.enhanced_strobe) {
+               config = readl_relaxed(host->ioaddr + CORE_DDR_200_CFG);
+               config |= CORE_CMDIN_RCLK_EN;
+               writel_relaxed(config, host->ioaddr + CORE_DDR_200_CFG);
+       }
+
        config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2);
        config |= CORE_DDR_CAL_EN;
        writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG_2);
@@ -627,6 +780,7 @@ static int sdhci_msm_hs400_dll_calibration(struct sdhci_host *host)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+       struct mmc_host *mmc = host->mmc;
        int ret;
        u32 config;
 
@@ -640,14 +794,17 @@ static int sdhci_msm_hs400_dll_calibration(struct sdhci_host *host)
        if (ret)
                goto out;
 
-       /* Set the selected phase in delay line hw block */
-       ret = msm_config_cm_dll_phase(host, msm_host->saved_tuning_phase);
-       if (ret)
-               goto out;
+       if (!mmc->ios.enhanced_strobe) {
+               /* Set the selected phase in delay line hw block */
+               ret = msm_config_cm_dll_phase(host,
+                                             msm_host->saved_tuning_phase);
+               if (ret)
+                       goto out;
+               config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
+               config |= CORE_CMD_DAT_TRACK_SEL;
+               writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
+       }
 
-       config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
-       config |= CORE_CMD_DAT_TRACK_SEL;
-       writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
        if (msm_host->use_cdclp533)
                ret = sdhci_msm_cdclp533_calibration(host);
        else
@@ -658,12 +815,12 @@ out:
        return ret;
 }
 
-static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
+static int sdhci_msm_execute_tuning(struct mmc_host *mmc, u32 opcode)
 {
+       struct sdhci_host *host = mmc_priv(mmc);
        int tuning_seq_cnt = 3;
        u8 phase, tuned_phases[16], tuned_phase_cnt = 0;
        int rc;
-       struct mmc_host *mmc = host->mmc;
        struct mmc_ios ios = host->mmc->ios;
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
@@ -678,6 +835,17 @@ static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
            ios.timing == MMC_TIMING_UHS_SDR104))
                return 0;
 
+       /*
+        * For HS400 tuning in HS200 timing requires:
+        * - select MCLK/2 in VENDOR_SPEC
+        * - program MCLK to 400MHz (or nearest supported) in GCC
+        */
+       if (host->flags & SDHCI_HS400_TUNING) {
+               sdhci_msm_hc_select_mode(host);
+               msm_set_clock_rate_for_bus_mode(host, ios.clock);
+               host->flags &= ~SDHCI_HS400_TUNING;
+       }
+
 retry:
        /* First of all reset the tuning block */
        rc = msm_init_cm_dll(host);
@@ -732,6 +900,30 @@ retry:
        return rc;
 }
 
+/*
+ * sdhci_msm_hs400 - Calibrate the DLL for HS400 bus speed mode operation.
+ * This needs to be done for both tuning and enhanced_strobe mode.
+ * DLL operation is only needed for clock > 100MHz. For clock <= 100MHz
+ * fixed feedback clock is used.
+ */
+static void sdhci_msm_hs400(struct sdhci_host *host, struct mmc_ios *ios)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+       int ret;
+
+       if (host->clock > CORE_FREQ_100MHZ &&
+           (msm_host->tuning_done || ios->enhanced_strobe) &&
+           !msm_host->calibration_done) {
+               ret = sdhci_msm_hs400_dll_calibration(host);
+               if (!ret)
+                       msm_host->calibration_done = true;
+               else
+                       pr_err("%s: Failed to calibrate DLL for hs400 mode (%d)\n",
+                              mmc_hostname(host->mmc), ret);
+       }
+}
+
 static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host,
                                        unsigned int uhs)
 {
@@ -800,12 +992,10 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host,
        sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
 
        spin_unlock_irq(&host->lock);
-       /* CDCLP533 HW calibration is only required for HS400 mode*/
-       if (host->clock > CORE_FREQ_100MHZ &&
-           msm_host->tuning_done && !msm_host->calibration_done &&
-           mmc->ios.timing == MMC_TIMING_MMC_HS400)
-               if (!sdhci_msm_hs400_dll_calibration(host))
-                       msm_host->calibration_done = true;
+
+       if (mmc->ios.timing == MMC_TIMING_MMC_HS400)
+               sdhci_msm_hs400(host, &mmc->ios);
+
        spin_lock_irq(&host->lock);
 }
 
@@ -893,9 +1083,6 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
-       struct mmc_ios curr_ios = host->mmc->ios;
-       u32 config, dll_lock;
-       int rc;
 
        if (!clock) {
                msm_host->clk_rate = clock;
@@ -903,117 +1090,11 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
        }
 
        spin_unlock_irq(&host->lock);
-       /*
-        * The SDHC requires internal clock frequency to be double the
-        * actual clock that will be set for DDR mode. The controller
-        * uses the faster clock(100/400MHz) for some of its parts and
-        * send the actual required clock (50/200MHz) to the card.
-        */
-       if (curr_ios.timing == MMC_TIMING_UHS_DDR50 ||
-           curr_ios.timing == MMC_TIMING_MMC_DDR52 ||
-           curr_ios.timing == MMC_TIMING_MMC_HS400)
-               clock *= 2;
-       /*
-        * In general all timing modes are controlled via UHS mode select in
-        * Host Control2 register. eMMC specific HS200/HS400 doesn't have
-        * their respective modes defined here, hence we use these values.
-        *
-        * HS200 - SDR104 (Since they both are equivalent in functionality)
-        * HS400 - This involves multiple configurations
-        *              Initially SDR104 - when tuning is required as HS200
-        *              Then when switching to DDR @ 400MHz (HS400) we use
-        *              the vendor specific HC_SELECT_IN to control the mode.
-        *
-        * In addition to controlling the modes we also need to select the
-        * correct input clock for DLL depending on the mode.
-        *
-        * HS400 - divided clock (free running MCLK/2)
-        * All other modes - default (free running MCLK)
-        */
-       if (curr_ios.timing == MMC_TIMING_MMC_HS400) {
-               /* Select the divided clock (free running MCLK/2) */
-               config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC);
-               config &= ~CORE_HC_MCLK_SEL_MASK;
-               config |= CORE_HC_MCLK_SEL_HS400;
 
-               writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC);
-               /*
-                * Select HS400 mode using the HC_SELECT_IN from VENDOR SPEC
-                * register
-                */
-               if (msm_host->tuning_done && !msm_host->calibration_done) {
-                       /*
-                        * Write 0x6 to HC_SELECT_IN and 1 to HC_SELECT_IN_EN
-                        * field in VENDOR_SPEC_FUNC
-                        */
-                       config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC);
-                       config |= CORE_HC_SELECT_IN_HS400;
-                       config |= CORE_HC_SELECT_IN_EN;
-                       writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC);
-               }
-               if (!msm_host->clk_rate && !msm_host->use_cdclp533) {
-                       /*
-                        * Poll on DLL_LOCK or DDR_DLL_LOCK bits in
-                        * CORE_DLL_STATUS to be set.  This should get set
-                        * within 15 us at 200 MHz.
-                        */
-                       rc = readl_relaxed_poll_timeout(host->ioaddr +
-                                                       CORE_DLL_STATUS,
-                                                       dll_lock,
-                                                       (dll_lock &
-                                                       (CORE_DLL_LOCK |
-                                                       CORE_DDR_DLL_LOCK)), 10,
-                                                       1000);
-                       if (rc == -ETIMEDOUT)
-                               pr_err("%s: Unable to get DLL_LOCK/DDR_DLL_LOCK, dll_status: 0x%08x\n",
-                                      mmc_hostname(host->mmc), dll_lock);
-               }
-       } else {
-               if (!msm_host->use_cdclp533) {
-                       config = readl_relaxed(host->ioaddr +
-                                       CORE_VENDOR_SPEC3);
-                       config &= ~CORE_PWRSAVE_DLL;
-                       writel_relaxed(config, host->ioaddr +
-                                       CORE_VENDOR_SPEC3);
-               }
+       sdhci_msm_hc_select_mode(host);
 
-               config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC);
-               config &= ~CORE_HC_MCLK_SEL_MASK;
-               config |= CORE_HC_MCLK_SEL_DFLT;
-               writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC);
+       msm_set_clock_rate_for_bus_mode(host, clock);
 
-               /*
-                * Disable HC_SELECT_IN to be able to use the UHS mode select
-                * configuration from Host Control2 register for all other
-                * modes.
-                * Write 0 to HC_SELECT_IN and HC_SELECT_IN_EN field
-                * in VENDOR_SPEC_FUNC
-                */
-               config = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC);
-               config &= ~CORE_HC_SELECT_IN_EN;
-               config &= ~CORE_HC_SELECT_IN_MASK;
-               writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC);
-       }
-
-       /*
-        * Make sure above writes impacting free running MCLK are completed
-        * before changing the clk_rate at GCC.
-        */
-       wmb();
-
-       rc = clk_set_rate(msm_host->clk, clock);
-       if (rc) {
-               pr_err("%s: Failed to set clock at rate %u at timing %d\n",
-                      mmc_hostname(host->mmc), clock,
-                      curr_ios.timing);
-               goto out_lock;
-       }
-       msm_host->clk_rate = clock;
-       pr_debug("%s: Setting clock at rate %lu at timing %d\n",
-                mmc_hostname(host->mmc), clk_get_rate(msm_host->clk),
-                curr_ios.timing);
-
-out_lock:
        spin_lock_irq(&host->lock);
 out:
        __sdhci_msm_set_clock(host, clock);
@@ -1027,7 +1108,6 @@ static const struct of_device_id sdhci_msm_dt_match[] = {
 MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match);
 
 static const struct sdhci_ops sdhci_msm_ops = {
-       .platform_execute_tuning = sdhci_msm_execute_tuning,
        .reset = sdhci_reset,
        .set_clock = sdhci_msm_set_clock,
        .get_min_clock = sdhci_msm_get_min_clock,
@@ -1134,17 +1214,9 @@ static int sdhci_msm_probe(struct platform_device *pdev)
                goto clk_disable;
        }
 
-       config = readl_relaxed(msm_host->core_mem + CORE_POWER);
-       config |= CORE_SW_RST;
-       writel_relaxed(config, msm_host->core_mem + CORE_POWER);
-
-       /* SW reset can take upto 10HCLK + 15MCLK cycles. (min 40us) */
-       usleep_range(1000, 5000);
-       if (readl(msm_host->core_mem + CORE_POWER) & CORE_SW_RST) {
-               dev_err(&pdev->dev, "Stuck in reset\n");
-               ret = -ETIMEDOUT;
-               goto clk_disable;
-       }
+       /* Reset the vendor spec register to power on reset state */
+       writel_relaxed(CORE_VENDOR_SPEC_POR_VAL,
+                      host->ioaddr + CORE_VENDOR_SPEC);
 
        /* Set HC_MODE_EN bit in HC_MODE register */
        writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE));
@@ -1210,6 +1282,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)
                                         MSM_MMC_AUTOSUSPEND_DELAY_MS);
        pm_runtime_use_autosuspend(&pdev->dev);
 
+       host->mmc_host_ops.execute_tuning = sdhci_msm_execute_tuning;
        ret = sdhci_add_host(host);
        if (ret)
                goto pm_runtime_disable;
index 9a6eb4492172fafd81cc9a2e6162f7d8b331b0c4..d3aa67142839b2e36e654febd911d8e9eee129b6 100644 (file)
@@ -431,6 +431,7 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
        struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
        int pre_div = 1;
        int div = 1;
+       u32 timeout;
        u32 temp;
 
        host->mmc->actual_clock = 0;
@@ -451,8 +452,8 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
        }
 
        temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
-       temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
-               | ESDHC_CLOCK_MASK);
+       temp &= ~(ESDHC_CLOCK_SDCLKEN | ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN |
+                 ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK);
        sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
 
        while (host->max_clk / pre_div / 16 > clock && pre_div < 256)
@@ -472,7 +473,21 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
                | (div << ESDHC_DIVIDER_SHIFT)
                | (pre_div << ESDHC_PREDIV_SHIFT));
        sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
-       mdelay(1);
+
+       /* Wait max 20 ms */
+       timeout = 20;
+       while (!(sdhci_readl(host, ESDHC_PRSSTAT) & ESDHC_CLOCK_STABLE)) {
+               if (timeout == 0) {
+                       pr_err("%s: Internal clock never stabilised.\n",
+                               mmc_hostname(host->mmc));
+                       return;
+               }
+               timeout--;
+               mdelay(1);
+       }
+
+       temp |= ESDHC_CLOCK_SDCLKEN;
+       sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
 }
 
 static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width)
@@ -569,16 +584,19 @@ static const struct sdhci_ops sdhci_esdhc_le_ops = {
 };
 
 static const struct sdhci_pltfm_data sdhci_esdhc_be_pdata = {
-       .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_CARD_DETECTION
-               | SDHCI_QUIRK_NO_CARD_NO_RESET
-               | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
+       .quirks = ESDHC_DEFAULT_QUIRKS |
+#ifdef CONFIG_PPC
+                 SDHCI_QUIRK_BROKEN_CARD_DETECTION |
+#endif
+                 SDHCI_QUIRK_NO_CARD_NO_RESET |
+                 SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
        .ops = &sdhci_esdhc_be_ops,
 };
 
 static const struct sdhci_pltfm_data sdhci_esdhc_le_pdata = {
-       .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_CARD_DETECTION
-               | SDHCI_QUIRK_NO_CARD_NO_RESET
-               | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
+       .quirks = ESDHC_DEFAULT_QUIRKS |
+                 SDHCI_QUIRK_NO_CARD_NO_RESET |
+                 SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
        .ops = &sdhci_esdhc_le_ops,
 };
 
@@ -643,8 +661,7 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
            of_device_is_compatible(np, "fsl,p5020-esdhc") ||
            of_device_is_compatible(np, "fsl,p4080-esdhc") ||
            of_device_is_compatible(np, "fsl,p1020-esdhc") ||
-           of_device_is_compatible(np, "fsl,t1040-esdhc") ||
-           of_device_is_compatible(np, "fsl,ls1021a-esdhc"))
+           of_device_is_compatible(np, "fsl,t1040-esdhc"))
                host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
 
        if (of_device_is_compatible(np, "fsl,ls1021a-esdhc"))
index 1a72d32af07f333504f7d85ff287fcd5dbf62c7b..982b3e349426141710abef87f75819c518bf4a45 100644 (file)
@@ -424,7 +424,6 @@ static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot)
 static int byt_sd_probe_slot(struct sdhci_pci_slot *slot)
 {
        slot->host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
-       slot->cd_con_id = NULL;
        slot->cd_idx = 0;
        slot->cd_override_level = true;
        if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BXT_SD ||
@@ -866,6 +865,86 @@ enum amd_chipset_gen {
        AMD_CHIPSET_UNKNOWN,
 };
 
+/* AMD registers */
+#define AMD_SD_AUTO_PATTERN            0xB8
+#define AMD_MSLEEP_DURATION            4
+#define AMD_SD_MISC_CONTROL            0xD0
+#define AMD_MAX_TUNE_VALUE             0x0B
+#define AMD_AUTO_TUNE_SEL              0x10800
+#define AMD_FIFO_PTR                   0x30
+#define AMD_BIT_MASK                   0x1F
+
+static void amd_tuning_reset(struct sdhci_host *host)
+{
+       unsigned int val;
+
+       val = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+       val |= SDHCI_CTRL_PRESET_VAL_ENABLE | SDHCI_CTRL_EXEC_TUNING;
+       sdhci_writew(host, val, SDHCI_HOST_CONTROL2);
+
+       val = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+       val &= ~SDHCI_CTRL_EXEC_TUNING;
+       sdhci_writew(host, val, SDHCI_HOST_CONTROL2);
+}
+
+static void amd_config_tuning_phase(struct pci_dev *pdev, u8 phase)
+{
+       unsigned int val;
+
+       pci_read_config_dword(pdev, AMD_SD_AUTO_PATTERN, &val);
+       val &= ~AMD_BIT_MASK;
+       val |= (AMD_AUTO_TUNE_SEL | (phase << 1));
+       pci_write_config_dword(pdev, AMD_SD_AUTO_PATTERN, val);
+}
+
+static void amd_enable_manual_tuning(struct pci_dev *pdev)
+{
+       unsigned int val;
+
+       pci_read_config_dword(pdev, AMD_SD_MISC_CONTROL, &val);
+       val |= AMD_FIFO_PTR;
+       pci_write_config_dword(pdev, AMD_SD_MISC_CONTROL, val);
+}
+
+static int amd_execute_tuning(struct sdhci_host *host, u32 opcode)
+{
+       struct sdhci_pci_slot *slot = sdhci_priv(host);
+       struct pci_dev *pdev = slot->chip->pdev;
+       u8 valid_win = 0;
+       u8 valid_win_max = 0;
+       u8 valid_win_end = 0;
+       u8 ctrl, tune_around;
+
+       amd_tuning_reset(host);
+
+       for (tune_around = 0; tune_around < 12; tune_around++) {
+               amd_config_tuning_phase(pdev, tune_around);
+
+               if (mmc_send_tuning(host->mmc, opcode, NULL)) {
+                       valid_win = 0;
+                       msleep(AMD_MSLEEP_DURATION);
+                       ctrl = SDHCI_RESET_CMD | SDHCI_RESET_DATA;
+                       sdhci_writeb(host, ctrl, SDHCI_SOFTWARE_RESET);
+               } else if (++valid_win > valid_win_max) {
+                       valid_win_max = valid_win;
+                       valid_win_end = tune_around;
+               }
+       }
+
+       if (!valid_win_max) {
+               dev_err(&pdev->dev, "no tuning point found\n");
+               return -EIO;
+       }
+
+       amd_config_tuning_phase(pdev, valid_win_end - valid_win_max / 2);
+
+       amd_enable_manual_tuning(pdev);
+
+       host->mmc->retune_period = 0;
+
+       return 0;
+}
+
 static int amd_probe(struct sdhci_pci_chip *chip)
 {
        struct pci_dev  *smbus_dev;
@@ -888,16 +967,24 @@ static int amd_probe(struct sdhci_pci_chip *chip)
                }
        }
 
-       if ((gen == AMD_CHIPSET_BEFORE_ML) || (gen == AMD_CHIPSET_CZ)) {
+       if (gen == AMD_CHIPSET_BEFORE_ML || gen == AMD_CHIPSET_CZ)
                chip->quirks2 |= SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD;
-               chip->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200;
-       }
 
        return 0;
 }
 
+static const struct sdhci_ops amd_sdhci_pci_ops = {
+       .set_clock                      = sdhci_set_clock,
+       .enable_dma                     = sdhci_pci_enable_dma,
+       .set_bus_width                  = sdhci_pci_set_bus_width,
+       .reset                          = sdhci_reset,
+       .set_uhs_signaling              = sdhci_set_uhs_signaling,
+       .platform_execute_tuning        = amd_execute_tuning,
+};
+
 static const struct sdhci_pci_fixes sdhci_amd = {
        .probe          = amd_probe,
+       .ops            = &amd_sdhci_pci_ops,
 };
 
 static const struct pci_device_id pci_ids[] = {
@@ -1817,7 +1904,7 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot(
        host->mmc->caps2 |= MMC_CAP2_NO_PRESCAN_POWERUP;
 
        if (slot->cd_idx >= 0) {
-               ret = mmc_gpiod_request_cd(host->mmc, slot->cd_con_id, slot->cd_idx,
+               ret = mmc_gpiod_request_cd(host->mmc, NULL, slot->cd_idx,
                                           slot->cd_override_level, 0, NULL);
                if (ret == -EPROBE_DEFER)
                        goto remove;
index 4abdaed72bd481b9195a42d0ead707c02227b7fa..36f743464fcceded6afa7fcb0aaf8e7f26c1440c 100644 (file)
@@ -81,7 +81,6 @@ struct sdhci_pci_slot {
        int                     cd_gpio;
        int                     cd_irq;
 
-       char                    *cd_con_id;
        int                     cd_idx;
        bool                    cd_override_level;
 
diff --git a/drivers/mmc/host/sdhci-s3c-regs.h b/drivers/mmc/host/sdhci-s3c-regs.h
deleted file mode 100644 (file)
index e34049a..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/* linux/arch/arm/plat-s3c/include/plat/regs-sdhci.h
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * S3C Platform - SDHCI (HSMMC) register definitions
- *
- * 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 __PLAT_S3C_SDHCI_REGS_H
-#define __PLAT_S3C_SDHCI_REGS_H __FILE__
-
-#define S3C_SDHCI_CONTROL2                     (0x80)
-#define S3C_SDHCI_CONTROL3                     (0x84)
-#define S3C64XX_SDHCI_CONTROL4                 (0x8C)
-
-#define S3C64XX_SDHCI_CTRL2_ENSTAASYNCCLR      (1 << 31)
-#define S3C64XX_SDHCI_CTRL2_ENCMDCNFMSK                (1 << 30)
-#define S3C_SDHCI_CTRL2_CDINVRXD3              (1 << 29)
-#define S3C_SDHCI_CTRL2_SLCARDOUT              (1 << 28)
-
-#define S3C_SDHCI_CTRL2_FLTCLKSEL_MASK         (0xf << 24)
-#define S3C_SDHCI_CTRL2_FLTCLKSEL_SHIFT                (24)
-#define S3C_SDHCI_CTRL2_FLTCLKSEL(_x)          ((_x) << 24)
-
-#define S3C_SDHCI_CTRL2_LVLDAT_MASK            (0xff << 16)
-#define S3C_SDHCI_CTRL2_LVLDAT_SHIFT           (16)
-#define S3C_SDHCI_CTRL2_LVLDAT(_x)             ((_x) << 16)
-
-#define S3C_SDHCI_CTRL2_ENFBCLKTX              (1 << 15)
-#define S3C_SDHCI_CTRL2_ENFBCLKRX              (1 << 14)
-#define S3C_SDHCI_CTRL2_SDCDSEL                        (1 << 13)
-#define S3C_SDHCI_CTRL2_SDSIGPC                        (1 << 12)
-#define S3C_SDHCI_CTRL2_ENBUSYCHKTXSTART       (1 << 11)
-
-#define S3C_SDHCI_CTRL2_DFCNT_MASK             (0x3 << 9)
-#define S3C_SDHCI_CTRL2_DFCNT_SHIFT            (9)
-#define S3C_SDHCI_CTRL2_DFCNT_NONE             (0x0 << 9)
-#define S3C_SDHCI_CTRL2_DFCNT_4SDCLK           (0x1 << 9)
-#define S3C_SDHCI_CTRL2_DFCNT_16SDCLK          (0x2 << 9)
-#define S3C_SDHCI_CTRL2_DFCNT_64SDCLK          (0x3 << 9)
-
-#define S3C_SDHCI_CTRL2_ENCLKOUTHOLD           (1 << 8)
-#define S3C_SDHCI_CTRL2_RWAITMODE              (1 << 7)
-#define S3C_SDHCI_CTRL2_DISBUFRD               (1 << 6)
-#define S3C_SDHCI_CTRL2_SELBASECLK_MASK                (0x3 << 4)
-#define S3C_SDHCI_CTRL2_SELBASECLK_SHIFT       (4)
-#define S3C_SDHCI_CTRL2_PWRSYNC                        (1 << 3)
-#define S3C_SDHCI_CTRL2_ENCLKOUTMSKCON         (1 << 1)
-#define S3C_SDHCI_CTRL2_HWINITFIN              (1 << 0)
-
-#define S3C_SDHCI_CTRL3_FCSEL3                 (1 << 31)
-#define S3C_SDHCI_CTRL3_FCSEL2                 (1 << 23)
-#define S3C_SDHCI_CTRL3_FCSEL1                 (1 << 15)
-#define S3C_SDHCI_CTRL3_FCSEL0                 (1 << 7)
-
-#define S3C_SDHCI_CTRL3_FIA3_MASK              (0x7f << 24)
-#define S3C_SDHCI_CTRL3_FIA3_SHIFT             (24)
-#define S3C_SDHCI_CTRL3_FIA3(_x)               ((_x) << 24)
-
-#define S3C_SDHCI_CTRL3_FIA2_MASK              (0x7f << 16)
-#define S3C_SDHCI_CTRL3_FIA2_SHIFT             (16)
-#define S3C_SDHCI_CTRL3_FIA2(_x)               ((_x) << 16)
-
-#define S3C_SDHCI_CTRL3_FIA1_MASK              (0x7f << 8)
-#define S3C_SDHCI_CTRL3_FIA1_SHIFT             (8)
-#define S3C_SDHCI_CTRL3_FIA1(_x)               ((_x) << 8)
-
-#define S3C_SDHCI_CTRL3_FIA0_MASK              (0x7f << 0)
-#define S3C_SDHCI_CTRL3_FIA0_SHIFT             (0)
-#define S3C_SDHCI_CTRL3_FIA0(_x)               ((_x) << 0)
-
-#define S3C64XX_SDHCI_CONTROL4_DRIVE_MASK      (0x3 << 16)
-#define S3C64XX_SDHCI_CONTROL4_DRIVE_SHIFT     (16)
-#define S3C64XX_SDHCI_CONTROL4_DRIVE_2mA       (0x0 << 16)
-#define S3C64XX_SDHCI_CONTROL4_DRIVE_4mA       (0x1 << 16)
-#define S3C64XX_SDHCI_CONTROL4_DRIVE_7mA       (0x2 << 16)
-#define S3C64XX_SDHCI_CONTROL4_DRIVE_9mA       (0x3 << 16)
-
-#define S3C64XX_SDHCI_CONTROL4_BUSY            (1)
-
-#endif /* __PLAT_S3C_SDHCI_REGS_H */
index de219ca7ea7c398d73e250f0d281b4e1fdc0a2db..3e5c83d435ae0078c1e6adca66feb5375169faf1 100644 (file)
 
 #include <linux/mmc/host.h>
 
-#include "sdhci-s3c-regs.h"
 #include "sdhci.h"
 
 #define MAX_BUS_CLK    (4)
 
+#define S3C_SDHCI_CONTROL2                     (0x80)
+#define S3C_SDHCI_CONTROL3                     (0x84)
+#define S3C64XX_SDHCI_CONTROL4                 (0x8C)
+
+#define S3C64XX_SDHCI_CTRL2_ENSTAASYNCCLR      BIT(31)
+#define S3C64XX_SDHCI_CTRL2_ENCMDCNFMSK                BIT(30)
+#define S3C_SDHCI_CTRL2_CDINVRXD3              BIT(29)
+#define S3C_SDHCI_CTRL2_SLCARDOUT              BIT(28)
+
+#define S3C_SDHCI_CTRL2_FLTCLKSEL_MASK         (0xf << 24)
+#define S3C_SDHCI_CTRL2_FLTCLKSEL_SHIFT                (24)
+#define S3C_SDHCI_CTRL2_FLTCLKSEL(_x)          ((_x) << 24)
+
+#define S3C_SDHCI_CTRL2_LVLDAT_MASK            (0xff << 16)
+#define S3C_SDHCI_CTRL2_LVLDAT_SHIFT           (16)
+#define S3C_SDHCI_CTRL2_LVLDAT(_x)             ((_x) << 16)
+
+#define S3C_SDHCI_CTRL2_ENFBCLKTX              BIT(15)
+#define S3C_SDHCI_CTRL2_ENFBCLKRX              BIT(14)
+#define S3C_SDHCI_CTRL2_SDCDSEL                        BIT(13)
+#define S3C_SDHCI_CTRL2_SDSIGPC                        BIT(12)
+#define S3C_SDHCI_CTRL2_ENBUSYCHKTXSTART       BIT(11)
+
+#define S3C_SDHCI_CTRL2_DFCNT_MASK             (0x3 << 9)
+#define S3C_SDHCI_CTRL2_DFCNT_SHIFT            (9)
+#define S3C_SDHCI_CTRL2_DFCNT_NONE             (0x0 << 9)
+#define S3C_SDHCI_CTRL2_DFCNT_4SDCLK           (0x1 << 9)
+#define S3C_SDHCI_CTRL2_DFCNT_16SDCLK          (0x2 << 9)
+#define S3C_SDHCI_CTRL2_DFCNT_64SDCLK          (0x3 << 9)
+
+#define S3C_SDHCI_CTRL2_ENCLKOUTHOLD           BIT(8)
+#define S3C_SDHCI_CTRL2_RWAITMODE              BIT(7)
+#define S3C_SDHCI_CTRL2_DISBUFRD               BIT(6)
+
+#define S3C_SDHCI_CTRL2_SELBASECLK_MASK                (0x3 << 4)
+#define S3C_SDHCI_CTRL2_SELBASECLK_SHIFT       (4)
+#define S3C_SDHCI_CTRL2_PWRSYNC                        BIT(3)
+#define S3C_SDHCI_CTRL2_ENCLKOUTMSKCON         BIT(1)
+#define S3C_SDHCI_CTRL2_HWINITFIN              BIT(0)
+
+#define S3C_SDHCI_CTRL3_FCSEL3                 BIT(31)
+#define S3C_SDHCI_CTRL3_FCSEL2                 BIT(23)
+#define S3C_SDHCI_CTRL3_FCSEL1                 BIT(15)
+#define S3C_SDHCI_CTRL3_FCSEL0                 BIT(7)
+
+#define S3C_SDHCI_CTRL3_FIA3_MASK              (0x7f << 24)
+#define S3C_SDHCI_CTRL3_FIA3_SHIFT             (24)
+#define S3C_SDHCI_CTRL3_FIA3(_x)               ((_x) << 24)
+
+#define S3C_SDHCI_CTRL3_FIA2_MASK              (0x7f << 16)
+#define S3C_SDHCI_CTRL3_FIA2_SHIFT             (16)
+#define S3C_SDHCI_CTRL3_FIA2(_x)               ((_x) << 16)
+
+#define S3C_SDHCI_CTRL3_FIA1_MASK              (0x7f << 8)
+#define S3C_SDHCI_CTRL3_FIA1_SHIFT             (8)
+#define S3C_SDHCI_CTRL3_FIA1(_x)               ((_x) << 8)
+
+#define S3C_SDHCI_CTRL3_FIA0_MASK              (0x7f << 0)
+#define S3C_SDHCI_CTRL3_FIA0_SHIFT             (0)
+#define S3C_SDHCI_CTRL3_FIA0(_x)               ((_x) << 0)
+
+#define S3C64XX_SDHCI_CONTROL4_DRIVE_MASK      (0x3 << 16)
+#define S3C64XX_SDHCI_CONTROL4_DRIVE_SHIFT     (16)
+#define S3C64XX_SDHCI_CONTROL4_DRIVE_2mA       (0x0 << 16)
+#define S3C64XX_SDHCI_CONTROL4_DRIVE_4mA       (0x1 << 16)
+#define S3C64XX_SDHCI_CONTROL4_DRIVE_7mA       (0x2 << 16)
+#define S3C64XX_SDHCI_CONTROL4_DRIVE_9mA       (0x3 << 16)
+
+#define S3C64XX_SDHCI_CONTROL4_BUSY            (1)
+
 /**
  * struct sdhci_s3c - S3C SDHCI instance
  * @host: The SDHCI host created
index 0def99590d162ebcfb86a16a6b9d5adf96f19cb6..6fdd7a70f229b8bfd08f6d8b9df509dd0fec2bbd 100644 (file)
@@ -2021,8 +2021,8 @@ static void sdhci_send_tuning(struct sdhci_host *host, u32 opcode,
                              unsigned long flags)
 {
        struct mmc_host *mmc = host->mmc;
-       struct mmc_command cmd = {0};
-       struct mmc_request mrq = {NULL};
+       struct mmc_command cmd = {};
+       struct mmc_request mrq = {};
 
        cmd.opcode = opcode;
        cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
@@ -2114,7 +2114,6 @@ int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
        spin_lock_irqsave(&host->lock, flags);
 
        hs400_tuning = host->flags & SDHCI_HS400_TUNING;
-       host->flags &= ~SDHCI_HS400_TUNING;
 
        if (host->tuning_mode == SDHCI_TUNING_MODE_1)
                tuning_count = host->tuning_count;
@@ -2156,7 +2155,9 @@ int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 
        if (host->ops->platform_execute_tuning) {
                spin_unlock_irqrestore(&host->lock, flags);
-               return host->ops->platform_execute_tuning(host, opcode);
+               err = host->ops->platform_execute_tuning(host, opcode);
+               spin_lock_irqsave(&host->lock, flags);
+               goto out_unlock;
        }
 
        host->mmc->retune_period = tuning_count;
@@ -2167,6 +2168,7 @@ int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 
        sdhci_end_tuning(host);
 out_unlock:
+       host->flags &= ~SDHCI_HS400_TUNING;
        spin_unlock_irqrestore(&host->lock, flags);
 
        return err;
index 0b66f210ae82c5d64f8301a81a6e938a39048b7f..edf3adfbc21325cff821ee63af8e6c9626549938 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/compiler.h>
 #include <linux/types.h>
 #include <linux/io.h>
+#include <linux/leds.h>
+#include <linux/interrupt.h>
 
 #include <linux/mmc/host.h>
 
index 900778421be69b22c05ff7fe5c8e8dbc6bd6917d..4062d6bef3c81a3e8054e809b248f5829b7cfaa6 100644 (file)
@@ -1079,26 +1079,10 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        host->state = STATE_IDLE;
 }
 
-static int sh_mmcif_get_cd(struct mmc_host *mmc)
-{
-       struct sh_mmcif_host *host = mmc_priv(mmc);
-       struct device *dev = sh_mmcif_host_to_dev(host);
-       struct sh_mmcif_plat_data *p = dev->platform_data;
-       int ret = mmc_gpio_get_cd(mmc);
-
-       if (ret >= 0)
-               return ret;
-
-       if (!p || !p->get_cd)
-               return -ENOSYS;
-       else
-               return p->get_cd(host->pd);
-}
-
 static struct mmc_host_ops sh_mmcif_ops = {
        .request        = sh_mmcif_request,
        .set_ios        = sh_mmcif_set_ios,
-       .get_cd         = sh_mmcif_get_cd,
+       .get_cd         = mmc_gpio_get_cd,
 };
 
 static bool sh_mmcif_end_cmd(struct sh_mmcif_host *host)
@@ -1443,8 +1427,8 @@ static int sh_mmcif_probe(struct platform_device *pdev)
        host->mmc       = mmc;
        host->addr      = reg;
        host->timeout   = msecs_to_jiffies(10000);
-       host->ccs_enable = !pd || !pd->ccs_unsupported;
-       host->clk_ctrl2_enable = pd && pd->clk_ctrl2_present;
+       host->ccs_enable = true;
+       host->clk_ctrl2_enable = false;
 
        host->pd = pdev;
 
@@ -1509,12 +1493,6 @@ static int sh_mmcif_probe(struct platform_device *pdev)
                }
        }
 
-       if (pd && pd->use_cd_gpio) {
-               ret = mmc_gpio_request_cd(mmc, pd->cd_gpio, 0);
-               if (ret < 0)
-                       goto err_clk;
-       }
-
        mutex_init(&host->thread_lock);
 
        ret = mmc_add_host(mmc);
index d46c2d00c18244b1c082497a42b6a97ca019ae60..bc6be0dbea392729798c34e2fd99815d72796c22 100644 (file)
@@ -143,6 +143,7 @@ MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match);
 
 struct sh_mobile_sdhi {
        struct clk *clk;
+       struct clk *clk_cd;
        struct tmio_mmc_data mmc_data;
        struct tmio_mmc_dma dma_priv;
        struct pinctrl *pinctrl;
@@ -190,6 +191,12 @@ static int sh_mobile_sdhi_clk_enable(struct tmio_mmc_host *host)
        if (ret < 0)
                return ret;
 
+       ret = clk_prepare_enable(priv->clk_cd);
+       if (ret < 0) {
+               clk_disable_unprepare(priv->clk);
+               return ret;
+       }
+
        /*
         * The clock driver may not know what maximum frequency
         * actually works, so it should be set with the max-frequency
@@ -255,6 +262,7 @@ static void sh_mobile_sdhi_clk_disable(struct tmio_mmc_host *host)
        struct sh_mobile_sdhi *priv = host_to_priv(host);
 
        clk_disable_unprepare(priv->clk);
+       clk_disable_unprepare(priv->clk_cd);
 }
 
 static int sh_mobile_sdhi_card_busy(struct mmc_host *mmc)
@@ -335,9 +343,6 @@ static unsigned int sh_mobile_sdhi_init_tuning(struct tmio_mmc_host *host)
 {
        struct sh_mobile_sdhi *priv;
 
-       if (!(host->mmc->caps & MMC_CAP_UHS_SDR104))
-               return 0;
-
        priv = host_to_priv(host);
 
        /* set sampling clock selection range */
@@ -444,12 +449,7 @@ static int sh_mobile_sdhi_select_tuning(struct tmio_mmc_host *host)
 
 static bool sh_mobile_sdhi_check_scc_error(struct tmio_mmc_host *host)
 {
-       struct sh_mobile_sdhi *priv;
-
-       if (!(host->mmc->caps & MMC_CAP_UHS_SDR104))
-               return 0;
-
-       priv = host_to_priv(host);
+       struct sh_mobile_sdhi *priv = host_to_priv(host);
 
        /* Check SCC error */
        if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL) &
@@ -468,9 +468,6 @@ static void sh_mobile_sdhi_hw_reset(struct tmio_mmc_host *host)
 {
        struct sh_mobile_sdhi *priv;
 
-       if (!(host->mmc->caps & MMC_CAP_UHS_SDR104))
-               return;
-
        priv = host_to_priv(host);
 
        /* Reset SCC */
@@ -556,8 +553,7 @@ static void sh_mobile_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable)
 
 static int sh_mobile_sdhi_probe(struct platform_device *pdev)
 {
-       const struct of_device_id *of_id =
-               of_match_device(sh_mobile_sdhi_of_match, &pdev->dev);
+       const struct sh_mobile_sdhi_of_data *of_data = of_device_get_match_data(&pdev->dev);
        struct sh_mobile_sdhi *priv;
        struct tmio_mmc_data *mmc_data;
        struct tmio_mmc_data *mmd = pdev->dev.platform_data;
@@ -584,6 +580,21 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
                goto eprobe;
        }
 
+       /*
+        * Some controllers provide a 2nd clock just to run the internal card
+        * detection logic. Unfortunately, the existing driver architecture does
+        * not support a separation of clocks for runtime PM usage. When
+        * native hotplug is used, the tmio driver assumes that the core
+        * must continue to run for card detect to stay active, so we cannot
+        * disable it.
+        * Additionally, it is prohibited to supply a clock to the core but not
+        * to the card detect circuit. That leaves us with if separate clocks
+        * are presented, we must treat them both as virtually 1 clock.
+        */
+       priv->clk_cd = devm_clk_get(&pdev->dev, "cd");
+       if (IS_ERR(priv->clk_cd))
+               priv->clk_cd = NULL;
+
        priv->pinctrl = devm_pinctrl_get(&pdev->dev);
        if (!IS_ERR(priv->pinctrl)) {
                priv->pins_default = pinctrl_lookup_state(priv->pinctrl,
@@ -598,9 +609,8 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
                goto eprobe;
        }
 
-       if (of_id && of_id->data) {
-               const struct sh_mobile_sdhi_of_data *of_data = of_id->data;
 
+       if (of_data) {
                mmc_data->flags |= of_data->tmio_flags;
                mmc_data->ocr_mask = of_data->tmio_ocr_mask;
                mmc_data->capabilities |= of_data->capabilities;
@@ -623,11 +633,6 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
                host->card_busy = sh_mobile_sdhi_card_busy;
                host->start_signal_voltage_switch =
                        sh_mobile_sdhi_start_signal_voltage_switch;
-               host->init_tuning       = sh_mobile_sdhi_init_tuning;
-               host->prepare_tuning    = sh_mobile_sdhi_prepare_tuning;
-               host->select_tuning     = sh_mobile_sdhi_select_tuning;
-               host->check_scc_error   = sh_mobile_sdhi_check_scc_error;
-               host->hw_reset          = sh_mobile_sdhi_hw_reset;
        }
 
        /* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */
@@ -659,40 +664,40 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
         */
        mmc_data->flags |= TMIO_MMC_HAVE_CMD12_CTRL;
 
-       /*
-        * All SDHI need SDIO_INFO1 reserved bit
-        */
-       mmc_data->flags |= TMIO_MMC_SDIO_STATUS_QUIRK;
+       /* All SDHI have SDIO status bits which must be 1 */
+       mmc_data->flags |= TMIO_MMC_SDIO_STATUS_SETBITS;
 
        ret = tmio_mmc_host_probe(host, mmc_data);
        if (ret < 0)
                goto efree;
 
-       if (host->mmc->caps & MMC_CAP_UHS_SDR104) {
+       /* Enable tuning iff we have an SCC and a supported mode */
+       if (of_data && of_data->scc_offset &&
+           (host->mmc->caps & MMC_CAP_UHS_SDR104 ||
+            host->mmc->caps2 & MMC_CAP2_HS200_1_8V_SDR)) {
+               const struct sh_mobile_sdhi_scc *taps = of_data->taps;
+               bool hit = false;
+
                host->mmc->caps |= MMC_CAP_HW_RESET;
 
-               if (of_id && of_id->data) {
-                       const struct sh_mobile_sdhi_of_data *of_data;
-                       const struct sh_mobile_sdhi_scc *taps;
-                       bool hit = false;
-
-                       of_data = of_id->data;
-                       taps = of_data->taps;
-
-                       for (i = 0; i < of_data->taps_num; i++) {
-                               if (taps[i].clk_rate == 0 ||
-                                   taps[i].clk_rate == host->mmc->f_max) {
-                                       host->scc_tappos = taps->tap;
-                                       hit = true;
-                                       break;
-                               }
+               for (i = 0; i < of_data->taps_num; i++) {
+                       if (taps[i].clk_rate == 0 ||
+                           taps[i].clk_rate == host->mmc->f_max) {
+                               host->scc_tappos = taps->tap;
+                               hit = true;
+                               break;
                        }
+               }
 
-                       if (!hit)
-                               dev_warn(&host->pdev->dev, "Unknown clock rate for SDR104\n");
+               if (!hit)
+                       dev_warn(&host->pdev->dev, "Unknown clock rate for SDR104\n");
 
-                       priv->scc_ctl = host->ctl + of_data->scc_offset;
-               }
+               priv->scc_ctl = host->ctl + of_data->scc_offset;
+               host->init_tuning = sh_mobile_sdhi_init_tuning;
+               host->prepare_tuning = sh_mobile_sdhi_prepare_tuning;
+               host->select_tuning = sh_mobile_sdhi_select_tuning;
+               host->check_scc_error = sh_mobile_sdhi_check_scc_error;
+               host->hw_reset = sh_mobile_sdhi_hw_reset;
        }
 
        i = 0;
index b1d1303389a71eb17f6def0e9941b1687061f589..6ffcd2838272c3333e1fbfeac1d1c867d23f9239 100644 (file)
@@ -5,6 +5,7 @@
  * (C) Copyright 2013-2014 O2S GmbH <www.o2s.ch>
  * (C) Copyright 2013-2014 David Lanzend�rfer <david.lanzendoerfer@o2s.ch>
  * (C) Copyright 2013-2014 Hans de Goede <hdegoede@redhat.com>
+ * (C) Copyright 2017 Sootech SA
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
        (SDXC_SOFT_RESET | SDXC_FIFO_RESET | SDXC_DMA_RESET)
 
 /* clock control bits */
+#define SDXC_MASK_DATA0                        BIT(31)
 #define SDXC_CARD_CLOCK_ON             BIT(16)
 #define SDXC_LOW_POWER_ON              BIT(17)
 
@@ -253,6 +255,11 @@ struct sunxi_mmc_cfg {
 
        /* does the IP block support autocalibration? */
        bool can_calibrate;
+
+       /* Does DATA0 needs to be masked while the clock is updated */
+       bool mask_data0;
+
+       bool needs_new_timings;
 };
 
 struct sunxi_mmc_host {
@@ -654,11 +661,16 @@ static int sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en)
        unsigned long expire = jiffies + msecs_to_jiffies(750);
        u32 rval;
 
+       dev_dbg(mmc_dev(host->mmc), "%sabling the clock\n",
+               oclk_en ? "en" : "dis");
+
        rval = mmc_readl(host, REG_CLKCR);
-       rval &= ~(SDXC_CARD_CLOCK_ON | SDXC_LOW_POWER_ON);
+       rval &= ~(SDXC_CARD_CLOCK_ON | SDXC_LOW_POWER_ON | SDXC_MASK_DATA0);
 
        if (oclk_en)
                rval |= SDXC_CARD_CLOCK_ON;
+       if (host->cfg->mask_data0)
+               rval |= SDXC_MASK_DATA0;
 
        mmc_writel(host, REG_CLKCR, rval);
 
@@ -678,46 +690,29 @@ static int sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en)
                return -EIO;
        }
 
+       if (host->cfg->mask_data0) {
+               rval = mmc_readl(host, REG_CLKCR);
+               mmc_writel(host, REG_CLKCR, rval & ~SDXC_MASK_DATA0);
+       }
+
        return 0;
 }
 
 static int sunxi_mmc_calibrate(struct sunxi_mmc_host *host, int reg_off)
 {
-       u32 reg = readl(host->reg_base + reg_off);
-       u32 delay;
-       unsigned long timeout;
-
        if (!host->cfg->can_calibrate)
                return 0;
 
-       reg &= ~(SDXC_CAL_DL_MASK << SDXC_CAL_DL_SW_SHIFT);
-       reg &= ~SDXC_CAL_DL_SW_EN;
-
-       writel(reg | SDXC_CAL_START, host->reg_base + reg_off);
-
-       dev_dbg(mmc_dev(host->mmc), "calibration started\n");
-
-       timeout = jiffies + HZ * SDXC_CAL_TIMEOUT;
-
-       while (!((reg = readl(host->reg_base + reg_off)) & SDXC_CAL_DONE)) {
-               if (time_before(jiffies, timeout))
-                       cpu_relax();
-               else {
-                       reg &= ~SDXC_CAL_START;
-                       writel(reg, host->reg_base + reg_off);
-
-                       return -ETIMEDOUT;
-               }
-       }
-
-       delay = (reg >> SDXC_CAL_DL_SHIFT) & SDXC_CAL_DL_MASK;
-
-       reg &= ~SDXC_CAL_START;
-       reg |= (delay << SDXC_CAL_DL_SW_SHIFT) | SDXC_CAL_DL_SW_EN;
-
-       writel(reg, host->reg_base + reg_off);
-
-       dev_dbg(mmc_dev(host->mmc), "calibration ended, reg is 0x%x\n", reg);
+       /*
+        * FIXME:
+        * This is not clear how the calibration is supposed to work
+        * yet. The best rate have been obtained by simply setting the
+        * delay to 0, as Allwinner does in its BSP.
+        *
+        * The only mode that doesn't have such a delay is HS400, that
+        * is in itself a TODO.
+        */
+       writel(SDXC_CAL_DL_SW_EN, host->reg_base + reg_off);
 
        return 0;
 }
@@ -745,6 +740,7 @@ static int sunxi_mmc_clk_set_phase(struct sunxi_mmc_host *host,
                        index = SDXC_CLK_50M_DDR;
                }
        } else {
+               dev_dbg(mmc_dev(host->mmc), "Invalid clock... returning\n");
                return -EINVAL;
        }
 
@@ -757,10 +753,21 @@ static int sunxi_mmc_clk_set_phase(struct sunxi_mmc_host *host,
 static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
                                  struct mmc_ios *ios)
 {
+       struct mmc_host *mmc = host->mmc;
        long rate;
        u32 rval, clock = ios->clock;
        int ret;
 
+       ret = sunxi_mmc_oclk_onoff(host, 0);
+       if (ret)
+               return ret;
+
+       /* Our clock is gated now */
+       mmc->actual_clock = 0;
+
+       if (!ios->clock)
+               return 0;
+
        /* 8 bit DDR requires a higher module clock */
        if (ios->timing == MMC_TIMING_MMC_DDR52 &&
            ios->bus_width == MMC_BUS_WIDTH_8)
@@ -768,25 +775,21 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
 
        rate = clk_round_rate(host->clk_mmc, clock);
        if (rate < 0) {
-               dev_err(mmc_dev(host->mmc), "error rounding clk to %d: %ld\n",
+               dev_err(mmc_dev(mmc), "error rounding clk to %d: %ld\n",
                        clock, rate);
                return rate;
        }
-       dev_dbg(mmc_dev(host->mmc), "setting clk to %d, rounded %ld\n",
+       dev_dbg(mmc_dev(mmc), "setting clk to %d, rounded %ld\n",
                clock, rate);
 
        /* setting clock rate */
        ret = clk_set_rate(host->clk_mmc, rate);
        if (ret) {
-               dev_err(mmc_dev(host->mmc), "error setting clk to %ld: %d\n",
+               dev_err(mmc_dev(mmc), "error setting clk to %ld: %d\n",
                        rate, ret);
                return ret;
        }
 
-       ret = sunxi_mmc_oclk_onoff(host, 0);
-       if (ret)
-               return ret;
-
        /* clear internal divider */
        rval = mmc_readl(host, REG_CLKCR);
        rval &= ~0xff;
@@ -798,6 +801,9 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
        }
        mmc_writel(host, REG_CLKCR, rval);
 
+       if (host->cfg->needs_new_timings)
+               mmc_writel(host, REG_SD_NTSR, SDXC_2X_TIMING_MODE);
+
        ret = sunxi_mmc_clk_set_phase(host, ios, rate);
        if (ret)
                return ret;
@@ -806,9 +812,22 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
        if (ret)
                return ret;
 
-       /* TODO: enable calibrate on sdc2 SDXC_REG_DS_DL_REG of A64 */
+       /*
+        * FIXME:
+        *
+        * In HS400 we'll also need to calibrate the data strobe
+        * signal. This should only happen on the MMC2 controller (at
+        * least on the A64).
+        */
+
+       ret = sunxi_mmc_oclk_onoff(host, 1);
+       if (ret)
+               return ret;
+
+       /* And we just enabled our clock back */
+       mmc->actual_clock = rate;
 
-       return sunxi_mmc_oclk_onoff(host, 1);
+       return 0;
 }
 
 static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
@@ -882,7 +901,7 @@ static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        mmc_writel(host, REG_GCTRL, rval);
 
        /* set up clock */
-       if (ios->clock && ios->power_mode) {
+       if (ios->power_mode) {
                host->ferror = sunxi_mmc_clk_set_rate(host, ios);
                /* Android code had a usleep_range(50000, 55000); here */
        }
@@ -1089,6 +1108,14 @@ static const struct sunxi_mmc_cfg sun50i_a64_cfg = {
        .idma_des_size_bits = 16,
        .clk_delays = NULL,
        .can_calibrate = true,
+       .mask_data0 = true,
+       .needs_new_timings = true,
+};
+
+static const struct sunxi_mmc_cfg sun50i_a64_emmc_cfg = {
+       .idma_des_size_bits = 13,
+       .clk_delays = NULL,
+       .can_calibrate = true,
 };
 
 static const struct of_device_id sunxi_mmc_of_match[] = {
@@ -1097,6 +1124,7 @@ static const struct of_device_id sunxi_mmc_of_match[] = {
        { .compatible = "allwinner,sun7i-a20-mmc", .data = &sun7i_a20_cfg },
        { .compatible = "allwinner,sun9i-a80-mmc", .data = &sun9i_a80_cfg },
        { .compatible = "allwinner,sun50i-a64-mmc", .data = &sun50i_a64_cfg },
+       { .compatible = "allwinner,sun50i-a64-emmc", .data = &sun50i_a64_emmc_cfg },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, sunxi_mmc_of_match);
index 9e20bcf3aa8d2da5fcb263e81a15845326592b36..2b349d48fb9a8a8bcbdb1f552c3b7bf04cf07a37 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/pagemap.h>
 #include <linux/scatterlist.h>
 #include <linux/spinlock.h>
+#include <linux/interrupt.h>
 
 #define CTL_SD_CMD 0x00
 #define CTL_ARG_REG 0x04
@@ -90,6 +91,8 @@
 #define TMIO_SDIO_STAT_EXWT    0x8000
 #define TMIO_SDIO_MASK_ALL     0xc007
 
+#define TMIO_SDIO_SETBITS_MASK 0x0006
+
 /* Define some IRQ masks */
 /* This is the mask used at reset by the chip */
 #define TMIO_MASK_ALL           0x837f031d
index 2064fa1a5bf11f9a5ca994b94087e389703bb550..6b789a739d4dfeb598a1fced82130ee05f1e4dc6 100644 (file)
@@ -134,18 +134,25 @@ static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
        struct tmio_mmc_host *host = mmc_priv(mmc);
 
        if (enable && !host->sdio_irq_enabled) {
+               u16 sdio_status;
+
                /* Keep device active while SDIO irq is enabled */
                pm_runtime_get_sync(mmc_dev(mmc));
-               host->sdio_irq_enabled = true;
 
+               host->sdio_irq_enabled = true;
                host->sdio_irq_mask = TMIO_SDIO_MASK_ALL &
                                        ~TMIO_SDIO_STAT_IOIRQ;
-               sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001);
+
+               /* Clear obsolete interrupts before enabling */
+               sdio_status = sd_ctrl_read16(host, CTL_SDIO_STATUS) & ~TMIO_SDIO_MASK_ALL;
+               if (host->pdata->flags & TMIO_MMC_SDIO_STATUS_SETBITS)
+                       sdio_status |= TMIO_SDIO_SETBITS_MASK;
+               sd_ctrl_write16(host, CTL_SDIO_STATUS, sdio_status);
+
                sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask);
        } else if (!enable && host->sdio_irq_enabled) {
                host->sdio_irq_mask = TMIO_SDIO_MASK_ALL;
                sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask);
-               sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0000);
 
                host->sdio_irq_enabled = false;
                pm_runtime_mark_last_busy(mmc_dev(mmc));
@@ -711,9 +718,8 @@ static bool __tmio_mmc_sdcard_irq(struct tmio_mmc_host *host,
        return false;
 }
 
-static void tmio_mmc_sdio_irq(int irq, void *devid)
+static void __tmio_mmc_sdio_irq(struct tmio_mmc_host *host)
 {
-       struct tmio_mmc_host *host = devid;
        struct mmc_host *mmc = host->mmc;
        struct tmio_mmc_data *pdata = host->pdata;
        unsigned int ireg, status;
@@ -726,8 +732,8 @@ static void tmio_mmc_sdio_irq(int irq, void *devid)
        ireg = status & TMIO_SDIO_MASK_ALL & ~host->sdio_irq_mask;
 
        sdio_status = status & ~TMIO_SDIO_MASK_ALL;
-       if (pdata->flags & TMIO_MMC_SDIO_STATUS_QUIRK)
-               sdio_status |= 6;
+       if (pdata->flags & TMIO_MMC_SDIO_STATUS_SETBITS)
+               sdio_status |= TMIO_SDIO_SETBITS_MASK;
 
        sd_ctrl_write16(host, CTL_SDIO_STATUS, sdio_status);
 
@@ -754,7 +760,7 @@ irqreturn_t tmio_mmc_irq(int irq, void *devid)
        if (__tmio_mmc_sdcard_irq(host, ireg, status))
                return IRQ_HANDLED;
 
-       tmio_mmc_sdio_irq(irq, devid);
+       __tmio_mmc_sdio_irq(host);
 
        return IRQ_HANDLED;
 }
@@ -902,6 +908,12 @@ static int tmio_mmc_clk_enable(struct tmio_mmc_host *host)
        return host->clk_enable(host);
 }
 
+static void tmio_mmc_clk_disable(struct tmio_mmc_host *host)
+{
+       if (host->clk_disable)
+               host->clk_disable(host);
+}
+
 static void tmio_mmc_power_on(struct tmio_mmc_host *host, unsigned short vdd)
 {
        struct mmc_host *mmc = host->mmc;
@@ -1145,7 +1157,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,
 
        ret = mmc_of_parse(mmc);
        if (ret < 0)
-               goto host_free;
+               return ret;
 
        _host->pdata = pdata;
        platform_set_drvdata(pdev, mmc);
@@ -1155,14 +1167,12 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,
 
        ret = tmio_mmc_init_ocr(_host);
        if (ret < 0)
-               goto host_free;
+               return ret;
 
        _host->ctl = devm_ioremap(&pdev->dev,
                                  res_ctl->start, resource_size(res_ctl));
-       if (!_host->ctl) {
-               ret = -ENOMEM;
-               goto host_free;
-       }
+       if (!_host->ctl)
+               return -ENOMEM;
 
        tmio_mmc_ops.card_busy = _host->card_busy;
        tmio_mmc_ops.start_signal_voltage_switch = _host->start_signal_voltage_switch;
@@ -1179,8 +1189,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,
 
        _host->native_hotplug = !(pdata->flags & TMIO_MMC_USE_GPIO_CD ||
                                  mmc->caps & MMC_CAP_NEEDS_POLL ||
-                                 !mmc_card_is_removable(mmc) ||
-                                 mmc->slot.cd_irq >= 0);
+                                 !mmc_card_is_removable(mmc));
 
        /*
         * On Gen2+, eMMC with NONREMOVABLE currently fails because native
@@ -1200,10 +1209,8 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,
         * Check the sanity of mmc->f_min to prevent tmio_mmc_set_clock() from
         * looping forever...
         */
-       if (mmc->f_min == 0) {
-               ret = -EINVAL;
-               goto host_free;
-       }
+       if (mmc->f_min == 0)
+               return -EINVAL;
 
        /*
         * While using internal tmio hardware logic for card detection, we need
@@ -1232,7 +1239,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,
        if (pdata->flags & TMIO_MMC_SDIO_IRQ) {
                _host->sdio_irq_mask = TMIO_SDIO_MASK_ALL;
                sd_ctrl_write16(_host, CTL_SDIO_IRQ_MASK, _host->sdio_irq_mask);
-               sd_ctrl_write16(_host, CTL_TRANSACTION_CTL, 0x0000);
+               sd_ctrl_write16(_host, CTL_TRANSACTION_CTL, 0x0001);
        }
 
        spin_lock_init(&_host->lock);
@@ -1268,10 +1275,6 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,
        }
 
        return 0;
-
-host_free:
-
-       return ret;
 }
 EXPORT_SYMBOL(tmio_mmc_host_probe);
 
@@ -1280,6 +1283,9 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host)
        struct platform_device *pdev = host->pdev;
        struct mmc_host *mmc = host->mmc;
 
+       if (host->pdata->flags & TMIO_MMC_SDIO_IRQ)
+               sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0000);
+
        if (!host->native_hotplug)
                pm_runtime_get_sync(&pdev->dev);
 
@@ -1292,6 +1298,8 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host)
 
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
+
+       tmio_mmc_clk_disable(host);
 }
 EXPORT_SYMBOL(tmio_mmc_host_remove);
 
@@ -1306,8 +1314,7 @@ int tmio_mmc_host_runtime_suspend(struct device *dev)
        if (host->clk_cache)
                tmio_mmc_clk_stop(host);
 
-       if (host->clk_disable)
-               host->clk_disable(host);
+       tmio_mmc_clk_disable(host);
 
        return 0;
 }
index 63fac78b3d46aaa0a76861cc8c359c441b367a76..6380044c06280c49291895d8c4f97fcedef5f038 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/highmem.h>
 #include <linux/delay.h>
+#include <linux/interrupt.h>
 
 #include <linux/mmc/host.h>
 
index bb3e0d1dd35501bc8e02a5c513adc2af12572e0d..c061e7c704be72b32aa9407b07e56401bbab2fcf 100644 (file)
@@ -640,8 +640,6 @@ static void __vub300_irqpoll_response(struct vub300_mmc_host *vub300)
                mutex_lock(&vub300->irq_mutex);
                if (vub300->irq_enabled)
                        mmc_signal_sdio_irq(vub300->mmc);
-               else if (vub300->irqs_queued)
-                       vub300->irqs_queued += 1;
                else
                        vub300->irqs_queued += 1;
                vub300->irq_disabled = 0;
@@ -728,8 +726,7 @@ static void vub300_deadwork_thread(struct work_struct *work)
                 */
        } else if (vub300->card_present) {
                check_vub300_port_status(vub300);
-       } else if (vub300->mmc && vub300->mmc->card &&
-                  mmc_card_present(vub300->mmc->card)) {
+       } else if (vub300->mmc && vub300->mmc->card) {
                /*
                 * the MMC core must not have responded
                 * to the previous indication - lets
@@ -1756,8 +1753,7 @@ static void vub300_cmndwork_thread(struct work_struct *work)
                int data_length;
                mutex_lock(&vub300->cmd_mutex);
                init_completion(&vub300->command_complete);
-               if (likely(vub300->vub_name[0]) || !vub300->mmc->card ||
-                   !mmc_card_present(vub300->mmc->card)) {
+               if (likely(vub300->vub_name[0]) || !vub300->mmc->card) {
                        /*
                         * the name of the EMPTY Pseudo firmware file
                         * is used as a flag to indicate that the file
index 80a3b11f3217143bee5e15fdb24f2f1c346a1105..bd04e8bae010c4f8ce9a4714b155ae06fb1ac1c0 100644 (file)
@@ -1437,11 +1437,14 @@ err:
 
 static void wbsd_release_dma(struct wbsd_host *host)
 {
-       if (!dma_mapping_error(mmc_dev(host->mmc), host->dma_addr)) {
+       /*
+        * host->dma_addr is valid here iff host->dma_buffer is not NULL.
+        */
+       if (host->dma_buffer) {
                dma_unmap_single(mmc_dev(host->mmc), host->dma_addr,
                        WBSD_DMA_SIZE, DMA_BIDIRECTIONAL);
+               kfree(host->dma_buffer);
        }
-       kfree(host->dma_buffer);
        if (host->dma >= 0)
                free_dma(host->dma);
 
index 5af00559e9d6f7f933bccd41db4e3dc334a41673..21ebba88679cd1616a48125f5b38b463ae6febce 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/irq.h>
 #include <linux/clk.h>
 #include <linux/gpio.h>
+#include <linux/interrupt.h>
 
 #include <linux/of.h>
 #include <linux/of_address.h>
index df8a5ef334c0a42e78cfd6e382d413916bd6f2a6..6b8d5cd7dbf6bdc3442c1d44ae136a3c6f885aff 100644 (file)
@@ -84,9 +84,6 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
        nsect = blk_rq_cur_bytes(req) >> tr->blkshift;
        buf = bio_data(req->bio);
 
-       if (req->cmd_type != REQ_TYPE_FS)
-               return -EIO;
-
        if (req_op(req) == REQ_OP_FLUSH)
                return tr->flush(dev);
 
@@ -94,16 +91,16 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
            get_capacity(req->rq_disk))
                return -EIO;
 
-       if (req_op(req) == REQ_OP_DISCARD)
+       switch (req_op(req)) {
+       case REQ_OP_DISCARD:
                return tr->discard(dev, block, nsect);
-
-       if (rq_data_dir(req) == READ) {
+       case REQ_OP_READ:
                for (; nsect > 0; nsect--, block++, buf += tr->blksize)
                        if (tr->readsect(dev, block, buf))
                                return -EIO;
                rq_flush_dcache_pages(req);
                return 0;
-       } else {
+       case REQ_OP_WRITE:
                if (!tr->writesect)
                        return -EIO;
 
@@ -112,6 +109,8 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
                        if (tr->writesect(dev, block, buf))
                                return -EIO;
                return 0;
+       default:
+               return -EIO;
        }
 }
 
index d1e6931c132f79a5a7a57557c75644170c6ee4a6..c80869e60909c91f66ea4a1bb532bd18368e724d 100644 (file)
@@ -323,16 +323,15 @@ static int ubiblock_queue_rq(struct blk_mq_hw_ctx *hctx,
        struct ubiblock *dev = hctx->queue->queuedata;
        struct ubiblock_pdu *pdu = blk_mq_rq_to_pdu(req);
 
-       if (req->cmd_type != REQ_TYPE_FS)
+       switch (req_op(req)) {
+       case REQ_OP_READ:
+               ubi_sgl_init(&pdu->usgl);
+               queue_work(dev->wq, &pdu->work);
+               return BLK_MQ_RQ_QUEUE_OK;
+       default:
                return BLK_MQ_RQ_QUEUE_ERROR;
+       }
 
-       if (rq_data_dir(req) != READ)
-               return BLK_MQ_RQ_QUEUE_ERROR; /* Write not implemented */
-
-       ubi_sgl_init(&pdu->usgl);
-       queue_work(dev->wq, &pdu->work);
-
-       return BLK_MQ_RQ_QUEUE_OK;
 }
 
 static int ubiblock_init_request(void *data, struct request *req,
index 47b481095d773fc9aaf1bf0045bdcee5bc89e3cc..f9bcf4a665bcaebc4f33bd28849cef2dadc4f698 100644 (file)
@@ -67,6 +67,7 @@ module_param(rx_drain_timeout_msecs, uint, 0444);
 unsigned int rx_stall_timeout_msecs = 60000;
 module_param(rx_stall_timeout_msecs, uint, 0444);
 
+#define MAX_QUEUES_DEFAULT 8
 unsigned int xenvif_max_queues;
 module_param_named(max_queues, xenvif_max_queues, uint, 0644);
 MODULE_PARM_DESC(max_queues,
@@ -1622,11 +1623,12 @@ static int __init netback_init(void)
        if (!xen_domain())
                return -ENODEV;
 
-       /* Allow as many queues as there are CPUs if user has not
+       /* Allow as many queues as there are CPUs but max. 8 if user has not
         * specified a value.
         */
        if (xenvif_max_queues == 0)
-               xenvif_max_queues = num_online_cpus();
+               xenvif_max_queues = min_t(unsigned int, MAX_QUEUES_DEFAULT,
+                                         num_online_cpus());
 
        if (fatal_skb_slots < XEN_NETBK_LEGACY_SLOTS_MAX) {
                pr_info("fatal_skb_slots too small (%d), bump it to XEN_NETBK_LEGACY_SLOTS_MAX (%d)\n",
index 85b742e1c42fa75bc771db4e8b91f80f3fe68d75..bb854f92f5a5cd4a531082cf04cf28c0f6801c42 100644 (file)
@@ -734,7 +734,7 @@ static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
 }
 
 static void xen_net_rate_changed(struct xenbus_watch *watch,
-                               const char **vec, unsigned int len)
+                                const char *path, const char *token)
 {
        struct xenvif *vif = container_of(watch, struct xenvif, credit_watch);
        struct xenbus_device *dev = xenvif_to_xenbus_device(vif);
@@ -791,7 +791,7 @@ static void xen_unregister_credit_watch(struct xenvif *vif)
 }
 
 static void xen_mcast_ctrl_changed(struct xenbus_watch *watch,
-                                  const char **vec, unsigned int len)
+                                  const char *path, const char *token)
 {
        struct xenvif *vif = container_of(watch, struct xenvif,
                                          mcast_ctrl_watch);
@@ -866,8 +866,8 @@ static void unregister_hotplug_status_watch(struct backend_info *be)
 }
 
 static void hotplug_status_changed(struct xenbus_watch *watch,
-                                  const char **vec,
-                                  unsigned int vec_size)
+                                  const char *path,
+                                  const char *token)
 {
        struct backend_info *be = container_of(watch,
                                               struct backend_info,
index 1e4125a98291245f5e806a79247a92ca1418092b..9c72842e3a58ea048c96243caeab72e02debbb98 100644 (file)
@@ -57,6 +57,7 @@
 #include <xen/interface/grant_table.h>
 
 /* Module parameters */
+#define MAX_QUEUES_DEFAULT 8
 static unsigned int xennet_max_queues;
 module_param_named(max_queues, xennet_max_queues, uint, 0644);
 MODULE_PARM_DESC(max_queues,
@@ -2166,11 +2167,12 @@ static int __init netif_init(void)
 
        pr_info("Initialising Xen virtual ethernet driver\n");
 
-       /* Allow as many queues as there are CPUs if user has not
+       /* Allow as many queues as there are CPUs inut max. 8 if user has not
         * specified a value.
         */
        if (xennet_max_queues == 0)
-               xennet_max_queues = num_online_cpus();
+               xennet_max_queues = min_t(unsigned int, MAX_QUEUES_DEFAULT,
+                                         num_online_cpus());
 
        return xenbus_register_frontend(&netfront_driver);
 }
index 8a3c3e32a704b3e359a78ed06e95c6e977f322bc..44a1a257e0b598738765ab7001e8ec862a00cdc0 100644 (file)
@@ -208,18 +208,18 @@ EXPORT_SYMBOL_GPL(nvme_requeue_req);
 struct request *nvme_alloc_request(struct request_queue *q,
                struct nvme_command *cmd, unsigned int flags, int qid)
 {
+       unsigned op = nvme_is_write(cmd) ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN;
        struct request *req;
 
        if (qid == NVME_QID_ANY) {
-               req = blk_mq_alloc_request(q, nvme_is_write(cmd), flags);
+               req = blk_mq_alloc_request(q, op, flags);
        } else {
-               req = blk_mq_alloc_request_hctx(q, nvme_is_write(cmd), flags,
+               req = blk_mq_alloc_request_hctx(q, op, flags,
                                qid ? qid - 1 : 0);
        }
        if (IS_ERR(req))
                return req;
 
-       req->cmd_type = REQ_TYPE_DRV_PRIV;
        req->cmd_flags |= REQ_FAILFAST_DRIVER;
        nvme_req(req)->cmd = cmd;
 
@@ -238,26 +238,38 @@ static inline void nvme_setup_flush(struct nvme_ns *ns,
 static inline int nvme_setup_discard(struct nvme_ns *ns, struct request *req,
                struct nvme_command *cmnd)
 {
+       unsigned short segments = blk_rq_nr_discard_segments(req), n = 0;
        struct nvme_dsm_range *range;
-       unsigned int nr_bytes = blk_rq_bytes(req);
+       struct bio *bio;
 
-       range = kmalloc(sizeof(*range), GFP_ATOMIC);
+       range = kmalloc_array(segments, sizeof(*range), GFP_ATOMIC);
        if (!range)
                return BLK_MQ_RQ_QUEUE_BUSY;
 
-       range->cattr = cpu_to_le32(0);
-       range->nlb = cpu_to_le32(nr_bytes >> ns->lba_shift);
-       range->slba = cpu_to_le64(nvme_block_nr(ns, blk_rq_pos(req)));
+       __rq_for_each_bio(bio, req) {
+               u64 slba = nvme_block_nr(ns, bio->bi_iter.bi_sector);
+               u32 nlb = bio->bi_iter.bi_size >> ns->lba_shift;
+
+               range[n].cattr = cpu_to_le32(0);
+               range[n].nlb = cpu_to_le32(nlb);
+               range[n].slba = cpu_to_le64(slba);
+               n++;
+       }
+
+       if (WARN_ON_ONCE(n != segments)) {
+               kfree(range);
+               return BLK_MQ_RQ_QUEUE_ERROR;
+       }
 
        memset(cmnd, 0, sizeof(*cmnd));
        cmnd->dsm.opcode = nvme_cmd_dsm;
        cmnd->dsm.nsid = cpu_to_le32(ns->ns_id);
-       cmnd->dsm.nr = 0;
+       cmnd->dsm.nr = segments - 1;
        cmnd->dsm.attributes = cpu_to_le32(NVME_DSMGMT_AD);
 
        req->special_vec.bv_page = virt_to_page(range);
        req->special_vec.bv_offset = offset_in_page(range);
-       req->special_vec.bv_len = sizeof(*range);
+       req->special_vec.bv_len = sizeof(*range) * segments;
        req->rq_flags |= RQF_SPECIAL_PAYLOAD;
 
        return BLK_MQ_RQ_QUEUE_OK;
@@ -309,17 +321,27 @@ int nvme_setup_cmd(struct nvme_ns *ns, struct request *req,
 {
        int ret = BLK_MQ_RQ_QUEUE_OK;
 
-       if (req->cmd_type == REQ_TYPE_DRV_PRIV)
+       switch (req_op(req)) {
+       case REQ_OP_DRV_IN:
+       case REQ_OP_DRV_OUT:
                memcpy(cmd, nvme_req(req)->cmd, sizeof(*cmd));
-       else if (req_op(req) == REQ_OP_FLUSH)
+               break;
+       case REQ_OP_FLUSH:
                nvme_setup_flush(ns, cmd);
-       else if (req_op(req) == REQ_OP_DISCARD)
+               break;
+       case REQ_OP_DISCARD:
                ret = nvme_setup_discard(ns, req, cmd);
-       else
+               break;
+       case REQ_OP_READ:
+       case REQ_OP_WRITE:
                nvme_setup_rw(ns, req, cmd);
+               break;
+       default:
+               WARN_ON_ONCE(1);
+               return BLK_MQ_RQ_QUEUE_ERROR;
+       }
 
        cmd->common.command_id = req->tag;
-
        return ret;
 }
 EXPORT_SYMBOL_GPL(nvme_setup_cmd);
@@ -784,6 +806,13 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode,
                return nvme_sg_io(ns, (void __user *)arg);
 #endif
        default:
+#ifdef CONFIG_NVM
+               if (ns->ndev)
+                       return nvme_nvm_ioctl(ns, cmd, arg);
+#endif
+               if (is_sed_ioctl(cmd))
+                       return sed_ioctl(ns->ctrl->opal_dev, cmd,
+                                        (void __user *) arg);
                return -ENOTTY;
        }
 }
@@ -861,6 +890,9 @@ static void nvme_config_discard(struct nvme_ns *ns)
        struct nvme_ctrl *ctrl = ns->ctrl;
        u32 logical_block_size = queue_logical_block_size(ns->queue);
 
+       BUILD_BUG_ON(PAGE_SIZE / sizeof(struct nvme_dsm_range) <
+                       NVME_DSM_MAX_RANGES);
+
        if (ctrl->quirks & NVME_QUIRK_DISCARD_ZEROES)
                ns->queue->limits.discard_zeroes_data = 1;
        else
@@ -869,6 +901,7 @@ static void nvme_config_discard(struct nvme_ns *ns)
        ns->queue->limits.discard_alignment = logical_block_size;
        ns->queue->limits.discard_granularity = logical_block_size;
        blk_queue_max_discard_sectors(ns->queue, UINT_MAX);
+       blk_queue_max_discard_segments(ns->queue, NVME_DSM_MAX_RANGES);
        queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, ns->queue);
 }
 
@@ -1051,6 +1084,28 @@ static const struct pr_ops nvme_pr_ops = {
        .pr_clear       = nvme_pr_clear,
 };
 
+#ifdef CONFIG_BLK_SED_OPAL
+int nvme_sec_submit(void *data, u16 spsp, u8 secp, void *buffer, size_t len,
+               bool send)
+{
+       struct nvme_ctrl *ctrl = data;
+       struct nvme_command cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+       if (send)
+               cmd.common.opcode = nvme_admin_security_send;
+       else
+               cmd.common.opcode = nvme_admin_security_recv;
+       cmd.common.nsid = 0;
+       cmd.common.cdw10[0] = cpu_to_le32(((u32)secp) << 24 | ((u32)spsp) << 8);
+       cmd.common.cdw10[1] = cpu_to_le32(len);
+
+       return __nvme_submit_sync_cmd(ctrl->admin_q, &cmd, NULL, buffer, len,
+                                     ADMIN_TIMEOUT, NVME_QID_ANY, 1, 0);
+}
+EXPORT_SYMBOL_GPL(nvme_sec_submit);
+#endif /* CONFIG_BLK_SED_OPAL */
+
 static const struct block_device_operations nvme_fops = {
        .owner          = THIS_MODULE,
        .ioctl          = nvme_ioctl,
@@ -1230,6 +1285,7 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
                return -EIO;
        }
 
+       ctrl->oacs = le16_to_cpu(id->oacs);
        ctrl->vid = le16_to_cpu(id->vid);
        ctrl->oncs = le16_to_cpup(&id->oncs);
        atomic_set(&ctrl->abort_limit, id->acl + 1);
index e65041c640cbc5bad3c284b77690605f071edfc3..fb51a8de9b29a770c93a34dfca7b3264e8dd0a6a 100644 (file)
@@ -1937,7 +1937,7 @@ nvme_fc_complete_rq(struct request *rq)
                        return;
                }
 
-               if (rq->cmd_type == REQ_TYPE_DRV_PRIV)
+               if (blk_rq_is_passthrough(rq))
                        error = rq->errors;
                else
                        error = nvme_error_status(rq->errors);
index 588d4a34c083492e047b42c3f8ac015bf3ce6277..21cac8523bd8e335434ba4bdf73c61e8cdb34f9d 100644 (file)
@@ -26,6 +26,8 @@
 #include <linux/bitops.h>
 #include <linux/lightnvm.h>
 #include <linux/vmalloc.h>
+#include <linux/sched/sysctl.h>
+#include <uapi/linux/lightnvm.h>
 
 enum nvme_nvm_admin_opcode {
        nvme_nvm_admin_identity         = 0xe2,
@@ -248,50 +250,48 @@ static int init_grps(struct nvm_id *nvm_id, struct nvme_nvm_id *nvme_nvm_id)
 {
        struct nvme_nvm_id_group *src;
        struct nvm_id_group *dst;
-       int i, end;
-
-       end = min_t(u32, 4, nvm_id->cgrps);
-
-       for (i = 0; i < end; i++) {
-               src = &nvme_nvm_id->groups[i];
-               dst = &nvm_id->groups[i];
-
-               dst->mtype = src->mtype;
-               dst->fmtype = src->fmtype;
-               dst->num_ch = src->num_ch;
-               dst->num_lun = src->num_lun;
-               dst->num_pln = src->num_pln;
-
-               dst->num_pg = le16_to_cpu(src->num_pg);
-               dst->num_blk = le16_to_cpu(src->num_blk);
-               dst->fpg_sz = le16_to_cpu(src->fpg_sz);
-               dst->csecs = le16_to_cpu(src->csecs);
-               dst->sos = le16_to_cpu(src->sos);
-
-               dst->trdt = le32_to_cpu(src->trdt);
-               dst->trdm = le32_to_cpu(src->trdm);
-               dst->tprt = le32_to_cpu(src->tprt);
-               dst->tprm = le32_to_cpu(src->tprm);
-               dst->tbet = le32_to_cpu(src->tbet);
-               dst->tbem = le32_to_cpu(src->tbem);
-               dst->mpos = le32_to_cpu(src->mpos);
-               dst->mccap = le32_to_cpu(src->mccap);
-
-               dst->cpar = le16_to_cpu(src->cpar);
-
-               if (dst->fmtype == NVM_ID_FMTYPE_MLC) {
-                       memcpy(dst->lptbl.id, src->lptbl.id, 8);
-                       dst->lptbl.mlc.num_pairs =
-                                       le16_to_cpu(src->lptbl.mlc.num_pairs);
-
-                       if (dst->lptbl.mlc.num_pairs > NVME_NVM_LP_MLC_PAIRS) {
-                               pr_err("nvm: number of MLC pairs not supported\n");
-                               return -EINVAL;
-                       }
 
-                       memcpy(dst->lptbl.mlc.pairs, src->lptbl.mlc.pairs,
-                                               dst->lptbl.mlc.num_pairs);
+       if (nvme_nvm_id->cgrps != 1)
+               return -EINVAL;
+
+       src = &nvme_nvm_id->groups[0];
+       dst = &nvm_id->grp;
+
+       dst->mtype = src->mtype;
+       dst->fmtype = src->fmtype;
+       dst->num_ch = src->num_ch;
+       dst->num_lun = src->num_lun;
+       dst->num_pln = src->num_pln;
+
+       dst->num_pg = le16_to_cpu(src->num_pg);
+       dst->num_blk = le16_to_cpu(src->num_blk);
+       dst->fpg_sz = le16_to_cpu(src->fpg_sz);
+       dst->csecs = le16_to_cpu(src->csecs);
+       dst->sos = le16_to_cpu(src->sos);
+
+       dst->trdt = le32_to_cpu(src->trdt);
+       dst->trdm = le32_to_cpu(src->trdm);
+       dst->tprt = le32_to_cpu(src->tprt);
+       dst->tprm = le32_to_cpu(src->tprm);
+       dst->tbet = le32_to_cpu(src->tbet);
+       dst->tbem = le32_to_cpu(src->tbem);
+       dst->mpos = le32_to_cpu(src->mpos);
+       dst->mccap = le32_to_cpu(src->mccap);
+
+       dst->cpar = le16_to_cpu(src->cpar);
+
+       if (dst->fmtype == NVM_ID_FMTYPE_MLC) {
+               memcpy(dst->lptbl.id, src->lptbl.id, 8);
+               dst->lptbl.mlc.num_pairs =
+                               le16_to_cpu(src->lptbl.mlc.num_pairs);
+
+               if (dst->lptbl.mlc.num_pairs > NVME_NVM_LP_MLC_PAIRS) {
+                       pr_err("nvm: number of MLC pairs not supported\n");
+                       return -EINVAL;
                }
+
+               memcpy(dst->lptbl.mlc.pairs, src->lptbl.mlc.pairs,
+                                       dst->lptbl.mlc.num_pairs);
        }
 
        return 0;
@@ -321,7 +321,6 @@ static int nvme_nvm_identity(struct nvm_dev *nvmdev, struct nvm_id *nvm_id)
 
        nvm_id->ver_id = nvme_nvm_id->ver_id;
        nvm_id->vmnt = nvme_nvm_id->vmnt;
-       nvm_id->cgrps = nvme_nvm_id->cgrps;
        nvm_id->cap = le32_to_cpu(nvme_nvm_id->cap);
        nvm_id->dom = le32_to_cpu(nvme_nvm_id->dom);
        memcpy(&nvm_id->ppaf, &nvme_nvm_id->ppaf,
@@ -372,7 +371,7 @@ static int nvme_nvm_get_l2p_tbl(struct nvm_dev *nvmdev, u64 slba, u32 nlb,
                }
 
                /* Transform physical address to target address space */
-               nvmdev->mt->part_to_tgt(nvmdev, entries, cmd_nlb);
+               nvm_part_to_tgt(nvmdev, entries, cmd_nlb);
 
                if (update_l2p(cmd_slba, cmd_nlb, entries, priv)) {
                        ret = -EINTR;
@@ -485,7 +484,8 @@ static void nvme_nvm_end_io(struct request *rq, int error)
        struct nvm_rq *rqd = rq->end_io_data;
 
        rqd->ppa_status = nvme_req(rq)->result.u64;
-       nvm_end_io(rqd, error);
+       rqd->error = error;
+       nvm_end_io(rqd);
 
        kfree(nvme_req(rq)->cmd);
        blk_mq_free_request(rq);
@@ -586,6 +586,224 @@ static struct nvm_dev_ops nvme_nvm_dev_ops = {
        .max_phys_sect          = 64,
 };
 
+static void nvme_nvm_end_user_vio(struct request *rq, int error)
+{
+       struct completion *waiting = rq->end_io_data;
+
+       complete(waiting);
+}
+
+static int nvme_nvm_submit_user_cmd(struct request_queue *q,
+                               struct nvme_ns *ns,
+                               struct nvme_nvm_command *vcmd,
+                               void __user *ubuf, unsigned int bufflen,
+                               void __user *meta_buf, unsigned int meta_len,
+                               void __user *ppa_buf, unsigned int ppa_len,
+                               u32 *result, u64 *status, unsigned int timeout)
+{
+       bool write = nvme_is_write((struct nvme_command *)vcmd);
+       struct nvm_dev *dev = ns->ndev;
+       struct gendisk *disk = ns->disk;
+       struct request *rq;
+       struct bio *bio = NULL;
+       __le64 *ppa_list = NULL;
+       dma_addr_t ppa_dma;
+       __le64 *metadata = NULL;
+       dma_addr_t metadata_dma;
+       DECLARE_COMPLETION_ONSTACK(wait);
+       int ret;
+
+       rq = nvme_alloc_request(q, (struct nvme_command *)vcmd, 0,
+                       NVME_QID_ANY);
+       if (IS_ERR(rq)) {
+               ret = -ENOMEM;
+               goto err_cmd;
+       }
+
+       rq->timeout = timeout ? timeout : ADMIN_TIMEOUT;
+
+       rq->cmd_flags &= ~REQ_FAILFAST_DRIVER;
+       rq->end_io_data = &wait;
+
+       if (ppa_buf && ppa_len) {
+               ppa_list = dma_pool_alloc(dev->dma_pool, GFP_KERNEL, &ppa_dma);
+               if (!ppa_list) {
+                       ret = -ENOMEM;
+                       goto err_rq;
+               }
+               if (copy_from_user(ppa_list, (void __user *)ppa_buf,
+                                               sizeof(u64) * (ppa_len + 1))) {
+                       ret = -EFAULT;
+                       goto err_ppa;
+               }
+               vcmd->ph_rw.spba = cpu_to_le64(ppa_dma);
+       } else {
+               vcmd->ph_rw.spba = cpu_to_le64((uintptr_t)ppa_buf);
+       }
+
+       if (ubuf && bufflen) {
+               ret = blk_rq_map_user(q, rq, NULL, ubuf, bufflen, GFP_KERNEL);
+               if (ret)
+                       goto err_ppa;
+               bio = rq->bio;
+
+               if (meta_buf && meta_len) {
+                       metadata = dma_pool_alloc(dev->dma_pool, GFP_KERNEL,
+                                                               &metadata_dma);
+                       if (!metadata) {
+                               ret = -ENOMEM;
+                               goto err_map;
+                       }
+
+                       if (write) {
+                               if (copy_from_user(metadata,
+                                               (void __user *)meta_buf,
+                                               meta_len)) {
+                                       ret = -EFAULT;
+                                       goto err_meta;
+                               }
+                       }
+                       vcmd->ph_rw.metadata = cpu_to_le64(metadata_dma);
+               }
+
+               if (!disk)
+                       goto submit;
+
+               bio->bi_bdev = bdget_disk(disk, 0);
+               if (!bio->bi_bdev) {
+                       ret = -ENODEV;
+                       goto err_meta;
+               }
+       }
+
+submit:
+       blk_execute_rq_nowait(q, NULL, rq, 0, nvme_nvm_end_user_vio);
+
+       wait_for_completion_io(&wait);
+
+       ret = nvme_error_status(rq->errors);
+       if (result)
+               *result = rq->errors & 0x7ff;
+       if (status)
+               *status = le64_to_cpu(nvme_req(rq)->result.u64);
+
+       if (metadata && !ret && !write) {
+               if (copy_to_user(meta_buf, (void *)metadata, meta_len))
+                       ret = -EFAULT;
+       }
+err_meta:
+       if (meta_buf && meta_len)
+               dma_pool_free(dev->dma_pool, metadata, metadata_dma);
+err_map:
+       if (bio) {
+               if (disk && bio->bi_bdev)
+                       bdput(bio->bi_bdev);
+               blk_rq_unmap_user(bio);
+       }
+err_ppa:
+       if (ppa_buf && ppa_len)
+               dma_pool_free(dev->dma_pool, ppa_list, ppa_dma);
+err_rq:
+       blk_mq_free_request(rq);
+err_cmd:
+       return ret;
+}
+
+static int nvme_nvm_submit_vio(struct nvme_ns *ns,
+                                       struct nvm_user_vio __user *uvio)
+{
+       struct nvm_user_vio vio;
+       struct nvme_nvm_command c;
+       unsigned int length;
+       int ret;
+
+       if (copy_from_user(&vio, uvio, sizeof(vio)))
+               return -EFAULT;
+       if (vio.flags)
+               return -EINVAL;
+
+       memset(&c, 0, sizeof(c));
+       c.ph_rw.opcode = vio.opcode;
+       c.ph_rw.nsid = cpu_to_le32(ns->ns_id);
+       c.ph_rw.control = cpu_to_le16(vio.control);
+       c.ph_rw.length = cpu_to_le16(vio.nppas);
+
+       length = (vio.nppas + 1) << ns->lba_shift;
+
+       ret = nvme_nvm_submit_user_cmd(ns->queue, ns, &c,
+                       (void __user *)(uintptr_t)vio.addr, length,
+                       (void __user *)(uintptr_t)vio.metadata,
+                                                       vio.metadata_len,
+                       (void __user *)(uintptr_t)vio.ppa_list, vio.nppas,
+                       &vio.result, &vio.status, 0);
+
+       if (ret && copy_to_user(uvio, &vio, sizeof(vio)))
+               return -EFAULT;
+
+       return ret;
+}
+
+static int nvme_nvm_user_vcmd(struct nvme_ns *ns, int admin,
+                                       struct nvm_passthru_vio __user *uvcmd)
+{
+       struct nvm_passthru_vio vcmd;
+       struct nvme_nvm_command c;
+       struct request_queue *q;
+       unsigned int timeout = 0;
+       int ret;
+
+       if (copy_from_user(&vcmd, uvcmd, sizeof(vcmd)))
+               return -EFAULT;
+       if ((vcmd.opcode != 0xF2) && (!capable(CAP_SYS_ADMIN)))
+               return -EACCES;
+       if (vcmd.flags)
+               return -EINVAL;
+
+       memset(&c, 0, sizeof(c));
+       c.common.opcode = vcmd.opcode;
+       c.common.nsid = cpu_to_le32(ns->ns_id);
+       c.common.cdw2[0] = cpu_to_le32(vcmd.cdw2);
+       c.common.cdw2[1] = cpu_to_le32(vcmd.cdw3);
+       /* cdw11-12 */
+       c.ph_rw.length = cpu_to_le16(vcmd.nppas);
+       c.ph_rw.control  = cpu_to_le32(vcmd.control);
+       c.common.cdw10[3] = cpu_to_le32(vcmd.cdw13);
+       c.common.cdw10[4] = cpu_to_le32(vcmd.cdw14);
+       c.common.cdw10[5] = cpu_to_le32(vcmd.cdw15);
+
+       if (vcmd.timeout_ms)
+               timeout = msecs_to_jiffies(vcmd.timeout_ms);
+
+       q = admin ? ns->ctrl->admin_q : ns->queue;
+
+       ret = nvme_nvm_submit_user_cmd(q, ns,
+                       (struct nvme_nvm_command *)&c,
+                       (void __user *)(uintptr_t)vcmd.addr, vcmd.data_len,
+                       (void __user *)(uintptr_t)vcmd.metadata,
+                                                       vcmd.metadata_len,
+                       (void __user *)(uintptr_t)vcmd.ppa_list, vcmd.nppas,
+                       &vcmd.result, &vcmd.status, timeout);
+
+       if (ret && copy_to_user(uvcmd, &vcmd, sizeof(vcmd)))
+               return -EFAULT;
+
+       return ret;
+}
+
+int nvme_nvm_ioctl(struct nvme_ns *ns, unsigned int cmd, unsigned long arg)
+{
+       switch (cmd) {
+       case NVME_NVM_IOCTL_ADMIN_VIO:
+               return nvme_nvm_user_vcmd(ns, 1, (void __user *)arg);
+       case NVME_NVM_IOCTL_IO_VIO:
+               return nvme_nvm_user_vcmd(ns, 0, (void __user *)arg);
+       case NVME_NVM_IOCTL_SUBMIT_VIO:
+               return nvme_nvm_submit_vio(ns, (void __user *)arg);
+       default:
+               return -ENOTTY;
+       }
+}
+
 int nvme_nvm_register(struct nvme_ns *ns, char *disk_name, int node)
 {
        struct request_queue *q = ns->queue;
@@ -622,7 +840,7 @@ static ssize_t nvm_dev_attr_show(struct device *dev,
                return 0;
 
        id = &ndev->identity;
-       grp = &id->groups[0];
+       grp = &id->grp;
        attr = &dattr->attr;
 
        if (strcmp(attr->name, "version") == 0) {
@@ -633,10 +851,9 @@ static ssize_t nvm_dev_attr_show(struct device *dev,
                return scnprintf(page, PAGE_SIZE, "%u\n", id->cap);
        } else if (strcmp(attr->name, "device_mode") == 0) {
                return scnprintf(page, PAGE_SIZE, "%u\n", id->dom);
+       /* kept for compatibility */
        } else if (strcmp(attr->name, "media_manager") == 0) {
-               if (!ndev->mt)
-                       return scnprintf(page, PAGE_SIZE, "%s\n", "none");
-               return scnprintf(page, PAGE_SIZE, "%s\n", ndev->mt->name);
+               return scnprintf(page, PAGE_SIZE, "%s\n", "gennvm");
        } else if (strcmp(attr->name, "ppa_format") == 0) {
                return scnprintf(page, PAGE_SIZE,
                        "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
index aead6d08ed2c83b4f67e9087b0ca446247b57d18..14cfc6f7facb240a96630a637ccc60bd45911302 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/kref.h>
 #include <linux/blk-mq.h>
 #include <linux/lightnvm.h>
+#include <linux/sed-opal.h>
 
 enum {
        /*
@@ -125,6 +126,8 @@ struct nvme_ctrl {
        struct list_head node;
        struct ida ns_ida;
 
+       struct opal_dev *opal_dev;
+
        char name[12];
        char serial[20];
        char model[40];
@@ -137,6 +140,7 @@ struct nvme_ctrl {
        u32 max_hw_sectors;
        u16 oncs;
        u16 vid;
+       u16 oacs;
        atomic_t abort_limit;
        u8 event_limit;
        u8 vwc;
@@ -267,6 +271,9 @@ int nvme_init_identify(struct nvme_ctrl *ctrl);
 void nvme_queue_scan(struct nvme_ctrl *ctrl);
 void nvme_remove_namespaces(struct nvme_ctrl *ctrl);
 
+int nvme_sec_submit(void *data, u16 spsp, u8 secp, void *buffer, size_t len,
+               bool send);
+
 #define NVME_NR_AERS   1
 void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status,
                union nvme_result *res);
@@ -318,6 +325,7 @@ int nvme_nvm_register(struct nvme_ns *ns, char *disk_name, int node);
 void nvme_nvm_unregister(struct nvme_ns *ns);
 int nvme_nvm_register_sysfs(struct nvme_ns *ns);
 void nvme_nvm_unregister_sysfs(struct nvme_ns *ns);
+int nvme_nvm_ioctl(struct nvme_ns *ns, unsigned int cmd, unsigned long arg);
 #else
 static inline int nvme_nvm_register(struct nvme_ns *ns, char *disk_name,
                                    int node)
@@ -335,6 +343,11 @@ static inline int nvme_nvm_ns_supported(struct nvme_ns *ns, struct nvme_id_ns *i
 {
        return 0;
 }
+static inline int nvme_nvm_ioctl(struct nvme_ns *ns, unsigned int cmd,
+                                                       unsigned long arg)
+{
+       return -ENOTTY;
+}
 #endif /* CONFIG_NVM */
 
 static inline struct nvme_ns *nvme_get_ns_from_dev(struct device *dev)
index 3faefabf339c98d221373437e411512543d29263..ddc51adb594d0ba3df2e800b9247e2b3cb161847 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/types.h>
 #include <linux/io-64-nonatomic-lo-hi.h>
 #include <asm/unaligned.h>
+#include <linux/sed-opal.h>
 
 #include "nvme.h"
 
@@ -588,7 +589,7 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
         */
        if (ns && ns->ms && !blk_integrity_rq(req)) {
                if (!(ns->pi_type && ns->ms == 8) &&
-                                       req->cmd_type != REQ_TYPE_DRV_PRIV) {
+                   !blk_rq_is_passthrough(req)) {
                        blk_mq_end_request(req, -EFAULT);
                        return BLK_MQ_RQ_QUEUE_OK;
                }
@@ -645,7 +646,7 @@ static void nvme_complete_rq(struct request *req)
                        return;
                }
 
-               if (req->cmd_type == REQ_TYPE_DRV_PRIV)
+               if (blk_rq_is_passthrough(req))
                        error = req->errors;
                else
                        error = nvme_error_status(req->errors);
@@ -895,12 +896,11 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved)
                return BLK_EH_HANDLED;
        }
 
-       iod->aborted = 1;
-
        if (atomic_dec_return(&dev->ctrl.abort_limit) < 0) {
                atomic_inc(&dev->ctrl.abort_limit);
                return BLK_EH_RESET_TIMER;
        }
+       iod->aborted = 1;
 
        memset(&cmd, 0, sizeof(cmd));
        cmd.abort.opcode = nvme_admin_abort_cmd;
@@ -1178,6 +1178,7 @@ static int nvme_alloc_admin_tags(struct nvme_dev *dev)
                dev->admin_tagset.timeout = ADMIN_TIMEOUT;
                dev->admin_tagset.numa_node = dev_to_node(dev->dev);
                dev->admin_tagset.cmd_size = nvme_cmd_size(dev);
+               dev->admin_tagset.flags = BLK_MQ_F_NO_SCHED;
                dev->admin_tagset.driver_data = dev;
 
                if (blk_mq_alloc_tag_set(&dev->admin_tagset))
@@ -1738,6 +1739,7 @@ static void nvme_pci_free_ctrl(struct nvme_ctrl *ctrl)
        if (dev->ctrl.admin_q)
                blk_put_queue(dev->ctrl.admin_q);
        kfree(dev->queues);
+       kfree(dev->ctrl.opal_dev);
        kfree(dev);
 }
 
@@ -1754,6 +1756,7 @@ static void nvme_remove_dead_ctrl(struct nvme_dev *dev, int status)
 static void nvme_reset_work(struct work_struct *work)
 {
        struct nvme_dev *dev = container_of(work, struct nvme_dev, reset_work);
+       bool was_suspend = !!(dev->ctrl.ctrl_config & NVME_CC_SHN_NORMAL);
        int result = -ENODEV;
 
        if (WARN_ON(dev->ctrl.state == NVME_CTRL_RESETTING))
@@ -1786,6 +1789,14 @@ static void nvme_reset_work(struct work_struct *work)
        if (result)
                goto out;
 
+       if ((dev->ctrl.oacs & NVME_CTRL_OACS_SEC_SUPP) && !dev->ctrl.opal_dev) {
+               dev->ctrl.opal_dev =
+                       init_opal_dev(&dev->ctrl, &nvme_sec_submit);
+       }
+
+       if (was_suspend)
+               opal_unlock_from_suspend(dev->ctrl.opal_dev);
+
        result = nvme_setup_io_queues(dev);
        if (result)
                goto out;
index 557f29b1f1bb23e4e5cded156db21b4f981b585a..a75e95d42b3febf5edba65c4ba7ed5181aa08c20 100644 (file)
@@ -1423,7 +1423,7 @@ static inline bool nvme_rdma_queue_is_ready(struct nvme_rdma_queue *queue,
        if (unlikely(!test_bit(NVME_RDMA_Q_LIVE, &queue->flags))) {
                struct nvme_command *cmd = nvme_req(rq)->cmd;
 
-               if (rq->cmd_type != REQ_TYPE_DRV_PRIV ||
+               if (!blk_rq_is_passthrough(rq) ||
                    cmd->common.opcode != nvme_fabrics_command ||
                    cmd->fabrics.fctype != nvme_fabrics_type_connect)
                        return false;
@@ -1471,7 +1471,7 @@ static int nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
        ib_dma_sync_single_for_device(dev, sqe->dma,
                        sizeof(struct nvme_command), DMA_TO_DEVICE);
 
-       if (rq->cmd_type == REQ_TYPE_FS && req_op(rq) == REQ_OP_FLUSH)
+       if (req_op(rq) == REQ_OP_FLUSH)
                flush = true;
        ret = nvme_rdma_post_send(queue, sqe, req->sge, req->num_sge,
                        req->mr->need_inval ? &req->reg_wr.wr : NULL, flush);
@@ -1522,7 +1522,7 @@ static void nvme_rdma_complete_rq(struct request *rq)
                        return;
                }
 
-               if (rq->cmd_type == REQ_TYPE_DRV_PRIV)
+               if (blk_rq_is_passthrough(rq))
                        error = rq->errors;
                else
                        error = nvme_error_status(rq->errors);
index a5c09e703bd8636d96c9c0c7d603226e46518f61..f49ae2758bb70d367edf057309b2a5f784fb1c20 100644 (file)
@@ -43,6 +43,7 @@
 #include <asm/unaligned.h>
 #include <scsi/sg.h>
 #include <scsi/scsi.h>
+#include <scsi/scsi_request.h>
 
 #include "nvme.h"
 
@@ -2347,12 +2348,14 @@ static int nvme_trans_unmap(struct nvme_ns *ns, struct sg_io_hdr *hdr,
 
 static int nvme_scsi_translate(struct nvme_ns *ns, struct sg_io_hdr *hdr)
 {
-       u8 cmd[BLK_MAX_CDB];
+       u8 cmd[16];
        int retcode;
        unsigned int opcode;
 
        if (hdr->cmdp == NULL)
                return -EMSGSIZE;
+       if (hdr->cmd_len > sizeof(cmd))
+               return -EINVAL;
        if (copy_from_user(cmd, hdr->cmdp, hdr->cmd_len))
                return -EFAULT;
 
@@ -2451,8 +2454,6 @@ int nvme_sg_io(struct nvme_ns *ns, struct sg_io_hdr __user *u_hdr)
                return -EFAULT;
        if (hdr.interface_id != 'S')
                return -EINVAL;
-       if (hdr.cmd_len > BLK_MAX_CDB)
-               return -EINVAL;
 
        /*
         * A positive return code means a NVMe status, which has been
index 9aaa70071ae555efc6b6cc41d08cdcb7a6108cbf..f3862e38f5748d8e21b4a55574cac30c7cf2054a 100644 (file)
@@ -104,7 +104,7 @@ static void nvme_loop_complete_rq(struct request *req)
                        return;
                }
 
-               if (req->cmd_type == REQ_TYPE_DRV_PRIV)
+               if (blk_rq_is_passthrough(req))
                        error = req->errors;
                else
                        error = nvme_error_status(req->errors);
index d4bea3c797d6a7b6a4d28c55cfdff1d30d03cc16..84cf2f3f396cbb2ccdeed8c8af679fab74a761d9 100644 (file)
@@ -2112,7 +2112,7 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align))
                        continue;
 
                /* Allocate an alias_prop with enough space for the stem */
-               ap = dt_alloc(sizeof(*ap) + len + 1, 4);
+               ap = dt_alloc(sizeof(*ap) + len + 1, __alignof__(*ap));
                if (!ap)
                        continue;
                memset(ap, 0, sizeof(*ap) + len + 1);
index c9b5cac03b361c980a20c888635bbb52093aa573..82967b07f7be7d094870c4bef172bdb9d29adad0 100644 (file)
@@ -738,9 +738,12 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node,
        const char *pathp;
        int offset, rc = 0, depth = -1;
 
-        for (offset = fdt_next_node(blob, -1, &depth);
-             offset >= 0 && depth >= 0 && !rc;
-             offset = fdt_next_node(blob, offset, &depth)) {
+       if (!blob)
+               return 0;
+
+       for (offset = fdt_next_node(blob, -1, &depth);
+            offset >= 0 && depth >= 0 && !rc;
+            offset = fdt_next_node(blob, offset, &depth)) {
 
                pathp = fdt_get_name(blob, offset, NULL);
                if (*pathp == '/')
index 54044a8ecbd7f7e923cb44634bf97f4bf97afa38..8f8c2af45781595cf3b1ee5d07a26623703af0d2 100644 (file)
@@ -8,9 +8,16 @@ config PINCTRL
 menu "Pin controllers"
        depends on PINCTRL
 
+config GENERIC_PINCTRL_GROUPS
+       bool
+
 config PINMUX
        bool "Support pin multiplexing controllers" if COMPILE_TEST
 
+config GENERIC_PINMUX_FUNCTIONS
+       bool
+       select PINMUX
+
 config PINCONF
        bool "Support pin configuration controllers" if COMPILE_TEST
 
@@ -159,8 +166,8 @@ config PINCTRL_ROCKCHIP
 config PINCTRL_SINGLE
        tristate "One-register-per-pin type device tree based pinctrl driver"
        depends on OF
-       select PINMUX
-       select PINCONF
+       select GENERIC_PINCTRL_GROUPS
+       select GENERIC_PINMUX_FUNCTIONS
        select GENERIC_PINCONF
        help
          This selects the device tree based generic pinctrl driver.
@@ -293,6 +300,7 @@ source "drivers/pinctrl/spear/Kconfig"
 source "drivers/pinctrl/stm32/Kconfig"
 source "drivers/pinctrl/sunxi/Kconfig"
 source "drivers/pinctrl/tegra/Kconfig"
+source "drivers/pinctrl/ti/Kconfig"
 source "drivers/pinctrl/uniphier/Kconfig"
 source "drivers/pinctrl/vt8500/Kconfig"
 source "drivers/pinctrl/mediatek/Kconfig"
index 25d50a86981d360ad805a3c13a1453e87d7d25cd..a251f439626f58d1678c8652b0db28ce3bcd3899 100644 (file)
@@ -53,6 +53,7 @@ obj-$(CONFIG_PINCTRL_SH_PFC)  += sh-pfc/
 obj-$(CONFIG_PINCTRL_SPEAR)    += spear/
 obj-$(CONFIG_PINCTRL_STM32)    += stm32/
 obj-$(CONFIG_PINCTRL_SUNXI)    += sunxi/
+obj-y                          += ti/
 obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/
 obj-$(CONFIG_ARCH_VT8500)      += vt8500/
 obj-$(CONFIG_PINCTRL_MTK)      += mediatek/
index a21b071ff290fa70c950ff234d7e1558ab97bf47..7de596e2b9d44d7d35a3688026a7f81acc90381b 100644 (file)
  * Not all pins have their signals defined (yet).
  */
 
+#define D6 0
+SSSF_PIN_DECL(D6, GPIOA0, MAC1LINK, SIG_DESC_SET(SCU80, 0));
+
+#define B5 1
+SSSF_PIN_DECL(B5, GPIOA1, MAC2LINK, SIG_DESC_SET(SCU80, 1));
+
 #define A4 2
 SSSF_PIN_DECL(A4, GPIOA2, TIMER3, SIG_DESC_SET(SCU80, 2));
 
+#define E6 3
+SSSF_PIN_DECL(E6, GPIOA3, TIMER4, SIG_DESC_SET(SCU80, 3));
+
 #define I2C9_DESC      SIG_DESC_SET(SCU90, 22)
 
 #define C5 4
@@ -80,6 +89,26 @@ MS_PIN_DECL(D5, GPIOA7, MDIO2, TIMER8);
 FUNC_GROUP_DECL(TIMER8, D5);
 FUNC_GROUP_DECL(MDIO2, A3, D5);
 
+#define J21 8
+SSSF_PIN_DECL(J21, GPIOB0, SALT1, SIG_DESC_SET(SCU80, 8));
+
+#define J20 9
+SSSF_PIN_DECL(J20, GPIOB1, SALT2, SIG_DESC_SET(SCU80, 9));
+
+#define H18 10
+SSSF_PIN_DECL(H18, GPIOB2, SALT3, SIG_DESC_SET(SCU80, 10));
+
+#define F18 11
+SSSF_PIN_DECL(F18, GPIOB3, SALT4, SIG_DESC_SET(SCU80, 11));
+
+#define E19 12
+SIG_EXPR_DECL(LPCRST, LPCRST, SIG_DESC_SET(SCU80, 12));
+SIG_EXPR_DECL(LPCRST, LPCRSTS, SIG_DESC_SET(HW_STRAP1, 14));
+SIG_EXPR_LIST_DECL_DUAL(LPCRST, LPCRST, LPCRSTS);
+SS_PIN_DECL(E19, GPIOB4, LPCRST);
+
+FUNC_GROUP_DECL(LPCRST, E19);
+
 #define H19 13
 #define H19_DESC        SIG_DESC_SET(SCU80, 13)
 SIG_EXPR_LIST_DECL_SINGLE(LPCPD, LPCPD, H19_DESC);
@@ -92,6 +121,19 @@ FUNC_GROUP_DECL(LPCSMI, H19);
 #define H20 14
 SSSF_PIN_DECL(H20, GPIOB6, LPCPME, SIG_DESC_SET(SCU80, 14));
 
+#define E18 15
+SIG_EXPR_LIST_DECL_SINGLE(EXTRST, EXTRST,
+               SIG_DESC_SET(SCU80, 15),
+               SIG_DESC_BIT(SCU90, 31, 0),
+               SIG_DESC_SET(SCU3C, 3));
+SIG_EXPR_LIST_DECL_SINGLE(SPICS1, SPICS1,
+               SIG_DESC_SET(SCU80, 15),
+               SIG_DESC_SET(SCU90, 31));
+MS_PIN_DECL(E18, GPIOB7, EXTRST, SPICS1);
+
+FUNC_GROUP_DECL(EXTRST, E18);
+FUNC_GROUP_DECL(SPICS1, E18);
+
 #define SD1_DESC       SIG_DESC_SET(SCU90, 0)
 #define I2C10_DESC     SIG_DESC_SET(SCU90, 23)
 
@@ -170,6 +212,62 @@ MS_PIN_DECL(D16, GPIOD1, SD2CMD, GPID0OUT);
 
 FUNC_GROUP_DECL(GPID0, A18, D16);
 
+#define GPID2_DESC     SIG_DESC_SET(SCU8C, 9)
+
+#define B17 26
+SIG_EXPR_LIST_DECL_SINGLE(SD2DAT0, SD2, SD2_DESC);
+SIG_EXPR_DECL(GPID2IN, GPID2, GPID2_DESC);
+SIG_EXPR_DECL(GPID2IN, GPID, GPID_DESC);
+SIG_EXPR_LIST_DECL_DUAL(GPID2IN, GPID2, GPID);
+MS_PIN_DECL(B17, GPIOD2, SD2DAT0, GPID2IN);
+
+#define A17 27
+SIG_EXPR_LIST_DECL_SINGLE(SD2DAT1, SD2, SD2_DESC);
+SIG_EXPR_DECL(GPID2OUT, GPID2, GPID2_DESC);
+SIG_EXPR_DECL(GPID2OUT, GPID, GPID_DESC);
+SIG_EXPR_LIST_DECL_DUAL(GPID2OUT, GPID2, GPID);
+MS_PIN_DECL(A17, GPIOD3, SD2DAT1, GPID2OUT);
+
+FUNC_GROUP_DECL(GPID2, B17, A17);
+
+#define GPID4_DESC     SIG_DESC_SET(SCU8C, 10)
+
+#define C16 28
+SIG_EXPR_LIST_DECL_SINGLE(SD2DAT2, SD2, SD2_DESC);
+SIG_EXPR_DECL(GPID4IN, GPID4, GPID4_DESC);
+SIG_EXPR_DECL(GPID4IN, GPID, GPID_DESC);
+SIG_EXPR_LIST_DECL_DUAL(GPID4IN, GPID4, GPID);
+MS_PIN_DECL(C16, GPIOD4, SD2DAT2, GPID4IN);
+
+#define B16 29
+SIG_EXPR_LIST_DECL_SINGLE(SD2DAT3, SD2, SD2_DESC);
+SIG_EXPR_DECL(GPID4OUT, GPID4, GPID4_DESC);
+SIG_EXPR_DECL(GPID4OUT, GPID, GPID_DESC);
+SIG_EXPR_LIST_DECL_DUAL(GPID4OUT, GPID4, GPID);
+MS_PIN_DECL(B16, GPIOD5, SD2DAT3, GPID4OUT);
+
+FUNC_GROUP_DECL(GPID4, C16, B16);
+
+#define GPID6_DESC     SIG_DESC_SET(SCU8C, 11)
+
+#define A16 30
+SIG_EXPR_LIST_DECL_SINGLE(SD2CD, SD2, SD2_DESC);
+SIG_EXPR_DECL(GPID6IN, GPID6, GPID6_DESC);
+SIG_EXPR_DECL(GPID6IN, GPID, GPID_DESC);
+SIG_EXPR_LIST_DECL_DUAL(GPID6IN, GPID6, GPID);
+MS_PIN_DECL(A16, GPIOD6, SD2CD, GPID6IN);
+
+#define E15 31
+SIG_EXPR_LIST_DECL_SINGLE(SD2WP, SD2, SD2_DESC);
+SIG_EXPR_DECL(GPID6OUT, GPID6, GPID6_DESC);
+SIG_EXPR_DECL(GPID6OUT, GPID, GPID_DESC);
+SIG_EXPR_LIST_DECL_DUAL(GPID6OUT, GPID6, GPID);
+MS_PIN_DECL(E15, GPIOD7, SD2WP, GPID6OUT);
+
+FUNC_GROUP_DECL(GPID6, A16, E15);
+FUNC_GROUP_DECL(SD2, A18, D16, B17, A17, C16, B16, A16, E15);
+FUNC_GROUP_DECL(GPID, A18, D16, B17, A17, C16, B16, A16, E15);
+
 #define GPIE_DESC       SIG_DESC_SET(HW_STRAP1, 22)
 #define GPIE0_DESC      SIG_DESC_SET(SCU8C, 12)
 #define GPIE2_DESC      SIG_DESC_SET(SCU8C, 13)
@@ -266,6 +364,15 @@ MS_PIN_DECL(B19, GPIOF1, NDCD4, SIOPBI);
 FUNC_GROUP_DECL(NDCD4, B19);
 FUNC_GROUP_DECL(SIOPBI, B19);
 
+#define A20 42
+SIG_EXPR_LIST_DECL_SINGLE(NDSR4, NDSR4, SIG_DESC_SET(SCU80, 26));
+SIG_EXPR_DECL(SIOPWRGD, SIOPWRGD, SIG_DESC_SET(SCUA4, 12));
+SIG_EXPR_DECL(SIOPWRGD, ACPI, ACPI_DESC);
+SIG_EXPR_LIST_DECL_DUAL(SIOPWRGD, SIOPWRGD, ACPI);
+MS_PIN_DECL(A20, GPIOF2, NDSR4, SIOPWRGD);
+FUNC_GROUP_DECL(NDSR4, A20);
+FUNC_GROUP_DECL(SIOPWRGD, A20);
+
 #define D17 43
 SIG_EXPR_LIST_DECL_SINGLE(NRI4, NRI4, SIG_DESC_SET(SCU80, 27));
 SIG_EXPR_DECL(SIOPBO, SIOPBO, SIG_DESC_SET(SCUA4, 14));
@@ -275,7 +382,17 @@ MS_PIN_DECL(D17, GPIOF3, NRI4, SIOPBO);
 FUNC_GROUP_DECL(NRI4, D17);
 FUNC_GROUP_DECL(SIOPBO, D17);
 
-FUNC_GROUP_DECL(ACPI, B19, D17);
+#define B18 44
+SSSF_PIN_DECL(B18, GPIOF4, NDTR4, SIG_DESC_SET(SCU80, 28));
+
+#define A19 45
+SIG_EXPR_LIST_DECL_SINGLE(NDTS4, NDTS4, SIG_DESC_SET(SCU80, 29));
+SIG_EXPR_DECL(SIOSCI, SIOSCI, SIG_DESC_SET(SCUA4, 15));
+SIG_EXPR_DECL(SIOSCI, ACPI, ACPI_DESC);
+SIG_EXPR_LIST_DECL_DUAL(SIOSCI, SIOSCI, ACPI);
+MS_PIN_DECL(A19, GPIOF5, NDTS4, SIOSCI);
+FUNC_GROUP_DECL(NDTS4, A19);
+FUNC_GROUP_DECL(SIOSCI, A19);
 
 #define E16 46
 SSSF_PIN_DECL(E16, GPIOF6, TXD4, SIG_DESC_SET(SCU80, 30));
@@ -283,6 +400,34 @@ SSSF_PIN_DECL(E16, GPIOF6, TXD4, SIG_DESC_SET(SCU80, 30));
 #define C17 47
 SSSF_PIN_DECL(C17, GPIOF7, RXD4, SIG_DESC_SET(SCU80, 31));
 
+#define A14 48
+SSSF_PIN_DECL(A14, GPIOG0, SGPSCK, SIG_DESC_SET(SCU84, 0));
+
+#define E13 49
+SSSF_PIN_DECL(E13, GPIOG1, SGPSLD, SIG_DESC_SET(SCU84, 1));
+
+#define D13 50
+SSSF_PIN_DECL(D13, GPIOG2, SGPSI0, SIG_DESC_SET(SCU84, 2));
+
+#define C13 51
+SSSF_PIN_DECL(C13, GPIOG3, SGPSI1, SIG_DESC_SET(SCU84, 3));
+
+#define B13 52
+SIG_EXPR_LIST_DECL_SINGLE(OSCCLK, OSCCLK, SIG_DESC_SET(SCU2C, 1));
+SIG_EXPR_LIST_DECL_SINGLE(WDTRST1, WDTRST1, SIG_DESC_SET(SCU84, 4));
+MS_PIN_DECL(B13, GPIOG4, OSCCLK, WDTRST1);
+
+FUNC_GROUP_DECL(OSCCLK, B13);
+FUNC_GROUP_DECL(WDTRST1, B13);
+
+#define Y21 53
+SIG_EXPR_LIST_DECL_SINGLE(USBCKI, USBCKI, SIG_DESC_SET(HW_STRAP1, 23));
+SIG_EXPR_LIST_DECL_SINGLE(WDTRST2, WDTRST2, SIG_DESC_SET(SCU84, 5));
+MS_PIN_DECL(Y21, GPIOG5, USBCKI, WDTRST2);
+
+FUNC_GROUP_DECL(USBCKI, Y21);
+FUNC_GROUP_DECL(WDTRST2, Y21);
+
 #define AA22 54
 SSSF_PIN_DECL(AA22, GPIOG6, FLBUSY, SIG_DESC_SET(SCU84, 6));
 
@@ -292,7 +437,7 @@ SSSF_PIN_DECL(U18, GPIOG7, FLWP, SIG_DESC_SET(SCU84, 7));
 #define UART6_DESC     SIG_DESC_SET(SCU90, 7)
 #define ROM16_DESC     SIG_DESC_SET(SCU90, 6)
 #define FLASH_WIDE     SIG_DESC_SET(HW_STRAP1, 4)
-#define BOOT_SRC_NOR   { HW_STRAP1, GENMASK(1, 0), 0, 0 }
+#define BOOT_SRC_NOR   { ASPEED_IP_SCU, HW_STRAP1, GENMASK(1, 0), 0, 0 }
 
 #define A8 56
 SIG_EXPR_DECL(ROMD8, ROM16, ROM16_DESC);
@@ -352,6 +497,93 @@ MS_PIN_DECL(E7, GPIOH7, ROMD15, RXD6);
 
 FUNC_GROUP_DECL(UART6, A8, C7, B7, A7, D7, B6, A6, E7);
 
+#define SPI1_DESC \
+       { ASPEED_IP_SCU, HW_STRAP1, GENMASK(13, 12), 1, 0 }
+#define SPI1DEBUG_DESC \
+       { ASPEED_IP_SCU, HW_STRAP1, GENMASK(13, 12), 2, 0 }
+#define SPI1PASSTHRU_DESC \
+       { ASPEED_IP_SCU, HW_STRAP1, GENMASK(13, 12), 3, 0 }
+
+#define C22 64
+SIG_EXPR_DECL(SYSCS, SPI1DEBUG, SPI1DEBUG_DESC);
+SIG_EXPR_DECL(SYSCS, SPI1PASSTHRU, SPI1PASSTHRU_DESC);
+SIG_EXPR_LIST_DECL_DUAL(SYSCS, SPI1DEBUG, SPI1PASSTHRU);
+SS_PIN_DECL(C22, GPIOI0, SYSCS);
+
+#define G18 65
+SIG_EXPR_DECL(SYSCK, SPI1DEBUG, SPI1DEBUG_DESC);
+SIG_EXPR_DECL(SYSCK, SPI1PASSTHRU, SPI1PASSTHRU_DESC);
+SIG_EXPR_LIST_DECL_DUAL(SYSCK, SPI1DEBUG, SPI1PASSTHRU);
+SS_PIN_DECL(G18, GPIOI1, SYSCK);
+
+#define D19 66
+SIG_EXPR_DECL(SYSDO, SPI1DEBUG, SPI1DEBUG_DESC);
+SIG_EXPR_DECL(SYSDO, SPI1PASSTHRU, SPI1PASSTHRU_DESC);
+SIG_EXPR_LIST_DECL_DUAL(SYSDO, SPI1DEBUG, SPI1PASSTHRU);
+SS_PIN_DECL(D19, GPIOI2, SYSDO);
+
+#define C20 67
+SIG_EXPR_DECL(SYSDI, SPI1DEBUG, SPI1DEBUG_DESC);
+SIG_EXPR_DECL(SYSDI, SPI1PASSTHRU, SPI1PASSTHRU_DESC);
+SIG_EXPR_LIST_DECL_DUAL(SYSDI, SPI1DEBUG, SPI1PASSTHRU);
+SS_PIN_DECL(C20, GPIOI3, SYSDI);
+
+#define VB_DESC        SIG_DESC_SET(HW_STRAP1, 5)
+
+#define B22 68
+SIG_EXPR_DECL(SPI1CS0, SPI1, SPI1_DESC);
+SIG_EXPR_DECL(SPI1CS0, SPI1DEBUG, SPI1DEBUG_DESC);
+SIG_EXPR_DECL(SPI1CS0, SPI1PASSTHRU, SPI1PASSTHRU_DESC);
+SIG_EXPR_LIST_DECL(SPI1CS0, SIG_EXPR_PTR(SPI1CS0, SPI1),
+                           SIG_EXPR_PTR(SPI1CS0, SPI1DEBUG),
+                           SIG_EXPR_PTR(SPI1CS0, SPI1PASSTHRU));
+SIG_EXPR_LIST_DECL_SINGLE(VBCS, VGABIOS_ROM, VB_DESC);
+MS_PIN_DECL(B22, GPIOI4, SPI1CS0, VBCS);
+
+#define G19 69
+SIG_EXPR_DECL(SPI1CK, SPI1, SPI1_DESC);
+SIG_EXPR_DECL(SPI1CK, SPI1DEBUG, SPI1DEBUG_DESC);
+SIG_EXPR_DECL(SPI1CK, SPI1PASSTHRU, SPI1PASSTHRU_DESC);
+SIG_EXPR_LIST_DECL(SPI1CK, SIG_EXPR_PTR(SPI1CK, SPI1),
+                           SIG_EXPR_PTR(SPI1CK, SPI1DEBUG),
+                           SIG_EXPR_PTR(SPI1CK, SPI1PASSTHRU));
+SIG_EXPR_LIST_DECL_SINGLE(VBCK, VGABIOS_ROM, VB_DESC);
+MS_PIN_DECL(G19, GPIOI5, SPI1CK, VBCK);
+
+#define C18 70
+SIG_EXPR_DECL(SPI1DO, SPI1, SPI1_DESC);
+SIG_EXPR_DECL(SPI1DO, SPI1DEBUG, SPI1DEBUG_DESC);
+SIG_EXPR_DECL(SPI1DO, SPI1PASSTHRU, SPI1PASSTHRU_DESC);
+SIG_EXPR_LIST_DECL(SPI1DO, SIG_EXPR_PTR(SPI1DO, SPI1),
+                           SIG_EXPR_PTR(SPI1DO, SPI1DEBUG),
+                           SIG_EXPR_PTR(SPI1DO, SPI1PASSTHRU));
+SIG_EXPR_LIST_DECL_SINGLE(VBDO, VGABIOS_ROM, VB_DESC);
+MS_PIN_DECL(C18, GPIOI6, SPI1DO, VBDO);
+
+#define E20 71
+SIG_EXPR_DECL(SPI1DI, SPI1, SPI1_DESC);
+SIG_EXPR_DECL(SPI1DI, SPI1DEBUG, SPI1DEBUG_DESC);
+SIG_EXPR_DECL(SPI1DI, SPI1PASSTHRU, SPI1PASSTHRU_DESC);
+SIG_EXPR_LIST_DECL(SPI1DI, SIG_EXPR_PTR(SPI1DI, SPI1),
+                           SIG_EXPR_PTR(SPI1DI, SPI1DEBUG),
+                           SIG_EXPR_PTR(SPI1DI, SPI1PASSTHRU));
+SIG_EXPR_LIST_DECL_SINGLE(VBDI, VGABIOS_ROM, VB_DESC);
+MS_PIN_DECL(E20, GPIOI7, SPI1DI, VBDI);
+
+FUNC_GROUP_DECL(SPI1, B22, G19, C18, E20);
+FUNC_GROUP_DECL(SPI1DEBUG, C22, G18, D19, C20, B22, G19, C18, E20);
+FUNC_GROUP_DECL(SPI1PASSTHRU, C22, G18, D19, C20, B22, G19, C18, E20);
+FUNC_GROUP_DECL(VGABIOS_ROM, B22, G19, C18, E20);
+
+#define J5 72
+SSSF_PIN_DECL(J5, GPIOJ0, SGPMCK, SIG_DESC_SET(SCU84, 8));
+
+#define J4 73
+SSSF_PIN_DECL(J4, GPIOJ1, SGPMLD, SIG_DESC_SET(SCU84, 9));
+
+#define K5 74
+SSSF_PIN_DECL(K5, GPIOJ2, SGPMO, SIG_DESC_SET(SCU84, 10));
+
 #define J3 75
 SSSF_PIN_DECL(J3, GPIOJ3, SGPMI, SIG_DESC_SET(SCU84, 11));
 
@@ -418,9 +650,9 @@ FUNC_GROUP_DECL(I2C8, G5, F3);
 #define U1 88
 SSSF_PIN_DECL(U1, GPIOL0, NCTS1, SIG_DESC_SET(SCU84, 16));
 
-#define VPI18_DESC     { SCU90, GENMASK(5, 4), 1, 0 }
-#define VPI24_DESC     { SCU90, GENMASK(5, 4), 2, 0 }
-#define VPI30_DESC     { SCU90, GENMASK(5, 4), 3, 0 }
+#define VPI18_DESC     { ASPEED_IP_SCU, SCU90, GENMASK(5, 4), 1, 0 }
+#define VPI24_DESC     { ASPEED_IP_SCU, SCU90, GENMASK(5, 4), 2, 0 }
+#define VPI30_DESC     { ASPEED_IP_SCU, SCU90, GENMASK(5, 4), 3, 0 }
 
 #define T5 89
 #define T5_DESC         SIG_DESC_SET(SCU84, 17)
@@ -496,6 +728,102 @@ SIG_EXPR_LIST_DECL_SINGLE(RXD1, RXD1, U5_DESC);
 MS_PIN_DECL(U5, GPIOL7, VPIB1, RXD1);
 FUNC_GROUP_DECL(RXD1, U5);
 
+#define V3 96
+#define V3_DESC                SIG_DESC_SET(SCU84, 24)
+SIG_EXPR_DECL(VPIOB2, VPI18, VPI18_DESC, V3_DESC);
+SIG_EXPR_DECL(VPIOB2, VPI24, VPI24_DESC, V3_DESC);
+SIG_EXPR_DECL(VPIOB2, VPI30, VPI30_DESC, V3_DESC);
+SIG_EXPR_LIST_DECL(VPIOB2, SIG_EXPR_PTR(VPIOB2, VPI18),
+               SIG_EXPR_PTR(VPIOB2, VPI24),
+               SIG_EXPR_PTR(VPIOB2, VPI30));
+SIG_EXPR_LIST_DECL_SINGLE(NCTS2, NCTS2, V3_DESC);
+MS_PIN_DECL(V3, GPIOM0, VPIOB2, NCTS2);
+FUNC_GROUP_DECL(NCTS2, V3);
+
+#define W2 97
+#define W2_DESC                SIG_DESC_SET(SCU84, 25)
+SIG_EXPR_DECL(VPIOB3, VPI18, VPI18_DESC, W2_DESC);
+SIG_EXPR_DECL(VPIOB3, VPI24, VPI24_DESC, W2_DESC);
+SIG_EXPR_DECL(VPIOB3, VPI30, VPI30_DESC, W2_DESC);
+SIG_EXPR_LIST_DECL(VPIOB3, SIG_EXPR_PTR(VPIOB3, VPI18),
+               SIG_EXPR_PTR(VPIOB3, VPI24),
+               SIG_EXPR_PTR(VPIOB3, VPI30));
+SIG_EXPR_LIST_DECL_SINGLE(NDCD2, NDCD2, W2_DESC);
+MS_PIN_DECL(W2, GPIOM1, VPIOB3, NDCD2);
+FUNC_GROUP_DECL(NDCD2, W2);
+
+#define Y1 98
+#define Y1_DESC                SIG_DESC_SET(SCU84, 26)
+SIG_EXPR_DECL(VPIOB4, VPI18, VPI18_DESC, Y1_DESC);
+SIG_EXPR_DECL(VPIOB4, VPI24, VPI24_DESC, Y1_DESC);
+SIG_EXPR_DECL(VPIOB4, VPI30, VPI30_DESC, Y1_DESC);
+SIG_EXPR_LIST_DECL(VPIOB4, SIG_EXPR_PTR(VPIOB4, VPI18),
+               SIG_EXPR_PTR(VPIOB4, VPI24),
+               SIG_EXPR_PTR(VPIOB4, VPI30));
+SIG_EXPR_LIST_DECL_SINGLE(NDSR2, NDSR2, Y1_DESC);
+MS_PIN_DECL(Y1, GPIOM2, VPIOB4, NDSR2);
+FUNC_GROUP_DECL(NDSR2, Y1);
+
+#define V4 99
+#define V4_DESC                SIG_DESC_SET(SCU84, 27)
+SIG_EXPR_DECL(VPIOB5, VPI18, VPI18_DESC, V4_DESC);
+SIG_EXPR_DECL(VPIOB5, VPI24, VPI24_DESC, V4_DESC);
+SIG_EXPR_DECL(VPIOB5, VPI30, VPI30_DESC, V4_DESC);
+SIG_EXPR_LIST_DECL(VPIOB5, SIG_EXPR_PTR(VPIOB5, VPI18),
+               SIG_EXPR_PTR(VPIOB5, VPI24),
+               SIG_EXPR_PTR(VPIOB5, VPI30));
+SIG_EXPR_LIST_DECL_SINGLE(NRI2, NRI2, V4_DESC);
+MS_PIN_DECL(V4, GPIOM3, VPIOB5, NRI2);
+FUNC_GROUP_DECL(NRI2, V4);
+
+#define W3 100
+#define W3_DESC                SIG_DESC_SET(SCU84, 28)
+SIG_EXPR_DECL(VPIOB6, VPI18, VPI18_DESC, W3_DESC);
+SIG_EXPR_DECL(VPIOB6, VPI24, VPI24_DESC, W3_DESC);
+SIG_EXPR_DECL(VPIOB6, VPI30, VPI30_DESC, W3_DESC);
+SIG_EXPR_LIST_DECL(VPIOB6, SIG_EXPR_PTR(VPIOB6, VPI18),
+               SIG_EXPR_PTR(VPIOB6, VPI24),
+               SIG_EXPR_PTR(VPIOB6, VPI30));
+SIG_EXPR_LIST_DECL_SINGLE(NDTR2, NDTR2, W3_DESC);
+MS_PIN_DECL(W3, GPIOM4, VPIOB6, NDTR2);
+FUNC_GROUP_DECL(NDTR2, W3);
+
+#define Y2 101
+#define Y2_DESC                SIG_DESC_SET(SCU84, 29)
+SIG_EXPR_DECL(VPIOB7, VPI18, VPI18_DESC, Y2_DESC);
+SIG_EXPR_DECL(VPIOB7, VPI24, VPI24_DESC, Y2_DESC);
+SIG_EXPR_DECL(VPIOB7, VPI30, VPI30_DESC, Y2_DESC);
+SIG_EXPR_LIST_DECL(VPIOB7, SIG_EXPR_PTR(VPIOB7, VPI18),
+               SIG_EXPR_PTR(VPIOB7, VPI24),
+               SIG_EXPR_PTR(VPIOB7, VPI30));
+SIG_EXPR_LIST_DECL_SINGLE(NRTS2, NRTS2, Y2_DESC);
+MS_PIN_DECL(Y2, GPIOM5, VPIOB7, NRTS2);
+FUNC_GROUP_DECL(NRTS2, Y2);
+
+#define AA1 102
+#define AA1_DESC       SIG_DESC_SET(SCU84, 30)
+SIG_EXPR_DECL(VPIOB8, VPI18, VPI18_DESC, AA1_DESC);
+SIG_EXPR_DECL(VPIOB8, VPI24, VPI24_DESC, AA1_DESC);
+SIG_EXPR_DECL(VPIOB8, VPI30, VPI30_DESC, AA1_DESC);
+SIG_EXPR_LIST_DECL(VPIOB8, SIG_EXPR_PTR(VPIOB8, VPI18),
+               SIG_EXPR_PTR(VPIOB8, VPI24),
+               SIG_EXPR_PTR(VPIOB8, VPI30));
+SIG_EXPR_LIST_DECL_SINGLE(TXD2, TXD2, AA1_DESC);
+MS_PIN_DECL(AA1, GPIOM6, VPIOB8, TXD2);
+FUNC_GROUP_DECL(TXD2, AA1);
+
+#define V5 103
+#define V5_DESC                SIG_DESC_SET(SCU84, 31)
+SIG_EXPR_DECL(VPIOB9, VPI18, VPI18_DESC, V5_DESC);
+SIG_EXPR_DECL(VPIOB9, VPI24, VPI24_DESC, V5_DESC);
+SIG_EXPR_DECL(VPIOB9, VPI30, VPI30_DESC, V5_DESC);
+SIG_EXPR_LIST_DECL(VPIOB9, SIG_EXPR_PTR(VPIOB9, VPI18),
+               SIG_EXPR_PTR(VPIOB9, VPI24),
+               SIG_EXPR_PTR(VPIOB9, VPI30));
+SIG_EXPR_LIST_DECL_SINGLE(RXD2, RXD2, V5_DESC);
+MS_PIN_DECL(V5, GPIOM7, VPIOB9, RXD2);
+FUNC_GROUP_DECL(RXD2, V5);
+
 #define W4 104
 #define W4_DESC         SIG_DESC_SET(SCU88, 0)
 SIG_EXPR_LIST_DECL_SINGLE(VPIG0, VPI30, VPI30_DESC, W4_DESC);
@@ -580,10 +908,57 @@ SS_PIN_DECL(V6, GPIOO0, VPIG8);
 SIG_EXPR_LIST_DECL_SINGLE(VPIG9, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 9));
 SS_PIN_DECL(Y5, GPIOO1, VPIG9);
 
-FUNC_GROUP_DECL(VPI18, T5, U3, V1, U4, V2, AA22, W5, Y4, AA3, AB2);
-FUNC_GROUP_DECL(VPI24, T5, U3, V1, U4, V2, AA22, W5, Y4, AA3, AB2, V6, Y5);
-FUNC_GROUP_DECL(VPI30, T5, U3, V1, U4, V2, W1, U5, W4, Y3, AA22, W5, Y4, AA3,
-               AB2);
+#define AA4 114
+SIG_EXPR_LIST_DECL_SINGLE(VPIR0, VPI30, VPI30_DESC, SIG_DESC_SET(SCU88, 10));
+SS_PIN_DECL(AA4, GPIOO2, VPIR0);
+
+#define AB3 115
+SIG_EXPR_LIST_DECL_SINGLE(VPIR1, VPI30, VPI30_DESC, SIG_DESC_SET(SCU88, 11));
+SS_PIN_DECL(AB3, GPIOO3, VPIR1);
+
+#define W6 116
+SIG_EXPR_LIST_DECL_SINGLE(VPIR2, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 12));
+SS_PIN_DECL(W6, GPIOO4, VPIR2);
+
+#define AA5 117
+SIG_EXPR_LIST_DECL_SINGLE(VPIR3, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 13));
+SS_PIN_DECL(AA5, GPIOO5, VPIR3);
+
+#define AB4 118
+SIG_EXPR_LIST_DECL_SINGLE(VPIR4, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 14));
+SS_PIN_DECL(AB4, GPIOO6, VPIR4);
+
+#define V7 119
+SIG_EXPR_LIST_DECL_SINGLE(VPIR5, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 15));
+SS_PIN_DECL(V7, GPIOO7, VPIR5);
+
+#define Y6 120
+SIG_EXPR_LIST_DECL_SINGLE(VPIR6, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 16));
+SS_PIN_DECL(Y6, GPIOP0, VPIR6);
+
+#define AB5 121
+SIG_EXPR_LIST_DECL_SINGLE(VPIR7, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 17));
+SS_PIN_DECL(AB5, GPIOP1, VPIR7);
+
+#define W7 122
+SIG_EXPR_LIST_DECL_SINGLE(VPIR8, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 18));
+SS_PIN_DECL(W7, GPIOP2, VPIR8);
+
+#define AA6 123
+SIG_EXPR_LIST_DECL_SINGLE(VPIR9, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 19));
+SS_PIN_DECL(AA6, GPIOP3, VPIR9);
+
+FUNC_GROUP_DECL(VPI18, T5, U3, V1, U4, V2, V3, W2, Y1, V4, W3, Y2, AA1, V5,
+               AA22, W5, Y4, AA3, AB2);
+FUNC_GROUP_DECL(VPI24, T5, U3, V1, U4, V2, V3, W2, Y1, V4, W3, Y2, AA1, V5,
+               AA22, W5, Y4, AA3, AB2, V6, Y5, W6, AA5, AB4, V7, Y6, AB5, W7,
+               AA6);
+FUNC_GROUP_DECL(VPI30, T5, U3, V1, U4, V2, W1, U5, V3, W2, Y1, V4, W3, Y2, AA1,
+               V5, W4, Y3, AA22, W5, Y4, AA3, AB2, AA4, AB3);
+
+#define AB6 124
+SIG_EXPR_LIST_DECL_SINGLE(GPIOP4, GPIOP4);
+MS_PIN_DECL_(AB6, SIG_EXPR_LIST_PTR(GPIOP4));
 
 #define Y7 125
 SIG_EXPR_LIST_DECL_SINGLE(GPIOP5, GPIOP5);
@@ -619,6 +994,18 @@ SS_PIN_DECL(F5, GPIOQ3, SDA4);
 
 FUNC_GROUP_DECL(I2C4, B1, F5);
 
+#define I2C14_DESC     SIG_DESC_SET(SCU90, 27)
+
+#define H4 132
+SIG_EXPR_LIST_DECL_SINGLE(SCL14, I2C14, I2C14_DESC);
+SS_PIN_DECL(H4, GPIOQ4, SCL14);
+
+#define H3 133
+SIG_EXPR_LIST_DECL_SINGLE(SDA14, I2C14, I2C14_DESC);
+SS_PIN_DECL(H3, GPIOQ5, SDA14);
+
+FUNC_GROUP_DECL(I2C14, H4, H3);
+
 #define DASH9028_DESC  SIG_DESC_SET(SCU90, 28)
 
 #define H2 134
@@ -641,11 +1028,11 @@ SSSF_PIN_DECL(Y22, GPIOR2, ROMCS3, SIG_DESC_SET(SCU88, 26));
 #define U19 139
 SSSF_PIN_DECL(U19, GPIOR3, ROMCS4, SIG_DESC_SET(SCU88, 27));
 
-#define VPOOFF0_DESC   { SCU94, GENMASK(1, 0), 0, 0 }
-#define VPO12_DESC     { SCU94, GENMASK(1, 0), 1, 0 }
-#define VPO24_DESC     { SCU94, GENMASK(1, 0), 2, 0 }
-#define VPOOFF1_DESC   { SCU94, GENMASK(1, 0), 3, 0 }
-#define VPO_OFF_12      { SCU94, 0x2, 0, 0 }
+#define VPOOFF0_DESC   { ASPEED_IP_SCU, SCU94, GENMASK(1, 0), 0, 0 }
+#define VPO12_DESC     { ASPEED_IP_SCU, SCU94, GENMASK(1, 0), 1, 0 }
+#define VPO24_DESC     { ASPEED_IP_SCU, SCU94, GENMASK(1, 0), 2, 0 }
+#define VPOOFF1_DESC   { ASPEED_IP_SCU, SCU94, GENMASK(1, 0), 3, 0 }
+#define VPO_OFF_12      { ASPEED_IP_SCU, SCU94, 0x2, 0, 0 }
 #define VPO_24_OFF      SIG_DESC_SET(SCU94, 1)
 
 #define V21 140
@@ -776,13 +1163,6 @@ SIG_EXPR_LIST_DECL(ROMA23, SIG_EXPR_PTR(ROMA23, ROM8),
 SIG_EXPR_LIST_DECL_SINGLE(VPOR5, VPO24, K18_DESC, VPO_24_OFF);
 MS_PIN_DECL(K18, GPIOS7, ROMA23, VPOR5);
 
-FUNC_GROUP_DECL(ROM8, V20, U21, T19, V22, U20, R18, N21, L22, K18, W21, Y22,
-               U19);
-FUNC_GROUP_DECL(ROM16, V20, U21, T19, V22, U20, R18, N21, L22, K18,
-               A8, C7, B7, A7, D7, B6, A6, E7, W21, Y22, U19);
-FUNC_GROUP_DECL(VPO12, U21, T19, V22, U20);
-FUNC_GROUP_DECL(VPO24, U21, T19, V22, U20, L22, K18, V21, W22);
-
 #define RMII1_DESC      SIG_DESC_BIT(HW_STRAP1, 6, 0)
 
 #define A12 152
@@ -827,6 +1207,50 @@ SIG_EXPR_LIST_DECL_SINGLE(RGMII1TXD3, RGMII1);
 MS_PIN_DECL_(A13, SIG_EXPR_LIST_PTR(GPIOT5), SIG_EXPR_LIST_PTR(DASHA13),
                SIG_EXPR_LIST_PTR(RGMII1TXD3));
 
+#define RMII2_DESC      SIG_DESC_BIT(HW_STRAP1, 7, 0)
+
+#define D9 158
+SIG_EXPR_LIST_DECL_SINGLE(GPIOT6, GPIOT6, SIG_DESC_SET(SCUA0, 6));
+SIG_EXPR_LIST_DECL_SINGLE(RMII2TXEN, RMII2, RMII2_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(RGMII2TXCK, RGMII2);
+MS_PIN_DECL_(D9, SIG_EXPR_LIST_PTR(GPIOT6), SIG_EXPR_LIST_PTR(RMII2TXEN),
+               SIG_EXPR_LIST_PTR(RGMII2TXCK));
+
+#define E9 159
+SIG_EXPR_LIST_DECL_SINGLE(GPIOT7, GPIOT7, SIG_DESC_SET(SCUA0, 7));
+SIG_EXPR_LIST_DECL_SINGLE(DASHE9, RMII2, RMII2_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(RGMII2TXCTL, RGMII2);
+MS_PIN_DECL_(E9, SIG_EXPR_LIST_PTR(GPIOT7), SIG_EXPR_LIST_PTR(DASHE9),
+               SIG_EXPR_LIST_PTR(RGMII2TXCTL));
+
+#define A10 160
+SIG_EXPR_LIST_DECL_SINGLE(GPIOU0, GPIOU0, SIG_DESC_SET(SCUA0, 8));
+SIG_EXPR_LIST_DECL_SINGLE(RMII2TXD0, RMII2, RMII2_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(RGMII2TXD0, RGMII2);
+MS_PIN_DECL_(A10, SIG_EXPR_LIST_PTR(GPIOU0), SIG_EXPR_LIST_PTR(RMII2TXD0),
+               SIG_EXPR_LIST_PTR(RGMII2TXD0));
+
+#define B10 161
+SIG_EXPR_LIST_DECL_SINGLE(GPIOU1, GPIOU1, SIG_DESC_SET(SCUA0, 9));
+SIG_EXPR_LIST_DECL_SINGLE(RMII2TXD1, RMII2, RMII2_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(RGMII2TXD1, RGMII2);
+MS_PIN_DECL_(B10, SIG_EXPR_LIST_PTR(GPIOU1), SIG_EXPR_LIST_PTR(RMII2TXD1),
+               SIG_EXPR_LIST_PTR(RGMII2TXD1));
+
+#define C10 162
+SIG_EXPR_LIST_DECL_SINGLE(GPIOU2, GPIOU2, SIG_DESC_SET(SCUA0, 10));
+SIG_EXPR_LIST_DECL_SINGLE(DASHC10, RMII2, RMII2_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(RGMII2TXD2, RGMII2);
+MS_PIN_DECL_(C10, SIG_EXPR_LIST_PTR(GPIOU2), SIG_EXPR_LIST_PTR(DASHC10),
+               SIG_EXPR_LIST_PTR(RGMII2TXD2));
+
+#define D10 163
+SIG_EXPR_LIST_DECL_SINGLE(GPIOU3, GPIOU3, SIG_DESC_SET(SCUA0, 11));
+SIG_EXPR_LIST_DECL_SINGLE(DASHD10, RMII2, RMII2_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(RGMII2TXD3, RGMII2);
+MS_PIN_DECL_(D10, SIG_EXPR_LIST_PTR(GPIOU3), SIG_EXPR_LIST_PTR(DASHD10),
+               SIG_EXPR_LIST_PTR(RGMII2TXD3));
+
 #define E11 164
 SIG_EXPR_LIST_DECL_SINGLE(GPIOU4, GPIOU4, SIG_DESC_SET(SCUA0, 12));
 SIG_EXPR_LIST_DECL_SINGLE(RMII1RCLK, RMII1, RMII1_DESC);
@@ -869,11 +1293,419 @@ SIG_EXPR_LIST_DECL_SINGLE(RGMII1RXD3, RGMII1);
 MS_PIN_DECL_(E10, SIG_EXPR_LIST_PTR(GPIOV1), SIG_EXPR_LIST_PTR(RMII1RXER),
                SIG_EXPR_LIST_PTR(RGMII1RXD3));
 
+#define C9 170
+SIG_EXPR_LIST_DECL_SINGLE(GPIOV2, GPIOV2, SIG_DESC_SET(SCUA0, 18));
+SIG_EXPR_LIST_DECL_SINGLE(RMII2RCLK, RMII2, RMII2_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(RGMII2RXCK, RGMII2);
+MS_PIN_DECL_(C9, SIG_EXPR_LIST_PTR(GPIOV2), SIG_EXPR_LIST_PTR(RMII2RCLK),
+               SIG_EXPR_LIST_PTR(RGMII2RXCK));
+
+#define B9 171
+SIG_EXPR_LIST_DECL_SINGLE(GPIOV3, GPIOV3, SIG_DESC_SET(SCUA0, 19));
+SIG_EXPR_LIST_DECL_SINGLE(DASHB9, RMII2, RMII2_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(RGMII2RXCTL, RGMII2);
+MS_PIN_DECL_(B9, SIG_EXPR_LIST_PTR(GPIOV3), SIG_EXPR_LIST_PTR(DASHB9),
+               SIG_EXPR_LIST_PTR(RGMII2RXCTL));
+
+#define A9 172
+SIG_EXPR_LIST_DECL_SINGLE(GPIOV4, GPIOV4, SIG_DESC_SET(SCUA0, 20));
+SIG_EXPR_LIST_DECL_SINGLE(RMII2RXD0, RMII2, RMII2_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(RGMII2RXD0, RGMII2);
+MS_PIN_DECL_(A9, SIG_EXPR_LIST_PTR(GPIOV4), SIG_EXPR_LIST_PTR(RMII2RXD0),
+               SIG_EXPR_LIST_PTR(RGMII2RXD0));
+
+#define E8 173
+SIG_EXPR_LIST_DECL_SINGLE(GPIOV5, GPIOV5, SIG_DESC_SET(SCUA0, 21));
+SIG_EXPR_LIST_DECL_SINGLE(RMII2RXD1, RMII2, RMII2_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(RGMII2RXD1, RGMII2);
+MS_PIN_DECL_(E8, SIG_EXPR_LIST_PTR(GPIOV5), SIG_EXPR_LIST_PTR(RMII2RXD1),
+               SIG_EXPR_LIST_PTR(RGMII2RXD1));
+
+#define D8 174
+SIG_EXPR_LIST_DECL_SINGLE(GPIOV6, GPIOV6, SIG_DESC_SET(SCUA0, 22));
+SIG_EXPR_LIST_DECL_SINGLE(RMII2CRSDV, RMII2, RMII2_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(RGMII2RXD2, RGMII2);
+MS_PIN_DECL_(D8, SIG_EXPR_LIST_PTR(GPIOV6), SIG_EXPR_LIST_PTR(RMII2CRSDV),
+               SIG_EXPR_LIST_PTR(RGMII2RXD2));
+
+#define C8 175
+SIG_EXPR_LIST_DECL_SINGLE(GPIOV7, GPIOV7, SIG_DESC_SET(SCUA0, 23));
+SIG_EXPR_LIST_DECL_SINGLE(RMII2RXER, RMII2, RMII2_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(RGMII2RXD3, RGMII2);
+MS_PIN_DECL_(C8, SIG_EXPR_LIST_PTR(GPIOV7), SIG_EXPR_LIST_PTR(RMII2RXER),
+               SIG_EXPR_LIST_PTR(RGMII2RXD3));
+
 FUNC_GROUP_DECL(RMII1, A12, B12, C12, D12, E12, A13, E11, D11, C11, B11, A11,
                E10);
 FUNC_GROUP_DECL(RGMII1, A12, B12, C12, D12, E12, A13, E11, D11, C11, B11, A11,
                E10);
 
+FUNC_GROUP_DECL(RMII2, D9, E9, A10, B10, C10, D10, C9, B9, A9, E8, D8, C8);
+FUNC_GROUP_DECL(RGMII2, D9, E9, A10, B10, C10, D10, C9, B9, A9, E8, D8, C8);
+
+#define L5 176
+SIG_EXPR_LIST_DECL_SINGLE(GPIOW0, GPIOW0, SIG_DESC_SET(SCUA0, 24));
+SIG_EXPR_LIST_DECL_SINGLE(ADC0, ADC0);
+MS_PIN_DECL_(L5, SIG_EXPR_LIST_PTR(GPIOW0), SIG_EXPR_LIST_PTR(ADC0));
+FUNC_GROUP_DECL(ADC0, L5);
+
+#define L4 177
+SIG_EXPR_LIST_DECL_SINGLE(GPIOW1, GPIOW1, SIG_DESC_SET(SCUA0, 25));
+SIG_EXPR_LIST_DECL_SINGLE(ADC1, ADC1);
+MS_PIN_DECL_(L4, SIG_EXPR_LIST_PTR(GPIOW1), SIG_EXPR_LIST_PTR(ADC1));
+FUNC_GROUP_DECL(ADC1, L4);
+
+#define L3 178
+SIG_EXPR_LIST_DECL_SINGLE(GPIOW2, GPIOW2, SIG_DESC_SET(SCUA0, 26));
+SIG_EXPR_LIST_DECL_SINGLE(ADC2, ADC2);
+MS_PIN_DECL_(L3, SIG_EXPR_LIST_PTR(GPIOW2), SIG_EXPR_LIST_PTR(ADC2));
+FUNC_GROUP_DECL(ADC2, L3);
+
+#define L2 179
+SIG_EXPR_LIST_DECL_SINGLE(GPIOW3, GPIOW3, SIG_DESC_SET(SCUA0, 27));
+SIG_EXPR_LIST_DECL_SINGLE(ADC3, ADC3);
+MS_PIN_DECL_(L2, SIG_EXPR_LIST_PTR(GPIOW3), SIG_EXPR_LIST_PTR(ADC3));
+FUNC_GROUP_DECL(ADC3, L2);
+
+#define L1 180
+SIG_EXPR_LIST_DECL_SINGLE(GPIOW4, GPIOW4, SIG_DESC_SET(SCUA0, 28));
+SIG_EXPR_LIST_DECL_SINGLE(ADC4, ADC4);
+MS_PIN_DECL_(L1, SIG_EXPR_LIST_PTR(GPIOW4), SIG_EXPR_LIST_PTR(ADC4));
+FUNC_GROUP_DECL(ADC4, L1);
+
+#define M5 181
+SIG_EXPR_LIST_DECL_SINGLE(GPIOW5, GPIOW5, SIG_DESC_SET(SCUA0, 29));
+SIG_EXPR_LIST_DECL_SINGLE(ADC5, ADC5);
+MS_PIN_DECL_(M5, SIG_EXPR_LIST_PTR(GPIOW5), SIG_EXPR_LIST_PTR(ADC5));
+FUNC_GROUP_DECL(ADC5, M5);
+
+#define M4 182
+SIG_EXPR_LIST_DECL_SINGLE(GPIOW6, GPIOW6, SIG_DESC_SET(SCUA0, 30));
+SIG_EXPR_LIST_DECL_SINGLE(ADC6, ADC6);
+MS_PIN_DECL_(M4, SIG_EXPR_LIST_PTR(GPIOW6), SIG_EXPR_LIST_PTR(ADC6));
+FUNC_GROUP_DECL(ADC6, M4);
+
+#define M3 183
+SIG_EXPR_LIST_DECL_SINGLE(GPIOW7, GPIOW7, SIG_DESC_SET(SCUA0, 31));
+SIG_EXPR_LIST_DECL_SINGLE(ADC7, ADC7);
+MS_PIN_DECL_(M3, SIG_EXPR_LIST_PTR(GPIOW7), SIG_EXPR_LIST_PTR(ADC7));
+FUNC_GROUP_DECL(ADC7, M3);
+
+#define M2 184
+SIG_EXPR_LIST_DECL_SINGLE(GPIOX0, GPIOX0, SIG_DESC_SET(SCUA4, 0));
+SIG_EXPR_LIST_DECL_SINGLE(ADC8, ADC8);
+MS_PIN_DECL_(M2, SIG_EXPR_LIST_PTR(GPIOX0), SIG_EXPR_LIST_PTR(ADC8));
+FUNC_GROUP_DECL(ADC8, M2);
+
+#define M1 185
+SIG_EXPR_LIST_DECL_SINGLE(GPIOX1, GPIOX1, SIG_DESC_SET(SCUA4, 1));
+SIG_EXPR_LIST_DECL_SINGLE(ADC9, ADC9);
+MS_PIN_DECL_(M1, SIG_EXPR_LIST_PTR(GPIOX1), SIG_EXPR_LIST_PTR(ADC9));
+FUNC_GROUP_DECL(ADC9, M1);
+
+#define N5 186
+SIG_EXPR_LIST_DECL_SINGLE(GPIOX2, GPIOX2, SIG_DESC_SET(SCUA4, 2));
+SIG_EXPR_LIST_DECL_SINGLE(ADC10, ADC10);
+MS_PIN_DECL_(N5, SIG_EXPR_LIST_PTR(GPIOX2), SIG_EXPR_LIST_PTR(ADC10));
+FUNC_GROUP_DECL(ADC10, N5);
+
+#define N4 187
+SIG_EXPR_LIST_DECL_SINGLE(GPIOX3, GPIOX3, SIG_DESC_SET(SCUA4, 3));
+SIG_EXPR_LIST_DECL_SINGLE(ADC11, ADC11);
+MS_PIN_DECL_(N4, SIG_EXPR_LIST_PTR(GPIOX3), SIG_EXPR_LIST_PTR(ADC11));
+FUNC_GROUP_DECL(ADC11, N4);
+
+#define N3 188
+SIG_EXPR_LIST_DECL_SINGLE(GPIOX4, GPIOX4, SIG_DESC_SET(SCUA4, 4));
+SIG_EXPR_LIST_DECL_SINGLE(ADC12, ADC12);
+MS_PIN_DECL_(N3, SIG_EXPR_LIST_PTR(GPIOX4), SIG_EXPR_LIST_PTR(ADC12));
+FUNC_GROUP_DECL(ADC12, N3);
+
+#define N2 189
+SIG_EXPR_LIST_DECL_SINGLE(GPIOX5, GPIOX5, SIG_DESC_SET(SCUA4, 5));
+SIG_EXPR_LIST_DECL_SINGLE(ADC13, ADC13);
+MS_PIN_DECL_(N2, SIG_EXPR_LIST_PTR(GPIOX5), SIG_EXPR_LIST_PTR(ADC13));
+FUNC_GROUP_DECL(ADC13, N2);
+
+#define N1 190
+SIG_EXPR_LIST_DECL_SINGLE(GPIOX6, GPIOX6, SIG_DESC_SET(SCUA4, 6));
+SIG_EXPR_LIST_DECL_SINGLE(ADC14, ADC14);
+MS_PIN_DECL_(N1, SIG_EXPR_LIST_PTR(GPIOX6), SIG_EXPR_LIST_PTR(ADC14));
+FUNC_GROUP_DECL(ADC14, N1);
+
+#define P5 191
+SIG_EXPR_LIST_DECL_SINGLE(GPIOX7, GPIOX7, SIG_DESC_SET(SCUA4, 7));
+SIG_EXPR_LIST_DECL_SINGLE(ADC15, ADC15);
+MS_PIN_DECL_(P5, SIG_EXPR_LIST_PTR(GPIOX7), SIG_EXPR_LIST_PTR(ADC15));
+FUNC_GROUP_DECL(ADC15, P5);
+
+#define C21 192
+SIG_EXPR_DECL(SIOS3, SIOS3, SIG_DESC_SET(SCUA4, 8));
+SIG_EXPR_DECL(SIOS3, ACPI, ACPI_DESC);
+SIG_EXPR_LIST_DECL_DUAL(SIOS3, SIOS3, ACPI);
+SS_PIN_DECL(C21, GPIOY0, SIOS3);
+FUNC_GROUP_DECL(SIOS3, C21);
+
+#define F20 193
+SIG_EXPR_DECL(SIOS5, SIOS5, SIG_DESC_SET(SCUA4, 9));
+SIG_EXPR_DECL(SIOS5, ACPI, ACPI_DESC);
+SIG_EXPR_LIST_DECL_DUAL(SIOS5, SIOS5, ACPI);
+SS_PIN_DECL(F20, GPIOY1, SIOS5);
+FUNC_GROUP_DECL(SIOS5, F20);
+
+#define G20 194
+SIG_EXPR_DECL(SIOPWREQ, SIOPWREQ, SIG_DESC_SET(SCUA4, 10));
+SIG_EXPR_DECL(SIOPWREQ, ACPI, ACPI_DESC);
+SIG_EXPR_LIST_DECL_DUAL(SIOPWREQ, SIOPWREQ, ACPI);
+SS_PIN_DECL(G20, GPIOY2, SIOPWREQ);
+FUNC_GROUP_DECL(SIOPWREQ, G20);
+
+#define K20 195
+SIG_EXPR_DECL(SIOONCTRL, SIOONCTRL, SIG_DESC_SET(SCUA4, 11));
+SIG_EXPR_DECL(SIOONCTRL, ACPI, ACPI_DESC);
+SIG_EXPR_LIST_DECL_DUAL(SIOONCTRL, SIOONCTRL, ACPI);
+SS_PIN_DECL(K20, GPIOY3, SIOONCTRL);
+FUNC_GROUP_DECL(SIOONCTRL, K20);
+
+FUNC_GROUP_DECL(ACPI, B19, A20, D17, A19, C21, F20, G20, K20);
+
+#define R22 200
+#define R22_DESC       SIG_DESC_SET(SCUA4, 16)
+SIG_EXPR_DECL(ROMA2, ROM8, R22_DESC, VPOOFF0_DESC);
+SIG_EXPR_DECL(ROMA2, ROM16, R22_DESC, VPOOFF0_DESC);
+SIG_EXPR_LIST_DECL_DUAL(ROMA2, ROM8, ROM16);
+SIG_EXPR_DECL(VPOB0, VPO12, R22_DESC, VPO12_DESC);
+SIG_EXPR_DECL(VPOB0, VPO24, R22_DESC, VPO24_DESC);
+SIG_EXPR_DECL(VPOB0, VPOOFF1, R22_DESC, VPOOFF1_DESC);
+SIG_EXPR_LIST_DECL(VPOB0, SIG_EXPR_PTR(VPOB0, VPO12),
+               SIG_EXPR_PTR(VPOB0, VPO24), SIG_EXPR_PTR(VPOB0, VPOOFF1));
+MS_PIN_DECL(R22, GPIOZ0, ROMA2, VPOB0);
+
+#define P18 201
+#define P18_DESC       SIG_DESC_SET(SCUA4, 17)
+SIG_EXPR_DECL(ROMA3, ROM8, P18_DESC, VPOOFF0_DESC);
+SIG_EXPR_DECL(ROMA3, ROM16, P18_DESC, VPOOFF0_DESC);
+SIG_EXPR_LIST_DECL_DUAL(ROMA3, ROM8, ROM16);
+SIG_EXPR_DECL(VPOB1, VPO12, P18_DESC, VPO12_DESC);
+SIG_EXPR_DECL(VPOB1, VPO24, P18_DESC, VPO24_DESC);
+SIG_EXPR_DECL(VPOB1, VPOOFF1, P18_DESC, VPOOFF1_DESC);
+SIG_EXPR_LIST_DECL(VPOB1, SIG_EXPR_PTR(VPOB1, VPO12),
+               SIG_EXPR_PTR(VPOB1, VPO24), SIG_EXPR_PTR(VPOB1, VPOOFF1));
+MS_PIN_DECL(P18, GPIOZ1, ROMA3, VPOB1);
+
+#define P19 202
+#define P19_DESC       SIG_DESC_SET(SCUA4, 18)
+SIG_EXPR_DECL(ROMA4, ROM8, P19_DESC, VPOOFF0_DESC);
+SIG_EXPR_DECL(ROMA4, ROM16, P19_DESC, VPOOFF0_DESC);
+SIG_EXPR_LIST_DECL_DUAL(ROMA4, ROM8, ROM16);
+SIG_EXPR_DECL(VPOB2, VPO12, P19_DESC, VPO12_DESC);
+SIG_EXPR_DECL(VPOB2, VPO24, P19_DESC, VPO24_DESC);
+SIG_EXPR_DECL(VPOB2, VPOOFF1, P19_DESC, VPOOFF1_DESC);
+SIG_EXPR_LIST_DECL(VPOB2, SIG_EXPR_PTR(VPOB2, VPO12),
+               SIG_EXPR_PTR(VPOB2, VPO24), SIG_EXPR_PTR(VPOB2, VPOOFF1));
+MS_PIN_DECL(P19, GPIOZ2, ROMA4, VPOB2);
+
+#define P20 203
+#define P20_DESC       SIG_DESC_SET(SCUA4, 19)
+SIG_EXPR_DECL(ROMA5, ROM8, P20_DESC, VPOOFF0_DESC);
+SIG_EXPR_DECL(ROMA5, ROM16, P20_DESC, VPOOFF0_DESC);
+SIG_EXPR_LIST_DECL_DUAL(ROMA5, ROM8, ROM16);
+SIG_EXPR_DECL(VPOB3, VPO12, P20_DESC, VPO12_DESC);
+SIG_EXPR_DECL(VPOB3, VPO24, P20_DESC, VPO24_DESC);
+SIG_EXPR_DECL(VPOB3, VPOOFF1, P20_DESC, VPOOFF1_DESC);
+SIG_EXPR_LIST_DECL(VPOB3, SIG_EXPR_PTR(VPOB3, VPO12),
+               SIG_EXPR_PTR(VPOB3, VPO24), SIG_EXPR_PTR(VPOB3, VPOOFF1));
+MS_PIN_DECL(P20, GPIOZ3, ROMA5, VPOB3);
+
+#define P21 204
+#define P21_DESC       SIG_DESC_SET(SCUA4, 20)
+SIG_EXPR_DECL(ROMA6, ROM8, P21_DESC, VPOOFF0_DESC);
+SIG_EXPR_DECL(ROMA6, ROM16, P21_DESC, VPOOFF0_DESC);
+SIG_EXPR_LIST_DECL_DUAL(ROMA6, ROM8, ROM16);
+SIG_EXPR_DECL(VPOB4, VPO12, P21_DESC, VPO12_DESC);
+SIG_EXPR_DECL(VPOB4, VPO24, P21_DESC, VPO24_DESC);
+SIG_EXPR_DECL(VPOB4, VPOOFF1, P21_DESC, VPOOFF1_DESC);
+SIG_EXPR_LIST_DECL(VPOB4, SIG_EXPR_PTR(VPOB4, VPO12),
+               SIG_EXPR_PTR(VPOB4, VPO24), SIG_EXPR_PTR(VPOB4, VPOOFF1));
+MS_PIN_DECL(P21, GPIOZ4, ROMA6, VPOB4);
+
+#define P22 205
+#define P22_DESC       SIG_DESC_SET(SCUA4, 21)
+SIG_EXPR_DECL(ROMA7, ROM8, P22_DESC, VPOOFF0_DESC);
+SIG_EXPR_DECL(ROMA7, ROM16, P22_DESC, VPOOFF0_DESC);
+SIG_EXPR_LIST_DECL_DUAL(ROMA7, ROM8, ROM16);
+SIG_EXPR_DECL(VPOB5, VPO12, P22_DESC, VPO12_DESC);
+SIG_EXPR_DECL(VPOB5, VPO24, P22_DESC, VPO24_DESC);
+SIG_EXPR_DECL(VPOB5, VPOOFF1, P22_DESC, VPOOFF1_DESC);
+SIG_EXPR_LIST_DECL(VPOB5, SIG_EXPR_PTR(VPOB5, VPO12),
+               SIG_EXPR_PTR(VPOB5, VPO24), SIG_EXPR_PTR(VPOB5, VPOOFF1));
+MS_PIN_DECL(P22, GPIOZ5, ROMA7, VPOB5);
+
+#define M19 206
+#define M19_DESC       SIG_DESC_SET(SCUA4, 22)
+SIG_EXPR_DECL(ROMA8, ROM8, M19_DESC, VPOOFF0_DESC);
+SIG_EXPR_DECL(ROMA8, ROM16, M19_DESC, VPOOFF0_DESC);
+SIG_EXPR_LIST_DECL_DUAL(ROMA8, ROM8, ROM16);
+SIG_EXPR_DECL(VPOB6, VPO12, M19_DESC, VPO12_DESC);
+SIG_EXPR_DECL(VPOB6, VPO24, M19_DESC, VPO24_DESC);
+SIG_EXPR_DECL(VPOB6, VPOOFF1, M19_DESC, VPOOFF1_DESC);
+SIG_EXPR_LIST_DECL(VPOB6, SIG_EXPR_PTR(VPOB6, VPO12),
+               SIG_EXPR_PTR(VPOB6, VPO24), SIG_EXPR_PTR(VPOB6, VPOOFF1));
+MS_PIN_DECL(M19, GPIOZ6, ROMA8, VPOB6);
+
+#define M20 207
+#define M20_DESC       SIG_DESC_SET(SCUA4, 23)
+SIG_EXPR_DECL(ROMA9, ROM8, M20_DESC, VPOOFF0_DESC);
+SIG_EXPR_DECL(ROMA9, ROM16, M20_DESC, VPOOFF0_DESC);
+SIG_EXPR_LIST_DECL_DUAL(ROMA9, ROM8, ROM16);
+SIG_EXPR_DECL(VPOB7, VPO12, M20_DESC, VPO12_DESC);
+SIG_EXPR_DECL(VPOB7, VPO24, M20_DESC, VPO24_DESC);
+SIG_EXPR_DECL(VPOB7, VPOOFF1, M20_DESC, VPOOFF1_DESC);
+SIG_EXPR_LIST_DECL(VPOB7, SIG_EXPR_PTR(VPOB7, VPO12),
+               SIG_EXPR_PTR(VPOB7, VPO24), SIG_EXPR_PTR(VPOB7, VPOOFF1));
+MS_PIN_DECL(M20, GPIOZ7, ROMA9, VPOB7);
+
+#define M21 208
+#define M21_DESC       SIG_DESC_SET(SCUA4, 24)
+SIG_EXPR_DECL(ROMA10, ROM8, M21_DESC, VPOOFF0_DESC);
+SIG_EXPR_DECL(ROMA10, ROM16, M21_DESC, VPOOFF0_DESC);
+SIG_EXPR_LIST_DECL_DUAL(ROMA10, ROM8, ROM16);
+SIG_EXPR_DECL(VPOG0, VPO12, M21_DESC, VPO12_DESC);
+SIG_EXPR_DECL(VPOG0, VPO24, M21_DESC, VPO24_DESC);
+SIG_EXPR_DECL(VPOG0, VPOOFF1, M21_DESC, VPOOFF1_DESC);
+SIG_EXPR_LIST_DECL(VPOG0, SIG_EXPR_PTR(VPOG0, VPO12),
+               SIG_EXPR_PTR(VPOG0, VPO24), SIG_EXPR_PTR(VPOG0, VPOOFF1));
+MS_PIN_DECL(M21, GPIOAA0, ROMA10, VPOG0);
+
+#define M22 209
+#define M22_DESC       SIG_DESC_SET(SCUA4, 25)
+SIG_EXPR_DECL(ROMA11, ROM8, M22_DESC, VPOOFF0_DESC);
+SIG_EXPR_DECL(ROMA11, ROM16, M22_DESC, VPOOFF0_DESC);
+SIG_EXPR_LIST_DECL_DUAL(ROMA11, ROM8, ROM16);
+SIG_EXPR_DECL(VPOG1, VPO12, M22_DESC, VPO12_DESC);
+SIG_EXPR_DECL(VPOG1, VPO24, M22_DESC, VPO24_DESC);
+SIG_EXPR_DECL(VPOG1, VPOOFF1, M22_DESC, VPOOFF1_DESC);
+SIG_EXPR_LIST_DECL(VPOG1, SIG_EXPR_PTR(VPOG1, VPO12),
+               SIG_EXPR_PTR(VPOG1, VPO24), SIG_EXPR_PTR(VPOG1, VPOOFF1));
+MS_PIN_DECL(M22, GPIOAA1, ROMA11, VPOG1);
+
+#define L18 210
+#define L18_DESC       SIG_DESC_SET(SCUA4, 26)
+SIG_EXPR_DECL(ROMA12, ROM8, L18_DESC, VPOOFF0_DESC);
+SIG_EXPR_DECL(ROMA12, ROM16, L18_DESC, VPOOFF0_DESC);
+SIG_EXPR_LIST_DECL_DUAL(ROMA12, ROM8, ROM16);
+SIG_EXPR_DECL(VPOG2, VPO12, L18_DESC, VPO12_DESC);
+SIG_EXPR_DECL(VPOG2, VPO24, L18_DESC, VPO24_DESC);
+SIG_EXPR_DECL(VPOG2, VPOOFF1, L18_DESC, VPOOFF1_DESC);
+SIG_EXPR_LIST_DECL(VPOG2, SIG_EXPR_PTR(VPOG2, VPO12),
+               SIG_EXPR_PTR(VPOG2, VPO24), SIG_EXPR_PTR(VPOG2, VPOOFF1));
+MS_PIN_DECL(L18, GPIOAA2, ROMA12, VPOG2);
+
+#define L19 211
+#define L19_DESC       SIG_DESC_SET(SCUA4, 27)
+SIG_EXPR_DECL(ROMA13, ROM8, L19_DESC, VPOOFF0_DESC);
+SIG_EXPR_DECL(ROMA13, ROM16, L19_DESC, VPOOFF0_DESC);
+SIG_EXPR_LIST_DECL_DUAL(ROMA13, ROM8, ROM16);
+SIG_EXPR_DECL(VPOG3, VPO12, L19_DESC, VPO12_DESC);
+SIG_EXPR_DECL(VPOG3, VPO24, L19_DESC, VPO24_DESC);
+SIG_EXPR_DECL(VPOG3, VPOOFF1, L19_DESC, VPOOFF1_DESC);
+SIG_EXPR_LIST_DECL(VPOG3, SIG_EXPR_PTR(VPOG3, VPO12),
+               SIG_EXPR_PTR(VPOG3, VPO24), SIG_EXPR_PTR(VPOG3, VPOOFF1));
+MS_PIN_DECL(L19, GPIOAA3, ROMA13, VPOG3);
+
+#define L20 212
+#define L20_DESC       SIG_DESC_SET(SCUA4, 28)
+SIG_EXPR_DECL(ROMA14, ROM8, L20_DESC, VPO_OFF_12);
+SIG_EXPR_DECL(ROMA14, ROM16, L20_DESC, VPO_OFF_12);
+SIG_EXPR_LIST_DECL_DUAL(ROMA14, ROM8, ROM16);
+SIG_EXPR_DECL(VPOG4, VPO24, L20_DESC, VPO24_DESC);
+SIG_EXPR_DECL(VPOG4, VPOOFF1, L20_DESC, VPOOFF1_DESC);
+SIG_EXPR_LIST_DECL_DUAL(VPOG4, VPO24, VPOOFF1);
+MS_PIN_DECL(L20, GPIOAA4, ROMA14, VPOG4);
+
+#define L21 213
+#define L21_DESC       SIG_DESC_SET(SCUA4, 29)
+SIG_EXPR_DECL(ROMA15, ROM8, L21_DESC, VPO_OFF_12);
+SIG_EXPR_DECL(ROMA15, ROM16, L21_DESC, VPO_OFF_12);
+SIG_EXPR_LIST_DECL_DUAL(ROMA15, ROM8, ROM16);
+SIG_EXPR_DECL(VPOG5, VPO24, L21_DESC, VPO24_DESC);
+SIG_EXPR_DECL(VPOG5, VPOOFF1, L21_DESC, VPOOFF1_DESC);
+SIG_EXPR_LIST_DECL_DUAL(VPOG5, VPO24, VPOOFF1);
+MS_PIN_DECL(L21, GPIOAA5, ROMA15, VPOG5);
+
+#define T18 214
+#define T18_DESC       SIG_DESC_SET(SCUA4, 30)
+SIG_EXPR_DECL(ROMA16, ROM8, T18_DESC, VPO_OFF_12);
+SIG_EXPR_DECL(ROMA16, ROM16, T18_DESC, VPO_OFF_12);
+SIG_EXPR_LIST_DECL_DUAL(ROMA16, ROM8, ROM16);
+SIG_EXPR_DECL(VPOG6, VPO24, T18_DESC, VPO24_DESC);
+SIG_EXPR_DECL(VPOG6, VPOOFF1, T18_DESC, VPOOFF1_DESC);
+SIG_EXPR_LIST_DECL_DUAL(VPOG6, VPO24, VPOOFF1);
+MS_PIN_DECL(T18, GPIOAA6, ROMA16, VPOG6);
+
+#define N18 215
+#define N18_DESC       SIG_DESC_SET(SCUA4, 31)
+SIG_EXPR_DECL(ROMA17, ROM8, N18_DESC, VPO_OFF_12);
+SIG_EXPR_DECL(ROMA17, ROM16, N18_DESC, VPO_OFF_12);
+SIG_EXPR_LIST_DECL_DUAL(ROMA17, ROM8, ROM16);
+SIG_EXPR_DECL(VPOG7, VPO24, N18_DESC, VPO24_DESC);
+SIG_EXPR_DECL(VPOG7, VPOOFF1, N18_DESC, VPOOFF1_DESC);
+SIG_EXPR_LIST_DECL_DUAL(VPOG7, VPO24, VPOOFF1);
+MS_PIN_DECL(N18, GPIOAA7, ROMA17, VPOG7);
+
+#define N19 216
+#define N19_DESC       SIG_DESC_SET(SCUA8, 0)
+SIG_EXPR_DECL(ROMA18, ROM8, N19_DESC, VPO_OFF_12);
+SIG_EXPR_DECL(ROMA18, ROM16, N19_DESC, VPO_OFF_12);
+SIG_EXPR_LIST_DECL_DUAL(ROMA18, ROM8, ROM16);
+SIG_EXPR_DECL(VPOR0, VPO24, N19_DESC, VPO24_DESC);
+SIG_EXPR_DECL(VPOR0, VPOOFF1, N19_DESC, VPOOFF1_DESC);
+SIG_EXPR_LIST_DECL_DUAL(VPOR0, VPO24, VPOOFF1);
+MS_PIN_DECL(N19, GPIOAB0, ROMA18, VPOR0);
+
+#define M18 217
+#define M18_DESC       SIG_DESC_SET(SCUA8, 1)
+SIG_EXPR_DECL(ROMA19, ROM8, M18_DESC, VPO_OFF_12);
+SIG_EXPR_DECL(ROMA19, ROM16, M18_DESC, VPO_OFF_12);
+SIG_EXPR_LIST_DECL_DUAL(ROMA19, ROM8, ROM16);
+SIG_EXPR_DECL(VPOR1, VPO24, M18_DESC, VPO24_DESC);
+SIG_EXPR_DECL(VPOR1, VPOOFF1, M18_DESC, VPOOFF1_DESC);
+SIG_EXPR_LIST_DECL_DUAL(VPOR1, VPO24, VPOOFF1);
+MS_PIN_DECL(M18, GPIOAB1, ROMA19, VPOR1);
+
+#define N22 218
+#define N22_DESC       SIG_DESC_SET(SCUA8, 2)
+SIG_EXPR_DECL(ROMA20, ROM8, N22_DESC, VPO_OFF_12);
+SIG_EXPR_DECL(ROMA20, ROM16, N22_DESC, VPO_OFF_12);
+SIG_EXPR_LIST_DECL_DUAL(ROMA20, ROM8, ROM16);
+SIG_EXPR_DECL(VPOR2, VPO24, N22_DESC, VPO24_DESC);
+SIG_EXPR_DECL(VPOR2, VPOOFF1, N22_DESC, VPOOFF1_DESC);
+SIG_EXPR_LIST_DECL_DUAL(VPOR2, VPO24, VPOOFF1);
+MS_PIN_DECL(N22, GPIOAB2, ROMA20, VPOR2);
+
+#define N20 219
+#define N20_DESC       SIG_DESC_SET(SCUA8, 3)
+SIG_EXPR_DECL(ROMA21, ROM8, N20_DESC, VPO_OFF_12);
+SIG_EXPR_DECL(ROMA21, ROM16, N20_DESC, VPO_OFF_12);
+SIG_EXPR_LIST_DECL_DUAL(ROMA21, ROM8, ROM16);
+SIG_EXPR_DECL(VPOR3, VPO24, N20_DESC, VPO24_DESC);
+SIG_EXPR_DECL(VPOR3, VPOOFF1, N20_DESC, VPOOFF1_DESC);
+SIG_EXPR_LIST_DECL_DUAL(VPOR3, VPO24, VPOOFF1);
+MS_PIN_DECL(N20, GPIOAB3, ROMA21, VPOR3);
+
+FUNC_GROUP_DECL(ROM8, V20, U21, T19, V22, U20, R18, N21, L22, K18, W21, Y22,
+               U19, R22, P18, P19, P20, P21, P22, M19, M20, M21, M22, L18,
+               L19, L20, L21, T18, N18, N19, M18, N22, N20);
+FUNC_GROUP_DECL(ROM16, V20, U21, T19, V22, U20, R18, N21, L22, K18,
+               A8, C7, B7, A7, D7, B6, A6, E7, W21, Y22, U19, R22, P18, P19,
+               P20, P21, P22, M19, M20, M21, M22, L18, L19, L20, L21, T18,
+               N18, N19, M18, N22, N20);
+FUNC_GROUP_DECL(VPO12, U21, T19, V22, U20, R22, P18, P19, P20, P21, P22, M19,
+               M20, M21, M22, L18, L19, L20, L21, T18, N18, N19, M18, N22,
+               N20);
+FUNC_GROUP_DECL(VPO24, U21, T19, V22, U20, L22, K18, V21, W22, R22, P18, P19,
+               P20, P21, P22, M19, M20, M21, M22, L18, L19);
+
 /* Note we account for GPIOY4-GPIOY7 even though they're not valid, thus 216
  * pins becomes 220.
  */
@@ -883,84 +1715,180 @@ FUNC_GROUP_DECL(RGMII1, A12, B12, C12, D12, E12, A13, E11, D11, C11, B11, A11,
 
 static struct pinctrl_pin_desc aspeed_g4_pins[ASPEED_G4_NR_PINS] = {
        ASPEED_PINCTRL_PIN(A1),
+       ASPEED_PINCTRL_PIN(A10),
        ASPEED_PINCTRL_PIN(A11),
        ASPEED_PINCTRL_PIN(A12),
        ASPEED_PINCTRL_PIN(A13),
+       ASPEED_PINCTRL_PIN(A14),
        ASPEED_PINCTRL_PIN(A15),
+       ASPEED_PINCTRL_PIN(A16),
+       ASPEED_PINCTRL_PIN(A17),
        ASPEED_PINCTRL_PIN(A18),
+       ASPEED_PINCTRL_PIN(A19),
        ASPEED_PINCTRL_PIN(A2),
+       ASPEED_PINCTRL_PIN(A20),
        ASPEED_PINCTRL_PIN(A3),
        ASPEED_PINCTRL_PIN(A4),
        ASPEED_PINCTRL_PIN(A5),
        ASPEED_PINCTRL_PIN(A6),
        ASPEED_PINCTRL_PIN(A7),
        ASPEED_PINCTRL_PIN(A8),
+       ASPEED_PINCTRL_PIN(A9),
+       ASPEED_PINCTRL_PIN(AA1),
        ASPEED_PINCTRL_PIN(AA2),
        ASPEED_PINCTRL_PIN(AA22),
        ASPEED_PINCTRL_PIN(AA3),
+       ASPEED_PINCTRL_PIN(AA4),
+       ASPEED_PINCTRL_PIN(AA5),
+       ASPEED_PINCTRL_PIN(AA6),
        ASPEED_PINCTRL_PIN(AA7),
        ASPEED_PINCTRL_PIN(AB1),
        ASPEED_PINCTRL_PIN(AB2),
+       ASPEED_PINCTRL_PIN(AB3),
+       ASPEED_PINCTRL_PIN(AB4),
+       ASPEED_PINCTRL_PIN(AB5),
+       ASPEED_PINCTRL_PIN(AB6),
        ASPEED_PINCTRL_PIN(AB7),
        ASPEED_PINCTRL_PIN(B1),
+       ASPEED_PINCTRL_PIN(B10),
        ASPEED_PINCTRL_PIN(B11),
        ASPEED_PINCTRL_PIN(B12),
+       ASPEED_PINCTRL_PIN(B13),
        ASPEED_PINCTRL_PIN(B14),
        ASPEED_PINCTRL_PIN(B15),
+       ASPEED_PINCTRL_PIN(B16),
+       ASPEED_PINCTRL_PIN(B17),
+       ASPEED_PINCTRL_PIN(B18),
        ASPEED_PINCTRL_PIN(B19),
        ASPEED_PINCTRL_PIN(B2),
+       ASPEED_PINCTRL_PIN(B22),
        ASPEED_PINCTRL_PIN(B3),
        ASPEED_PINCTRL_PIN(B4),
+       ASPEED_PINCTRL_PIN(B5),
        ASPEED_PINCTRL_PIN(B6),
        ASPEED_PINCTRL_PIN(B7),
+       ASPEED_PINCTRL_PIN(B9),
        ASPEED_PINCTRL_PIN(C1),
+       ASPEED_PINCTRL_PIN(C10),
        ASPEED_PINCTRL_PIN(C11),
        ASPEED_PINCTRL_PIN(C12),
+       ASPEED_PINCTRL_PIN(C13),
        ASPEED_PINCTRL_PIN(C14),
        ASPEED_PINCTRL_PIN(C15),
+       ASPEED_PINCTRL_PIN(C16),
        ASPEED_PINCTRL_PIN(C17),
+       ASPEED_PINCTRL_PIN(C18),
        ASPEED_PINCTRL_PIN(C2),
+       ASPEED_PINCTRL_PIN(C20),
+       ASPEED_PINCTRL_PIN(C21),
+       ASPEED_PINCTRL_PIN(C22),
        ASPEED_PINCTRL_PIN(C3),
        ASPEED_PINCTRL_PIN(C4),
        ASPEED_PINCTRL_PIN(C5),
        ASPEED_PINCTRL_PIN(C6),
        ASPEED_PINCTRL_PIN(C7),
+       ASPEED_PINCTRL_PIN(C8),
+       ASPEED_PINCTRL_PIN(C9),
        ASPEED_PINCTRL_PIN(D1),
+       ASPEED_PINCTRL_PIN(D10),
        ASPEED_PINCTRL_PIN(D11),
        ASPEED_PINCTRL_PIN(D12),
+       ASPEED_PINCTRL_PIN(D13),
        ASPEED_PINCTRL_PIN(D14),
        ASPEED_PINCTRL_PIN(D15),
        ASPEED_PINCTRL_PIN(D16),
        ASPEED_PINCTRL_PIN(D17),
        ASPEED_PINCTRL_PIN(D18),
+       ASPEED_PINCTRL_PIN(D19),
        ASPEED_PINCTRL_PIN(D2),
        ASPEED_PINCTRL_PIN(D3),
        ASPEED_PINCTRL_PIN(D4),
        ASPEED_PINCTRL_PIN(D5),
+       ASPEED_PINCTRL_PIN(D6),
        ASPEED_PINCTRL_PIN(D7),
+       ASPEED_PINCTRL_PIN(D8),
+       ASPEED_PINCTRL_PIN(D9),
        ASPEED_PINCTRL_PIN(E10),
        ASPEED_PINCTRL_PIN(E11),
        ASPEED_PINCTRL_PIN(E12),
+       ASPEED_PINCTRL_PIN(E13),
        ASPEED_PINCTRL_PIN(E14),
+       ASPEED_PINCTRL_PIN(E15),
        ASPEED_PINCTRL_PIN(E16),
+       ASPEED_PINCTRL_PIN(E18),
+       ASPEED_PINCTRL_PIN(E19),
        ASPEED_PINCTRL_PIN(E2),
+       ASPEED_PINCTRL_PIN(E20),
        ASPEED_PINCTRL_PIN(E3),
        ASPEED_PINCTRL_PIN(E5),
+       ASPEED_PINCTRL_PIN(E6),
        ASPEED_PINCTRL_PIN(E7),
+       ASPEED_PINCTRL_PIN(E8),
+       ASPEED_PINCTRL_PIN(E9),
+       ASPEED_PINCTRL_PIN(F18),
+       ASPEED_PINCTRL_PIN(F20),
        ASPEED_PINCTRL_PIN(F3),
        ASPEED_PINCTRL_PIN(F4),
        ASPEED_PINCTRL_PIN(F5),
+       ASPEED_PINCTRL_PIN(G18),
+       ASPEED_PINCTRL_PIN(G19),
+       ASPEED_PINCTRL_PIN(G20),
        ASPEED_PINCTRL_PIN(G5),
        ASPEED_PINCTRL_PIN(H1),
+       ASPEED_PINCTRL_PIN(H18),
        ASPEED_PINCTRL_PIN(H19),
        ASPEED_PINCTRL_PIN(H2),
        ASPEED_PINCTRL_PIN(H20),
+       ASPEED_PINCTRL_PIN(H3),
+       ASPEED_PINCTRL_PIN(H4),
+       ASPEED_PINCTRL_PIN(J20),
+       ASPEED_PINCTRL_PIN(J21),
        ASPEED_PINCTRL_PIN(J3),
+       ASPEED_PINCTRL_PIN(J4),
+       ASPEED_PINCTRL_PIN(J5),
        ASPEED_PINCTRL_PIN(K18),
+       ASPEED_PINCTRL_PIN(K20),
+       ASPEED_PINCTRL_PIN(K5),
+       ASPEED_PINCTRL_PIN(L1),
+       ASPEED_PINCTRL_PIN(L18),
+       ASPEED_PINCTRL_PIN(L19),
+       ASPEED_PINCTRL_PIN(L2),
+       ASPEED_PINCTRL_PIN(L20),
+       ASPEED_PINCTRL_PIN(L21),
        ASPEED_PINCTRL_PIN(L22),
+       ASPEED_PINCTRL_PIN(L3),
+       ASPEED_PINCTRL_PIN(L4),
+       ASPEED_PINCTRL_PIN(L5),
+       ASPEED_PINCTRL_PIN(M1),
+       ASPEED_PINCTRL_PIN(M18),
+       ASPEED_PINCTRL_PIN(M19),
+       ASPEED_PINCTRL_PIN(M2),
+       ASPEED_PINCTRL_PIN(M20),
+       ASPEED_PINCTRL_PIN(M21),
+       ASPEED_PINCTRL_PIN(M22),
+       ASPEED_PINCTRL_PIN(M3),
+       ASPEED_PINCTRL_PIN(M4),
+       ASPEED_PINCTRL_PIN(M5),
+       ASPEED_PINCTRL_PIN(N1),
+       ASPEED_PINCTRL_PIN(N18),
+       ASPEED_PINCTRL_PIN(N19),
+       ASPEED_PINCTRL_PIN(N2),
+       ASPEED_PINCTRL_PIN(N20),
        ASPEED_PINCTRL_PIN(N21),
+       ASPEED_PINCTRL_PIN(N22),
+       ASPEED_PINCTRL_PIN(N3),
+       ASPEED_PINCTRL_PIN(N4),
+       ASPEED_PINCTRL_PIN(N5),
+       ASPEED_PINCTRL_PIN(P18),
+       ASPEED_PINCTRL_PIN(P19),
+       ASPEED_PINCTRL_PIN(P20),
+       ASPEED_PINCTRL_PIN(P21),
+       ASPEED_PINCTRL_PIN(P22),
+       ASPEED_PINCTRL_PIN(P5),
        ASPEED_PINCTRL_PIN(R18),
+       ASPEED_PINCTRL_PIN(R22),
        ASPEED_PINCTRL_PIN(T1),
+       ASPEED_PINCTRL_PIN(T18),
        ASPEED_PINCTRL_PIN(T19),
        ASPEED_PINCTRL_PIN(T2),
        ASPEED_PINCTRL_PIN(T4),
@@ -979,28 +1907,61 @@ static struct pinctrl_pin_desc aspeed_g4_pins[ASPEED_G4_NR_PINS] = {
        ASPEED_PINCTRL_PIN(V20),
        ASPEED_PINCTRL_PIN(V21),
        ASPEED_PINCTRL_PIN(V22),
+       ASPEED_PINCTRL_PIN(V3),
+       ASPEED_PINCTRL_PIN(V4),
+       ASPEED_PINCTRL_PIN(V5),
        ASPEED_PINCTRL_PIN(V6),
+       ASPEED_PINCTRL_PIN(V7),
        ASPEED_PINCTRL_PIN(W1),
+       ASPEED_PINCTRL_PIN(W2),
        ASPEED_PINCTRL_PIN(W21),
        ASPEED_PINCTRL_PIN(W22),
+       ASPEED_PINCTRL_PIN(W3),
        ASPEED_PINCTRL_PIN(W4),
        ASPEED_PINCTRL_PIN(W5),
+       ASPEED_PINCTRL_PIN(W6),
+       ASPEED_PINCTRL_PIN(W7),
+       ASPEED_PINCTRL_PIN(Y1),
+       ASPEED_PINCTRL_PIN(Y2),
+       ASPEED_PINCTRL_PIN(Y21),
        ASPEED_PINCTRL_PIN(Y22),
        ASPEED_PINCTRL_PIN(Y3),
        ASPEED_PINCTRL_PIN(Y4),
        ASPEED_PINCTRL_PIN(Y5),
+       ASPEED_PINCTRL_PIN(Y6),
        ASPEED_PINCTRL_PIN(Y7),
 };
 
 static const struct aspeed_pin_group aspeed_g4_groups[] = {
        ASPEED_PINCTRL_GROUP(ACPI),
+       ASPEED_PINCTRL_GROUP(ADC0),
+       ASPEED_PINCTRL_GROUP(ADC1),
+       ASPEED_PINCTRL_GROUP(ADC10),
+       ASPEED_PINCTRL_GROUP(ADC11),
+       ASPEED_PINCTRL_GROUP(ADC12),
+       ASPEED_PINCTRL_GROUP(ADC13),
+       ASPEED_PINCTRL_GROUP(ADC14),
+       ASPEED_PINCTRL_GROUP(ADC15),
+       ASPEED_PINCTRL_GROUP(ADC2),
+       ASPEED_PINCTRL_GROUP(ADC3),
+       ASPEED_PINCTRL_GROUP(ADC4),
+       ASPEED_PINCTRL_GROUP(ADC5),
+       ASPEED_PINCTRL_GROUP(ADC6),
+       ASPEED_PINCTRL_GROUP(ADC7),
+       ASPEED_PINCTRL_GROUP(ADC8),
+       ASPEED_PINCTRL_GROUP(ADC9),
        ASPEED_PINCTRL_GROUP(BMCINT),
        ASPEED_PINCTRL_GROUP(DDCCLK),
        ASPEED_PINCTRL_GROUP(DDCDAT),
+       ASPEED_PINCTRL_GROUP(EXTRST),
        ASPEED_PINCTRL_GROUP(FLACK),
        ASPEED_PINCTRL_GROUP(FLBUSY),
        ASPEED_PINCTRL_GROUP(FLWP),
+       ASPEED_PINCTRL_GROUP(GPID),
        ASPEED_PINCTRL_GROUP(GPID0),
+       ASPEED_PINCTRL_GROUP(GPID2),
+       ASPEED_PINCTRL_GROUP(GPID4),
+       ASPEED_PINCTRL_GROUP(GPID6),
        ASPEED_PINCTRL_GROUP(GPIE0),
        ASPEED_PINCTRL_GROUP(GPIE2),
        ASPEED_PINCTRL_GROUP(GPIE4),
@@ -1009,6 +1970,7 @@ static const struct aspeed_pin_group aspeed_g4_groups[] = {
        ASPEED_PINCTRL_GROUP(I2C11),
        ASPEED_PINCTRL_GROUP(I2C12),
        ASPEED_PINCTRL_GROUP(I2C13),
+       ASPEED_PINCTRL_GROUP(I2C14),
        ASPEED_PINCTRL_GROUP(I2C3),
        ASPEED_PINCTRL_GROUP(I2C4),
        ASPEED_PINCTRL_GROUP(I2C5),
@@ -1018,25 +1980,37 @@ static const struct aspeed_pin_group aspeed_g4_groups[] = {
        ASPEED_PINCTRL_GROUP(I2C9),
        ASPEED_PINCTRL_GROUP(LPCPD),
        ASPEED_PINCTRL_GROUP(LPCPME),
-       ASPEED_PINCTRL_GROUP(LPCPME),
+       ASPEED_PINCTRL_GROUP(LPCRST),
        ASPEED_PINCTRL_GROUP(LPCSMI),
+       ASPEED_PINCTRL_GROUP(MAC1LINK),
+       ASPEED_PINCTRL_GROUP(MAC2LINK),
        ASPEED_PINCTRL_GROUP(MDIO1),
        ASPEED_PINCTRL_GROUP(MDIO2),
        ASPEED_PINCTRL_GROUP(NCTS1),
+       ASPEED_PINCTRL_GROUP(NCTS2),
        ASPEED_PINCTRL_GROUP(NCTS3),
        ASPEED_PINCTRL_GROUP(NCTS4),
        ASPEED_PINCTRL_GROUP(NDCD1),
+       ASPEED_PINCTRL_GROUP(NDCD2),
        ASPEED_PINCTRL_GROUP(NDCD3),
        ASPEED_PINCTRL_GROUP(NDCD4),
        ASPEED_PINCTRL_GROUP(NDSR1),
+       ASPEED_PINCTRL_GROUP(NDSR2),
        ASPEED_PINCTRL_GROUP(NDSR3),
+       ASPEED_PINCTRL_GROUP(NDSR4),
        ASPEED_PINCTRL_GROUP(NDTR1),
+       ASPEED_PINCTRL_GROUP(NDTR2),
        ASPEED_PINCTRL_GROUP(NDTR3),
+       ASPEED_PINCTRL_GROUP(NDTR4),
+       ASPEED_PINCTRL_GROUP(NDTS4),
        ASPEED_PINCTRL_GROUP(NRI1),
+       ASPEED_PINCTRL_GROUP(NRI2),
        ASPEED_PINCTRL_GROUP(NRI3),
        ASPEED_PINCTRL_GROUP(NRI4),
        ASPEED_PINCTRL_GROUP(NRTS1),
+       ASPEED_PINCTRL_GROUP(NRTS2),
        ASPEED_PINCTRL_GROUP(NRTS3),
+       ASPEED_PINCTRL_GROUP(OSCCLK),
        ASPEED_PINCTRL_GROUP(PWM0),
        ASPEED_PINCTRL_GROUP(PWM1),
        ASPEED_PINCTRL_GROUP(PWM2),
@@ -1046,7 +2020,9 @@ static const struct aspeed_pin_group aspeed_g4_groups[] = {
        ASPEED_PINCTRL_GROUP(PWM6),
        ASPEED_PINCTRL_GROUP(PWM7),
        ASPEED_PINCTRL_GROUP(RGMII1),
+       ASPEED_PINCTRL_GROUP(RGMII2),
        ASPEED_PINCTRL_GROUP(RMII1),
+       ASPEED_PINCTRL_GROUP(RMII2),
        ASPEED_PINCTRL_GROUP(ROM16),
        ASPEED_PINCTRL_GROUP(ROM8),
        ASPEED_PINCTRL_GROUP(ROMCS1),
@@ -1054,21 +2030,48 @@ static const struct aspeed_pin_group aspeed_g4_groups[] = {
        ASPEED_PINCTRL_GROUP(ROMCS3),
        ASPEED_PINCTRL_GROUP(ROMCS4),
        ASPEED_PINCTRL_GROUP(RXD1),
+       ASPEED_PINCTRL_GROUP(RXD2),
        ASPEED_PINCTRL_GROUP(RXD3),
        ASPEED_PINCTRL_GROUP(RXD4),
+       ASPEED_PINCTRL_GROUP(SALT1),
+       ASPEED_PINCTRL_GROUP(SALT2),
+       ASPEED_PINCTRL_GROUP(SALT3),
+       ASPEED_PINCTRL_GROUP(SALT4),
        ASPEED_PINCTRL_GROUP(SD1),
+       ASPEED_PINCTRL_GROUP(SD2),
+       ASPEED_PINCTRL_GROUP(SGPMCK),
        ASPEED_PINCTRL_GROUP(SGPMI),
+       ASPEED_PINCTRL_GROUP(SGPMLD),
+       ASPEED_PINCTRL_GROUP(SGPMO),
+       ASPEED_PINCTRL_GROUP(SGPSCK),
+       ASPEED_PINCTRL_GROUP(SGPSI0),
+       ASPEED_PINCTRL_GROUP(SGPSI1),
+       ASPEED_PINCTRL_GROUP(SGPSLD),
+       ASPEED_PINCTRL_GROUP(SIOONCTRL),
        ASPEED_PINCTRL_GROUP(SIOPBI),
        ASPEED_PINCTRL_GROUP(SIOPBO),
+       ASPEED_PINCTRL_GROUP(SIOPWREQ),
+       ASPEED_PINCTRL_GROUP(SIOPWRGD),
+       ASPEED_PINCTRL_GROUP(SIOS3),
+       ASPEED_PINCTRL_GROUP(SIOS5),
+       ASPEED_PINCTRL_GROUP(SIOSCI),
+       ASPEED_PINCTRL_GROUP(SPI1),
+       ASPEED_PINCTRL_GROUP(SPI1DEBUG),
+       ASPEED_PINCTRL_GROUP(SPI1PASSTHRU),
+       ASPEED_PINCTRL_GROUP(SPICS1),
        ASPEED_PINCTRL_GROUP(TIMER3),
+       ASPEED_PINCTRL_GROUP(TIMER4),
        ASPEED_PINCTRL_GROUP(TIMER5),
        ASPEED_PINCTRL_GROUP(TIMER6),
        ASPEED_PINCTRL_GROUP(TIMER7),
        ASPEED_PINCTRL_GROUP(TIMER8),
        ASPEED_PINCTRL_GROUP(TXD1),
+       ASPEED_PINCTRL_GROUP(TXD2),
        ASPEED_PINCTRL_GROUP(TXD3),
        ASPEED_PINCTRL_GROUP(TXD4),
        ASPEED_PINCTRL_GROUP(UART6),
+       ASPEED_PINCTRL_GROUP(USBCKI),
+       ASPEED_PINCTRL_GROUP(VGABIOS_ROM),
        ASPEED_PINCTRL_GROUP(VGAHS),
        ASPEED_PINCTRL_GROUP(VGAVS),
        ASPEED_PINCTRL_GROUP(VPI18),
@@ -1076,17 +2079,40 @@ static const struct aspeed_pin_group aspeed_g4_groups[] = {
        ASPEED_PINCTRL_GROUP(VPI30),
        ASPEED_PINCTRL_GROUP(VPO12),
        ASPEED_PINCTRL_GROUP(VPO24),
+       ASPEED_PINCTRL_GROUP(WDTRST1),
+       ASPEED_PINCTRL_GROUP(WDTRST2),
 };
 
 static const struct aspeed_pin_function aspeed_g4_functions[] = {
        ASPEED_PINCTRL_FUNC(ACPI),
+       ASPEED_PINCTRL_FUNC(ADC0),
+       ASPEED_PINCTRL_FUNC(ADC1),
+       ASPEED_PINCTRL_FUNC(ADC10),
+       ASPEED_PINCTRL_FUNC(ADC11),
+       ASPEED_PINCTRL_FUNC(ADC12),
+       ASPEED_PINCTRL_FUNC(ADC13),
+       ASPEED_PINCTRL_FUNC(ADC14),
+       ASPEED_PINCTRL_FUNC(ADC15),
+       ASPEED_PINCTRL_FUNC(ADC2),
+       ASPEED_PINCTRL_FUNC(ADC3),
+       ASPEED_PINCTRL_FUNC(ADC4),
+       ASPEED_PINCTRL_FUNC(ADC5),
+       ASPEED_PINCTRL_FUNC(ADC6),
+       ASPEED_PINCTRL_FUNC(ADC7),
+       ASPEED_PINCTRL_FUNC(ADC8),
+       ASPEED_PINCTRL_FUNC(ADC9),
        ASPEED_PINCTRL_FUNC(BMCINT),
        ASPEED_PINCTRL_FUNC(DDCCLK),
        ASPEED_PINCTRL_FUNC(DDCDAT),
+       ASPEED_PINCTRL_FUNC(EXTRST),
        ASPEED_PINCTRL_FUNC(FLACK),
        ASPEED_PINCTRL_FUNC(FLBUSY),
        ASPEED_PINCTRL_FUNC(FLWP),
+       ASPEED_PINCTRL_FUNC(GPID),
        ASPEED_PINCTRL_FUNC(GPID0),
+       ASPEED_PINCTRL_FUNC(GPID2),
+       ASPEED_PINCTRL_FUNC(GPID4),
+       ASPEED_PINCTRL_FUNC(GPID6),
        ASPEED_PINCTRL_FUNC(GPIE0),
        ASPEED_PINCTRL_FUNC(GPIE2),
        ASPEED_PINCTRL_FUNC(GPIE4),
@@ -1095,6 +2121,7 @@ static const struct aspeed_pin_function aspeed_g4_functions[] = {
        ASPEED_PINCTRL_FUNC(I2C11),
        ASPEED_PINCTRL_FUNC(I2C12),
        ASPEED_PINCTRL_FUNC(I2C13),
+       ASPEED_PINCTRL_FUNC(I2C14),
        ASPEED_PINCTRL_FUNC(I2C3),
        ASPEED_PINCTRL_FUNC(I2C4),
        ASPEED_PINCTRL_FUNC(I2C5),
@@ -1104,24 +2131,37 @@ static const struct aspeed_pin_function aspeed_g4_functions[] = {
        ASPEED_PINCTRL_FUNC(I2C9),
        ASPEED_PINCTRL_FUNC(LPCPD),
        ASPEED_PINCTRL_FUNC(LPCPME),
+       ASPEED_PINCTRL_FUNC(LPCRST),
        ASPEED_PINCTRL_FUNC(LPCSMI),
+       ASPEED_PINCTRL_FUNC(MAC1LINK),
+       ASPEED_PINCTRL_FUNC(MAC2LINK),
        ASPEED_PINCTRL_FUNC(MDIO1),
        ASPEED_PINCTRL_FUNC(MDIO2),
        ASPEED_PINCTRL_FUNC(NCTS1),
+       ASPEED_PINCTRL_FUNC(NCTS2),
        ASPEED_PINCTRL_FUNC(NCTS3),
        ASPEED_PINCTRL_FUNC(NCTS4),
        ASPEED_PINCTRL_FUNC(NDCD1),
+       ASPEED_PINCTRL_FUNC(NDCD2),
        ASPEED_PINCTRL_FUNC(NDCD3),
        ASPEED_PINCTRL_FUNC(NDCD4),
        ASPEED_PINCTRL_FUNC(NDSR1),
+       ASPEED_PINCTRL_FUNC(NDSR2),
        ASPEED_PINCTRL_FUNC(NDSR3),
+       ASPEED_PINCTRL_FUNC(NDSR4),
        ASPEED_PINCTRL_FUNC(NDTR1),
+       ASPEED_PINCTRL_FUNC(NDTR2),
        ASPEED_PINCTRL_FUNC(NDTR3),
+       ASPEED_PINCTRL_FUNC(NDTR4),
+       ASPEED_PINCTRL_FUNC(NDTS4),
        ASPEED_PINCTRL_FUNC(NRI1),
+       ASPEED_PINCTRL_FUNC(NRI2),
        ASPEED_PINCTRL_FUNC(NRI3),
        ASPEED_PINCTRL_FUNC(NRI4),
        ASPEED_PINCTRL_FUNC(NRTS1),
+       ASPEED_PINCTRL_FUNC(NRTS2),
        ASPEED_PINCTRL_FUNC(NRTS3),
+       ASPEED_PINCTRL_FUNC(OSCCLK),
        ASPEED_PINCTRL_FUNC(PWM0),
        ASPEED_PINCTRL_FUNC(PWM1),
        ASPEED_PINCTRL_FUNC(PWM2),
@@ -1131,7 +2171,9 @@ static const struct aspeed_pin_function aspeed_g4_functions[] = {
        ASPEED_PINCTRL_FUNC(PWM6),
        ASPEED_PINCTRL_FUNC(PWM7),
        ASPEED_PINCTRL_FUNC(RGMII1),
+       ASPEED_PINCTRL_FUNC(RGMII2),
        ASPEED_PINCTRL_FUNC(RMII1),
+       ASPEED_PINCTRL_FUNC(RMII2),
        ASPEED_PINCTRL_FUNC(ROM16),
        ASPEED_PINCTRL_FUNC(ROM8),
        ASPEED_PINCTRL_FUNC(ROMCS1),
@@ -1139,21 +2181,48 @@ static const struct aspeed_pin_function aspeed_g4_functions[] = {
        ASPEED_PINCTRL_FUNC(ROMCS3),
        ASPEED_PINCTRL_FUNC(ROMCS4),
        ASPEED_PINCTRL_FUNC(RXD1),
+       ASPEED_PINCTRL_FUNC(RXD2),
        ASPEED_PINCTRL_FUNC(RXD3),
        ASPEED_PINCTRL_FUNC(RXD4),
+       ASPEED_PINCTRL_FUNC(SALT1),
+       ASPEED_PINCTRL_FUNC(SALT2),
+       ASPEED_PINCTRL_FUNC(SALT3),
+       ASPEED_PINCTRL_FUNC(SALT4),
        ASPEED_PINCTRL_FUNC(SD1),
+       ASPEED_PINCTRL_FUNC(SD2),
+       ASPEED_PINCTRL_FUNC(SGPMCK),
        ASPEED_PINCTRL_FUNC(SGPMI),
+       ASPEED_PINCTRL_FUNC(SGPMLD),
+       ASPEED_PINCTRL_FUNC(SGPMO),
+       ASPEED_PINCTRL_FUNC(SGPSCK),
+       ASPEED_PINCTRL_FUNC(SGPSI0),
+       ASPEED_PINCTRL_FUNC(SGPSI1),
+       ASPEED_PINCTRL_FUNC(SGPSLD),
+       ASPEED_PINCTRL_FUNC(SIOONCTRL),
        ASPEED_PINCTRL_FUNC(SIOPBI),
        ASPEED_PINCTRL_FUNC(SIOPBO),
+       ASPEED_PINCTRL_FUNC(SIOPWREQ),
+       ASPEED_PINCTRL_FUNC(SIOPWRGD),
+       ASPEED_PINCTRL_FUNC(SIOS3),
+       ASPEED_PINCTRL_FUNC(SIOS5),
+       ASPEED_PINCTRL_FUNC(SIOSCI),
+       ASPEED_PINCTRL_FUNC(SPI1),
+       ASPEED_PINCTRL_FUNC(SPI1DEBUG),
+       ASPEED_PINCTRL_FUNC(SPI1PASSTHRU),
+       ASPEED_PINCTRL_FUNC(SPICS1),
        ASPEED_PINCTRL_FUNC(TIMER3),
+       ASPEED_PINCTRL_FUNC(TIMER4),
        ASPEED_PINCTRL_FUNC(TIMER5),
        ASPEED_PINCTRL_FUNC(TIMER6),
        ASPEED_PINCTRL_FUNC(TIMER7),
        ASPEED_PINCTRL_FUNC(TIMER8),
        ASPEED_PINCTRL_FUNC(TXD1),
+       ASPEED_PINCTRL_FUNC(TXD2),
        ASPEED_PINCTRL_FUNC(TXD3),
        ASPEED_PINCTRL_FUNC(TXD4),
        ASPEED_PINCTRL_FUNC(UART6),
+       ASPEED_PINCTRL_FUNC(USBCKI),
+       ASPEED_PINCTRL_FUNC(VGABIOS_ROM),
        ASPEED_PINCTRL_FUNC(VGAHS),
        ASPEED_PINCTRL_FUNC(VGAVS),
        ASPEED_PINCTRL_FUNC(VPI18),
@@ -1161,6 +2230,8 @@ static const struct aspeed_pin_function aspeed_g4_functions[] = {
        ASPEED_PINCTRL_FUNC(VPI30),
        ASPEED_PINCTRL_FUNC(VPO12),
        ASPEED_PINCTRL_FUNC(VPO24),
+       ASPEED_PINCTRL_FUNC(WDTRST1),
+       ASPEED_PINCTRL_FUNC(WDTRST2),
 };
 
 static struct aspeed_pinctrl_data aspeed_g4_pinctrl_data = {
index 87b46390b69597a3299143f3ec4e0ab282475718..43221a3c7e231208dfde4335237c412fad702670 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
 #include <linux/mutex.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include "../pinctrl-utils.h"
 #include "pinctrl-aspeed.h"
 
-#define ASPEED_G5_NR_PINS 228
+#define ASPEED_G5_NR_PINS 232
 
-#define COND1          { SCU90, BIT(6), 0, 0 }
-#define COND2          { SCU94, GENMASK(1, 0), 0, 0 }
+#define COND1          { ASPEED_IP_SCU, SCU90, BIT(6), 0, 0 }
+#define COND2          { ASPEED_IP_SCU, SCU94, GENMASK(1, 0), 0, 0 }
+
+/* LHCR0 is offset from the end of the H8S/2168-compatible registers */
+#define LHCR0          0x20
+#define GFX064         0x64
 
 #define B14 0
 SSSF_PIN_DECL(B14, GPIOA0, MAC1LINK, SIG_DESC_SET(SCU80, 0));
 
+#define D14 1
+SSSF_PIN_DECL(D14, GPIOA1, MAC2LINK, SIG_DESC_SET(SCU80, 1));
+
+#define D13 2
+SIG_EXPR_LIST_DECL_SINGLE(SPI1CS1, SPI1CS1, SIG_DESC_SET(SCU80, 15));
+SIG_EXPR_LIST_DECL_SINGLE(TIMER3, TIMER3, SIG_DESC_SET(SCU80, 2));
+MS_PIN_DECL(D13, GPIOA2, SPI1CS1, TIMER3);
+FUNC_GROUP_DECL(SPI1CS1, D13);
+FUNC_GROUP_DECL(TIMER3, D13);
+
 #define E13 3
 SSSF_PIN_DECL(E13, GPIOA3, TIMER4, SIG_DESC_SET(SCU80, 3));
 
@@ -71,6 +86,32 @@ FUNC_GROUP_DECL(TIMER8, B13);
 
 FUNC_GROUP_DECL(MDIO2, C13, B13);
 
+#define K19 8
+GPIO_PIN_DECL(K19, GPIOB0);
+
+#define L19 9
+GPIO_PIN_DECL(L19, GPIOB1);
+
+#define L18 10
+GPIO_PIN_DECL(L18, GPIOB2);
+
+#define K18 11
+GPIO_PIN_DECL(K18, GPIOB3);
+
+#define J20 12
+SSSF_PIN_DECL(J20, GPIOB4, USBCKI, SIG_DESC_SET(HW_STRAP1, 23));
+
+#define H21 13
+#define H21_DESC       SIG_DESC_SET(SCU80, 13)
+SIG_EXPR_LIST_DECL_SINGLE(LPCPD, LPCPD, H21_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(LPCSMI, LPCSMI, H21_DESC);
+MS_PIN_DECL(H21, GPIOB5, LPCPD, LPCSMI);
+FUNC_GROUP_DECL(LPCPD, H21);
+FUNC_GROUP_DECL(LPCSMI, H21);
+
+#define H22 14
+SSSF_PIN_DECL(H22, GPIOB6, LPCPME, SIG_DESC_SET(SCU80, 14));
+
 #define H20 15
 GPIO_PIN_DECL(H20, GPIOB7);
 
@@ -167,7 +208,44 @@ MS_PIN_DECL(D20, GPIOD3, SD2DAT1, GPID2OUT);
 
 FUNC_GROUP_DECL(GPID2, F20, D20);
 
-#define GPIE_DESC      SIG_DESC_SET(HW_STRAP1, 21)
+#define GPID4_DESC      SIG_DESC_SET(SCU8C, 10)
+
+#define D21 28
+SIG_EXPR_LIST_DECL_SINGLE(SD2DAT2, SD2, SD2_DESC);
+SIG_EXPR_DECL(GPID4IN, GPID4, GPID4_DESC);
+SIG_EXPR_DECL(GPID4IN, GPID, GPID_DESC);
+SIG_EXPR_LIST_DECL_DUAL(GPID4IN, GPID4, GPID);
+MS_PIN_DECL(D21, GPIOD4, SD2DAT2, GPID4IN);
+
+#define E20 29
+SIG_EXPR_LIST_DECL_SINGLE(SD2DAT3, SD2, SD2_DESC);
+SIG_EXPR_DECL(GPID4OUT, GPID4, GPID4_DESC);
+SIG_EXPR_DECL(GPID4OUT, GPID, GPID_DESC);
+SIG_EXPR_LIST_DECL_DUAL(GPID4OUT, GPID4, GPID);
+MS_PIN_DECL(E20, GPIOD5, SD2DAT3, GPID4OUT);
+
+FUNC_GROUP_DECL(GPID4, D21, E20);
+
+#define GPID6_DESC      SIG_DESC_SET(SCU8C, 11)
+
+#define G18 30
+SIG_EXPR_LIST_DECL_SINGLE(SD2CD, SD2, SD2_DESC);
+SIG_EXPR_DECL(GPID6IN, GPID6, GPID6_DESC);
+SIG_EXPR_DECL(GPID6IN, GPID, GPID_DESC);
+SIG_EXPR_LIST_DECL_DUAL(GPID6IN, GPID6, GPID);
+MS_PIN_DECL(G18, GPIOD6, SD2CD, GPID6IN);
+
+#define C21 31
+SIG_EXPR_LIST_DECL_SINGLE(SD2WP, SD2, SD2_DESC);
+SIG_EXPR_DECL(GPID6OUT, GPID6, GPID6_DESC);
+SIG_EXPR_DECL(GPID6OUT, GPID, GPID_DESC);
+SIG_EXPR_LIST_DECL_DUAL(GPID6OUT, GPID6, GPID);
+MS_PIN_DECL(C21, GPIOD7, SD2WP, GPID6OUT);
+
+FUNC_GROUP_DECL(GPID6, G18, C21);
+FUNC_GROUP_DECL(SD2, F19, E21, F20, D20, D21, E20, G18, C21);
+
+#define GPIE_DESC      SIG_DESC_SET(HW_STRAP1, 22)
 #define GPIE0_DESC     SIG_DESC_SET(SCU8C, 12)
 
 #define B20 32
@@ -176,6 +254,7 @@ SIG_EXPR_DECL(GPIE0IN, GPIE0, GPIE0_DESC);
 SIG_EXPR_DECL(GPIE0IN, GPIE, GPIE_DESC);
 SIG_EXPR_LIST_DECL_DUAL(GPIE0IN, GPIE0, GPIE);
 MS_PIN_DECL(B20, GPIOE0, NCTS3, GPIE0IN);
+FUNC_GROUP_DECL(NCTS3, B20);
 
 #define C20 33
 SIG_EXPR_LIST_DECL_SINGLE(NDCD3, NDCD3, SIG_DESC_SET(SCU80, 17));
@@ -183,12 +262,233 @@ SIG_EXPR_DECL(GPIE0OUT, GPIE0, GPIE0_DESC);
 SIG_EXPR_DECL(GPIE0OUT, GPIE, GPIE_DESC);
 SIG_EXPR_LIST_DECL_DUAL(GPIE0OUT, GPIE0, GPIE);
 MS_PIN_DECL(C20, GPIOE1, NDCD3, GPIE0OUT);
+FUNC_GROUP_DECL(NDCD3, C20);
 
 FUNC_GROUP_DECL(GPIE0, B20, C20);
 
-#define SPI1_DESC              { HW_STRAP1, GENMASK(13, 12), 1, 0 }
-#define SPI1DEBUG_DESC         { HW_STRAP1, GENMASK(13, 12), 2, 0 }
-#define SPI1PASSTHRU_DESC      { HW_STRAP1, GENMASK(13, 12), 3, 0 }
+#define GPIE2_DESC     SIG_DESC_SET(SCU8C, 13)
+
+#define F18 34
+SIG_EXPR_LIST_DECL_SINGLE(NDSR3, NDSR3, SIG_DESC_SET(SCU80, 18));
+SIG_EXPR_DECL(GPIE2IN, GPIE2, GPIE2_DESC);
+SIG_EXPR_DECL(GPIE2IN, GPIE, GPIE_DESC);
+SIG_EXPR_LIST_DECL_DUAL(GPIE2IN, GPIE2, GPIE);
+MS_PIN_DECL(F18, GPIOE2, NDSR3, GPIE2IN);
+FUNC_GROUP_DECL(NDSR3, F18);
+
+
+#define F17 35
+SIG_EXPR_LIST_DECL_SINGLE(NRI3, NRI3, SIG_DESC_SET(SCU80, 19));
+SIG_EXPR_DECL(GPIE2OUT, GPIE2, GPIE2_DESC);
+SIG_EXPR_DECL(GPIE2OUT, GPIE, GPIE_DESC);
+SIG_EXPR_LIST_DECL_DUAL(GPIE2OUT, GPIE2, GPIE);
+MS_PIN_DECL(F17, GPIOE3, NRI3, GPIE2OUT);
+FUNC_GROUP_DECL(NRI3, F17);
+
+FUNC_GROUP_DECL(GPIE2, F18, F17);
+
+#define GPIE4_DESC     SIG_DESC_SET(SCU8C, 14)
+
+#define E18 36
+SIG_EXPR_LIST_DECL_SINGLE(NDTR3, NDTR3, SIG_DESC_SET(SCU80, 20));
+SIG_EXPR_DECL(GPIE4IN, GPIE4, GPIE4_DESC);
+SIG_EXPR_DECL(GPIE4IN, GPIE, GPIE_DESC);
+SIG_EXPR_LIST_DECL_DUAL(GPIE4IN, GPIE4, GPIE);
+MS_PIN_DECL(E18, GPIOE4, NDTR3, GPIE4IN);
+FUNC_GROUP_DECL(NDTR3, E18);
+
+#define D19 37
+SIG_EXPR_LIST_DECL_SINGLE(NRTS3, NRTS3, SIG_DESC_SET(SCU80, 21));
+SIG_EXPR_DECL(GPIE4OUT, GPIE4, GPIE4_DESC);
+SIG_EXPR_DECL(GPIE4OUT, GPIE, GPIE_DESC);
+SIG_EXPR_LIST_DECL_DUAL(GPIE4OUT, GPIE4, GPIE);
+MS_PIN_DECL(D19, GPIOE5, NRTS3, GPIE4OUT);
+FUNC_GROUP_DECL(NRTS3, D19);
+
+FUNC_GROUP_DECL(GPIE4, E18, D19);
+
+#define GPIE6_DESC     SIG_DESC_SET(SCU8C, 15)
+
+#define A20 38
+SIG_EXPR_LIST_DECL_SINGLE(TXD3, TXD3, SIG_DESC_SET(SCU80, 22));
+SIG_EXPR_DECL(GPIE6IN, GPIE6, GPIE6_DESC);
+SIG_EXPR_DECL(GPIE6IN, GPIE, GPIE_DESC);
+SIG_EXPR_LIST_DECL_DUAL(GPIE6IN, GPIE6, GPIE);
+MS_PIN_DECL(A20, GPIOE6, TXD3, GPIE6IN);
+FUNC_GROUP_DECL(TXD3, A20);
+
+#define B19 39
+SIG_EXPR_LIST_DECL_SINGLE(RXD3, RXD3, SIG_DESC_SET(SCU80, 23));
+SIG_EXPR_DECL(GPIE6OUT, GPIE6, GPIE6_DESC);
+SIG_EXPR_DECL(GPIE6OUT, GPIE, GPIE_DESC);
+SIG_EXPR_LIST_DECL_DUAL(GPIE6OUT, GPIE6, GPIE);
+MS_PIN_DECL(B19, GPIOE7, RXD3, GPIE6OUT);
+FUNC_GROUP_DECL(RXD3, B19);
+
+FUNC_GROUP_DECL(GPIE6, A20, B19);
+
+#define LPCHC_DESC     SIG_DESC_IP_SET(ASPEED_IP_LPC, LHCR0, 0)
+#define LPCPLUS_DESC   SIG_DESC_SET(SCU90, 30)
+
+#define J19 40
+SIG_EXPR_DECL(LHAD0, LPCHC, LPCHC_DESC);
+SIG_EXPR_DECL(LHAD0, LPCPLUS, LPCPLUS_DESC);
+SIG_EXPR_LIST_DECL_DUAL(LHAD0, LPCHC, LPCPLUS);
+SIG_EXPR_LIST_DECL_SINGLE(NCTS4, NCTS4, SIG_DESC_SET(SCU80, 24));
+MS_PIN_DECL(J19, GPIOF0, LHAD0, NCTS4);
+FUNC_GROUP_DECL(NCTS4, J19);
+
+#define J18 41
+SIG_EXPR_DECL(LHAD1, LPCHC, LPCHC_DESC);
+SIG_EXPR_DECL(LHAD1, LPCPLUS, LPCPLUS_DESC);
+SIG_EXPR_LIST_DECL_DUAL(LHAD1, LPCHC, LPCPLUS);
+SIG_EXPR_LIST_DECL_SINGLE(NDCD4, NDCD4, SIG_DESC_SET(SCU80, 25));
+MS_PIN_DECL(J18, GPIOF1, LHAD1, NDCD4);
+FUNC_GROUP_DECL(NDCD4, J18);
+
+#define B22 42
+SIG_EXPR_DECL(LHAD2, LPCHC, LPCHC_DESC);
+SIG_EXPR_DECL(LHAD2, LPCPLUS, LPCPLUS_DESC);
+SIG_EXPR_LIST_DECL_DUAL(LHAD2, LPCHC, LPCPLUS);
+SIG_EXPR_LIST_DECL_SINGLE(NDSR4, NDSR4, SIG_DESC_SET(SCU80, 26));
+MS_PIN_DECL(B22, GPIOF2, LHAD2, NDSR4);
+FUNC_GROUP_DECL(NDSR4, B22);
+
+#define B21 43
+SIG_EXPR_DECL(LHAD3, LPCHC, LPCHC_DESC);
+SIG_EXPR_DECL(LHAD3, LPCPLUS, LPCPLUS_DESC);
+SIG_EXPR_LIST_DECL_DUAL(LHAD3, LPCHC, LPCPLUS);
+SIG_EXPR_LIST_DECL_SINGLE(NRI4, NRI4, SIG_DESC_SET(SCU80, 27));
+MS_PIN_DECL(B21, GPIOF3, LHAD3, NRI4);
+FUNC_GROUP_DECL(NRI4, B21);
+
+#define A21 44
+SIG_EXPR_DECL(LHCLK, LPCHC, LPCHC_DESC);
+SIG_EXPR_DECL(LHCLK, LPCPLUS, LPCPLUS_DESC);
+SIG_EXPR_LIST_DECL_DUAL(LHCLK, LPCHC, LPCPLUS);
+SIG_EXPR_LIST_DECL_SINGLE(NDTR4, NDTR4, SIG_DESC_SET(SCU80, 28));
+MS_PIN_DECL(A21, GPIOF4, LHCLK, NDTR4);
+FUNC_GROUP_DECL(NDTR4, A21);
+
+#define H19 45
+SIG_EXPR_DECL(LHFRAME, LPCHC, LPCHC_DESC);
+SIG_EXPR_DECL(LHFRAME, LPCPLUS, LPCPLUS_DESC);
+SIG_EXPR_LIST_DECL_DUAL(LHFRAME, LPCHC, LPCPLUS);
+SIG_EXPR_LIST_DECL_SINGLE(NRTS4, NRTS4, SIG_DESC_SET(SCU80, 29));
+MS_PIN_DECL(H19, GPIOF5, LHFRAME, NRTS4);
+FUNC_GROUP_DECL(NRTS4, H19);
+
+#define G17 46
+SIG_EXPR_LIST_DECL_SINGLE(LHSIRQ, LPCHC, LPCHC_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(TXD4, TXD4, SIG_DESC_SET(SCU80, 30));
+MS_PIN_DECL(G17, GPIOF6, LHSIRQ, TXD4);
+FUNC_GROUP_DECL(TXD4, G17);
+
+#define H18 47
+SIG_EXPR_DECL(LHRST, LPCHC, LPCHC_DESC);
+SIG_EXPR_DECL(LHRST, LPCPLUS, LPCPLUS_DESC);
+SIG_EXPR_LIST_DECL_DUAL(LHRST, LPCHC, LPCPLUS);
+SIG_EXPR_LIST_DECL_SINGLE(RXD4, RXD4, SIG_DESC_SET(SCU80, 31));
+MS_PIN_DECL(H18, GPIOF7, LHRST, RXD4);
+FUNC_GROUP_DECL(RXD4, H18);
+
+FUNC_GROUP_DECL(LPCHC, J19, J18, B22, B21, A21, H19, G17, H18);
+FUNC_GROUP_DECL(LPCPLUS, J19, J18, B22, B21, A21, H19, H18);
+
+#define A19 48
+SIG_EXPR_LIST_DECL_SINGLE(SGPS1CK, SGPS1, COND1, SIG_DESC_SET(SCU84, 0));
+SS_PIN_DECL(A19, GPIOG0, SGPS1CK);
+
+#define E19 49
+SIG_EXPR_LIST_DECL_SINGLE(SGPS1LD, SGPS1, COND1, SIG_DESC_SET(SCU84, 1));
+SS_PIN_DECL(E19, GPIOG1, SGPS1LD);
+
+#define C19 50
+SIG_EXPR_LIST_DECL_SINGLE(SGPS1I0, SGPS1, COND1, SIG_DESC_SET(SCU84, 2));
+SS_PIN_DECL(C19, GPIOG2, SGPS1I0);
+
+#define E16 51
+SIG_EXPR_LIST_DECL_SINGLE(SGPS1I1, SGPS1, COND1, SIG_DESC_SET(SCU84, 3));
+SS_PIN_DECL(E16, GPIOG3, SGPS1I1);
+
+FUNC_GROUP_DECL(SGPS1, A19, E19, C19, E16);
+
+#define SGPS2_DESC     SIG_DESC_SET(SCU94, 12)
+
+#define E17 52
+SIG_EXPR_LIST_DECL_SINGLE(SGPS2CK, SGPS2, COND1, SGPS2_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(SALT1, SALT1, COND1, SIG_DESC_SET(SCU84, 4));
+MS_PIN_DECL(E17, GPIOG4, SGPS2CK, SALT1);
+FUNC_GROUP_DECL(SALT1, E17);
+
+#define D16 53
+SIG_EXPR_LIST_DECL_SINGLE(SGPS2LD, SGPS2, COND1, SGPS2_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(SALT2, SALT2, COND1, SIG_DESC_SET(SCU84, 5));
+MS_PIN_DECL(D16, GPIOG5, SGPS2LD, SALT2);
+FUNC_GROUP_DECL(SALT2, D16);
+
+#define D15 54
+SIG_EXPR_LIST_DECL_SINGLE(SGPS2I0, SGPS2, COND1, SGPS2_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(SALT3, SALT3, COND1, SIG_DESC_SET(SCU84, 6));
+MS_PIN_DECL(D15, GPIOG6, SGPS2I0, SALT3);
+FUNC_GROUP_DECL(SALT3, D15);
+
+#define E14 55
+SIG_EXPR_LIST_DECL_SINGLE(SGPS2I1, SGPS2, COND1, SGPS2_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(SALT4, SALT4, COND1, SIG_DESC_SET(SCU84, 7));
+MS_PIN_DECL(E14, GPIOG7, SGPS2I1, SALT4);
+FUNC_GROUP_DECL(SALT4, E14);
+
+FUNC_GROUP_DECL(SGPS2, E17, D16, D15, E14);
+
+#define UART6_DESC     SIG_DESC_SET(SCU90, 7)
+
+#define A18 56
+SIG_EXPR_LIST_DECL_SINGLE(DASHA18, DASHA18, COND1, SIG_DESC_SET(SCU94, 5));
+SIG_EXPR_LIST_DECL_SINGLE(NCTS6, UART6, COND1, UART6_DESC);
+MS_PIN_DECL(A18, GPIOH0, DASHA18, NCTS6);
+
+#define B18 57
+SIG_EXPR_LIST_DECL_SINGLE(DASHB18, DASHB18, COND1, SIG_DESC_SET(SCU94, 5));
+SIG_EXPR_LIST_DECL_SINGLE(NDCD6, UART6, COND1, UART6_DESC);
+MS_PIN_DECL(B18, GPIOH1, DASHB18, NDCD6);
+
+#define D17 58
+SIG_EXPR_LIST_DECL_SINGLE(DASHD17, DASHD17, COND1, SIG_DESC_SET(SCU94, 6));
+SIG_EXPR_LIST_DECL_SINGLE(NDSR6, UART6, COND1, UART6_DESC);
+MS_PIN_DECL(D17, GPIOH2, DASHD17, NDSR6);
+
+#define C17 59
+SIG_EXPR_LIST_DECL_SINGLE(DASHC17, DASHC17, COND1, SIG_DESC_SET(SCU94, 6));
+SIG_EXPR_LIST_DECL_SINGLE(NRI6, UART6, COND1, UART6_DESC);
+MS_PIN_DECL(C17, GPIOH3, DASHC17, NRI6);
+
+#define A17 60
+SIG_EXPR_LIST_DECL_SINGLE(DASHA17, DASHA17, COND1, SIG_DESC_SET(SCU94, 7));
+SIG_EXPR_LIST_DECL_SINGLE(NDTR6, UART6, COND1, UART6_DESC);
+MS_PIN_DECL(A17, GPIOH4, DASHA17, NDTR6);
+
+#define B17 61
+SIG_EXPR_LIST_DECL_SINGLE(DASHB17, DASHB17, COND1, SIG_DESC_SET(SCU94, 7));
+SIG_EXPR_LIST_DECL_SINGLE(NRTS6, UART6, COND1, UART6_DESC);
+MS_PIN_DECL(B17, GPIOH5, DASHB17, NRTS6);
+
+#define A16 62
+SIG_EXPR_LIST_DECL_SINGLE(TXD6, UART6, COND1, UART6_DESC);
+SS_PIN_DECL(A16, GPIOH6, TXD6);
+
+#define D18 63
+SIG_EXPR_LIST_DECL_SINGLE(RXD6, UART6, COND1, UART6_DESC);
+SS_PIN_DECL(D18, GPIOH7, RXD6);
+
+FUNC_GROUP_DECL(UART6, A18, B18, D17, C17, A17, B17, A16, D18);
+
+#define SPI1_DESC \
+       { ASPEED_IP_SCU, HW_STRAP1, GENMASK(13, 12), 1, 0 }
+#define SPI1DEBUG_DESC \
+       { ASPEED_IP_SCU, HW_STRAP1, GENMASK(13, 12), 2, 0 }
+#define SPI1PASSTHRU_DESC \
+       { ASPEED_IP_SCU, HW_STRAP1, GENMASK(13, 12), 3, 0 }
 
 #define C18 64
 SIG_EXPR_DECL(SYSCS, SPI1DEBUG, COND1, SPI1DEBUG_DESC);
@@ -277,6 +577,30 @@ SS_PIN_DECL(N3, GPIOJ2, SGPMO);
 SIG_EXPR_LIST_DECL_SINGLE(SGPMI, SGPM, SIG_DESC_SET(SCU84, 11));
 SS_PIN_DECL(N4, GPIOJ3, SGPMI);
 
+#define N5 76
+SIG_EXPR_LIST_DECL_SINGLE(VGAHS, VGAHS, SIG_DESC_SET(SCU84, 12));
+SIG_EXPR_LIST_DECL_SINGLE(DASHN5, DASHN5, SIG_DESC_SET(SCU94, 8));
+MS_PIN_DECL(N5, GPIOJ4, VGAHS, DASHN5);
+FUNC_GROUP_DECL(VGAHS, N5);
+
+#define R4 77
+SIG_EXPR_LIST_DECL_SINGLE(VGAVS, VGAVS, SIG_DESC_SET(SCU84, 13));
+SIG_EXPR_LIST_DECL_SINGLE(DASHR4, DASHR4, SIG_DESC_SET(SCU94, 8));
+MS_PIN_DECL(R4, GPIOJ5, VGAVS, DASHR4);
+FUNC_GROUP_DECL(VGAVS, R4);
+
+#define R3 78
+SIG_EXPR_LIST_DECL_SINGLE(DDCCLK, DDCCLK, SIG_DESC_SET(SCU84, 14));
+SIG_EXPR_LIST_DECL_SINGLE(DASHR3, DASHR3, SIG_DESC_SET(SCU94, 9));
+MS_PIN_DECL(R3, GPIOJ6, DDCCLK, DASHR3);
+FUNC_GROUP_DECL(DDCCLK, R3);
+
+#define T3 79
+SIG_EXPR_LIST_DECL_SINGLE(DDCDAT, DDCDAT, SIG_DESC_SET(SCU84, 15));
+SIG_EXPR_LIST_DECL_SINGLE(DASHT3, DASHT3, SIG_DESC_SET(SCU94, 9));
+MS_PIN_DECL(T3, GPIOJ7, DDCDAT, DASHT3);
+FUNC_GROUP_DECL(DDCDAT, T3);
+
 #define I2C5_DESC       SIG_DESC_SET(SCU90, 18)
 
 #define L3 80
@@ -325,10 +649,119 @@ SS_PIN_DECL(R1, GPIOK7, SDA8);
 
 FUNC_GROUP_DECL(I2C8, P2, R1);
 
-#define VPIOFF0_DESC    { SCU90, GENMASK(5, 4), 0, 0 }
-#define VPIOFF1_DESC    { SCU90, GENMASK(5, 4), 1, 0 }
-#define VPI24_DESC      { SCU90, GENMASK(5, 4), 2, 0 }
-#define VPIRSVD_DESC    { SCU90, GENMASK(5, 4), 3, 0 }
+#define T2 88
+SSSF_PIN_DECL(T2, GPIOL0, NCTS1, SIG_DESC_SET(SCU84, 16));
+
+#define VPIOFF0_DESC    { ASPEED_IP_SCU, SCU90, GENMASK(5, 4), 0, 0 }
+#define VPIOFF1_DESC    { ASPEED_IP_SCU, SCU90, GENMASK(5, 4), 1, 0 }
+#define VPI24_DESC      { ASPEED_IP_SCU, SCU90, GENMASK(5, 4), 2, 0 }
+#define VPIRSVD_DESC    { ASPEED_IP_SCU, SCU90, GENMASK(5, 4), 3, 0 }
+#define VPI_24_RSVD_DESC       SIG_DESC_SET(SCU90, 5)
+
+#define T1 89
+#define T1_DESC                SIG_DESC_SET(SCU84, 17)
+SIG_EXPR_LIST_DECL_SINGLE(VPIDE, VPI24, VPI_24_RSVD_DESC, T1_DESC, COND2);
+SIG_EXPR_LIST_DECL_SINGLE(NDCD1, NDCD1, T1_DESC, COND2);
+MS_PIN_DECL(T1, GPIOL1, VPIDE, NDCD1);
+FUNC_GROUP_DECL(NDCD1, T1);
+
+#define U1 90
+#define U1_DESC                SIG_DESC_SET(SCU84, 18)
+SIG_EXPR_LIST_DECL_SINGLE(DASHU1, VPI24, VPI_24_RSVD_DESC, U1_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(NDSR1, NDSR1, U1_DESC);
+MS_PIN_DECL(U1, GPIOL2, DASHU1, NDSR1);
+FUNC_GROUP_DECL(NDSR1, U1);
+
+#define U2 91
+#define U2_DESC                SIG_DESC_SET(SCU84, 19)
+SIG_EXPR_LIST_DECL_SINGLE(VPIHS, VPI24, VPI_24_RSVD_DESC, U2_DESC, COND2);
+SIG_EXPR_LIST_DECL_SINGLE(NRI1, NRI1, U2_DESC, COND2);
+MS_PIN_DECL(U2, GPIOL3, VPIHS, NRI1);
+FUNC_GROUP_DECL(NRI1, U2);
+
+#define P4 92
+#define P4_DESC                SIG_DESC_SET(SCU84, 20)
+SIG_EXPR_LIST_DECL_SINGLE(VPIVS, VPI24, VPI_24_RSVD_DESC, P4_DESC, COND2);
+SIG_EXPR_LIST_DECL_SINGLE(NDTR1, NDTR1, P4_DESC, COND2);
+MS_PIN_DECL(P4, GPIOL4, VPIVS, NDTR1);
+FUNC_GROUP_DECL(NDTR1, P4);
+
+#define P3 93
+#define P3_DESC                SIG_DESC_SET(SCU84, 21)
+SIG_EXPR_LIST_DECL_SINGLE(VPICLK, VPI24, VPI_24_RSVD_DESC, P3_DESC, COND2);
+SIG_EXPR_LIST_DECL_SINGLE(NRTS1, NRTS1, P3_DESC, COND2);
+MS_PIN_DECL(P3, GPIOL5, VPICLK, NRTS1);
+FUNC_GROUP_DECL(NRTS1, P3);
+
+#define V1 94
+#define V1_DESC                SIG_DESC_SET(SCU84, 22)
+SIG_EXPR_LIST_DECL_SINGLE(DASHV1, DASHV1, VPIRSVD_DESC, V1_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(TXD1, TXD1, V1_DESC, COND2);
+MS_PIN_DECL(V1, GPIOL6, DASHV1, TXD1);
+FUNC_GROUP_DECL(TXD1, V1);
+
+#define W1 95
+#define W1_DESC                SIG_DESC_SET(SCU84, 23)
+SIG_EXPR_LIST_DECL_SINGLE(DASHW1, DASHW1, VPIRSVD_DESC, W1_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(RXD1, RXD1, W1_DESC, COND2);
+MS_PIN_DECL(W1, GPIOL7, DASHW1, RXD1);
+FUNC_GROUP_DECL(RXD1, W1);
+
+#define Y1 96
+#define Y1_DESC                SIG_DESC_SET(SCU84, 24)
+SIG_EXPR_LIST_DECL_SINGLE(VPIB2, VPI24, VPI_24_RSVD_DESC, Y1_DESC, COND2);
+SIG_EXPR_LIST_DECL_SINGLE(NCTS2, NCTS2, Y1_DESC, COND2);
+MS_PIN_DECL(Y1, GPIOM0, VPIB2, NCTS2);
+FUNC_GROUP_DECL(NCTS2, Y1);
+
+#define AB2 97
+#define AB2_DESC       SIG_DESC_SET(SCU84, 25)
+SIG_EXPR_LIST_DECL_SINGLE(VPIB3, VPI24, VPI_24_RSVD_DESC, AB2_DESC, COND2);
+SIG_EXPR_LIST_DECL_SINGLE(NDCD2, NDCD2, AB2_DESC, COND2);
+MS_PIN_DECL(AB2, GPIOM1, VPIB3, NDCD2);
+FUNC_GROUP_DECL(NDCD2, AB2);
+
+#define AA1 98
+#define AA1_DESC       SIG_DESC_SET(SCU84, 26)
+SIG_EXPR_LIST_DECL_SINGLE(VPIB4, VPI24, VPI_24_RSVD_DESC, AA1_DESC, COND2);
+SIG_EXPR_LIST_DECL_SINGLE(NDSR2, NDSR2, AA1_DESC, COND2);
+MS_PIN_DECL(AA1, GPIOM2, VPIB4, NDSR2);
+FUNC_GROUP_DECL(NDSR2, AA1);
+
+#define Y2 99
+#define Y2_DESC                SIG_DESC_SET(SCU84, 27)
+SIG_EXPR_LIST_DECL_SINGLE(VPIB5, VPI24, VPI_24_RSVD_DESC, Y2_DESC, COND2);
+SIG_EXPR_LIST_DECL_SINGLE(NRI2, NRI2, Y2_DESC, COND2);
+MS_PIN_DECL(Y2, GPIOM3, VPIB5, NRI2);
+FUNC_GROUP_DECL(NRI2, Y2);
+
+#define AA2 100
+#define AA2_DESC       SIG_DESC_SET(SCU84, 28)
+SIG_EXPR_LIST_DECL_SINGLE(VPIB6, VPI24, VPI_24_RSVD_DESC, AA2_DESC, COND2);
+SIG_EXPR_LIST_DECL_SINGLE(NDTR2, NDTR2, AA2_DESC, COND2);
+MS_PIN_DECL(AA2, GPIOM4, VPIB6, NDTR2);
+FUNC_GROUP_DECL(NDTR2, AA2);
+
+#define P5 101
+#define P5_DESC        SIG_DESC_SET(SCU84, 29)
+SIG_EXPR_LIST_DECL_SINGLE(VPIB7, VPI24, VPI_24_RSVD_DESC, P5_DESC, COND2);
+SIG_EXPR_LIST_DECL_SINGLE(NRTS2, NRTS2, P5_DESC, COND2);
+MS_PIN_DECL(P5, GPIOM5, VPIB7, NRTS2);
+FUNC_GROUP_DECL(NRTS2, P5);
+
+#define R5 102
+#define R5_DESC        SIG_DESC_SET(SCU84, 30)
+SIG_EXPR_LIST_DECL_SINGLE(VPIB8, VPI24, VPI_24_RSVD_DESC, R5_DESC, COND2);
+SIG_EXPR_LIST_DECL_SINGLE(TXD2, TXD2, R5_DESC, COND2);
+MS_PIN_DECL(R5, GPIOM6, VPIB8, TXD2);
+FUNC_GROUP_DECL(TXD2, R5);
+
+#define T5 103
+#define T5_DESC        SIG_DESC_SET(SCU84, 31)
+SIG_EXPR_LIST_DECL_SINGLE(VPIB9, VPI24, VPI_24_RSVD_DESC, T5_DESC, COND2);
+SIG_EXPR_LIST_DECL_SINGLE(RXD2, RXD2, T5_DESC, COND2);
+MS_PIN_DECL(T5, GPIOM7, VPIB9, RXD2);
+FUNC_GROUP_DECL(RXD2, T5);
 
 #define V2 104
 #define V2_DESC         SIG_DESC_SET(SCU88, 0)
@@ -394,9 +827,88 @@ SIG_EXPR_LIST_DECL_SINGLE(PWM7, PWM7, T4_DESC, COND2);
 MS_PIN_DECL(T4, GPION7, VPIG7, PWM7);
 FUNC_GROUP_DECL(PWM7, T4);
 
+#define U5 112
+SIG_EXPR_LIST_DECL_SINGLE(VPIG8, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 8),
+                         COND2);
+SS_PIN_DECL(U5, GPIOO0, VPIG8);
+
+#define U4 113
+SIG_EXPR_LIST_DECL_SINGLE(VPIG9, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 9),
+                         COND2);
+SS_PIN_DECL(U4, GPIOO1, VPIG9);
+
+#define V5 114
+SIG_EXPR_LIST_DECL_SINGLE(DASHV5, DASHV5, VPI_24_RSVD_DESC,
+                         SIG_DESC_SET(SCU88, 10));
+SS_PIN_DECL(V5, GPIOO2, DASHV5);
+
+#define AB4 115
+SIG_EXPR_LIST_DECL_SINGLE(DASHAB4, DASHAB4, VPI_24_RSVD_DESC,
+                         SIG_DESC_SET(SCU88, 11));
+SS_PIN_DECL(AB4, GPIOO3, DASHAB4);
+
+#define AB3 116
+SIG_EXPR_LIST_DECL_SINGLE(VPIR2, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 12),
+                         COND2);
+SS_PIN_DECL(AB3, GPIOO4, VPIR2);
+
+#define Y4 117
+SIG_EXPR_LIST_DECL_SINGLE(VPIR3, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 13),
+                         COND2);
+SS_PIN_DECL(Y4, GPIOO5, VPIR3);
+
+#define AA4 118
+SIG_EXPR_LIST_DECL_SINGLE(VPIR4, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 14),
+                         COND2);
+SS_PIN_DECL(AA4, GPIOO6, VPIR4);
+
+#define W4 119
+SIG_EXPR_LIST_DECL_SINGLE(VPIR5, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 15),
+                         COND2);
+SS_PIN_DECL(W4, GPIOO7, VPIR5);
+
+#define V4 120
+SIG_EXPR_LIST_DECL_SINGLE(VPIR6, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 16),
+                         COND2);
+SS_PIN_DECL(V4, GPIOP0, VPIR6);
+
+#define W5 121
+SIG_EXPR_LIST_DECL_SINGLE(VPIR7, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 17),
+                         COND2);
+SS_PIN_DECL(W5, GPIOP1, VPIR7);
+
+#define AA5 122
+SIG_EXPR_LIST_DECL_SINGLE(VPIR8, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 18),
+                         COND2);
+SS_PIN_DECL(AA5, GPIOP2, VPIR8);
+
+#define AB5 123
+SIG_EXPR_LIST_DECL_SINGLE(VPIR9, VPI24, VPI24_DESC, SIG_DESC_SET(SCU88, 19),
+                         COND2);
+SS_PIN_DECL(AB5, GPIOP3, VPIR9);
+
+FUNC_GROUP_DECL(VPI24, T1, U2, P4, P3, Y1, AB2, AA1, Y2, AA2, P5, R5, T5, V3,
+               U3, W3, AA3, Y3, T4, U5, U4, AB3, Y4, AA4, W4, V4, W5, AA5,
+               AB5);
+
+#define Y6 124
+SIG_EXPR_LIST_DECL_SINGLE(DASHY6, DASHY6, SIG_DESC_SET(SCU90, 28),
+                         SIG_DESC_SET(SCU88, 20));
+SS_PIN_DECL(Y6, GPIOP4, DASHY6);
+
+#define Y5 125
+SIG_EXPR_LIST_DECL_SINGLE(DASHY5, DASHY5, SIG_DESC_SET(SCU90, 28),
+                         SIG_DESC_SET(SCU88, 21));
+SS_PIN_DECL(Y5, GPIOP5, DASHY5);
+
+#define W6 126
+SIG_EXPR_LIST_DECL_SINGLE(DASHW6, DASHW6, SIG_DESC_SET(SCU90, 28),
+                         SIG_DESC_SET(SCU88, 22));
+SS_PIN_DECL(W6, GPIOP6, DASHW6);
+
 #define V6 127
 SIG_EXPR_LIST_DECL_SINGLE(DASHV6, DASHV6, SIG_DESC_SET(SCU90, 28),
-               SIG_DESC_SET(SCU88, 23));
+                         SIG_DESC_SET(SCU88, 23));
 SS_PIN_DECL(V6, GPIOP7, DASHV6);
 
 #define I2C3_DESC      SIG_DESC_SET(SCU90, 16)
@@ -441,6 +953,24 @@ SSSF_PIN_DECL(B10, GPIOQ6, OSCCLK, SIG_DESC_SET(SCU2C, 1));
 #define N20 135
 SSSF_PIN_DECL(N20, GPIOQ7, PEWAKE, SIG_DESC_SET(SCU2C, 29));
 
+#define AA19 136
+SSSF_PIN_DECL(AA19, GPIOR0, FWSPICS1, SIG_DESC_SET(SCU88, 24), COND2);
+
+#define T19 137
+SSSF_PIN_DECL(T19, GPIOR1, FWSPICS2, SIG_DESC_SET(SCU88, 25), COND2);
+
+#define T17 138
+SSSF_PIN_DECL(T17, GPIOR2, SPI2CS0, SIG_DESC_SET(SCU88, 26), COND2);
+
+#define Y19 139
+SSSF_PIN_DECL(Y19, GPIOR3, SPI2CK, SIG_DESC_SET(SCU88, 27), COND2);
+
+#define W19 140
+SSSF_PIN_DECL(W19, GPIOR4, SPI2MOSI, SIG_DESC_SET(SCU88, 28), COND2);
+
+#define V19 141
+SSSF_PIN_DECL(V19, GPIOR5, SPI2MISO, SIG_DESC_SET(SCU88, 29), COND2);
+
 #define D8 142
 SIG_EXPR_LIST_DECL_SINGLE(MDC1, MDIO1, SIG_DESC_SET(SCU88, 30));
 SS_PIN_DECL(D8, GPIOR6, MDC1);
@@ -451,6 +981,93 @@ SS_PIN_DECL(E10, GPIOR7, MDIO1);
 
 FUNC_GROUP_DECL(MDIO1, D8, E10);
 
+#define VPOOFF0_DESC   { ASPEED_IP_SCU, SCU94, GENMASK(1, 0), 0, 0 }
+#define VPO_DESC       { ASPEED_IP_SCU, SCU94, GENMASK(1, 0), 1, 0 }
+#define VPOOFF1_DESC   { ASPEED_IP_SCU, SCU94, GENMASK(1, 0), 2, 0 }
+#define VPOOFF2_DESC   { ASPEED_IP_SCU, SCU94, GENMASK(1, 0), 3, 0 }
+
+#define CRT_DVO_EN_DESC        SIG_DESC_IP_SET(ASPEED_IP_GFX, GFX064, 7)
+
+#define V20 144
+#define V20_DESC       SIG_DESC_SET(SCU8C, 0)
+SIG_EXPR_DECL(VPOB2, VPO, V20_DESC, VPO_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOB2, VPOOFF1, V20_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOB2, VPOOFF2, V20_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_LIST_DECL(VPOB2, SIG_EXPR_PTR(VPOB2, VPO),
+               SIG_EXPR_PTR(VPOB2, VPOOFF1), SIG_EXPR_PTR(VPOB2, VPOOFF2));
+SIG_EXPR_LIST_DECL_SINGLE(SPI2CS1, SPI2CS1, V20_DESC);
+MS_PIN_DECL(V20, GPIOS0, VPOB2, SPI2CS1);
+FUNC_GROUP_DECL(SPI2CS1, V20);
+
+#define U19 145
+#define U19_DESC       SIG_DESC_SET(SCU8C, 1)
+SIG_EXPR_DECL(VPOB3, VPO, U19_DESC, VPO_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOB3, VPOOFF1, U19_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOB3, VPOOFF2, U19_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_LIST_DECL(VPOB3, SIG_EXPR_PTR(VPOB3, VPO),
+               SIG_EXPR_PTR(VPOB3, VPOOFF1), SIG_EXPR_PTR(VPOB3, VPOOFF2));
+SIG_EXPR_LIST_DECL_SINGLE(BMCINT, BMCINT, U19_DESC);
+MS_PIN_DECL(U19, GPIOS1, VPOB3, BMCINT);
+FUNC_GROUP_DECL(BMCINT, U19);
+
+#define R18 146
+#define R18_DESC       SIG_DESC_SET(SCU8C, 2)
+SIG_EXPR_DECL(VPOB4, VPO, R18_DESC, VPO_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOB4, VPOOFF1, R18_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOB4, VPOOFF2, R18_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_LIST_DECL(VPOB4, SIG_EXPR_PTR(VPOB4, VPO),
+               SIG_EXPR_PTR(VPOB4, VPOOFF1), SIG_EXPR_PTR(VPOB4, VPOOFF2));
+SIG_EXPR_LIST_DECL_SINGLE(SALT5, SALT5, R18_DESC);
+MS_PIN_DECL(R18, GPIOS2, VPOB4, SALT5);
+FUNC_GROUP_DECL(SALT5, R18);
+
+#define P18 147
+#define P18_DESC       SIG_DESC_SET(SCU8C, 3)
+SIG_EXPR_DECL(VPOB5, VPO, P18_DESC, VPO_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOB5, VPOOFF1, P18_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOB5, VPOOFF2, P18_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_LIST_DECL(VPOB5, SIG_EXPR_PTR(VPOB5, VPO),
+               SIG_EXPR_PTR(VPOB5, VPOOFF1), SIG_EXPR_PTR(VPOB5, VPOOFF2));
+SIG_EXPR_LIST_DECL_SINGLE(SALT6, SALT6, P18_DESC);
+MS_PIN_DECL(P18, GPIOS3, VPOB5, SALT6);
+FUNC_GROUP_DECL(SALT6, P18);
+
+#define R19 148
+#define R19_DESC       SIG_DESC_SET(SCU8C, 4)
+SIG_EXPR_DECL(VPOB6, VPO, R19_DESC, VPO_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOB6, VPOOFF1, R19_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOB6, VPOOFF2, R19_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_LIST_DECL(VPOB6, SIG_EXPR_PTR(VPOB6, VPO),
+               SIG_EXPR_PTR(VPOB6, VPOOFF1), SIG_EXPR_PTR(VPOB6, VPOOFF2));
+SS_PIN_DECL(R19, GPIOS4, VPOB6);
+
+#define W20 149
+#define W20_DESC       SIG_DESC_SET(SCU8C, 5)
+SIG_EXPR_DECL(VPOB7, VPO, W20_DESC, VPO_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOB7, VPOOFF1, W20_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOB7, VPOOFF2, W20_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_LIST_DECL(VPOB7, SIG_EXPR_PTR(VPOB7, VPO),
+               SIG_EXPR_PTR(VPOB7, VPOOFF1), SIG_EXPR_PTR(VPOB7, VPOOFF2));
+SS_PIN_DECL(W20, GPIOS5, VPOB7);
+
+#define U20 150
+#define U20_DESC       SIG_DESC_SET(SCU8C, 6)
+SIG_EXPR_DECL(VPOB8, VPO, U20_DESC, VPO_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOB8, VPOOFF1, U20_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOB8, VPOOFF2, U20_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_LIST_DECL(VPOB8, SIG_EXPR_PTR(VPOB8, VPO),
+               SIG_EXPR_PTR(VPOB8, VPOOFF1), SIG_EXPR_PTR(VPOB8, VPOOFF2));
+SS_PIN_DECL(U20, GPIOS6, VPOB8);
+
+#define AA20 151
+#define AA20_DESC      SIG_DESC_SET(SCU8C, 7)
+SIG_EXPR_DECL(VPOB9, VPO, AA20_DESC, VPO_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOB9, VPOOFF1, AA20_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOB9, VPOOFF2, AA20_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_LIST_DECL(VPOB9, SIG_EXPR_PTR(VPOB9, VPO),
+               SIG_EXPR_PTR(VPOB9, VPOOFF1), SIG_EXPR_PTR(VPOB9, VPOOFF2));
+SS_PIN_DECL(AA20, GPIOS7, VPOB9);
+
 /* RGMII1/RMII1 */
 
 #define RMII1_DESC      SIG_DESC_BIT(HW_STRAP1, 6, 0)
@@ -632,6 +1249,481 @@ MS_PIN_DECL_(E6, SIG_EXPR_LIST_PTR(GPIOV7), SIG_EXPR_LIST_PTR(RMII2RXER),
 FUNC_GROUP_DECL(RGMII2, B2, B1, A2, B3, D5, D4, C2, C1, C3, D1, D2, E6);
 FUNC_GROUP_DECL(RMII2, B2, B1, A2, B3, C2, C3, D1, D2, E6);
 
+#define F4 176
+SIG_EXPR_LIST_DECL_SINGLE(GPIOW0, GPIOW0, SIG_DESC_SET(SCUA0, 24));
+SIG_EXPR_LIST_DECL_SINGLE(ADC0, ADC0);
+MS_PIN_DECL_(F4, SIG_EXPR_LIST_PTR(GPIOW0), SIG_EXPR_LIST_PTR(ADC0));
+FUNC_GROUP_DECL(ADC0, F4);
+
+#define F5 177
+SIG_EXPR_LIST_DECL_SINGLE(GPIOW1, GPIOW1, SIG_DESC_SET(SCUA0, 25));
+SIG_EXPR_LIST_DECL_SINGLE(ADC1, ADC1);
+MS_PIN_DECL_(F5, SIG_EXPR_LIST_PTR(GPIOW1), SIG_EXPR_LIST_PTR(ADC1));
+FUNC_GROUP_DECL(ADC1, F5);
+
+#define E2 178
+SIG_EXPR_LIST_DECL_SINGLE(GPIOW2, GPIOW2, SIG_DESC_SET(SCUA0, 26));
+SIG_EXPR_LIST_DECL_SINGLE(ADC2, ADC2);
+MS_PIN_DECL_(E2, SIG_EXPR_LIST_PTR(GPIOW2), SIG_EXPR_LIST_PTR(ADC2));
+FUNC_GROUP_DECL(ADC2, E2);
+
+#define E1 179
+SIG_EXPR_LIST_DECL_SINGLE(GPIOW3, GPIOW3, SIG_DESC_SET(SCUA0, 27));
+SIG_EXPR_LIST_DECL_SINGLE(ADC3, ADC3);
+MS_PIN_DECL_(E1, SIG_EXPR_LIST_PTR(GPIOW3), SIG_EXPR_LIST_PTR(ADC3));
+FUNC_GROUP_DECL(ADC3, E1);
+
+#define F3 180
+SIG_EXPR_LIST_DECL_SINGLE(GPIOW4, GPIOW4, SIG_DESC_SET(SCUA0, 28));
+SIG_EXPR_LIST_DECL_SINGLE(ADC4, ADC4);
+MS_PIN_DECL_(F3, SIG_EXPR_LIST_PTR(GPIOW4), SIG_EXPR_LIST_PTR(ADC4));
+FUNC_GROUP_DECL(ADC4, F3);
+
+#define E3 181
+SIG_EXPR_LIST_DECL_SINGLE(GPIOW5, GPIOW5, SIG_DESC_SET(SCUA0, 29));
+SIG_EXPR_LIST_DECL_SINGLE(ADC5, ADC5);
+MS_PIN_DECL_(E3, SIG_EXPR_LIST_PTR(GPIOW5), SIG_EXPR_LIST_PTR(ADC5));
+FUNC_GROUP_DECL(ADC5, E3);
+
+#define G5 182
+SIG_EXPR_LIST_DECL_SINGLE(GPIOW6, GPIOW6, SIG_DESC_SET(SCUA0, 30));
+SIG_EXPR_LIST_DECL_SINGLE(ADC6, ADC6);
+MS_PIN_DECL_(G5, SIG_EXPR_LIST_PTR(GPIOW6), SIG_EXPR_LIST_PTR(ADC6));
+FUNC_GROUP_DECL(ADC6, G5);
+
+#define G4 183
+SIG_EXPR_LIST_DECL_SINGLE(GPIOW7, GPIOW7, SIG_DESC_SET(SCUA0, 31));
+SIG_EXPR_LIST_DECL_SINGLE(ADC7, ADC7);
+MS_PIN_DECL_(G4, SIG_EXPR_LIST_PTR(GPIOW7), SIG_EXPR_LIST_PTR(ADC7));
+FUNC_GROUP_DECL(ADC7, G4);
+
+#define F2 184
+SIG_EXPR_LIST_DECL_SINGLE(GPIOX0, GPIOX0, SIG_DESC_SET(SCUA4, 0));
+SIG_EXPR_LIST_DECL_SINGLE(ADC8, ADC8);
+MS_PIN_DECL_(F2, SIG_EXPR_LIST_PTR(GPIOX0), SIG_EXPR_LIST_PTR(ADC8));
+FUNC_GROUP_DECL(ADC8, F2);
+
+#define G3 185
+SIG_EXPR_LIST_DECL_SINGLE(GPIOX1, GPIOX1, SIG_DESC_SET(SCUA4, 1));
+SIG_EXPR_LIST_DECL_SINGLE(ADC9, ADC9);
+MS_PIN_DECL_(G3, SIG_EXPR_LIST_PTR(GPIOX1), SIG_EXPR_LIST_PTR(ADC9));
+FUNC_GROUP_DECL(ADC9, G3);
+
+#define G2 186
+SIG_EXPR_LIST_DECL_SINGLE(GPIOX2, GPIOX2, SIG_DESC_SET(SCUA4, 2));
+SIG_EXPR_LIST_DECL_SINGLE(ADC10, ADC10);
+MS_PIN_DECL_(G2, SIG_EXPR_LIST_PTR(GPIOX2), SIG_EXPR_LIST_PTR(ADC10));
+FUNC_GROUP_DECL(ADC10, G2);
+
+#define F1 187
+SIG_EXPR_LIST_DECL_SINGLE(GPIOX3, GPIOX3, SIG_DESC_SET(SCUA4, 3));
+SIG_EXPR_LIST_DECL_SINGLE(ADC11, ADC11);
+MS_PIN_DECL_(F1, SIG_EXPR_LIST_PTR(GPIOX3), SIG_EXPR_LIST_PTR(ADC11));
+FUNC_GROUP_DECL(ADC11, F1);
+
+#define H5 188
+SIG_EXPR_LIST_DECL_SINGLE(GPIOX4, GPIOX4, SIG_DESC_SET(SCUA4, 4));
+SIG_EXPR_LIST_DECL_SINGLE(ADC12, ADC12);
+MS_PIN_DECL_(H5, SIG_EXPR_LIST_PTR(GPIOX4), SIG_EXPR_LIST_PTR(ADC12));
+FUNC_GROUP_DECL(ADC12, H5);
+
+#define G1 189
+SIG_EXPR_LIST_DECL_SINGLE(GPIOX5, GPIOX5, SIG_DESC_SET(SCUA4, 5));
+SIG_EXPR_LIST_DECL_SINGLE(ADC13, ADC13);
+MS_PIN_DECL_(G1, SIG_EXPR_LIST_PTR(GPIOX5), SIG_EXPR_LIST_PTR(ADC13));
+FUNC_GROUP_DECL(ADC13, G1);
+
+#define H3 190
+SIG_EXPR_LIST_DECL_SINGLE(GPIOX6, GPIOX6, SIG_DESC_SET(SCUA4, 6));
+SIG_EXPR_LIST_DECL_SINGLE(ADC14, ADC14);
+MS_PIN_DECL_(H3, SIG_EXPR_LIST_PTR(GPIOX6), SIG_EXPR_LIST_PTR(ADC14));
+FUNC_GROUP_DECL(ADC14, H3);
+
+#define H4 191
+SIG_EXPR_LIST_DECL_SINGLE(GPIOX7, GPIOX7, SIG_DESC_SET(SCUA4, 7));
+SIG_EXPR_LIST_DECL_SINGLE(ADC15, ADC15);
+MS_PIN_DECL_(H4, SIG_EXPR_LIST_PTR(GPIOX7), SIG_EXPR_LIST_PTR(ADC15));
+FUNC_GROUP_DECL(ADC15, H4);
+
+#define ACPI_DESC      SIG_DESC_SET(HW_STRAP1, 19)
+
+#define R22 192
+SIG_EXPR_DECL(SIOS3, SIOS3, SIG_DESC_SET(SCUA4, 8));
+SIG_EXPR_DECL(SIOS3, ACPI, ACPI_DESC);
+SIG_EXPR_LIST_DECL_DUAL(SIOS3, SIOS3, ACPI);
+SIG_EXPR_LIST_DECL_SINGLE(DASHR22, DASHR22, SIG_DESC_SET(SCU94, 10));
+MS_PIN_DECL(R22, GPIOY0, SIOS3, DASHR22);
+FUNC_GROUP_DECL(SIOS3, R22);
+
+#define R21 193
+SIG_EXPR_DECL(SIOS5, SIOS5, SIG_DESC_SET(SCUA4, 9));
+SIG_EXPR_DECL(SIOS5, ACPI, ACPI_DESC);
+SIG_EXPR_LIST_DECL_DUAL(SIOS5, SIOS5, ACPI);
+SIG_EXPR_LIST_DECL_SINGLE(DASHR21, DASHR21, SIG_DESC_SET(SCU94, 10));
+MS_PIN_DECL(R21, GPIOY1, SIOS5, DASHR21);
+FUNC_GROUP_DECL(SIOS5, R21);
+
+#define P22 194
+SIG_EXPR_DECL(SIOPWREQ, SIOPWREQ, SIG_DESC_SET(SCUA4, 10));
+SIG_EXPR_DECL(SIOPWREQ, ACPI, ACPI_DESC);
+SIG_EXPR_LIST_DECL_DUAL(SIOPWREQ, SIOPWREQ, ACPI);
+SIG_EXPR_LIST_DECL_SINGLE(DASHP22, DASHP22, SIG_DESC_SET(SCU94, 11));
+MS_PIN_DECL(P22, GPIOY2, SIOPWREQ, DASHP22);
+FUNC_GROUP_DECL(SIOPWREQ, P22);
+
+#define P21 195
+SIG_EXPR_DECL(SIOONCTRL, SIOONCTRL, SIG_DESC_SET(SCUA4, 11));
+SIG_EXPR_DECL(SIOONCTRL, ACPI, ACPI_DESC);
+SIG_EXPR_LIST_DECL_DUAL(SIOONCTRL, SIOONCTRL, ACPI);
+SIG_EXPR_LIST_DECL_SINGLE(DASHP21, DASHP21, SIG_DESC_SET(SCU94, 11));
+MS_PIN_DECL(P21, GPIOY3, SIOONCTRL, DASHP21);
+FUNC_GROUP_DECL(SIOONCTRL, P21);
+
+#define M18 196
+SSSF_PIN_DECL(M18, GPIOY4, SCL1, SIG_DESC_SET(SCUA4, 12));
+
+#define M19 197
+SSSF_PIN_DECL(M19, GPIOY5, SDA1, SIG_DESC_SET(SCUA4, 13));
+
+#define M20 198
+SSSF_PIN_DECL(M20, GPIOY6, SCL2, SIG_DESC_SET(SCUA4, 14));
+
+#define P20 199
+SSSF_PIN_DECL(P20, GPIOY7, SDA2, SIG_DESC_SET(SCUA4, 15));
+
+#define PNOR_DESC      SIG_DESC_SET(SCU90, 31)
+
+#define Y20 200
+#define Y20_DESC       SIG_DESC_SET(SCUA4, 16)
+SIG_EXPR_DECL(VPOG2, VPO, Y20_DESC, VPO_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOG2, VPOOFF1, Y20_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOG2, VPOOFF2, Y20_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_LIST_DECL(VPOG2, SIG_EXPR_PTR(VPOG2, VPO),
+               SIG_EXPR_PTR(VPOG2, VPOOFF1), SIG_EXPR_PTR(VPOG2, VPOOFF2));
+SIG_EXPR_DECL(SIOPBI, SIOPBI, Y20_DESC);
+SIG_EXPR_DECL(SIOPBI, ACPI, Y20_DESC);
+SIG_EXPR_LIST_DECL_DUAL(SIOPBI, SIOPBI, ACPI);
+SIG_EXPR_LIST_DECL_SINGLE(NORA0, PNOR, PNOR_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(GPIOZ0, GPIOZ0);
+MS_PIN_DECL_(Y20, SIG_EXPR_LIST_PTR(VPOG2), SIG_EXPR_LIST_PTR(SIOPBI),
+               SIG_EXPR_LIST_PTR(NORA0), SIG_EXPR_LIST_PTR(GPIOZ0));
+FUNC_GROUP_DECL(SIOPBI, Y20);
+
+#define AB20 201
+#define AB20_DESC      SIG_DESC_SET(SCUA4, 17)
+SIG_EXPR_DECL(VPOG3, VPO, AB20_DESC, VPO_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOG3, VPOOFF1, AB20_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOG3, VPOOFF2, AB20_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_LIST_DECL(VPOG3, SIG_EXPR_PTR(VPOG3, VPO),
+               SIG_EXPR_PTR(VPOG3, VPOOFF1), SIG_EXPR_PTR(VPOG3, VPOOFF2));
+SIG_EXPR_DECL(SIOPWRGD, SIOPWRGD, AB20_DESC);
+SIG_EXPR_DECL(SIOPWRGD, ACPI, AB20_DESC);
+SIG_EXPR_LIST_DECL_DUAL(SIOPWRGD, SIOPWRGD, ACPI);
+SIG_EXPR_LIST_DECL_SINGLE(NORA1, PNOR, PNOR_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(GPIOZ1, GPIOZ1);
+MS_PIN_DECL_(AB20, SIG_EXPR_LIST_PTR(VPOG3), SIG_EXPR_LIST_PTR(SIOPWRGD),
+               SIG_EXPR_LIST_PTR(NORA1), SIG_EXPR_LIST_PTR(GPIOZ1));
+FUNC_GROUP_DECL(SIOPWRGD, AB20);
+
+#define AB21 202
+#define AB21_DESC      SIG_DESC_SET(SCUA4, 18)
+SIG_EXPR_DECL(VPOG4, VPO, AB21_DESC, VPO_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOG4, VPOOFF1, AB21_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOG4, VPOOFF2, AB21_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_LIST_DECL(VPOG4, SIG_EXPR_PTR(VPOG4, VPO),
+               SIG_EXPR_PTR(VPOG4, VPOOFF1), SIG_EXPR_PTR(VPOG4, VPOOFF2));
+SIG_EXPR_DECL(SIOPBO, SIOPBO, AB21_DESC);
+SIG_EXPR_DECL(SIOPBO, ACPI, AB21_DESC);
+SIG_EXPR_LIST_DECL_DUAL(SIOPBO, SIOPBO, ACPI);
+SIG_EXPR_LIST_DECL_SINGLE(NORA2, PNOR, PNOR_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(GPIOZ2, GPIOZ2);
+MS_PIN_DECL_(AB21, SIG_EXPR_LIST_PTR(VPOG4), SIG_EXPR_LIST_PTR(SIOPBO),
+               SIG_EXPR_LIST_PTR(NORA2), SIG_EXPR_LIST_PTR(GPIOZ2));
+FUNC_GROUP_DECL(SIOPBO, AB21);
+
+#define AA21 203
+#define AA21_DESC      SIG_DESC_SET(SCUA4, 19)
+SIG_EXPR_DECL(VPOG5, VPO, AA21_DESC, VPO_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOG5, VPOOFF1, AA21_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOG5, VPOOFF2, AA21_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_LIST_DECL(VPOG5, SIG_EXPR_PTR(VPOG5, VPO),
+               SIG_EXPR_PTR(VPOG5, VPOOFF1), SIG_EXPR_PTR(VPOG5, VPOOFF2));
+SIG_EXPR_DECL(SIOSCI, SIOSCI, AA21_DESC);
+SIG_EXPR_DECL(SIOSCI, ACPI, AA21_DESC);
+SIG_EXPR_LIST_DECL_DUAL(SIOSCI, SIOSCI, ACPI);
+SIG_EXPR_LIST_DECL_SINGLE(NORA3, PNOR, PNOR_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(GPIOZ3, GPIOZ3);
+MS_PIN_DECL_(AA21, SIG_EXPR_LIST_PTR(VPOG5), SIG_EXPR_LIST_PTR(SIOSCI),
+               SIG_EXPR_LIST_PTR(NORA3), SIG_EXPR_LIST_PTR(GPIOZ3));
+FUNC_GROUP_DECL(SIOSCI, AA21);
+
+FUNC_GROUP_DECL(ACPI, R22, R21, P22, P21, Y20, AB20, AB21, AA21);
+
+/* CRT DVO disabled, configured for single-edge mode */
+#define CRT_DVO_DS_DESC { ASPEED_IP_GFX, GFX064, GENMASK(7, 6), 0, 0 }
+
+/* CRT DVO disabled, configured for dual-edge mode */
+#define CRT_DVO_DD_DESC { ASPEED_IP_GFX, GFX064, GENMASK(7, 6), 1, 1 }
+
+/* CRT DVO enabled, configured for single-edge mode */
+#define CRT_DVO_ES_DESC { ASPEED_IP_GFX, GFX064, GENMASK(7, 6), 2, 2 }
+
+/* CRT DVO enabled, configured for dual-edge mode */
+#define CRT_DVO_ED_DESC { ASPEED_IP_GFX, GFX064, GENMASK(7, 6), 3, 3 }
+
+#define U21 204
+#define U21_DESC       SIG_DESC_SET(SCUA4, 20)
+SIG_EXPR_DECL(VPOG6, VPO, U21_DESC, VPO_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_DECL(VPOG6, VPOOFF1, U21_DESC, VPOOFF1_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_DECL(VPOG6, VPOOFF2, U21_DESC, VPOOFF2_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_LIST_DECL(VPOG6, SIG_EXPR_PTR(VPOG6, VPO),
+               SIG_EXPR_PTR(VPOG6, VPOOFF1), SIG_EXPR_PTR(VPOG6, VPOOFF2));
+SIG_EXPR_LIST_DECL_SINGLE(NORA4, PNOR, PNOR_DESC);
+MS_PIN_DECL(U21, GPIOZ4, VPOG6, NORA4);
+
+#define W22 205
+#define W22_DESC       SIG_DESC_SET(SCUA4, 21)
+SIG_EXPR_DECL(VPOG7, VPO, W22_DESC, VPO_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_DECL(VPOG7, VPOOFF1, W22_DESC, VPOOFF1_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_DECL(VPOG7, VPOOFF2, W22_DESC, VPOOFF2_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_LIST_DECL(VPOG7, SIG_EXPR_PTR(VPOG7, VPO),
+               SIG_EXPR_PTR(VPOG7, VPOOFF1), SIG_EXPR_PTR(VPOG7, VPOOFF2));
+SIG_EXPR_LIST_DECL_SINGLE(NORA5, PNOR, PNOR_DESC);
+MS_PIN_DECL(W22, GPIOZ5, VPOG7, NORA5);
+
+#define V22 206
+#define V22_DESC       SIG_DESC_SET(SCUA4, 22)
+SIG_EXPR_DECL(VPOG8, VPO, V22_DESC, VPO_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_DECL(VPOG8, VPOOFF1, V22_DESC, VPOOFF1_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_DECL(VPOG8, VPOOFF2, V22_DESC, VPOOFF2_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_LIST_DECL(VPOG8, SIG_EXPR_PTR(VPOG8, VPO),
+               SIG_EXPR_PTR(VPOG8, VPOOFF1), SIG_EXPR_PTR(VPOG8, VPOOFF2));
+SIG_EXPR_LIST_DECL_SINGLE(NORA6, PNOR, PNOR_DESC);
+MS_PIN_DECL(V22, GPIOZ6, VPOG8, NORA6);
+
+#define W21 207
+#define W21_DESC       SIG_DESC_SET(SCUA4, 23)
+SIG_EXPR_DECL(VPOG9, VPO, W21_DESC, VPO_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_DECL(VPOG9, VPOOFF1, W21_DESC, VPOOFF1_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_DECL(VPOG9, VPOOFF2, W21_DESC, VPOOFF2_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_LIST_DECL(VPOG9, SIG_EXPR_PTR(VPOG9, VPO),
+               SIG_EXPR_PTR(VPOG9, VPOOFF1), SIG_EXPR_PTR(VPOG9, VPOOFF2));
+SIG_EXPR_LIST_DECL_SINGLE(NORA7, PNOR, PNOR_DESC);
+MS_PIN_DECL(W21, GPIOZ7, VPOG9, NORA7);
+
+#define Y21 208
+#define Y21_DESC       SIG_DESC_SET(SCUA4, 24)
+SIG_EXPR_DECL(VPOR2, VPO, Y21_DESC, VPO_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_DECL(VPOR2, VPOOFF1, Y21_DESC, VPOOFF1_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_DECL(VPOR2, VPOOFF2, Y21_DESC, VPOOFF2_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_LIST_DECL(VPOR2, SIG_EXPR_PTR(VPOR2, VPO),
+               SIG_EXPR_PTR(VPOR2, VPOOFF1), SIG_EXPR_PTR(VPOR2, VPOOFF2));
+SIG_EXPR_LIST_DECL_SINGLE(SALT7, SALT7, Y21_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(NORD0, PNOR, PNOR_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(GPIOAA0, GPIOAA0);
+MS_PIN_DECL_(Y21, SIG_EXPR_LIST_PTR(VPOR2), SIG_EXPR_LIST_PTR(SALT7),
+               SIG_EXPR_LIST_PTR(NORD0), SIG_EXPR_LIST_PTR(GPIOAA0));
+FUNC_GROUP_DECL(SALT7, Y21);
+
+#define V21 209
+#define V21_DESC       SIG_DESC_SET(SCUA4, 25)
+SIG_EXPR_DECL(VPOR3, VPO, V21_DESC, VPO_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_DECL(VPOR3, VPOOFF1, V21_DESC, VPOOFF1_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_DECL(VPOR3, VPOOFF2, V21_DESC, VPOOFF2_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_LIST_DECL(VPOR3, SIG_EXPR_PTR(VPOR3, VPO),
+               SIG_EXPR_PTR(VPOR3, VPOOFF1), SIG_EXPR_PTR(VPOR3, VPOOFF2));
+SIG_EXPR_LIST_DECL_SINGLE(SALT8, SALT8, V21_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(NORD1, PNOR, PNOR_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(GPIOAA1, GPIOAA1);
+MS_PIN_DECL_(V21, SIG_EXPR_LIST_PTR(VPOR3), SIG_EXPR_LIST_PTR(SALT8),
+               SIG_EXPR_LIST_PTR(NORD1), SIG_EXPR_LIST_PTR(GPIOAA1));
+FUNC_GROUP_DECL(SALT8, V21);
+
+#define Y22 210
+#define Y22_DESC       SIG_DESC_SET(SCUA4, 26)
+SIG_EXPR_DECL(VPOR4, VPO, Y22_DESC, VPO_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_DECL(VPOR4, VPOOFF1, Y22_DESC, VPOOFF1_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_DECL(VPOR4, VPOOFF2, Y22_DESC, VPOOFF2_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_LIST_DECL(VPOR4, SIG_EXPR_PTR(VPOR4, VPO),
+               SIG_EXPR_PTR(VPOR4, VPOOFF1), SIG_EXPR_PTR(VPOR4, VPOOFF2));
+SIG_EXPR_LIST_DECL_SINGLE(SALT9, SALT9, Y22_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(NORD2, PNOR, PNOR_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(GPIOAA2, GPIOAA2);
+MS_PIN_DECL_(Y22, SIG_EXPR_LIST_PTR(VPOR4), SIG_EXPR_LIST_PTR(SALT9),
+               SIG_EXPR_LIST_PTR(NORD2), SIG_EXPR_LIST_PTR(GPIOAA2));
+FUNC_GROUP_DECL(SALT9, Y22);
+
+#define AA22 211
+#define AA22_DESC      SIG_DESC_SET(SCUA4, 27)
+SIG_EXPR_DECL(VPOR5, VPO, AA22_DESC, VPO_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_DECL(VPOR5, VPOOFF1, AA22_DESC, VPOOFF1_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_DECL(VPOR5, VPOOFF2, AA22_DESC, VPOOFF2_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_LIST_DECL(VPOR5, SIG_EXPR_PTR(VPOR5, VPO),
+               SIG_EXPR_PTR(VPOR5, VPOOFF1), SIG_EXPR_PTR(VPOR5, VPOOFF2));
+SIG_EXPR_LIST_DECL_SINGLE(SALT10, SALT10, AA22_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(NORD3, PNOR, PNOR_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(GPIOAA3, GPIOAA3);
+MS_PIN_DECL_(AA22, SIG_EXPR_LIST_PTR(VPOR5), SIG_EXPR_LIST_PTR(SALT10),
+               SIG_EXPR_LIST_PTR(NORD3), SIG_EXPR_LIST_PTR(GPIOAA3));
+FUNC_GROUP_DECL(SALT10, AA22);
+
+#define U22 212
+#define U22_DESC       SIG_DESC_SET(SCUA4, 28)
+SIG_EXPR_DECL(VPOR6, VPO, U22_DESC, VPO_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_DECL(VPOR6, VPOOFF1, U22_DESC, VPOOFF1_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_DECL(VPOR6, VPOOFF2, U22_DESC, VPOOFF2_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_LIST_DECL(VPOR6, SIG_EXPR_PTR(VPOR6, VPO),
+               SIG_EXPR_PTR(VPOR6, VPOOFF1), SIG_EXPR_PTR(VPOR6, VPOOFF2));
+SIG_EXPR_LIST_DECL_SINGLE(SALT11, SALT11, U22_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(NORD4, PNOR, PNOR_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(GPIOAA4, GPIOAA4);
+MS_PIN_DECL_(U22, SIG_EXPR_LIST_PTR(VPOR6), SIG_EXPR_LIST_PTR(SALT11),
+               SIG_EXPR_LIST_PTR(NORD4), SIG_EXPR_LIST_PTR(GPIOAA4));
+FUNC_GROUP_DECL(SALT11, U22);
+
+#define T20 213
+#define T20_DESC       SIG_DESC_SET(SCUA4, 29)
+SIG_EXPR_DECL(VPOR7, VPO, T20_DESC, VPO_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_DECL(VPOR7, VPOOFF1, T20_DESC, VPOOFF1_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_DECL(VPOR7, VPOOFF2, T20_DESC, VPOOFF2_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_LIST_DECL(VPOR7, SIG_EXPR_PTR(VPOR7, VPO),
+               SIG_EXPR_PTR(VPOR7, VPOOFF1), SIG_EXPR_PTR(VPOR7, VPOOFF2));
+SIG_EXPR_LIST_DECL_SINGLE(SALT12, SALT12, T20_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(NORD5, PNOR, PNOR_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(GPIOAA5, GPIOAA5);
+MS_PIN_DECL_(T20, SIG_EXPR_LIST_PTR(VPOR7), SIG_EXPR_LIST_PTR(SALT12),
+               SIG_EXPR_LIST_PTR(NORD5), SIG_EXPR_LIST_PTR(GPIOAA5));
+FUNC_GROUP_DECL(SALT12, T20);
+
+#define N18 214
+#define N18_DESC       SIG_DESC_SET(SCUA4, 30)
+SIG_EXPR_DECL(VPOR8, VPO, N18_DESC, VPO_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_DECL(VPOR8, VPOOFF1, N18_DESC, VPOOFF1_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_DECL(VPOR8, VPOOFF2, N18_DESC, VPOOFF2_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_LIST_DECL(VPOR8, SIG_EXPR_PTR(VPOR8, VPO),
+               SIG_EXPR_PTR(VPOR8, VPOOFF1), SIG_EXPR_PTR(VPOR8, VPOOFF2));
+SIG_EXPR_LIST_DECL_SINGLE(SALT13, SALT13, N18_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(NORD6, PNOR, PNOR_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(GPIOAA6, GPIOAA6);
+MS_PIN_DECL_(N18, SIG_EXPR_LIST_PTR(VPOR8), SIG_EXPR_LIST_PTR(SALT13),
+               SIG_EXPR_LIST_PTR(NORD6), SIG_EXPR_LIST_PTR(GPIOAA6));
+FUNC_GROUP_DECL(SALT13, N18);
+
+#define P19 215
+#define P19_DESC       SIG_DESC_SET(SCUA4, 31)
+SIG_EXPR_DECL(VPOR9, VPO, P19_DESC, VPO_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_DECL(VPOR9, VPOOFF1, P19_DESC, VPOOFF1_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_DECL(VPOR9, VPOOFF2, P19_DESC, VPOOFF2_DESC, CRT_DVO_ES_DESC);
+SIG_EXPR_LIST_DECL(VPOR9, SIG_EXPR_PTR(VPOR9, VPO),
+               SIG_EXPR_PTR(VPOR9, VPOOFF1), SIG_EXPR_PTR(VPOR9, VPOOFF2));
+SIG_EXPR_LIST_DECL_SINGLE(SALT14, SALT14, P19_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(NORD7, PNOR, PNOR_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(GPIOAA7, GPIOAA7);
+MS_PIN_DECL_(P19, SIG_EXPR_LIST_PTR(VPOR9), SIG_EXPR_LIST_PTR(SALT14),
+               SIG_EXPR_LIST_PTR(NORD7), SIG_EXPR_LIST_PTR(GPIOAA7));
+FUNC_GROUP_DECL(SALT14, P19);
+
+#define N19 216
+#define N19_DESC       SIG_DESC_SET(SCUA8, 0)
+SIG_EXPR_DECL(VPODE, VPO, N19_DESC, VPO_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPODE, VPOOFF1, N19_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPODE, VPOOFF2, N19_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_LIST_DECL(VPODE, SIG_EXPR_PTR(VPODE, VPO),
+               SIG_EXPR_PTR(VPODE, VPOOFF1), SIG_EXPR_PTR(VPODE, VPOOFF2));
+SIG_EXPR_LIST_DECL_SINGLE(NOROE, PNOR, PNOR_DESC);
+MS_PIN_DECL(N19, GPIOAB0, VPODE, NOROE);
+
+#define T21 217
+#define T21_DESC       SIG_DESC_SET(SCUA8, 1)
+SIG_EXPR_DECL(VPOHS, VPO, T21_DESC, VPO_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOHS, VPOOFF1, T21_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOHS, VPOOFF2, T21_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_LIST_DECL(VPOHS, SIG_EXPR_PTR(VPOHS, VPO),
+               SIG_EXPR_PTR(VPOHS, VPOOFF1), SIG_EXPR_PTR(VPOHS, VPOOFF2));
+SIG_EXPR_LIST_DECL_SINGLE(NORWE, PNOR, PNOR_DESC);
+MS_PIN_DECL(T21, GPIOAB1, VPOHS, NORWE);
+
+FUNC_GROUP_DECL(PNOR, Y20, AB20, AB21, AA21, U21, W22, V22, W21, Y21, V21, Y22,
+               AA22, U22, T20, N18, P19, N19, T21);
+
+#define T22 218
+#define T22_DESC       SIG_DESC_SET(SCUA8, 2)
+SIG_EXPR_DECL(VPOVS, VPO, T22_DESC, VPO_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOVS, VPOOFF1, T22_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOVS, VPOOFF2, T22_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_LIST_DECL(VPOVS, SIG_EXPR_PTR(VPOVS, VPO),
+               SIG_EXPR_PTR(VPOVS, VPOOFF1), SIG_EXPR_PTR(VPOVS, VPOOFF2));
+SIG_EXPR_LIST_DECL_SINGLE(WDTRST1, WDTRST1, T22_DESC);
+MS_PIN_DECL(T22, GPIOAB2, VPOVS, WDTRST1);
+FUNC_GROUP_DECL(WDTRST1, T22);
+
+#define R20 219
+#define R20_DESC       SIG_DESC_SET(SCUA8, 3)
+SIG_EXPR_DECL(VPOCLK, VPO, R20_DESC, VPO_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOCLK, VPOOFF1, R20_DESC, VPOOFF1_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_DECL(VPOCLK, VPOOFF2, R20_DESC, VPOOFF2_DESC, CRT_DVO_EN_DESC);
+SIG_EXPR_LIST_DECL(VPOCLK, SIG_EXPR_PTR(VPOCLK, VPO),
+               SIG_EXPR_PTR(VPOCLK, VPOOFF1), SIG_EXPR_PTR(VPOCLK, VPOOFF2));
+SIG_EXPR_LIST_DECL_SINGLE(WDTRST2, WDTRST2, R20_DESC);
+MS_PIN_DECL(R20, GPIOAB3, VPOCLK, WDTRST2);
+FUNC_GROUP_DECL(WDTRST2, R20);
+
+FUNC_GROUP_DECL(VPO, V20, U19, R18, P18, R19, W20, U20, AA20, Y20, AB20,
+               AB21, AA21, U21, W22, V22, W21, Y21, V21, Y22, AA22, U22, T20,
+               N18, P19, N19, T21, T22, R20);
+
+#define ESPI_DESC      SIG_DESC_SET(HW_STRAP1, 25)
+
+#define G21 224
+SIG_EXPR_LIST_DECL_SINGLE(ESPID0, ESPI, ESPI_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(LAD0, LAD0, SIG_DESC_SET(SCUAC, 0));
+MS_PIN_DECL(G21, GPIOAC0, ESPID0, LAD0);
+FUNC_GROUP_DECL(LAD0, G21);
+
+#define G20 225
+SIG_EXPR_LIST_DECL_SINGLE(ESPID1, ESPI, ESPI_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(LAD1, LAD1, SIG_DESC_SET(SCUAC, 1));
+MS_PIN_DECL(G20, GPIOAC1, ESPID1, LAD1);
+FUNC_GROUP_DECL(LAD1, G20);
+
+#define D22 226
+SIG_EXPR_LIST_DECL_SINGLE(ESPID2, ESPI, ESPI_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(LAD2, LAD2, SIG_DESC_SET(SCUAC, 2));
+MS_PIN_DECL(D22, GPIOAC2, ESPID2, LAD2);
+FUNC_GROUP_DECL(LAD2, D22);
+
+#define E22 227
+SIG_EXPR_LIST_DECL_SINGLE(ESPID3, ESPI, ESPI_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(LAD3, LAD3, SIG_DESC_SET(SCUAC, 3));
+MS_PIN_DECL(E22, GPIOAC3, ESPID3, LAD3);
+FUNC_GROUP_DECL(LAD3, E22);
+
+#define C22 228
+SIG_EXPR_LIST_DECL_SINGLE(ESPICK, ESPI, ESPI_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(LCLK, LCLK, SIG_DESC_SET(SCUAC, 4));
+MS_PIN_DECL(C22, GPIOAC4, ESPICK, LCLK);
+FUNC_GROUP_DECL(LCLK, C22);
+
+#define F21 229
+SIG_EXPR_LIST_DECL_SINGLE(ESPICS, ESPI, ESPI_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(LFRAME, LFRAME, SIG_DESC_SET(SCUAC, 5));
+MS_PIN_DECL(F21, GPIOAC5, ESPICS, LFRAME);
+FUNC_GROUP_DECL(LFRAME, F21);
+
+#define F22 230
+SIG_EXPR_LIST_DECL_SINGLE(ESPIALT, ESPI, ESPI_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(LSIRQ, LSIRQ, SIG_DESC_SET(SCUAC, 6));
+MS_PIN_DECL(F22, GPIOAC6, ESPIALT, LSIRQ);
+FUNC_GROUP_DECL(LSIRQ, F22);
+
+#define G22 231
+SIG_EXPR_LIST_DECL_SINGLE(ESPIRST, ESPI, ESPI_DESC);
+SIG_EXPR_LIST_DECL_SINGLE(LPCRST, LPCRST, SIG_DESC_SET(SCUAC, 7));
+MS_PIN_DECL(G22, GPIOAC7, ESPIRST, LPCRST);
+FUNC_GROUP_DECL(LPCRST, G22);
+
+FUNC_GROUP_DECL(ESPI, G21, G20, D22, E22, C22, F21, F22, G22);
+
 /* Pins, groups and functions are sort(1):ed alphabetically for sanity */
 
 static struct pinctrl_pin_desc aspeed_g5_pins[ASPEED_G5_NR_PINS] = {
@@ -641,12 +1733,32 @@ static struct pinctrl_pin_desc aspeed_g5_pins[ASPEED_G5_NR_PINS] = {
        ASPEED_PINCTRL_PIN(A13),
        ASPEED_PINCTRL_PIN(A14),
        ASPEED_PINCTRL_PIN(A15),
+       ASPEED_PINCTRL_PIN(A16),
+       ASPEED_PINCTRL_PIN(A17),
+       ASPEED_PINCTRL_PIN(A18),
+       ASPEED_PINCTRL_PIN(A19),
        ASPEED_PINCTRL_PIN(A2),
+       ASPEED_PINCTRL_PIN(A20),
+       ASPEED_PINCTRL_PIN(A21),
        ASPEED_PINCTRL_PIN(A3),
        ASPEED_PINCTRL_PIN(A4),
        ASPEED_PINCTRL_PIN(A5),
        ASPEED_PINCTRL_PIN(A9),
+       ASPEED_PINCTRL_PIN(AA1),
+       ASPEED_PINCTRL_PIN(AA19),
+       ASPEED_PINCTRL_PIN(AA2),
+       ASPEED_PINCTRL_PIN(AA20),
+       ASPEED_PINCTRL_PIN(AA21),
+       ASPEED_PINCTRL_PIN(AA22),
        ASPEED_PINCTRL_PIN(AA3),
+       ASPEED_PINCTRL_PIN(AA4),
+       ASPEED_PINCTRL_PIN(AA5),
+       ASPEED_PINCTRL_PIN(AB2),
+       ASPEED_PINCTRL_PIN(AB20),
+       ASPEED_PINCTRL_PIN(AB21),
+       ASPEED_PINCTRL_PIN(AB3),
+       ASPEED_PINCTRL_PIN(AB4),
+       ASPEED_PINCTRL_PIN(AB5),
        ASPEED_PINCTRL_PIN(B1),
        ASPEED_PINCTRL_PIN(B10),
        ASPEED_PINCTRL_PIN(B11),
@@ -655,8 +1767,13 @@ static struct pinctrl_pin_desc aspeed_g5_pins[ASPEED_G5_NR_PINS] = {
        ASPEED_PINCTRL_PIN(B14),
        ASPEED_PINCTRL_PIN(B15),
        ASPEED_PINCTRL_PIN(B16),
+       ASPEED_PINCTRL_PIN(B17),
+       ASPEED_PINCTRL_PIN(B18),
+       ASPEED_PINCTRL_PIN(B19),
        ASPEED_PINCTRL_PIN(B2),
        ASPEED_PINCTRL_PIN(B20),
+       ASPEED_PINCTRL_PIN(B21),
+       ASPEED_PINCTRL_PIN(B22),
        ASPEED_PINCTRL_PIN(B3),
        ASPEED_PINCTRL_PIN(B4),
        ASPEED_PINCTRL_PIN(B5),
@@ -668,62 +1785,210 @@ static struct pinctrl_pin_desc aspeed_g5_pins[ASPEED_G5_NR_PINS] = {
        ASPEED_PINCTRL_PIN(C14),
        ASPEED_PINCTRL_PIN(C15),
        ASPEED_PINCTRL_PIN(C16),
+       ASPEED_PINCTRL_PIN(C17),
        ASPEED_PINCTRL_PIN(C18),
+       ASPEED_PINCTRL_PIN(C19),
        ASPEED_PINCTRL_PIN(C2),
        ASPEED_PINCTRL_PIN(C20),
+       ASPEED_PINCTRL_PIN(C21),
+       ASPEED_PINCTRL_PIN(C22),
        ASPEED_PINCTRL_PIN(C3),
        ASPEED_PINCTRL_PIN(C4),
        ASPEED_PINCTRL_PIN(C5),
        ASPEED_PINCTRL_PIN(D1),
        ASPEED_PINCTRL_PIN(D10),
+       ASPEED_PINCTRL_PIN(D13),
+       ASPEED_PINCTRL_PIN(D14),
+       ASPEED_PINCTRL_PIN(D15),
+       ASPEED_PINCTRL_PIN(D16),
+       ASPEED_PINCTRL_PIN(D17),
+       ASPEED_PINCTRL_PIN(D18),
+       ASPEED_PINCTRL_PIN(D19),
        ASPEED_PINCTRL_PIN(D2),
        ASPEED_PINCTRL_PIN(D20),
+       ASPEED_PINCTRL_PIN(D21),
+       ASPEED_PINCTRL_PIN(D22),
        ASPEED_PINCTRL_PIN(D4),
        ASPEED_PINCTRL_PIN(D5),
        ASPEED_PINCTRL_PIN(D6),
        ASPEED_PINCTRL_PIN(D7),
        ASPEED_PINCTRL_PIN(D8),
        ASPEED_PINCTRL_PIN(D9),
+       ASPEED_PINCTRL_PIN(E1),
        ASPEED_PINCTRL_PIN(E10),
        ASPEED_PINCTRL_PIN(E12),
        ASPEED_PINCTRL_PIN(E13),
+       ASPEED_PINCTRL_PIN(E14),
        ASPEED_PINCTRL_PIN(E15),
+       ASPEED_PINCTRL_PIN(E16),
+       ASPEED_PINCTRL_PIN(E17),
+       ASPEED_PINCTRL_PIN(E18),
+       ASPEED_PINCTRL_PIN(E19),
+       ASPEED_PINCTRL_PIN(E2),
+       ASPEED_PINCTRL_PIN(E20),
        ASPEED_PINCTRL_PIN(E21),
+       ASPEED_PINCTRL_PIN(E22),
+       ASPEED_PINCTRL_PIN(E3),
        ASPEED_PINCTRL_PIN(E6),
        ASPEED_PINCTRL_PIN(E7),
        ASPEED_PINCTRL_PIN(E9),
+       ASPEED_PINCTRL_PIN(F1),
+       ASPEED_PINCTRL_PIN(F17),
+       ASPEED_PINCTRL_PIN(F18),
        ASPEED_PINCTRL_PIN(F19),
+       ASPEED_PINCTRL_PIN(F2),
        ASPEED_PINCTRL_PIN(F20),
+       ASPEED_PINCTRL_PIN(F21),
+       ASPEED_PINCTRL_PIN(F22),
+       ASPEED_PINCTRL_PIN(F3),
+       ASPEED_PINCTRL_PIN(F4),
+       ASPEED_PINCTRL_PIN(F5),
        ASPEED_PINCTRL_PIN(F9),
+       ASPEED_PINCTRL_PIN(G1),
+       ASPEED_PINCTRL_PIN(G17),
+       ASPEED_PINCTRL_PIN(G18),
+       ASPEED_PINCTRL_PIN(G2),
+       ASPEED_PINCTRL_PIN(G20),
+       ASPEED_PINCTRL_PIN(G21),
+       ASPEED_PINCTRL_PIN(G22),
+       ASPEED_PINCTRL_PIN(G3),
+       ASPEED_PINCTRL_PIN(G4),
+       ASPEED_PINCTRL_PIN(G5),
+       ASPEED_PINCTRL_PIN(H18),
+       ASPEED_PINCTRL_PIN(H19),
        ASPEED_PINCTRL_PIN(H20),
+       ASPEED_PINCTRL_PIN(H21),
+       ASPEED_PINCTRL_PIN(H22),
+       ASPEED_PINCTRL_PIN(H3),
+       ASPEED_PINCTRL_PIN(H4),
+       ASPEED_PINCTRL_PIN(H5),
+       ASPEED_PINCTRL_PIN(J18),
+       ASPEED_PINCTRL_PIN(J19),
+       ASPEED_PINCTRL_PIN(J20),
+       ASPEED_PINCTRL_PIN(K18),
+       ASPEED_PINCTRL_PIN(K19),
        ASPEED_PINCTRL_PIN(L1),
+       ASPEED_PINCTRL_PIN(L18),
+       ASPEED_PINCTRL_PIN(L19),
        ASPEED_PINCTRL_PIN(L2),
        ASPEED_PINCTRL_PIN(L3),
        ASPEED_PINCTRL_PIN(L4),
+       ASPEED_PINCTRL_PIN(M18),
+       ASPEED_PINCTRL_PIN(M19),
+       ASPEED_PINCTRL_PIN(M20),
        ASPEED_PINCTRL_PIN(N1),
+       ASPEED_PINCTRL_PIN(N18),
+       ASPEED_PINCTRL_PIN(N19),
        ASPEED_PINCTRL_PIN(N2),
        ASPEED_PINCTRL_PIN(N20),
        ASPEED_PINCTRL_PIN(N21),
        ASPEED_PINCTRL_PIN(N22),
        ASPEED_PINCTRL_PIN(N3),
        ASPEED_PINCTRL_PIN(N4),
+       ASPEED_PINCTRL_PIN(N5),
        ASPEED_PINCTRL_PIN(P1),
+       ASPEED_PINCTRL_PIN(P18),
+       ASPEED_PINCTRL_PIN(P19),
        ASPEED_PINCTRL_PIN(P2),
+       ASPEED_PINCTRL_PIN(P20),
+       ASPEED_PINCTRL_PIN(P21),
+       ASPEED_PINCTRL_PIN(P22),
+       ASPEED_PINCTRL_PIN(P3),
+       ASPEED_PINCTRL_PIN(P4),
+       ASPEED_PINCTRL_PIN(P5),
        ASPEED_PINCTRL_PIN(R1),
+       ASPEED_PINCTRL_PIN(R18),
+       ASPEED_PINCTRL_PIN(R19),
+       ASPEED_PINCTRL_PIN(R2),
+       ASPEED_PINCTRL_PIN(R20),
+       ASPEED_PINCTRL_PIN(R21),
+       ASPEED_PINCTRL_PIN(R22),
+       ASPEED_PINCTRL_PIN(R3),
+       ASPEED_PINCTRL_PIN(R4),
+       ASPEED_PINCTRL_PIN(R5),
+       ASPEED_PINCTRL_PIN(T1),
+       ASPEED_PINCTRL_PIN(T17),
+       ASPEED_PINCTRL_PIN(T19),
+       ASPEED_PINCTRL_PIN(T2),
+       ASPEED_PINCTRL_PIN(T20),
+       ASPEED_PINCTRL_PIN(T21),
+       ASPEED_PINCTRL_PIN(T22),
+       ASPEED_PINCTRL_PIN(T3),
        ASPEED_PINCTRL_PIN(T4),
+       ASPEED_PINCTRL_PIN(T5),
+       ASPEED_PINCTRL_PIN(U1),
+       ASPEED_PINCTRL_PIN(U19),
+       ASPEED_PINCTRL_PIN(U2),
+       ASPEED_PINCTRL_PIN(U20),
+       ASPEED_PINCTRL_PIN(U21),
+       ASPEED_PINCTRL_PIN(U22),
        ASPEED_PINCTRL_PIN(U3),
+       ASPEED_PINCTRL_PIN(U4),
+       ASPEED_PINCTRL_PIN(U5),
+       ASPEED_PINCTRL_PIN(V1),
+       ASPEED_PINCTRL_PIN(V19),
        ASPEED_PINCTRL_PIN(V2),
+       ASPEED_PINCTRL_PIN(V20),
+       ASPEED_PINCTRL_PIN(V21),
+       ASPEED_PINCTRL_PIN(V22),
        ASPEED_PINCTRL_PIN(V3),
+       ASPEED_PINCTRL_PIN(V4),
+       ASPEED_PINCTRL_PIN(V5),
        ASPEED_PINCTRL_PIN(V6),
+       ASPEED_PINCTRL_PIN(W1),
+       ASPEED_PINCTRL_PIN(W19),
        ASPEED_PINCTRL_PIN(W2),
+       ASPEED_PINCTRL_PIN(W20),
+       ASPEED_PINCTRL_PIN(W21),
+       ASPEED_PINCTRL_PIN(W22),
        ASPEED_PINCTRL_PIN(W3),
+       ASPEED_PINCTRL_PIN(W4),
+       ASPEED_PINCTRL_PIN(W5),
+       ASPEED_PINCTRL_PIN(W6),
+       ASPEED_PINCTRL_PIN(Y1),
+       ASPEED_PINCTRL_PIN(Y19),
+       ASPEED_PINCTRL_PIN(Y2),
+       ASPEED_PINCTRL_PIN(Y20),
+       ASPEED_PINCTRL_PIN(Y21),
+       ASPEED_PINCTRL_PIN(Y22),
        ASPEED_PINCTRL_PIN(Y3),
+       ASPEED_PINCTRL_PIN(Y4),
+       ASPEED_PINCTRL_PIN(Y5),
+       ASPEED_PINCTRL_PIN(Y6),
 };
 
 static const struct aspeed_pin_group aspeed_g5_groups[] = {
+       ASPEED_PINCTRL_GROUP(ACPI),
+       ASPEED_PINCTRL_GROUP(ADC0),
+       ASPEED_PINCTRL_GROUP(ADC1),
+       ASPEED_PINCTRL_GROUP(ADC10),
+       ASPEED_PINCTRL_GROUP(ADC11),
+       ASPEED_PINCTRL_GROUP(ADC12),
+       ASPEED_PINCTRL_GROUP(ADC13),
+       ASPEED_PINCTRL_GROUP(ADC14),
+       ASPEED_PINCTRL_GROUP(ADC15),
+       ASPEED_PINCTRL_GROUP(ADC2),
+       ASPEED_PINCTRL_GROUP(ADC3),
+       ASPEED_PINCTRL_GROUP(ADC4),
+       ASPEED_PINCTRL_GROUP(ADC5),
+       ASPEED_PINCTRL_GROUP(ADC6),
+       ASPEED_PINCTRL_GROUP(ADC7),
+       ASPEED_PINCTRL_GROUP(ADC8),
+       ASPEED_PINCTRL_GROUP(ADC9),
+       ASPEED_PINCTRL_GROUP(BMCINT),
+       ASPEED_PINCTRL_GROUP(DDCCLK),
+       ASPEED_PINCTRL_GROUP(DDCDAT),
+       ASPEED_PINCTRL_GROUP(ESPI),
+       ASPEED_PINCTRL_GROUP(FWSPICS1),
+       ASPEED_PINCTRL_GROUP(FWSPICS2),
        ASPEED_PINCTRL_GROUP(GPID0),
        ASPEED_PINCTRL_GROUP(GPID2),
+       ASPEED_PINCTRL_GROUP(GPID4),
+       ASPEED_PINCTRL_GROUP(GPID6),
        ASPEED_PINCTRL_GROUP(GPIE0),
+       ASPEED_PINCTRL_GROUP(GPIE2),
+       ASPEED_PINCTRL_GROUP(GPIE4),
+       ASPEED_PINCTRL_GROUP(GPIE6),
        ASPEED_PINCTRL_GROUP(I2C10),
        ASPEED_PINCTRL_GROUP(I2C11),
        ASPEED_PINCTRL_GROUP(I2C12),
@@ -736,11 +2001,50 @@ static const struct aspeed_pin_group aspeed_g5_groups[] = {
        ASPEED_PINCTRL_GROUP(I2C7),
        ASPEED_PINCTRL_GROUP(I2C8),
        ASPEED_PINCTRL_GROUP(I2C9),
+       ASPEED_PINCTRL_GROUP(LAD0),
+       ASPEED_PINCTRL_GROUP(LAD1),
+       ASPEED_PINCTRL_GROUP(LAD2),
+       ASPEED_PINCTRL_GROUP(LAD3),
+       ASPEED_PINCTRL_GROUP(LCLK),
+       ASPEED_PINCTRL_GROUP(LFRAME),
+       ASPEED_PINCTRL_GROUP(LPCHC),
+       ASPEED_PINCTRL_GROUP(LPCPD),
+       ASPEED_PINCTRL_GROUP(LPCPLUS),
+       ASPEED_PINCTRL_GROUP(LPCPME),
+       ASPEED_PINCTRL_GROUP(LPCRST),
+       ASPEED_PINCTRL_GROUP(LPCSMI),
+       ASPEED_PINCTRL_GROUP(LSIRQ),
        ASPEED_PINCTRL_GROUP(MAC1LINK),
+       ASPEED_PINCTRL_GROUP(MAC2LINK),
        ASPEED_PINCTRL_GROUP(MDIO1),
        ASPEED_PINCTRL_GROUP(MDIO2),
+       ASPEED_PINCTRL_GROUP(NCTS1),
+       ASPEED_PINCTRL_GROUP(NCTS2),
+       ASPEED_PINCTRL_GROUP(NCTS3),
+       ASPEED_PINCTRL_GROUP(NCTS4),
+       ASPEED_PINCTRL_GROUP(NDCD1),
+       ASPEED_PINCTRL_GROUP(NDCD2),
+       ASPEED_PINCTRL_GROUP(NDCD3),
+       ASPEED_PINCTRL_GROUP(NDCD4),
+       ASPEED_PINCTRL_GROUP(NDSR1),
+       ASPEED_PINCTRL_GROUP(NDSR2),
+       ASPEED_PINCTRL_GROUP(NDSR3),
+       ASPEED_PINCTRL_GROUP(NDSR4),
+       ASPEED_PINCTRL_GROUP(NDTR1),
+       ASPEED_PINCTRL_GROUP(NDTR2),
+       ASPEED_PINCTRL_GROUP(NDTR3),
+       ASPEED_PINCTRL_GROUP(NDTR4),
+       ASPEED_PINCTRL_GROUP(NRI1),
+       ASPEED_PINCTRL_GROUP(NRI2),
+       ASPEED_PINCTRL_GROUP(NRI3),
+       ASPEED_PINCTRL_GROUP(NRI4),
+       ASPEED_PINCTRL_GROUP(NRTS1),
+       ASPEED_PINCTRL_GROUP(NRTS2),
+       ASPEED_PINCTRL_GROUP(NRTS3),
+       ASPEED_PINCTRL_GROUP(NRTS4),
        ASPEED_PINCTRL_GROUP(OSCCLK),
        ASPEED_PINCTRL_GROUP(PEWAKE),
+       ASPEED_PINCTRL_GROUP(PNOR),
        ASPEED_PINCTRL_GROUP(PWM0),
        ASPEED_PINCTRL_GROUP(PWM1),
        ASPEED_PINCTRL_GROUP(PWM2),
@@ -753,22 +2057,102 @@ static const struct aspeed_pin_group aspeed_g5_groups[] = {
        ASPEED_PINCTRL_GROUP(RGMII2),
        ASPEED_PINCTRL_GROUP(RMII1),
        ASPEED_PINCTRL_GROUP(RMII2),
+       ASPEED_PINCTRL_GROUP(RXD1),
+       ASPEED_PINCTRL_GROUP(RXD2),
+       ASPEED_PINCTRL_GROUP(RXD3),
+       ASPEED_PINCTRL_GROUP(RXD4),
+       ASPEED_PINCTRL_GROUP(SALT1),
+       ASPEED_PINCTRL_GROUP(SALT10),
+       ASPEED_PINCTRL_GROUP(SALT11),
+       ASPEED_PINCTRL_GROUP(SALT12),
+       ASPEED_PINCTRL_GROUP(SALT13),
+       ASPEED_PINCTRL_GROUP(SALT14),
+       ASPEED_PINCTRL_GROUP(SALT2),
+       ASPEED_PINCTRL_GROUP(SALT3),
+       ASPEED_PINCTRL_GROUP(SALT4),
+       ASPEED_PINCTRL_GROUP(SALT5),
+       ASPEED_PINCTRL_GROUP(SALT6),
+       ASPEED_PINCTRL_GROUP(SALT7),
+       ASPEED_PINCTRL_GROUP(SALT8),
+       ASPEED_PINCTRL_GROUP(SALT9),
+       ASPEED_PINCTRL_GROUP(SCL1),
+       ASPEED_PINCTRL_GROUP(SCL2),
        ASPEED_PINCTRL_GROUP(SD1),
+       ASPEED_PINCTRL_GROUP(SD2),
+       ASPEED_PINCTRL_GROUP(SDA1),
+       ASPEED_PINCTRL_GROUP(SDA2),
+       ASPEED_PINCTRL_GROUP(SGPS1),
+       ASPEED_PINCTRL_GROUP(SGPS2),
+       ASPEED_PINCTRL_GROUP(SIOONCTRL),
+       ASPEED_PINCTRL_GROUP(SIOPBI),
+       ASPEED_PINCTRL_GROUP(SIOPBO),
+       ASPEED_PINCTRL_GROUP(SIOPWREQ),
+       ASPEED_PINCTRL_GROUP(SIOPWRGD),
+       ASPEED_PINCTRL_GROUP(SIOS3),
+       ASPEED_PINCTRL_GROUP(SIOS5),
+       ASPEED_PINCTRL_GROUP(SIOSCI),
        ASPEED_PINCTRL_GROUP(SPI1),
+       ASPEED_PINCTRL_GROUP(SPI1CS1),
        ASPEED_PINCTRL_GROUP(SPI1DEBUG),
        ASPEED_PINCTRL_GROUP(SPI1PASSTHRU),
+       ASPEED_PINCTRL_GROUP(SPI2CK),
+       ASPEED_PINCTRL_GROUP(SPI2CS0),
+       ASPEED_PINCTRL_GROUP(SPI2CS1),
+       ASPEED_PINCTRL_GROUP(SPI2MISO),
+       ASPEED_PINCTRL_GROUP(SPI2MOSI),
+       ASPEED_PINCTRL_GROUP(TIMER3),
        ASPEED_PINCTRL_GROUP(TIMER4),
        ASPEED_PINCTRL_GROUP(TIMER5),
        ASPEED_PINCTRL_GROUP(TIMER6),
        ASPEED_PINCTRL_GROUP(TIMER7),
        ASPEED_PINCTRL_GROUP(TIMER8),
+       ASPEED_PINCTRL_GROUP(TXD1),
+       ASPEED_PINCTRL_GROUP(TXD2),
+       ASPEED_PINCTRL_GROUP(TXD3),
+       ASPEED_PINCTRL_GROUP(TXD4),
+       ASPEED_PINCTRL_GROUP(UART6),
+       ASPEED_PINCTRL_GROUP(USBCKI),
        ASPEED_PINCTRL_GROUP(VGABIOSROM),
+       ASPEED_PINCTRL_GROUP(VGAHS),
+       ASPEED_PINCTRL_GROUP(VGAVS),
+       ASPEED_PINCTRL_GROUP(VPI24),
+       ASPEED_PINCTRL_GROUP(VPO),
+       ASPEED_PINCTRL_GROUP(WDTRST1),
+       ASPEED_PINCTRL_GROUP(WDTRST2),
 };
 
 static const struct aspeed_pin_function aspeed_g5_functions[] = {
+       ASPEED_PINCTRL_FUNC(ACPI),
+       ASPEED_PINCTRL_FUNC(ADC0),
+       ASPEED_PINCTRL_FUNC(ADC1),
+       ASPEED_PINCTRL_FUNC(ADC10),
+       ASPEED_PINCTRL_FUNC(ADC11),
+       ASPEED_PINCTRL_FUNC(ADC12),
+       ASPEED_PINCTRL_FUNC(ADC13),
+       ASPEED_PINCTRL_FUNC(ADC14),
+       ASPEED_PINCTRL_FUNC(ADC15),
+       ASPEED_PINCTRL_FUNC(ADC2),
+       ASPEED_PINCTRL_FUNC(ADC3),
+       ASPEED_PINCTRL_FUNC(ADC4),
+       ASPEED_PINCTRL_FUNC(ADC5),
+       ASPEED_PINCTRL_FUNC(ADC6),
+       ASPEED_PINCTRL_FUNC(ADC7),
+       ASPEED_PINCTRL_FUNC(ADC8),
+       ASPEED_PINCTRL_FUNC(ADC9),
+       ASPEED_PINCTRL_FUNC(BMCINT),
+       ASPEED_PINCTRL_FUNC(DDCCLK),
+       ASPEED_PINCTRL_FUNC(DDCDAT),
+       ASPEED_PINCTRL_FUNC(ESPI),
+       ASPEED_PINCTRL_FUNC(FWSPICS1),
+       ASPEED_PINCTRL_FUNC(FWSPICS2),
        ASPEED_PINCTRL_FUNC(GPID0),
        ASPEED_PINCTRL_FUNC(GPID2),
+       ASPEED_PINCTRL_FUNC(GPID4),
+       ASPEED_PINCTRL_FUNC(GPID6),
        ASPEED_PINCTRL_FUNC(GPIE0),
+       ASPEED_PINCTRL_FUNC(GPIE2),
+       ASPEED_PINCTRL_FUNC(GPIE4),
+       ASPEED_PINCTRL_FUNC(GPIE6),
        ASPEED_PINCTRL_FUNC(I2C10),
        ASPEED_PINCTRL_FUNC(I2C11),
        ASPEED_PINCTRL_FUNC(I2C12),
@@ -781,11 +2165,50 @@ static const struct aspeed_pin_function aspeed_g5_functions[] = {
        ASPEED_PINCTRL_FUNC(I2C7),
        ASPEED_PINCTRL_FUNC(I2C8),
        ASPEED_PINCTRL_FUNC(I2C9),
+       ASPEED_PINCTRL_FUNC(LAD0),
+       ASPEED_PINCTRL_FUNC(LAD1),
+       ASPEED_PINCTRL_FUNC(LAD2),
+       ASPEED_PINCTRL_FUNC(LAD3),
+       ASPEED_PINCTRL_FUNC(LCLK),
+       ASPEED_PINCTRL_FUNC(LFRAME),
+       ASPEED_PINCTRL_FUNC(LPCHC),
+       ASPEED_PINCTRL_FUNC(LPCPD),
+       ASPEED_PINCTRL_FUNC(LPCPLUS),
+       ASPEED_PINCTRL_FUNC(LPCPME),
+       ASPEED_PINCTRL_FUNC(LPCRST),
+       ASPEED_PINCTRL_FUNC(LPCSMI),
+       ASPEED_PINCTRL_FUNC(LSIRQ),
        ASPEED_PINCTRL_FUNC(MAC1LINK),
+       ASPEED_PINCTRL_FUNC(MAC2LINK),
        ASPEED_PINCTRL_FUNC(MDIO1),
        ASPEED_PINCTRL_FUNC(MDIO2),
+       ASPEED_PINCTRL_FUNC(NCTS1),
+       ASPEED_PINCTRL_FUNC(NCTS2),
+       ASPEED_PINCTRL_FUNC(NCTS3),
+       ASPEED_PINCTRL_FUNC(NCTS4),
+       ASPEED_PINCTRL_FUNC(NDCD1),
+       ASPEED_PINCTRL_FUNC(NDCD2),
+       ASPEED_PINCTRL_FUNC(NDCD3),
+       ASPEED_PINCTRL_FUNC(NDCD4),
+       ASPEED_PINCTRL_FUNC(NDSR1),
+       ASPEED_PINCTRL_FUNC(NDSR2),
+       ASPEED_PINCTRL_FUNC(NDSR3),
+       ASPEED_PINCTRL_FUNC(NDSR4),
+       ASPEED_PINCTRL_FUNC(NDTR1),
+       ASPEED_PINCTRL_FUNC(NDTR2),
+       ASPEED_PINCTRL_FUNC(NDTR3),
+       ASPEED_PINCTRL_FUNC(NDTR4),
+       ASPEED_PINCTRL_FUNC(NRI1),
+       ASPEED_PINCTRL_FUNC(NRI2),
+       ASPEED_PINCTRL_FUNC(NRI3),
+       ASPEED_PINCTRL_FUNC(NRI4),
+       ASPEED_PINCTRL_FUNC(NRTS1),
+       ASPEED_PINCTRL_FUNC(NRTS2),
+       ASPEED_PINCTRL_FUNC(NRTS3),
+       ASPEED_PINCTRL_FUNC(NRTS4),
        ASPEED_PINCTRL_FUNC(OSCCLK),
        ASPEED_PINCTRL_FUNC(PEWAKE),
+       ASPEED_PINCTRL_FUNC(PNOR),
        ASPEED_PINCTRL_FUNC(PWM0),
        ASPEED_PINCTRL_FUNC(PWM1),
        ASPEED_PINCTRL_FUNC(PWM2),
@@ -798,16 +2221,68 @@ static const struct aspeed_pin_function aspeed_g5_functions[] = {
        ASPEED_PINCTRL_FUNC(RGMII2),
        ASPEED_PINCTRL_FUNC(RMII1),
        ASPEED_PINCTRL_FUNC(RMII2),
+       ASPEED_PINCTRL_FUNC(RXD1),
+       ASPEED_PINCTRL_FUNC(RXD2),
+       ASPEED_PINCTRL_FUNC(RXD3),
+       ASPEED_PINCTRL_FUNC(RXD4),
+       ASPEED_PINCTRL_FUNC(SALT1),
+       ASPEED_PINCTRL_FUNC(SALT10),
+       ASPEED_PINCTRL_FUNC(SALT11),
+       ASPEED_PINCTRL_FUNC(SALT12),
+       ASPEED_PINCTRL_FUNC(SALT13),
+       ASPEED_PINCTRL_FUNC(SALT14),
+       ASPEED_PINCTRL_FUNC(SALT2),
+       ASPEED_PINCTRL_FUNC(SALT3),
+       ASPEED_PINCTRL_FUNC(SALT4),
+       ASPEED_PINCTRL_FUNC(SALT5),
+       ASPEED_PINCTRL_FUNC(SALT6),
+       ASPEED_PINCTRL_FUNC(SALT7),
+       ASPEED_PINCTRL_FUNC(SALT8),
+       ASPEED_PINCTRL_FUNC(SALT9),
+       ASPEED_PINCTRL_FUNC(SCL1),
+       ASPEED_PINCTRL_FUNC(SCL2),
        ASPEED_PINCTRL_FUNC(SD1),
+       ASPEED_PINCTRL_FUNC(SD2),
+       ASPEED_PINCTRL_FUNC(SDA1),
+       ASPEED_PINCTRL_FUNC(SDA2),
+       ASPEED_PINCTRL_FUNC(SGPS1),
+       ASPEED_PINCTRL_FUNC(SGPS2),
+       ASPEED_PINCTRL_FUNC(SIOONCTRL),
+       ASPEED_PINCTRL_FUNC(SIOPBI),
+       ASPEED_PINCTRL_FUNC(SIOPBO),
+       ASPEED_PINCTRL_FUNC(SIOPWREQ),
+       ASPEED_PINCTRL_FUNC(SIOPWRGD),
+       ASPEED_PINCTRL_FUNC(SIOS3),
+       ASPEED_PINCTRL_FUNC(SIOS5),
+       ASPEED_PINCTRL_FUNC(SIOSCI),
        ASPEED_PINCTRL_FUNC(SPI1),
+       ASPEED_PINCTRL_FUNC(SPI1CS1),
        ASPEED_PINCTRL_FUNC(SPI1DEBUG),
        ASPEED_PINCTRL_FUNC(SPI1PASSTHRU),
+       ASPEED_PINCTRL_FUNC(SPI2CK),
+       ASPEED_PINCTRL_FUNC(SPI2CS0),
+       ASPEED_PINCTRL_FUNC(SPI2CS1),
+       ASPEED_PINCTRL_FUNC(SPI2MISO),
+       ASPEED_PINCTRL_FUNC(SPI2MOSI),
+       ASPEED_PINCTRL_FUNC(TIMER3),
        ASPEED_PINCTRL_FUNC(TIMER4),
        ASPEED_PINCTRL_FUNC(TIMER5),
        ASPEED_PINCTRL_FUNC(TIMER6),
        ASPEED_PINCTRL_FUNC(TIMER7),
        ASPEED_PINCTRL_FUNC(TIMER8),
+       ASPEED_PINCTRL_FUNC(TXD1),
+       ASPEED_PINCTRL_FUNC(TXD2),
+       ASPEED_PINCTRL_FUNC(TXD3),
+       ASPEED_PINCTRL_FUNC(TXD4),
+       ASPEED_PINCTRL_FUNC(UART6),
+       ASPEED_PINCTRL_FUNC(USBCKI),
        ASPEED_PINCTRL_FUNC(VGABIOSROM),
+       ASPEED_PINCTRL_FUNC(VGAHS),
+       ASPEED_PINCTRL_FUNC(VGAVS),
+       ASPEED_PINCTRL_FUNC(VPI24),
+       ASPEED_PINCTRL_FUNC(VPO),
+       ASPEED_PINCTRL_FUNC(WDTRST1),
+       ASPEED_PINCTRL_FUNC(WDTRST2),
 };
 
 static struct aspeed_pinctrl_data aspeed_g5_pinctrl_data = {
@@ -848,10 +2323,35 @@ static struct pinctrl_desc aspeed_g5_pinctrl_desc = {
 static int aspeed_g5_pinctrl_probe(struct platform_device *pdev)
 {
        int i;
+       struct regmap *map;
+       struct device_node *node;
 
        for (i = 0; i < ARRAY_SIZE(aspeed_g5_pins); i++)
                aspeed_g5_pins[i].number = i;
 
+       node = of_parse_phandle(pdev->dev.of_node, "aspeed,external-nodes", 0);
+       map = syscon_node_to_regmap(node);
+       of_node_put(node);
+       if (IS_ERR(map)) {
+               dev_warn(&pdev->dev, "No GFX phandle found, some mux configurations may fail\n");
+               map = NULL;
+       }
+       aspeed_g5_pinctrl_data.maps[ASPEED_IP_GFX] = map;
+
+       node = of_parse_phandle(pdev->dev.of_node, "aspeed,external-nodes", 1);
+       if (node) {
+               map = syscon_node_to_regmap(node->parent);
+               if (IS_ERR(map)) {
+                       dev_warn(&pdev->dev, "LHC parent is not a syscon, some mux configurations may fail\n");
+                       map = NULL;
+               }
+       } else {
+               dev_warn(&pdev->dev, "No LHC phandle found, some mux configurations may fail\n");
+               map = NULL;
+       }
+       of_node_put(node);
+       aspeed_g5_pinctrl_data.maps[ASPEED_IP_LPC] = map;
+
        return aspeed_pinctrl_probe(pdev, &aspeed_g5_pinctrl_desc,
                        &aspeed_g5_pinctrl_data);
 }
index 49aeba91253198c644794c23cb4877368f6905ad..76f62bd45f022b4512e9a5683ed62aa8bda9d170 100644 (file)
 #include "../core.h"
 #include "pinctrl-aspeed.h"
 
+static const char *const aspeed_pinmux_ips[] = {
+       [ASPEED_IP_SCU] = "SCU",
+       [ASPEED_IP_GFX] = "GFX",
+       [ASPEED_IP_LPC] = "LPC",
+};
+
 int aspeed_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
 {
        struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
@@ -78,7 +84,8 @@ int aspeed_pinmux_get_fn_groups(struct pinctrl_dev *pctldev,
 static inline void aspeed_sig_desc_print_val(
                const struct aspeed_sig_desc *desc, bool enable, u32 rv)
 {
-       pr_debug("SCU%x[0x%08x]=0x%x, got 0x%x from 0x%08x\n", desc->reg,
+       pr_debug("Want %s%X[0x%08X]=0x%X, got 0x%X from 0x%08X\n",
+                       aspeed_pinmux_ips[desc->ip], desc->reg,
                        desc->mask, enable ? desc->enable : desc->disable,
                        (rv & desc->mask) >> __ffs(desc->mask), rv);
 }
@@ -88,10 +95,11 @@ static inline void aspeed_sig_desc_print_val(
  *
  * @desc: The signal descriptor of interest
  * @enabled: True to query the enabled state, false to query disabled state
- * @regmap: The SCU regmap instance
+ * @regmap: The IP block's regmap instance
  *
- * @return True if the descriptor's bitfield is configured to the state
- * selected by @enabled, false otherwise
+ * Return: 1 if the descriptor's bitfield is configured to the state
+ * selected by @enabled, 0 if not, and less than zero if an unrecoverable
+ * failure occurred
  *
  * Evaluation of descriptor state is non-trivial in that it is not a binary
  * outcome: The bitfields can be greater than one bit in size and thus can take
@@ -99,14 +107,19 @@ static inline void aspeed_sig_desc_print_val(
  * descriptor (typically this means a different function to the one of interest
  * is enabled). Thus we must explicitly test for either condition as required.
  */
-static bool aspeed_sig_desc_eval(const struct aspeed_sig_desc *desc,
+static int aspeed_sig_desc_eval(const struct aspeed_sig_desc *desc,
                                 bool enabled, struct regmap *map)
 {
+       int ret;
        unsigned int raw;
        u32 want;
 
-       if (regmap_read(map, desc->reg, &raw) < 0)
-               return false;
+       if (!map)
+               return -ENODEV;
+
+       ret = regmap_read(map, desc->reg, &raw);
+       if (ret)
+               return ret;
 
        aspeed_sig_desc_print_val(desc, enabled, raw);
        want = enabled ? desc->enable : desc->disable;
@@ -119,10 +132,10 @@ static bool aspeed_sig_desc_eval(const struct aspeed_sig_desc *desc,
  *
  * @expr: An expression controlling the signal for a mux function on a pin
  * @enabled: True to query the enabled state, false to query disabled state
- * @regmap: The SCU regmap instance
+ * @maps: The list of regmap instances
  *
- * @return True if the expression composed by @enabled evaluates true, false
- * otherwise
+ * Return: 1 if the expression composed by @enabled evaluates true, 0 if not,
+ * and less than zero if an unrecoverable failure occurred.
  *
  * A mux function is enabled or disabled if the function's signal expression
  * for each pin in the function's pin group evaluates true for the desired
@@ -135,19 +148,21 @@ static bool aspeed_sig_desc_eval(const struct aspeed_sig_desc *desc,
  * neither the enabled nor disabled state. Thus we must explicitly test for
  * either condition as required.
  */
-static bool aspeed_sig_expr_eval(const struct aspeed_sig_expr *expr,
-                                bool enabled, struct regmap *map)
+static int aspeed_sig_expr_eval(const struct aspeed_sig_expr *expr,
+                                bool enabled, struct regmap * const *maps)
 {
        int i;
+       int ret;
 
        for (i = 0; i < expr->ndescs; i++) {
                const struct aspeed_sig_desc *desc = &expr->descs[i];
 
-               if (!aspeed_sig_desc_eval(desc, enabled, map))
-                       return false;
+               ret = aspeed_sig_desc_eval(desc, enabled, maps[desc->ip]);
+               if (ret <= 0)
+                       return ret;
        }
 
-       return true;
+       return 1;
 }
 
 /**
@@ -158,19 +173,24 @@ static bool aspeed_sig_expr_eval(const struct aspeed_sig_expr *expr,
  *        configured
  * @enable: true to enable an function's signal through a pin's signal
  *          expression, false to disable the function's signal
- * @map: The SCU's regmap instance for pinmux register access.
+ * @maps: The list of regmap instances for pinmux register access.
  *
- * @return true if the expression is configured as requested, false otherwise
+ * Return: 0 if the expression is configured as requested and a negative error
+ * code otherwise
  */
-static bool aspeed_sig_expr_set(const struct aspeed_sig_expr *expr,
-                               bool enable, struct regmap *map)
+static int aspeed_sig_expr_set(const struct aspeed_sig_expr *expr,
+                               bool enable, struct regmap * const *maps)
 {
+       int ret;
        int i;
 
        for (i = 0; i < expr->ndescs; i++) {
-               bool ret;
                const struct aspeed_sig_desc *desc = &expr->descs[i];
                u32 pattern = enable ? desc->enable : desc->disable;
+               u32 val = (pattern << __ffs(desc->mask));
+
+               if (!maps[desc->ip])
+                       return -ENODEV;
 
                /*
                 * Strap registers are configured in hardware or by early-boot
@@ -179,64 +199,79 @@ static bool aspeed_sig_expr_set(const struct aspeed_sig_expr *expr,
                 * deconfigured and is the reason we re-evaluate after writing
                 * all descriptor bits.
                 */
-               if (desc->reg == HW_STRAP1 || desc->reg == HW_STRAP2)
+               if ((desc->reg == HW_STRAP1 || desc->reg == HW_STRAP2) &&
+                               desc->ip == ASPEED_IP_SCU)
                        continue;
 
-               ret = regmap_update_bits(map, desc->reg, desc->mask,
-                               pattern << __ffs(desc->mask)) == 0;
+               ret = regmap_update_bits(maps[desc->ip], desc->reg,
+                                        desc->mask, val);
 
-               if (!ret)
+               if (ret)
                        return ret;
        }
 
-       return aspeed_sig_expr_eval(expr, enable, map);
+       ret = aspeed_sig_expr_eval(expr, enable, maps);
+       if (ret < 0)
+               return ret;
+
+       if (!ret)
+               return -EPERM;
+
+       return 0;
 }
 
-static bool aspeed_sig_expr_enable(const struct aspeed_sig_expr *expr,
-                                  struct regmap *map)
+static int aspeed_sig_expr_enable(const struct aspeed_sig_expr *expr,
+                                  struct regmap * const *maps)
 {
-       if (aspeed_sig_expr_eval(expr, true, map))
-               return true;
+       int ret;
+
+       ret = aspeed_sig_expr_eval(expr, true, maps);
+       if (ret < 0)
+               return ret;
+
+       if (!ret)
+               return aspeed_sig_expr_set(expr, true, maps);
 
-       return aspeed_sig_expr_set(expr, true, map);
+       return 0;
 }
 
-static bool aspeed_sig_expr_disable(const struct aspeed_sig_expr *expr,
-                                   struct regmap *map)
+static int aspeed_sig_expr_disable(const struct aspeed_sig_expr *expr,
+                                   struct regmap * const *maps)
 {
-       if (!aspeed_sig_expr_eval(expr, true, map))
-               return true;
+       int ret;
+
+       ret = aspeed_sig_expr_eval(expr, true, maps);
+       if (ret < 0)
+               return ret;
+
+       if (ret)
+               return aspeed_sig_expr_set(expr, false, maps);
 
-       return aspeed_sig_expr_set(expr, false, map);
+       return 0;
 }
 
 /**
  * Disable a signal on a pin by disabling all provided signal expressions.
  *
  * @exprs: The list of signal expressions (from a priority level on a pin)
- * @map: The SCU's regmap instance for pinmux register access.
+ * @maps: The list of regmap instances for pinmux register access.
  *
- * @return true if all expressions in the list are successfully disabled, false
- * otherwise
+ * Return: 0 if all expressions are disabled, otherwise a negative error code
  */
-static bool aspeed_disable_sig(const struct aspeed_sig_expr **exprs,
-                              struct regmap *map)
+static int aspeed_disable_sig(const struct aspeed_sig_expr **exprs,
+                              struct regmap * const *maps)
 {
-       bool disabled = true;
+       int ret = 0;
 
        if (!exprs)
                return true;
 
-       while (*exprs) {
-               bool ret;
-
-               ret = aspeed_sig_expr_disable(*exprs, map);
-               disabled = disabled && ret;
-
+       while (*exprs && !ret) {
+               ret = aspeed_sig_expr_disable(*exprs, maps);
                exprs++;
        }
 
-       return disabled;
+       return ret;
 }
 
 /**
@@ -246,8 +281,8 @@ static bool aspeed_disable_sig(const struct aspeed_sig_expr **exprs,
  * @exprs: List of signal expressions (haystack)
  * @name: The name of the requested function (needle)
  *
- * @return A pointer to the signal expression whose function tag matches the
- *         provided name, otherwise NULL.
+ * Return: A pointer to the signal expression whose function tag matches the
+ * provided name, otherwise NULL.
  *
  */
 static const struct aspeed_sig_expr *aspeed_find_expr_by_name(
@@ -330,6 +365,7 @@ int aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
                          unsigned int group)
 {
        int i;
+       int ret;
        const struct aspeed_pinctrl_data *pdata =
                pinctrl_dev_get_drvdata(pctldev);
        const struct aspeed_pin_group *pgroup = &pdata->groups[group];
@@ -343,6 +379,8 @@ int aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
                const struct aspeed_sig_expr **funcs;
                const struct aspeed_sig_expr ***prios;
 
+               pr_debug("Muxing pin %d for %s\n", pin, pfunc->name);
+
                if (!pdesc)
                        return -EINVAL;
 
@@ -358,8 +396,9 @@ int aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
                        if (expr)
                                break;
 
-                       if (!aspeed_disable_sig(funcs, pdata->map))
-                               return -EPERM;
+                       ret = aspeed_disable_sig(funcs, pdata->maps);
+                       if (ret)
+                               return ret;
 
                        prios++;
                }
@@ -377,8 +416,9 @@ int aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
                        return -ENXIO;
                }
 
-               if (!aspeed_sig_expr_enable(expr, pdata->map))
-                       return -EPERM;
+               ret = aspeed_sig_expr_enable(expr, pdata->maps);
+               if (ret)
+                       return ret;
        }
 
        return 0;
@@ -414,6 +454,7 @@ int aspeed_gpio_request_enable(struct pinctrl_dev *pctldev,
                               struct pinctrl_gpio_range *range,
                               unsigned int offset)
 {
+       int ret;
        const struct aspeed_pinctrl_data *pdata =
                pinctrl_dev_get_drvdata(pctldev);
        const struct aspeed_pin_desc *pdesc = pdata->pins[offset].drv_data;
@@ -432,8 +473,9 @@ int aspeed_gpio_request_enable(struct pinctrl_dev *pctldev,
                if (aspeed_gpio_in_exprs(funcs))
                        break;
 
-               if (!aspeed_disable_sig(funcs, pdata->map))
-                       return -EPERM;
+               ret = aspeed_disable_sig(funcs, pdata->maps);
+               if (ret)
+                       return ret;
 
                prios++;
        }
@@ -462,10 +504,7 @@ int aspeed_gpio_request_enable(struct pinctrl_dev *pctldev,
         * If GPIO is not the lowest priority signal type, assume there is only
         * one expression defined to enable the GPIO function
         */
-       if (!aspeed_sig_expr_enable(expr, pdata->map))
-               return -EPERM;
-
-       return 0;
+       return aspeed_sig_expr_enable(expr, pdata->maps);
 }
 
 int aspeed_pinctrl_probe(struct platform_device *pdev,
@@ -481,10 +520,10 @@ int aspeed_pinctrl_probe(struct platform_device *pdev,
                return -ENODEV;
        }
 
-       pdata->map = syscon_node_to_regmap(parent->of_node);
-       if (IS_ERR(pdata->map)) {
+       pdata->maps[ASPEED_IP_SCU] = syscon_node_to_regmap(parent->of_node);
+       if (IS_ERR(pdata->maps[ASPEED_IP_SCU])) {
                dev_err(&pdev->dev, "No regmap for syscon pincontroller parent\n");
-               return PTR_ERR(pdata->map);
+               return PTR_ERR(pdata->maps[ASPEED_IP_SCU]);
        }
 
        pctl = pinctrl_register(pdesc, &pdev->dev, pdata);
index 3e72ef8c54bf76d464afd12e82df2fb06db308cf..08a10d4db22974cbbeb650baa445afd62c97c5ce 100644 (file)
  * group.
  */
 
+#define ASPEED_IP_SCU          0
+#define ASPEED_IP_GFX          1
+#define ASPEED_IP_LPC          2
+#define ASPEED_NR_PINMUX_IPS   3
+
 /*
  * The "Multi-function Pins Mapping and Control" table in the SoC datasheet
  * references registers by the device/offset mnemonic. The register macros
 #define SCUA0           0xA0 /* Multi-function Pin Control #7 */
 #define SCUA4           0xA4 /* Multi-function Pin Control #8 */
 #define SCUA8           0xA8 /* Multi-function Pin Control #9 */
+#define SCUAC           0xAC /* Multi-function Pin Control #10 */
 #define HW_STRAP2       0xD0 /* Strapping */
 
  /**
   * A signal descriptor, which describes the register, bits and the
   * enable/disable values that should be compared or written.
   *
-  * @reg: The register offset from base in bytes
+  * @ip: The IP block identifier, used as an index into the regmap array in
+  *      struct aspeed_pinctrl_data
+  * @reg: The register offset with respect to the base address of the IP block
   * @mask: The mask to apply to the register. The lowest set bit of the mask is
   *        used to derive the shift value.
   * @enable: The value that enables the function. Value should be in the LSBs,
   *           LSBs, not at the position of the mask.
   */
 struct aspeed_sig_desc {
+       unsigned int ip;
        unsigned int reg;
        u32 mask;
        u32 enable;
@@ -313,24 +322,30 @@ struct aspeed_pin_desc {
 
 /* Macro hell */
 
+#define SIG_DESC_IP_BIT(ip, reg, idx, val) \
+       { ip, reg, BIT_MASK(idx), val, (((val) + 1) & 1) }
+
 /**
- * Short-hand macro for describing a configuration enabled by the state of one
- * bit. The disable value is derived.
+ * Short-hand macro for describing an SCU descriptor enabled by the state of
+ * one bit. The disable value is derived.
  *
  * @reg: The signal's associated register, offset from base
  * @idx: The signal's bit index in the register
  * @val: The value (0 or 1) that enables the function
  */
 #define SIG_DESC_BIT(reg, idx, val) \
-       { reg, BIT_MASK(idx), val, (((val) + 1) & 1) }
+       SIG_DESC_IP_BIT(ASPEED_IP_SCU, reg, idx, val)
+
+#define SIG_DESC_IP_SET(ip, reg, idx) SIG_DESC_IP_BIT(ip, reg, idx, 1)
 
 /**
- * A further short-hand macro describing a configuration enabled with a set bit.
+ * A further short-hand macro expanding to an SCU descriptor enabled by a set
+ * bit.
  *
- * @reg: The configuration's associated register, offset from base
- * @idx: The configuration's bit index in the register
+ * @reg: The register, offset from base
+ * @idx: The bit index in the register
  */
-#define SIG_DESC_SET(reg, idx) SIG_DESC_BIT(reg, idx, 1)
+#define SIG_DESC_SET(reg, idx) SIG_DESC_IP_BIT(ASPEED_IP_SCU, reg, idx, 1)
 
 #define SIG_DESC_LIST_SYM(sig, func) sig_descs_ ## sig ## _ ## func
 #define SIG_DESC_LIST_DECL(sig, func, ...) \
@@ -500,7 +515,7 @@ struct aspeed_pin_desc {
        MS_PIN_DECL_(pin, SIG_EXPR_LIST_PTR(gpio))
 
 struct aspeed_pinctrl_data {
-       struct regmap *map;
+       struct regmap *maps[ASPEED_NR_PINMUX_IPS];
 
        const struct pinctrl_pin_desc *pins;
        const unsigned int npins;
index a5331fdfc795edfa57dff3f4677dcf41eef4fd61..810a81786f62d4013cde819099eaee231ae056c1 100644 (file)
@@ -1106,7 +1106,7 @@ static int bcm281xx_std_pin_update(struct pinctrl_dev *pctldev,
        struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
        int i;
        enum pin_config_param param;
-       u16 arg;
+       u32 arg;
 
        for (i = 0; i < num_configs; i++) {
                param = pinconf_to_config_param(configs[i]);
@@ -1222,7 +1222,7 @@ static int bcm281xx_i2c_pin_update(struct pinctrl_dev *pctldev,
        struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
        int i, j;
        enum pin_config_param param;
-       u16 arg;
+       u32 arg;
 
        for (i = 0; i < num_configs; i++) {
                param = pinconf_to_config_param(configs[i]);
@@ -1292,7 +1292,7 @@ static int bcm281xx_hdmi_pin_update(struct pinctrl_dev *pctldev,
        struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
        int i;
        enum pin_config_param param;
-       u16 arg;
+       u32 arg;
 
        for (i = 0; i < num_configs; i++) {
                param = pinconf_to_config_param(configs[i]);
index 5d1e505c3c63d76a85af0dcb7051b9a3da15c2e5..3ca925dfefd14092c8bff6eaddc8d95a44591bca 100644 (file)
@@ -619,7 +619,7 @@ static int iproc_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
 {
        struct iproc_gpio *chip = pinctrl_dev_get_drvdata(pctldev);
        enum pin_config_param param;
-       u16 arg;
+       u32 arg;
        unsigned i, gpio = iproc_pin_to_gpio(pin);
        int ret = -ENOTSUPP;
 
index 13a4c27741572e04fb03532cfc0820dd1623ff6b..4b5cf0e0f16e2dbfcea320414f1aa8c9e8a56179 100644 (file)
@@ -703,7 +703,7 @@ static int ns2_pin_get_enable(struct pinctrl_dev *pctrldev, unsigned int pin)
 }
 
 static int ns2_pin_set_slew(struct pinctrl_dev *pctrldev, unsigned int pin,
-                           u16 slew)
+                           u32 slew)
 {
        struct ns2_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrldev);
        struct ns2_pin *pin_data = pctrldev->desc->pins[pin].drv_data;
@@ -793,7 +793,7 @@ static void ns2_pin_get_pull(struct pinctrl_dev *pctrldev,
 }
 
 static int ns2_pin_set_strength(struct pinctrl_dev *pctrldev, unsigned int pin,
-                               u16 strength)
+                               u32 strength)
 {
        struct ns2_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrldev);
        struct ns2_pin *pin_data = pctrldev->desc->pins[pin].drv_data;
@@ -904,7 +904,7 @@ static int ns2_pin_config_set(struct pinctrl_dev *pctrldev, unsigned int pin,
        struct ns2_pin *pin_data = pctrldev->desc->pins[pin].drv_data;
        enum pin_config_param param;
        unsigned int i;
-       u16 arg;
+       u32 arg;
        int ret = -ENOTSUPP;
 
        if (pin_data->pin_conf.base == -1)
index c8deb8be1da785fd15d8f5182b3b19143ca3c33f..91ea32dc1e7f2f292c5c6dc5a0d39044feeb7d0a 100644 (file)
@@ -366,7 +366,7 @@ static const struct pinctrl_ops nsp_pctrl_ops = {
        .dt_free_map = pinctrl_utils_free_map,
 };
 
-static int nsp_gpio_set_slew(struct nsp_gpio *chip, unsigned gpio, u16 slew)
+static int nsp_gpio_set_slew(struct nsp_gpio *chip, unsigned gpio, u32 slew)
 {
        if (slew)
                nsp_set_bit(chip, IO_CTRL, NSP_GPIO_SLEW_RATE_EN, gpio, true);
@@ -403,7 +403,7 @@ static void nsp_gpio_get_pull(struct nsp_gpio *chip, unsigned gpio,
 }
 
 static int nsp_gpio_set_strength(struct nsp_gpio *chip, unsigned gpio,
-                                u16 strength)
+                                u32 strength)
 {
        u32 offset, shift, i;
        u32 val;
@@ -522,7 +522,7 @@ static int nsp_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
 {
        struct nsp_gpio *chip = pinctrl_dev_get_drvdata(pctldev);
        enum pin_config_param param;
-       u16 arg;
+       u32 arg;
        unsigned int i, gpio;
        int ret = -ENOTSUPP;
 
index fabe728ae268305400bde48abba549e33f49ec94..bf2e17d0d6e41cb23cb31b83b69da6c1a56ccf18 100644 (file)
@@ -10,7 +10,7 @@
  * warranty of any kind, whether express or implied.
  */
 
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
@@ -227,7 +227,6 @@ static const struct of_device_id berlin2_pinctrl_match[] = {
        },
        {}
 };
-MODULE_DEVICE_TABLE(of, berlin2_pinctrl_match);
 
 static int berlin2_pinctrl_probe(struct platform_device *pdev)
 {
@@ -244,8 +243,4 @@ static struct platform_driver berlin2_pinctrl_driver = {
                .of_match_table = berlin2_pinctrl_match,
        },
 };
-module_platform_driver(berlin2_pinctrl_driver);
-
-MODULE_AUTHOR("Antoine Ténart <antoine.tenart@free-electrons.com>");
-MODULE_DESCRIPTION("Marvell Berlin BG2 pinctrl driver");
-MODULE_LICENSE("GPL");
+builtin_platform_driver(berlin2_pinctrl_driver);
index ad8c7586137312fd77780b83a1b4b4795f837e0f..9bee7bd1650fa18b718de0f63e8e43bab7e5dda8 100644 (file)
@@ -10,7 +10,7 @@
  * warranty of any kind, whether express or implied.
  */
 
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
@@ -172,7 +172,6 @@ static const struct of_device_id berlin2cd_pinctrl_match[] = {
        },
        {}
 };
-MODULE_DEVICE_TABLE(of, berlin2cd_pinctrl_match);
 
 static int berlin2cd_pinctrl_probe(struct platform_device *pdev)
 {
@@ -189,8 +188,4 @@ static struct platform_driver berlin2cd_pinctrl_driver = {
                .of_match_table = berlin2cd_pinctrl_match,
        },
 };
-module_platform_driver(berlin2cd_pinctrl_driver);
-
-MODULE_AUTHOR("Antoine Ténart <antoine.tenart@free-electrons.com>");
-MODULE_DESCRIPTION("Marvell Berlin BG2CD pinctrl driver");
-MODULE_LICENSE("GPL");
+builtin_platform_driver(berlin2cd_pinctrl_driver);
index cd171aea8ca8da2f6ae7aac096e90ee61ba644b9..eee6763f114c054493800442d70e06378032d7ed 100644 (file)
@@ -10,7 +10,7 @@
  * warranty of any kind, whether express or implied.
  */
 
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
@@ -389,7 +389,6 @@ static const struct of_device_id berlin2q_pinctrl_match[] = {
        },
        {}
 };
-MODULE_DEVICE_TABLE(of, berlin2q_pinctrl_match);
 
 static int berlin2q_pinctrl_probe(struct platform_device *pdev)
 {
@@ -406,8 +405,4 @@ static struct platform_driver berlin2q_pinctrl_driver = {
                .of_match_table = berlin2q_pinctrl_match,
        },
 };
-module_platform_driver(berlin2q_pinctrl_driver);
-
-MODULE_AUTHOR("Antoine Ténart <antoine.tenart@free-electrons.com>");
-MODULE_DESCRIPTION("Marvell Berlin BG2Q pinctrl driver");
-MODULE_LICENSE("GPL");
+builtin_platform_driver(berlin2q_pinctrl_driver);
index c617ec49e9edeeebb1f33b78fa6b7214fb23207c..e6740656ee7c4e3c505356718ca9b412527d2e6e 100644 (file)
@@ -18,7 +18,7 @@
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
@@ -457,7 +457,6 @@ static const struct of_device_id berlin4ct_pinctrl_match[] = {
        },
        {}
 };
-MODULE_DEVICE_TABLE(of, berlin4ct_pinctrl_match);
 
 static int berlin4ct_pinctrl_probe(struct platform_device *pdev)
 {
@@ -496,8 +495,4 @@ static struct platform_driver berlin4ct_pinctrl_driver = {
                .of_match_table = berlin4ct_pinctrl_match,
        },
 };
-module_platform_driver(berlin4ct_pinctrl_driver);
-
-MODULE_AUTHOR("Jisheng Zhang <jszhang@marvell.com>");
-MODULE_DESCRIPTION("Marvell berlin4ct pinctrl driver");
-MODULE_LICENSE("GPL");
+builtin_platform_driver(berlin4ct_pinctrl_driver);
index fb38e208f32dd2199f427207fe6a0e19d3987a5a..d69046537b75f31d0b1c881686677967865001e0 100644 (file)
@@ -237,10 +237,8 @@ static int pinctrl_register_one_pin(struct pinctrl_dev *pctldev,
        }
 
        pindesc = kzalloc(sizeof(*pindesc), GFP_KERNEL);
-       if (pindesc == NULL) {
-               dev_err(pctldev->dev, "failed to alloc struct pin_desc\n");
+       if (!pindesc)
                return -ENOMEM;
-       }
 
        /* Set owner */
        pindesc->pctldev = pctldev;
@@ -540,6 +538,182 @@ void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev,
 }
 EXPORT_SYMBOL_GPL(pinctrl_remove_gpio_range);
 
+#ifdef CONFIG_GENERIC_PINCTRL_GROUPS
+
+/**
+ * pinctrl_generic_get_group_count() - returns the number of pin groups
+ * @pctldev: pin controller device
+ */
+int pinctrl_generic_get_group_count(struct pinctrl_dev *pctldev)
+{
+       return pctldev->num_groups;
+}
+EXPORT_SYMBOL_GPL(pinctrl_generic_get_group_count);
+
+/**
+ * pinctrl_generic_get_group_name() - returns the name of a pin group
+ * @pctldev: pin controller device
+ * @selector: group number
+ */
+const char *pinctrl_generic_get_group_name(struct pinctrl_dev *pctldev,
+                                          unsigned int selector)
+{
+       struct group_desc *group;
+
+       group = radix_tree_lookup(&pctldev->pin_group_tree,
+                                 selector);
+       if (!group)
+               return NULL;
+
+       return group->name;
+}
+EXPORT_SYMBOL_GPL(pinctrl_generic_get_group_name);
+
+/**
+ * pinctrl_generic_get_group_pins() - gets the pin group pins
+ * @pctldev: pin controller device
+ * @selector: group number
+ * @pins: pins in the group
+ * @num_pins: number of pins in the group
+ */
+int pinctrl_generic_get_group_pins(struct pinctrl_dev *pctldev,
+                                  unsigned int selector,
+                                  const unsigned int **pins,
+                                  unsigned int *num_pins)
+{
+       struct group_desc *group;
+
+       group = radix_tree_lookup(&pctldev->pin_group_tree,
+                                 selector);
+       if (!group) {
+               dev_err(pctldev->dev, "%s could not find pingroup%i\n",
+                       __func__, selector);
+               return -EINVAL;
+       }
+
+       *pins = group->pins;
+       *num_pins = group->num_pins;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pinctrl_generic_get_group_pins);
+
+/**
+ * pinctrl_generic_get_group() - returns a pin group based on the number
+ * @pctldev: pin controller device
+ * @gselector: group number
+ */
+struct group_desc *pinctrl_generic_get_group(struct pinctrl_dev *pctldev,
+                                            unsigned int selector)
+{
+       struct group_desc *group;
+
+       group = radix_tree_lookup(&pctldev->pin_group_tree,
+                                 selector);
+       if (!group)
+               return NULL;
+
+       return group;
+}
+EXPORT_SYMBOL_GPL(pinctrl_generic_get_group);
+
+/**
+ * pinctrl_generic_add_group() - adds a new pin group
+ * @pctldev: pin controller device
+ * @name: name of the pin group
+ * @pins: pins in the pin group
+ * @num_pins: number of pins in the pin group
+ * @data: pin controller driver specific data
+ *
+ * Note that the caller must take care of locking.
+ */
+int pinctrl_generic_add_group(struct pinctrl_dev *pctldev, const char *name,
+                             int *pins, int num_pins, void *data)
+{
+       struct group_desc *group;
+
+       group = devm_kzalloc(pctldev->dev, sizeof(*group), GFP_KERNEL);
+       if (!group)
+               return -ENOMEM;
+
+       group->name = name;
+       group->pins = pins;
+       group->num_pins = num_pins;
+       group->data = data;
+
+       radix_tree_insert(&pctldev->pin_group_tree, pctldev->num_groups,
+                         group);
+
+       pctldev->num_groups++;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pinctrl_generic_add_group);
+
+/**
+ * pinctrl_generic_remove_group() - removes a numbered pin group
+ * @pctldev: pin controller device
+ * @selector: group number
+ *
+ * Note that the caller must take care of locking.
+ */
+int pinctrl_generic_remove_group(struct pinctrl_dev *pctldev,
+                                unsigned int selector)
+{
+       struct group_desc *group;
+
+       group = radix_tree_lookup(&pctldev->pin_group_tree,
+                                 selector);
+       if (!group)
+               return -ENOENT;
+
+       radix_tree_delete(&pctldev->pin_group_tree, selector);
+       devm_kfree(pctldev->dev, group);
+
+       pctldev->num_groups--;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pinctrl_generic_remove_group);
+
+/**
+ * pinctrl_generic_free_groups() - removes all pin groups
+ * @pctldev: pin controller device
+ *
+ * Note that the caller must take care of locking.
+ */
+static void pinctrl_generic_free_groups(struct pinctrl_dev *pctldev)
+{
+       struct radix_tree_iter iter;
+       struct group_desc *group;
+       unsigned long *indices;
+       void **slot;
+       int i = 0;
+
+       indices = devm_kzalloc(pctldev->dev, sizeof(*indices) *
+                              pctldev->num_groups, GFP_KERNEL);
+       if (!indices)
+               return;
+
+       radix_tree_for_each_slot(slot, &pctldev->pin_group_tree, &iter, 0)
+               indices[i++] = iter.index;
+
+       for (i = 0; i < pctldev->num_groups; i++) {
+               group = radix_tree_lookup(&pctldev->pin_group_tree,
+                                         indices[i]);
+               radix_tree_delete(&pctldev->pin_group_tree, indices[i]);
+               devm_kfree(pctldev->dev, group);
+       }
+
+       pctldev->num_groups = 0;
+}
+
+#else
+static inline void pinctrl_generic_free_groups(struct pinctrl_dev *pctldev)
+{
+}
+#endif /* CONFIG_GENERIC_PINCTRL_GROUPS */
+
 /**
  * pinctrl_get_group_selector() - returns the group selector for a group
  * @pctldev: the pin controller handling the group
@@ -688,6 +862,35 @@ int pinctrl_gpio_direction_output(unsigned gpio)
 }
 EXPORT_SYMBOL_GPL(pinctrl_gpio_direction_output);
 
+/**
+ * pinctrl_gpio_set_config() - Apply config to given GPIO pin
+ * @gpio: the GPIO pin number from the GPIO subsystem number space
+ * @config: the configuration to apply to the GPIO
+ *
+ * This function should *ONLY* be used from gpiolib-based GPIO drivers, if
+ * they need to call the underlying pin controller to change GPIO config
+ * (for example set debounce time).
+ */
+int pinctrl_gpio_set_config(unsigned gpio, unsigned long config)
+{
+       unsigned long configs[] = { config };
+       struct pinctrl_gpio_range *range;
+       struct pinctrl_dev *pctldev;
+       int ret, pin;
+
+       ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
+       if (ret)
+               return ret;
+
+       mutex_lock(&pctldev->mutex);
+       pin = gpio_to_pin(range, gpio);
+       ret = pinconf_set_config(pctldev, pin, configs, ARRAY_SIZE(configs));
+       mutex_unlock(&pctldev->mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(pinctrl_gpio_set_config);
+
 static struct pinctrl_state *find_state(struct pinctrl *p,
                                        const char *name)
 {
@@ -706,11 +909,8 @@ static struct pinctrl_state *create_state(struct pinctrl *p,
        struct pinctrl_state *state;
 
        state = kzalloc(sizeof(*state), GFP_KERNEL);
-       if (state == NULL) {
-               dev_err(p->dev,
-                       "failed to alloc struct pinctrl_state\n");
+       if (!state)
                return ERR_PTR(-ENOMEM);
-       }
 
        state->name = name;
        INIT_LIST_HEAD(&state->settings);
@@ -720,7 +920,8 @@ static struct pinctrl_state *create_state(struct pinctrl *p,
        return state;
 }
 
-static int add_setting(struct pinctrl *p, struct pinctrl_map const *map)
+static int add_setting(struct pinctrl *p, struct pinctrl_dev *pctldev,
+                      struct pinctrl_map const *map)
 {
        struct pinctrl_state *state;
        struct pinctrl_setting *setting;
@@ -736,15 +937,16 @@ static int add_setting(struct pinctrl *p, struct pinctrl_map const *map)
                return 0;
 
        setting = kzalloc(sizeof(*setting), GFP_KERNEL);
-       if (setting == NULL) {
-               dev_err(p->dev,
-                       "failed to alloc struct pinctrl_setting\n");
+       if (!setting)
                return -ENOMEM;
-       }
 
        setting->type = map->type;
 
-       setting->pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name);
+       if (pctldev)
+               setting->pctldev = pctldev;
+       else
+               setting->pctldev =
+                       get_pinctrl_dev_from_devname(map->ctrl_dev_name);
        if (setting->pctldev == NULL) {
                kfree(setting);
                /* Do not defer probing of hogs (circular loop) */
@@ -800,7 +1002,8 @@ static struct pinctrl *find_pinctrl(struct device *dev)
 
 static void pinctrl_free(struct pinctrl *p, bool inlist);
 
-static struct pinctrl *create_pinctrl(struct device *dev)
+static struct pinctrl *create_pinctrl(struct device *dev,
+                                     struct pinctrl_dev *pctldev)
 {
        struct pinctrl *p;
        const char *devname;
@@ -815,15 +1018,13 @@ static struct pinctrl *create_pinctrl(struct device *dev)
         * a pin control handle with pinctrl_get()
         */
        p = kzalloc(sizeof(*p), GFP_KERNEL);
-       if (p == NULL) {
-               dev_err(dev, "failed to alloc struct pinctrl\n");
+       if (!p)
                return ERR_PTR(-ENOMEM);
-       }
        p->dev = dev;
        INIT_LIST_HEAD(&p->states);
        INIT_LIST_HEAD(&p->dt_maps);
 
-       ret = pinctrl_dt_to_map(p);
+       ret = pinctrl_dt_to_map(p, pctldev);
        if (ret < 0) {
                kfree(p);
                return ERR_PTR(ret);
@@ -838,7 +1039,7 @@ static struct pinctrl *create_pinctrl(struct device *dev)
                if (strcmp(map->dev_name, devname))
                        continue;
 
-               ret = add_setting(p, map);
+               ret = add_setting(p, pctldev, map);
                /*
                 * At this point the adding of a setting may:
                 *
@@ -899,7 +1100,7 @@ struct pinctrl *pinctrl_get(struct device *dev)
                return p;
        }
 
-       return create_pinctrl(dev);
+       return create_pinctrl(dev, NULL);
 }
 EXPORT_SYMBOL_GPL(pinctrl_get);
 
@@ -1175,10 +1376,8 @@ int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
        }
 
        maps_node = kzalloc(sizeof(*maps_node), GFP_KERNEL);
-       if (!maps_node) {
-               pr_err("failed to alloc struct pinctrl_maps\n");
+       if (!maps_node)
                return -ENOMEM;
-       }
 
        maps_node->num_maps = num_maps;
        if (dup) {
@@ -1731,20 +1930,18 @@ static int pinctrl_check_ops(struct pinctrl_dev *pctldev)
            !ops->get_group_name)
                return -EINVAL;
 
-       if (ops->dt_node_to_map && !ops->dt_free_map)
-               return -EINVAL;
-
        return 0;
 }
 
 /**
- * pinctrl_register() - register a pin controller device
+ * pinctrl_init_controller() - init a pin controller device
  * @pctldesc: descriptor for this pin controller
  * @dev: parent device for this pin controller
  * @driver_data: private pin controller data for this pin controller
  */
-struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
-                                   struct device *dev, void *driver_data)
+struct pinctrl_dev *pinctrl_init_controller(struct pinctrl_desc *pctldesc,
+                                           struct device *dev,
+                                           void *driver_data)
 {
        struct pinctrl_dev *pctldev;
        int ret;
@@ -1755,17 +1952,22 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
                return ERR_PTR(-EINVAL);
 
        pctldev = kzalloc(sizeof(*pctldev), GFP_KERNEL);
-       if (pctldev == NULL) {
-               dev_err(dev, "failed to alloc struct pinctrl_dev\n");
+       if (!pctldev)
                return ERR_PTR(-ENOMEM);
-       }
 
        /* Initialize pin control device struct */
        pctldev->owner = pctldesc->owner;
        pctldev->desc = pctldesc;
        pctldev->driver_data = driver_data;
        INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL);
+#ifdef CONFIG_GENERIC_PINCTRL_GROUPS
+       INIT_RADIX_TREE(&pctldev->pin_group_tree, GFP_KERNEL);
+#endif
+#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS
+       INIT_RADIX_TREE(&pctldev->pin_function_tree, GFP_KERNEL);
+#endif
        INIT_LIST_HEAD(&pctldev->gpio_ranges);
+       INIT_LIST_HEAD(&pctldev->node);
        pctldev->dev = dev;
        mutex_init(&pctldev->mutex);
 
@@ -1800,21 +2002,28 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
                goto out_err;
        }
 
-       mutex_lock(&pinctrldev_list_mutex);
-       list_add_tail(&pctldev->node, &pinctrldev_list);
-       mutex_unlock(&pinctrldev_list_mutex);
+       return pctldev;
 
-       pctldev->p = pinctrl_get(pctldev->dev);
+out_err:
+       mutex_destroy(&pctldev->mutex);
+       kfree(pctldev);
+       return ERR_PTR(ret);
+}
 
+static int pinctrl_create_and_start(struct pinctrl_dev *pctldev)
+{
+       pctldev->p = create_pinctrl(pctldev->dev, pctldev);
        if (!IS_ERR(pctldev->p)) {
+               kref_get(&pctldev->p->users);
                pctldev->hog_default =
                        pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_DEFAULT);
                if (IS_ERR(pctldev->hog_default)) {
-                       dev_dbg(dev, "failed to lookup the default state\n");
+                       dev_dbg(pctldev->dev,
+                               "failed to lookup the default state\n");
                } else {
                        if (pinctrl_select_state(pctldev->p,
                                                pctldev->hog_default))
-                               dev_err(dev,
+                               dev_err(pctldev->dev,
                                        "failed to select default state\n");
                }
 
@@ -1822,20 +2031,85 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
                        pinctrl_lookup_state(pctldev->p,
                                                    PINCTRL_STATE_SLEEP);
                if (IS_ERR(pctldev->hog_sleep))
-                       dev_dbg(dev, "failed to lookup the sleep state\n");
+                       dev_dbg(pctldev->dev,
+                               "failed to lookup the sleep state\n");
        }
 
+       mutex_lock(&pinctrldev_list_mutex);
+       list_add_tail(&pctldev->node, &pinctrldev_list);
+       mutex_unlock(&pinctrldev_list_mutex);
+
        pinctrl_init_device_debugfs(pctldev);
 
+       return 0;
+}
+
+/**
+ * pinctrl_register() - register a pin controller device
+ * @pctldesc: descriptor for this pin controller
+ * @dev: parent device for this pin controller
+ * @driver_data: private pin controller data for this pin controller
+ *
+ * Note that pinctrl_register() is known to have problems as the pin
+ * controller driver functions are called before the driver has a
+ * struct pinctrl_dev handle. To avoid issues later on, please use the
+ * new pinctrl_register_and_init() below instead.
+ */
+struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
+                                   struct device *dev, void *driver_data)
+{
+       struct pinctrl_dev *pctldev;
+       int error;
+
+       pctldev = pinctrl_init_controller(pctldesc, dev, driver_data);
+       if (IS_ERR(pctldev))
+               return pctldev;
+
+       error = pinctrl_create_and_start(pctldev);
+       if (error) {
+               mutex_destroy(&pctldev->mutex);
+               kfree(pctldev);
+
+               return ERR_PTR(error);
+       }
+
        return pctldev;
 
-out_err:
-       mutex_destroy(&pctldev->mutex);
-       kfree(pctldev);
-       return ERR_PTR(ret);
 }
 EXPORT_SYMBOL_GPL(pinctrl_register);
 
+int pinctrl_register_and_init(struct pinctrl_desc *pctldesc,
+                             struct device *dev, void *driver_data,
+                             struct pinctrl_dev **pctldev)
+{
+       struct pinctrl_dev *p;
+       int error;
+
+       p = pinctrl_init_controller(pctldesc, dev, driver_data);
+       if (IS_ERR(p))
+               return PTR_ERR(p);
+
+       /*
+        * We have pinctrl_start() call functions in the pin controller
+        * driver with create_pinctrl() for at least dt_node_to_map(). So
+        * let's make sure pctldev is properly initialized for the
+        * pin controller driver before we do anything.
+        */
+       *pctldev = p;
+
+       error = pinctrl_create_and_start(p);
+       if (error) {
+               mutex_destroy(&p->mutex);
+               kfree(p);
+               *pctldev = NULL;
+
+               return error;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pinctrl_register_and_init);
+
 /**
  * pinctrl_unregister() - unregister pinmux
  * @pctldev: pin controller to unregister
@@ -1845,6 +2119,7 @@ EXPORT_SYMBOL_GPL(pinctrl_register);
 void pinctrl_unregister(struct pinctrl_dev *pctldev)
 {
        struct pinctrl_gpio_range *range, *n;
+
        if (pctldev == NULL)
                return;
 
@@ -1852,13 +2127,15 @@ void pinctrl_unregister(struct pinctrl_dev *pctldev)
        pinctrl_remove_device_debugfs(pctldev);
        mutex_unlock(&pctldev->mutex);
 
-       if (!IS_ERR(pctldev->p))
+       if (!IS_ERR_OR_NULL(pctldev->p))
                pinctrl_put(pctldev->p);
 
        mutex_lock(&pinctrldev_list_mutex);
        mutex_lock(&pctldev->mutex);
        /* TODO: check that no pinmuxes are still active? */
        list_del(&pctldev->node);
+       pinmux_generic_free_functions(pctldev);
+       pinctrl_generic_free_groups(pctldev);
        /* Destroy descriptor tree */
        pinctrl_free_pindescs(pctldev, pctldev->desc->pins,
                              pctldev->desc->npins);
@@ -1924,6 +2201,42 @@ struct pinctrl_dev *devm_pinctrl_register(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(devm_pinctrl_register);
 
+/**
+ * devm_pinctrl_register_and_init() - Resource managed pinctrl register and init
+ * @dev: parent device for this pin controller
+ * @pctldesc: descriptor for this pin controller
+ * @driver_data: private pin controller data for this pin controller
+ *
+ * Returns an error pointer if pincontrol register failed. Otherwise
+ * it returns valid pinctrl handle.
+ *
+ * The pinctrl device will be automatically released when the device is unbound.
+ */
+int devm_pinctrl_register_and_init(struct device *dev,
+                                  struct pinctrl_desc *pctldesc,
+                                  void *driver_data,
+                                  struct pinctrl_dev **pctldev)
+{
+       struct pinctrl_dev **ptr;
+       int error;
+
+       ptr = devres_alloc(devm_pinctrl_dev_release, sizeof(*ptr), GFP_KERNEL);
+       if (!ptr)
+               return -ENOMEM;
+
+       error = pinctrl_register_and_init(pctldesc, dev, driver_data, pctldev);
+       if (error) {
+               devres_free(ptr);
+               return error;
+       }
+
+       *ptr = *pctldev;
+       devres_add(dev, ptr);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(devm_pinctrl_register_and_init);
+
 /**
  * devm_pinctrl_unregister() - Resource managed version of pinctrl_unregister().
  * @dev: device for which which resource was allocated
index 747c423c11f34ab65a491b3d76fddff7d15e0049..1c35de59a658d44a880ff8ffec50c89c18d7466f 100644 (file)
@@ -24,6 +24,10 @@ struct pinctrl_gpio_range;
  *     controller
  * @pin_desc_tree: each pin descriptor for this pin controller is stored in
  *     this radix tree
+ * @pin_group_tree: optionally each pin group can be stored in this radix tree
+ * @num_groups: optionally number of groups can be kept here
+ * @pin_function_tree: optionally each function can be stored in this radix tree
+ * @num_functions: optionally number of functions can be kept here
  * @gpio_ranges: a list of GPIO ranges that is handled by this pin controller,
  *     ranges are added to this list at runtime
  * @dev: the device entry for this pin controller
@@ -40,6 +44,14 @@ struct pinctrl_dev {
        struct list_head node;
        struct pinctrl_desc *desc;
        struct radix_tree_root pin_desc_tree;
+#ifdef CONFIG_GENERIC_PINCTRL_GROUPS
+       struct radix_tree_root pin_group_tree;
+       unsigned int num_groups;
+#endif
+#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS
+       struct radix_tree_root pin_function_tree;
+       unsigned int num_functions;
+#endif
        struct list_head gpio_ranges;
        struct device *dev;
        struct module *owner;
@@ -171,6 +183,49 @@ struct pinctrl_maps {
        unsigned num_maps;
 };
 
+#ifdef CONFIG_GENERIC_PINCTRL_GROUPS
+
+/**
+ * struct group_desc - generic pin group descriptor
+ * @name: name of the pin group
+ * @pins: array of pins that belong to the group
+ * @num_pins: number of pins in the group
+ * @data: pin controller driver specific data
+ */
+struct group_desc {
+       const char *name;
+       int *pins;
+       int num_pins;
+       void *data;
+};
+
+int pinctrl_generic_get_group_count(struct pinctrl_dev *pctldev);
+
+const char *pinctrl_generic_get_group_name(struct pinctrl_dev *pctldev,
+                                          unsigned int group_selector);
+
+int pinctrl_generic_get_group_pins(struct pinctrl_dev *pctldev,
+                                  unsigned int group_selector,
+                                  const unsigned int **pins,
+                                  unsigned int *npins);
+
+struct group_desc *pinctrl_generic_get_group(struct pinctrl_dev *pctldev,
+                                            unsigned int group_selector);
+
+int pinctrl_generic_add_group(struct pinctrl_dev *pctldev, const char *name,
+                             int *gpins, int ngpins, void *data);
+
+int pinctrl_generic_remove_group(struct pinctrl_dev *pctldev,
+                                unsigned int group_selector);
+
+static inline int
+pinctrl_generic_remove_last_group(struct pinctrl_dev *pctldev)
+{
+       return pinctrl_generic_remove_group(pctldev, pctldev->num_groups - 1);
+}
+
+#endif /* CONFIG_GENERIC_PINCTRL_GROUPS */
+
 struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name);
 struct pinctrl_dev *get_pinctrl_dev_from_of_node(struct device_node *np);
 int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name);
index 260908480075a246bf6d311ab83566a9c706486c..0e5c9f14a706e6f25cceeccecc0e67527e7051aa 100644 (file)
@@ -42,7 +42,8 @@ static void dt_free_map(struct pinctrl_dev *pctldev,
 {
        if (pctldev) {
                const struct pinctrl_ops *ops = pctldev->desc->pctlops;
-               ops->dt_free_map(pctldev, map, num_maps);
+               if (ops->dt_free_map)
+                       ops->dt_free_map(pctldev, map, num_maps);
        } else {
                /* There is no pctldev for PIN_MAP_TYPE_DUMMY_STATE */
                kfree(map);
@@ -100,11 +101,12 @@ struct pinctrl_dev *of_pinctrl_get(struct device_node *np)
        return get_pinctrl_dev_from_of_node(np);
 }
 
-static int dt_to_map_one_config(struct pinctrl *p, const char *statename,
+static int dt_to_map_one_config(struct pinctrl *p,
+                               struct pinctrl_dev *pctldev,
+                               const char *statename,
                                struct device_node *np_config)
 {
        struct device_node *np_pctldev;
-       struct pinctrl_dev *pctldev;
        const struct pinctrl_ops *ops;
        int ret;
        struct pinctrl_map *map;
@@ -121,7 +123,8 @@ static int dt_to_map_one_config(struct pinctrl *p, const char *statename,
                        /* OK let's just assume this will appear later then */
                        return -EPROBE_DEFER;
                }
-               pctldev = get_pinctrl_dev_from_of_node(np_pctldev);
+               if (!pctldev)
+                       pctldev = get_pinctrl_dev_from_of_node(np_pctldev);
                if (pctldev)
                        break;
                /* Do not defer probing of hogs (circular loop) */
@@ -166,7 +169,22 @@ static int dt_remember_dummy_state(struct pinctrl *p, const char *statename)
        return dt_remember_or_free_map(p, statename, NULL, map, 1);
 }
 
-int pinctrl_dt_to_map(struct pinctrl *p)
+bool pinctrl_dt_has_hogs(struct pinctrl_dev *pctldev)
+{
+       struct device_node *np;
+       struct property *prop;
+       int size;
+
+       np = pctldev->dev->of_node;
+       if (!np)
+               return false;
+
+       prop = of_find_property(np, "pinctrl-0", &size);
+
+       return prop ? true : false;
+}
+
+int pinctrl_dt_to_map(struct pinctrl *p, struct pinctrl_dev *pctldev)
 {
        struct device_node *np = p->dev->of_node;
        int state, ret;
@@ -233,7 +251,8 @@ int pinctrl_dt_to_map(struct pinctrl *p)
                        }
 
                        /* Parse the node */
-                       ret = dt_to_map_one_config(p, statename, np_config);
+                       ret = dt_to_map_one_config(p, pctldev, statename,
+                                                  np_config);
                        of_node_put(np_config);
                        if (ret < 0)
                                goto err;
index c2d1a550585070524a50465b388af4393c7e8d15..43d8d19aa5ee3aab509d181935c7cd26be09e0a8 100644 (file)
@@ -20,8 +20,10 @@ struct of_phandle_args;
 
 #ifdef CONFIG_OF
 
+bool pinctrl_dt_has_hogs(struct pinctrl_dev *pctldev);
+
 void pinctrl_dt_free_maps(struct pinctrl *p);
-int pinctrl_dt_to_map(struct pinctrl *p);
+int pinctrl_dt_to_map(struct pinctrl *p, struct pinctrl_dev *pctldev);
 
 int pinctrl_count_index_with_args(const struct device_node *np,
                                  const char *list_name);
@@ -32,7 +34,13 @@ int pinctrl_parse_index_with_args(const struct device_node *np,
 
 #else
 
-static inline int pinctrl_dt_to_map(struct pinctrl *p)
+static inline bool pinctrl_dt_has_hogs(struct pinctrl_dev *pctldev)
+{
+       return false;
+}
+
+static inline int pinctrl_dt_to_map(struct pinctrl *p,
+                                   struct pinctrl_dev *pctldev)
 {
        return 0;
 }
index fc8cbf6117234ba31541b3f0153d0d23e8bc644b..cae05e76c1117680675ed48b60bdbf41186346bc 100644 (file)
@@ -1,6 +1,7 @@
 config PINCTRL_IMX
        bool
-       select PINMUX
+       select GENERIC_PINCTRL_GROUPS
+       select GENERIC_PINMUX_FUNCTIONS
        select PINCONF
        select REGMAP
 
index 5ef7e875b50e89a9d39dcfbd67e927b42ff9d087..a7ace9e1ad81f24f571d34ca155ba5d03c5f9a36 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/regmap.h>
 
 #include "../core.h"
+#include "../pinmux.h"
 #include "pinctrl-imx.h"
 
 /* The bits in CONFIG cell defined in binding doc*/
@@ -42,59 +43,25 @@ struct imx_pinctrl {
        struct pinctrl_dev *pctl;
        void __iomem *base;
        void __iomem *input_sel_base;
-       const struct imx_pinctrl_soc_info *info;
+       struct imx_pinctrl_soc_info *info;
 };
 
-static inline const struct imx_pin_group *imx_pinctrl_find_group_by_name(
-                               const struct imx_pinctrl_soc_info *info,
+static inline const struct group_desc *imx_pinctrl_find_group_by_name(
+                               struct pinctrl_dev *pctldev,
                                const char *name)
 {
-       const struct imx_pin_group *grp = NULL;
+       const struct group_desc *grp = NULL;
        int i;
 
-       for (i = 0; i < info->ngroups; i++) {
-               if (!strcmp(info->groups[i].name, name)) {
-                       grp = &info->groups[i];
+       for (i = 0; i < pctldev->num_groups; i++) {
+               grp = pinctrl_generic_get_group(pctldev, i);
+               if (grp && !strcmp(grp->name, name))
                        break;
-               }
        }
 
        return grp;
 }
 
-static int imx_get_groups_count(struct pinctrl_dev *pctldev)
-{
-       struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
-       const struct imx_pinctrl_soc_info *info = ipctl->info;
-
-       return info->ngroups;
-}
-
-static const char *imx_get_group_name(struct pinctrl_dev *pctldev,
-                                      unsigned selector)
-{
-       struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
-       const struct imx_pinctrl_soc_info *info = ipctl->info;
-
-       return info->groups[selector].name;
-}
-
-static int imx_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
-                              const unsigned **pins,
-                              unsigned *npins)
-{
-       struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
-       const struct imx_pinctrl_soc_info *info = ipctl->info;
-
-       if (selector >= info->ngroups)
-               return -EINVAL;
-
-       *pins = info->groups[selector].pin_ids;
-       *npins = info->groups[selector].npins;
-
-       return 0;
-}
-
 static void imx_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
                   unsigned offset)
 {
@@ -106,8 +73,8 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev,
                        struct pinctrl_map **map, unsigned *num_maps)
 {
        struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
-       const struct imx_pinctrl_soc_info *info = ipctl->info;
-       const struct imx_pin_group *grp;
+       struct imx_pinctrl_soc_info *info = ipctl->info;
+       const struct group_desc *grp;
        struct pinctrl_map *new_map;
        struct device_node *parent;
        int map_num = 1;
@@ -117,15 +84,17 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev,
         * first find the group of this node and check if we need create
         * config maps for pins
         */
-       grp = imx_pinctrl_find_group_by_name(info, np->name);
+       grp = imx_pinctrl_find_group_by_name(pctldev, np->name);
        if (!grp) {
                dev_err(info->dev, "unable to find group for node %s\n",
                        np->name);
                return -EINVAL;
        }
 
-       for (i = 0; i < grp->npins; i++) {
-               if (!(grp->pins[i].config & IMX_NO_PAD_CTL))
+       for (i = 0; i < grp->num_pins; i++) {
+               struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i];
+
+               if (!(pin->config & IMX_NO_PAD_CTL))
                        map_num++;
        }
 
@@ -149,12 +118,14 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev,
 
        /* create config map */
        new_map++;
-       for (i = j = 0; i < grp->npins; i++) {
-               if (!(grp->pins[i].config & IMX_NO_PAD_CTL)) {
+       for (i = j = 0; i < grp->num_pins; i++) {
+               struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i];
+
+               if (!(pin->config & IMX_NO_PAD_CTL)) {
                        new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN;
                        new_map[j].data.configs.group_or_pin =
-                                       pin_get_name(pctldev, grp->pins[i].pin);
-                       new_map[j].data.configs.configs = &grp->pins[i].config;
+                                       pin_get_name(pctldev, pin->pin);
+                       new_map[j].data.configs.configs = &pin->config;
                        new_map[j].data.configs.num_configs = 1;
                        j++;
                }
@@ -173,9 +144,9 @@ static void imx_dt_free_map(struct pinctrl_dev *pctldev,
 }
 
 static const struct pinctrl_ops imx_pctrl_ops = {
-       .get_groups_count = imx_get_groups_count,
-       .get_group_name = imx_get_group_name,
-       .get_group_pins = imx_get_group_pins,
+       .get_groups_count = pinctrl_generic_get_group_count,
+       .get_group_name = pinctrl_generic_get_group_name,
+       .get_group_pins = pinctrl_generic_get_group_pins,
        .pin_dbg_show = imx_pin_dbg_show,
        .dt_node_to_map = imx_dt_node_to_map,
        .dt_free_map = imx_dt_free_map,
@@ -186,24 +157,33 @@ static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector,
                       unsigned group)
 {
        struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
-       const struct imx_pinctrl_soc_info *info = ipctl->info;
+       struct imx_pinctrl_soc_info *info = ipctl->info;
        const struct imx_pin_reg *pin_reg;
        unsigned int npins, pin_id;
        int i;
-       struct imx_pin_group *grp;
+       struct group_desc *grp = NULL;
+       struct function_desc *func = NULL;
 
        /*
         * Configure the mux mode for each pin in the group for a specific
         * function.
         */
-       grp = &info->groups[group];
-       npins = grp->npins;
+       grp = pinctrl_generic_get_group(pctldev, group);
+       if (!grp)
+               return -EINVAL;
+
+       func = pinmux_generic_get_function(pctldev, selector);
+       if (!func)
+               return -EINVAL;
+
+       npins = grp->num_pins;
 
        dev_dbg(ipctl->dev, "enable function %s group %s\n",
-               info->functions[selector].name, grp->name);
+               func->name, grp->name);
 
        for (i = 0; i < npins; i++) {
-               struct imx_pin *pin = &grp->pins[i];
+               struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i];
+
                pin_id = pin->pin;
                pin_reg = &info->pin_regs[pin_id];
 
@@ -272,43 +252,13 @@ static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector,
        return 0;
 }
 
-static int imx_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
-{
-       struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
-       const struct imx_pinctrl_soc_info *info = ipctl->info;
-
-       return info->nfunctions;
-}
-
-static const char *imx_pmx_get_func_name(struct pinctrl_dev *pctldev,
-                                         unsigned selector)
-{
-       struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
-       const struct imx_pinctrl_soc_info *info = ipctl->info;
-
-       return info->functions[selector].name;
-}
-
-static int imx_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
-                              const char * const **groups,
-                              unsigned * const num_groups)
-{
-       struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
-       const struct imx_pinctrl_soc_info *info = ipctl->info;
-
-       *groups = info->functions[selector].groups;
-       *num_groups = info->functions[selector].num_groups;
-
-       return 0;
-}
-
 static int imx_pmx_gpio_request_enable(struct pinctrl_dev *pctldev,
                        struct pinctrl_gpio_range *range, unsigned offset)
 {
        struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
-       const struct imx_pinctrl_soc_info *info = ipctl->info;
+       struct imx_pinctrl_soc_info *info = ipctl->info;
        const struct imx_pin_reg *pin_reg;
-       struct imx_pin_group *grp;
+       struct group_desc *grp;
        struct imx_pin *imx_pin;
        unsigned int pin, group;
        u32 reg;
@@ -322,10 +272,12 @@ static int imx_pmx_gpio_request_enable(struct pinctrl_dev *pctldev,
                return -EINVAL;
 
        /* Find the pinctrl config with GPIO mux mode for the requested pin */
-       for (group = 0; group < info->ngroups; group++) {
-               grp = &info->groups[group];
-               for (pin = 0; pin < grp->npins; pin++) {
-                       imx_pin = &grp->pins[pin];
+       for (group = 0; group < pctldev->num_groups; group++) {
+               grp = pinctrl_generic_get_group(pctldev, group);
+               if (!grp)
+                       continue;
+               for (pin = 0; pin < grp->num_pins; pin++) {
+                       imx_pin = &((struct imx_pin *)(grp->data))[pin];
                        if (imx_pin->pin == offset && !imx_pin->mux_mode)
                                goto mux_pin;
                }
@@ -346,7 +298,7 @@ static void imx_pmx_gpio_disable_free(struct pinctrl_dev *pctldev,
                        struct pinctrl_gpio_range *range, unsigned offset)
 {
        struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
-       const struct imx_pinctrl_soc_info *info = ipctl->info;
+       struct imx_pinctrl_soc_info *info = ipctl->info;
        const struct imx_pin_reg *pin_reg;
        u32 reg;
 
@@ -371,7 +323,7 @@ static int imx_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
           struct pinctrl_gpio_range *range, unsigned offset, bool input)
 {
        struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
-       const struct imx_pinctrl_soc_info *info = ipctl->info;
+       struct imx_pinctrl_soc_info *info = ipctl->info;
        const struct imx_pin_reg *pin_reg;
        u32 reg;
 
@@ -398,9 +350,9 @@ static int imx_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
 }
 
 static const struct pinmux_ops imx_pmx_ops = {
-       .get_functions_count = imx_pmx_get_funcs_count,
-       .get_function_name = imx_pmx_get_func_name,
-       .get_function_groups = imx_pmx_get_groups,
+       .get_functions_count = pinmux_generic_get_function_count,
+       .get_function_name = pinmux_generic_get_function_name,
+       .get_function_groups = pinmux_generic_get_function_groups,
        .set_mux = imx_pmx_set,
        .gpio_request_enable = imx_pmx_gpio_request_enable,
        .gpio_disable_free = imx_pmx_gpio_disable_free,
@@ -411,7 +363,7 @@ static int imx_pinconf_get(struct pinctrl_dev *pctldev,
                             unsigned pin_id, unsigned long *config)
 {
        struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
-       const struct imx_pinctrl_soc_info *info = ipctl->info;
+       struct imx_pinctrl_soc_info *info = ipctl->info;
        const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
 
        if (pin_reg->conf_reg == -1) {
@@ -433,7 +385,7 @@ static int imx_pinconf_set(struct pinctrl_dev *pctldev,
                             unsigned num_configs)
 {
        struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
-       const struct imx_pinctrl_soc_info *info = ipctl->info;
+       struct imx_pinctrl_soc_info *info = ipctl->info;
        const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
        int i;
 
@@ -467,7 +419,7 @@ static void imx_pinconf_dbg_show(struct pinctrl_dev *pctldev,
                                   struct seq_file *s, unsigned pin_id)
 {
        struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
-       const struct imx_pinctrl_soc_info *info = ipctl->info;
+       struct imx_pinctrl_soc_info *info = ipctl->info;
        const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
        unsigned long config;
 
@@ -483,20 +435,22 @@ static void imx_pinconf_dbg_show(struct pinctrl_dev *pctldev,
 static void imx_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
                                         struct seq_file *s, unsigned group)
 {
-       struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
-       const struct imx_pinctrl_soc_info *info = ipctl->info;
-       struct imx_pin_group *grp;
+       struct group_desc *grp;
        unsigned long config;
        const char *name;
        int i, ret;
 
-       if (group > info->ngroups)
+       if (group > pctldev->num_groups)
                return;
 
        seq_printf(s, "\n");
-       grp = &info->groups[group];
-       for (i = 0; i < grp->npins; i++) {
-               struct imx_pin *pin = &grp->pins[i];
+       grp = pinctrl_generic_get_group(pctldev, group);
+       if (!grp)
+               return;
+
+       for (i = 0; i < grp->num_pins; i++) {
+               struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i];
+
                name = pin_get_name(pctldev, pin->pin);
                ret = imx_pinconf_get(pctldev, pin->pin, &config);
                if (ret)
@@ -520,7 +474,7 @@ static const struct pinconf_ops imx_pinconf_ops = {
 #define SHARE_FSL_PIN_SIZE 20
 
 static int imx_pinctrl_parse_groups(struct device_node *np,
-                                   struct imx_pin_group *grp,
+                                   struct group_desc *grp,
                                    struct imx_pinctrl_soc_info *info,
                                    u32 index)
 {
@@ -554,20 +508,20 @@ static int imx_pinctrl_parse_groups(struct device_node *np,
                return -EINVAL;
        }
 
-       grp->npins = size / pin_size;
-       grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(struct imx_pin),
-                               GFP_KERNEL);
-       grp->pin_ids = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int),
-                               GFP_KERNEL);
-       if (!grp->pins || ! grp->pin_ids)
+       grp->num_pins = size / pin_size;
+       grp->data = devm_kzalloc(info->dev, grp->num_pins *
+                                sizeof(struct imx_pin), GFP_KERNEL);
+       grp->pins = devm_kzalloc(info->dev, grp->num_pins *
+                                sizeof(unsigned int), GFP_KERNEL);
+       if (!grp->pins || !grp->data)
                return -ENOMEM;
 
-       for (i = 0; i < grp->npins; i++) {
+       for (i = 0; i < grp->num_pins; i++) {
                u32 mux_reg = be32_to_cpu(*list++);
                u32 conf_reg;
                unsigned int pin_id;
                struct imx_pin_reg *pin_reg;
-               struct imx_pin *pin = &grp->pins[i];
+               struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i];
 
                if (!(info->flags & ZERO_OFFSET_VALID) && !mux_reg)
                        mux_reg = -1;
@@ -583,7 +537,7 @@ static int imx_pinctrl_parse_groups(struct device_node *np,
                pin_id = (mux_reg != -1) ? mux_reg / 4 : conf_reg / 4;
                pin_reg = &info->pin_regs[pin_id];
                pin->pin = pin_id;
-               grp->pin_ids[i] = pin_id;
+               grp->pins[i] = pin_id;
                pin_reg->mux_reg = mux_reg;
                pin_reg->conf_reg = conf_reg;
                pin->input_reg = be32_to_cpu(*list++);
@@ -604,31 +558,46 @@ static int imx_pinctrl_parse_groups(struct device_node *np,
 }
 
 static int imx_pinctrl_parse_functions(struct device_node *np,
-                                      struct imx_pinctrl_soc_info *info,
+                                      struct imx_pinctrl *ipctl,
                                       u32 index)
 {
+       struct pinctrl_dev *pctl = ipctl->pctl;
+       struct imx_pinctrl_soc_info *info = ipctl->info;
        struct device_node *child;
-       struct imx_pmx_func *func;
-       struct imx_pin_group *grp;
+       struct function_desc *func;
+       struct group_desc *grp;
        u32 i = 0;
 
        dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name);
 
-       func = &info->functions[index];
+       func = pinmux_generic_get_function(pctl, index);
+       if (!func)
+               return -EINVAL;
 
        /* Initialise function */
        func->name = np->name;
-       func->num_groups = of_get_child_count(np);
-       if (func->num_groups == 0) {
+       func->num_group_names = of_get_child_count(np);
+       if (func->num_group_names == 0) {
                dev_err(info->dev, "no groups defined in %s\n", np->full_name);
                return -EINVAL;
        }
-       func->groups = devm_kzalloc(info->dev,
-                       func->num_groups * sizeof(char *), GFP_KERNEL);
+       func->group_names = devm_kzalloc(info->dev,
+                                        func->num_group_names *
+                                        sizeof(char *), GFP_KERNEL);
 
        for_each_child_of_node(np, child) {
-               func->groups[i] = child->name;
-               grp = &info->groups[info->group_index++];
+               func->group_names[i] = child->name;
+
+               grp = devm_kzalloc(info->dev, sizeof(struct group_desc),
+                                  GFP_KERNEL);
+               if (!grp)
+                       return -ENOMEM;
+
+               mutex_lock(&info->mutex);
+               radix_tree_insert(&pctl->pin_group_tree,
+                                 info->group_index++, grp);
+               mutex_unlock(&info->mutex);
+
                imx_pinctrl_parse_groups(child, grp, info, i++);
        }
 
@@ -659,10 +628,12 @@ static bool imx_pinctrl_dt_is_flat_functions(struct device_node *np)
 }
 
 static int imx_pinctrl_probe_dt(struct platform_device *pdev,
-                               struct imx_pinctrl_soc_info *info)
+                               struct imx_pinctrl *ipctl)
 {
        struct device_node *np = pdev->dev.of_node;
        struct device_node *child;
+       struct pinctrl_dev *pctl = ipctl->pctl;
+       struct imx_pinctrl_soc_info *info = ipctl->info;
        u32 nfuncs = 0;
        u32 i = 0;
        bool flat_funcs;
@@ -681,35 +652,50 @@ static int imx_pinctrl_probe_dt(struct platform_device *pdev,
                }
        }
 
-       info->nfunctions = nfuncs;
-       info->functions = devm_kzalloc(&pdev->dev, nfuncs * sizeof(struct imx_pmx_func),
+       for (i = 0; i < nfuncs; i++) {
+               struct function_desc *function;
+
+               function = devm_kzalloc(&pdev->dev, sizeof(*function),
                                        GFP_KERNEL);
-       if (!info->functions)
-               return -ENOMEM;
+               if (!function)
+                       return -ENOMEM;
+
+               mutex_lock(&info->mutex);
+               radix_tree_insert(&pctl->pin_function_tree, i, function);
+               mutex_unlock(&info->mutex);
+       }
+       pctl->num_functions = nfuncs;
 
        info->group_index = 0;
        if (flat_funcs) {
-               info->ngroups = of_get_child_count(np);
+               pctl->num_groups = of_get_child_count(np);
        } else {
-               info->ngroups = 0;
+               pctl->num_groups = 0;
                for_each_child_of_node(np, child)
-                       info->ngroups += of_get_child_count(child);
+                       pctl->num_groups += of_get_child_count(child);
        }
-       info->groups = devm_kzalloc(&pdev->dev, info->ngroups * sizeof(struct imx_pin_group),
-                                       GFP_KERNEL);
-       if (!info->groups)
-               return -ENOMEM;
 
        if (flat_funcs) {
-               imx_pinctrl_parse_functions(np, info, 0);
+               imx_pinctrl_parse_functions(np, ipctl, 0);
        } else {
+               i = 0;
                for_each_child_of_node(np, child)
-                       imx_pinctrl_parse_functions(child, info, i++);
+                       imx_pinctrl_parse_functions(child, ipctl, i++);
        }
 
        return 0;
 }
 
+/*
+ * imx_free_resources() - free memory used by this driver
+ * @info: info driver instance
+ */
+static void imx_free_resources(struct imx_pinctrl *ipctl)
+{
+       if (ipctl->pctl)
+               pinctrl_unregister(ipctl->pctl);
+}
+
 int imx_pinctrl_probe(struct platform_device *pdev,
                      struct imx_pinctrl_soc_info *info)
 {
@@ -783,23 +769,31 @@ int imx_pinctrl_probe(struct platform_device *pdev,
        imx_pinctrl_desc->confops = &imx_pinconf_ops;
        imx_pinctrl_desc->owner = THIS_MODULE;
 
-       ret = imx_pinctrl_probe_dt(pdev, info);
-       if (ret) {
-               dev_err(&pdev->dev, "fail to probe dt properties\n");
-               return ret;
-       }
+       mutex_init(&info->mutex);
 
        ipctl->info = info;
        ipctl->dev = info->dev;
        platform_set_drvdata(pdev, ipctl);
-       ipctl->pctl = devm_pinctrl_register(&pdev->dev,
-                                           imx_pinctrl_desc, ipctl);
-       if (IS_ERR(ipctl->pctl)) {
+       ret = devm_pinctrl_register_and_init(&pdev->dev,
+                                            imx_pinctrl_desc, ipctl,
+                                            &ipctl->pctl);
+       if (ret) {
                dev_err(&pdev->dev, "could not register IMX pinctrl driver\n");
-               return PTR_ERR(ipctl->pctl);
+               goto free;
+       }
+
+       ret = imx_pinctrl_probe_dt(pdev, ipctl);
+       if (ret) {
+               dev_err(&pdev->dev, "fail to probe dt properties\n");
+               goto free;
        }
 
        dev_info(&pdev->dev, "initialized IMX pinctrl driver\n");
 
        return 0;
+
+free:
+       imx_free_resources(ipctl);
+
+       return ret;
 }
index 8af8aa2897abfaec7a8b281a2e54704a1fa13e4e..ff2d3e56b7c50322eb1ef1220e955db71fac841d 100644 (file)
@@ -18,7 +18,7 @@
 struct platform_device;
 
 /**
- * struct imx_pin_group - describes a single i.MX pin
+ * struct imx_pin - describes a single i.MX pin
  * @pin: the pin_id of this pin
  * @mux_mode: the mux mode for this pin.
  * @input_reg: the select input register offset for this pin if any
@@ -34,33 +34,6 @@ struct imx_pin {
        unsigned long config;
 };
 
-/**
- * struct imx_pin_group - describes an IMX pin group
- * @name: the name of this specific pin group
- * @npins: the number of pins in this group array, i.e. the number of
- *     elements in .pins so we can iterate over that array
- * @pin_ids: array of pin_ids. pinctrl forces us to maintain such an array
- * @pins: array of pins
- */
-struct imx_pin_group {
-       const char *name;
-       unsigned npins;
-       unsigned int *pin_ids;
-       struct imx_pin *pins;
-};
-
-/**
- * struct imx_pmx_func - describes IMX pinmux functions
- * @name: the name of this specific function
- * @groups: corresponding pin groups
- * @num_groups: the number of groups
- */
-struct imx_pmx_func {
-       const char *name;
-       const char **groups;
-       unsigned num_groups;
-};
-
 /**
  * struct imx_pin_reg - describe a pin reg map
  * @mux_reg: mux register offset
@@ -76,13 +49,10 @@ struct imx_pinctrl_soc_info {
        const struct pinctrl_pin_desc *pins;
        unsigned int npins;
        struct imx_pin_reg *pin_regs;
-       struct imx_pin_group *groups;
-       unsigned int ngroups;
        unsigned int group_index;
-       struct imx_pmx_func *functions;
-       unsigned int nfunctions;
        unsigned int flags;
        const char *gpr_compatible;
+       struct mutex mutex;
 };
 
 #define SHARE_MUX_CONF_REG     0x1
index 00fb055a489794597c6abf45b6909c4a2907db88..396830a41127a7538d2df8967f46f96f9e91e52e 100644 (file)
@@ -56,6 +56,14 @@ config PINCTRL_BROXTON
          Broxton pinctrl driver provides an interface that allows
          configuring of SoC pins and using them as GPIOs.
 
+config PINCTRL_GEMINILAKE
+       tristate "Intel Gemini Lake SoC pinctrl and GPIO driver"
+       depends on ACPI
+       select PINCTRL_INTEL
+       help
+         This pinctrl driver provides an interface that allows configuring
+         of Intel Gemini Lake SoC pins and using them as GPIOs.
+
 config PINCTRL_SUNRISEPOINT
        tristate "Intel Sunrisepoint pinctrl and GPIO driver"
        depends on ACPI
index 30803078f09eeb6865cb1cf9ffac886c3d9ca6e0..12f3af5b2ca5da690086168170781e4d37a6dc60 100644 (file)
@@ -5,4 +5,5 @@ obj-$(CONFIG_PINCTRL_CHERRYVIEW)        += pinctrl-cherryview.o
 obj-$(CONFIG_PINCTRL_MERRIFIELD)       += pinctrl-merrifield.o
 obj-$(CONFIG_PINCTRL_INTEL)            += pinctrl-intel.o
 obj-$(CONFIG_PINCTRL_BROXTON)          += pinctrl-broxton.o
+obj-$(CONFIG_PINCTRL_GEMINILAKE)       += pinctrl-geminilake.o
 obj-$(CONFIG_PINCTRL_SUNRISEPOINT)     += pinctrl-sunrisepoint.o
index d94aef17348b4b88f3952670886b863b952cfc60..fa3c5758ac6739f3fe07df34bc29fb13cfab21af 100644 (file)
@@ -1466,7 +1466,7 @@ static void byt_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
                           val & BYT_INPUT_EN ? "  " : "in",
                           val & BYT_OUTPUT_EN ? "   " : "out",
                           val & BYT_LEVEL ? "hi" : "lo",
-                          comm->pad_map[i], comm->pad_map[i] * 32,
+                          comm->pad_map[i], comm->pad_map[i] * 16,
                           conf0 & 0x7,
                           conf0 & BYT_TRIG_NEG ? " fall" : "     ",
                           conf0 & BYT_TRIG_POS ? " rise" : "     ",
@@ -1709,7 +1709,7 @@ static int byt_gpio_probe(struct byt_gpio *vg)
        vg->saved_context = devm_kcalloc(&vg->pdev->dev, gc->ngpio,
                                       sizeof(*vg->saved_context), GFP_KERNEL);
 #endif
-       ret = gpiochip_add_data(gc, vg);
+       ret = devm_gpiochip_add_data(&vg->pdev->dev, gc, vg);
        if (ret) {
                dev_err(&vg->pdev->dev, "failed adding byt-gpio chip\n");
                return ret;
@@ -1719,7 +1719,7 @@ static int byt_gpio_probe(struct byt_gpio *vg)
                                     0, 0, vg->soc_data->npins);
        if (ret) {
                dev_err(&vg->pdev->dev, "failed to add GPIO pin range\n");
-               goto fail;
+               return ret;
        }
 
        /* set up interrupts  */
@@ -1730,7 +1730,7 @@ static int byt_gpio_probe(struct byt_gpio *vg)
                                           handle_bad_irq, IRQ_TYPE_NONE);
                if (ret) {
                        dev_err(&vg->pdev->dev, "failed to add irqchip\n");
-                       goto fail;
+                       return ret;
                }
 
                gpiochip_set_chained_irqchip(gc, &byt_irqchip,
@@ -1738,11 +1738,6 @@ static int byt_gpio_probe(struct byt_gpio *vg)
                                             byt_gpio_irq_handler);
        }
 
-       return ret;
-
-fail:
-       gpiochip_remove(&vg->chip);
-
        return ret;
 }
 
@@ -1826,7 +1821,7 @@ static int byt_pinctrl_probe(struct platform_device *pdev)
        vg->pctl_desc.pins      = vg->soc_data->pins;
        vg->pctl_desc.npins     = vg->soc_data->npins;
 
-       vg->pctl_dev = pinctrl_register(&vg->pctl_desc, &pdev->dev, vg);
+       vg->pctl_dev = devm_pinctrl_register(&pdev->dev, &vg->pctl_desc, vg);
        if (IS_ERR(vg->pctl_dev)) {
                dev_err(&pdev->dev, "failed to register pinctrl driver\n");
                return PTR_ERR(vg->pctl_dev);
@@ -1835,10 +1830,8 @@ static int byt_pinctrl_probe(struct platform_device *pdev)
        raw_spin_lock_init(&vg->lock);
 
        ret = byt_gpio_probe(vg);
-       if (ret) {
-               pinctrl_unregister(vg->pctl_dev);
+       if (ret)
                return ret;
-       }
 
        platform_set_drvdata(pdev, vg);
        pm_runtime_enable(&pdev->dev);
index 901b356b09d71679a2b4a03f7cd57b30a22fa6f4..e6e6fd1125858b45fd1053d37f75c178cc91cf36 100644 (file)
@@ -1004,8 +1004,8 @@ static const struct acpi_device_id bxt_pinctrl_acpi_match[] = {
 MODULE_DEVICE_TABLE(acpi, bxt_pinctrl_acpi_match);
 
 static const struct platform_device_id bxt_pinctrl_platform_ids[] = {
-       { "apl-pinctrl", (kernel_ulong_t)&apl_pinctrl_soc_data },
-       { "broxton-pinctrl", (kernel_ulong_t)&bxt_pinctrl_soc_data },
+       { "apollolake-pinctrl", (kernel_ulong_t)apl_pinctrl_soc_data },
+       { "broxton-pinctrl", (kernel_ulong_t)bxt_pinctrl_soc_data },
        { },
 };
 
@@ -1058,7 +1058,6 @@ static const struct dev_pm_ops bxt_pinctrl_pm_ops = {
 
 static struct platform_driver bxt_pinctrl_driver = {
        .probe = bxt_pinctrl_probe,
-       .remove = intel_pinctrl_remove,
        .driver = {
                .name = "broxton-pinctrl",
                .acpi_match_table = bxt_pinctrl_acpi_match,
index 5e66860a5e677290a0c649728cc48f852cc408b9..f80134e3e0b68aba9f8b94771702cdd3df83a678 100644 (file)
@@ -1059,7 +1059,7 @@ static int chv_config_get(struct pinctrl_dev *pctldev, unsigned pin,
 }
 
 static int chv_config_set_pull(struct chv_pinctrl *pctrl, unsigned pin,
-                              enum pin_config_param param, u16 arg)
+                              enum pin_config_param param, u32 arg)
 {
        void __iomem *reg = chv_padreg(pctrl, pin, CHV_PADCTRL0);
        unsigned long flags;
@@ -1151,7 +1151,7 @@ static int chv_config_set(struct pinctrl_dev *pctldev, unsigned pin,
        struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
        enum pin_config_param param;
        int i, ret;
-       u16 arg;
+       u32 arg;
 
        if (chv_pad_locked(pctrl, pin))
                return -EBUSY;
diff --git a/drivers/pinctrl/intel/pinctrl-geminilake.c b/drivers/pinctrl/intel/pinctrl-geminilake.c
new file mode 100644 (file)
index 0000000..a6b94c9
--- /dev/null
@@ -0,0 +1,512 @@
+/*
+ * Intel Gemini Lake SoC pinctrl/GPIO driver
+ *
+ * Copyright (C) 2017 Intel Corporation
+ * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/acpi.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-intel.h"
+
+#define GLK_PAD_OWN    0x020
+#define GLK_HOSTSW_OWN 0x0b0
+#define GLK_PADCFGLOCK 0x080
+#define GLK_GPI_IE     0x110
+
+#define GLK_COMMUNITY(s, e)                            \
+       {                                               \
+               .padown_offset = GLK_PAD_OWN,           \
+               .padcfglock_offset = GLK_PADCFGLOCK,    \
+               .hostown_offset = GLK_HOSTSW_OWN,       \
+               .ie_offset = GLK_GPI_IE,                \
+               .gpp_size = 32,                         \
+               .pin_base = (s),                        \
+               .npins = ((e) - (s) + 1),               \
+       }
+
+/* GLK */
+static const struct pinctrl_pin_desc glk_northwest_pins[] = {
+       PINCTRL_PIN(0, "TCK"),
+       PINCTRL_PIN(1, "TRST_B"),
+       PINCTRL_PIN(2, "TMS"),
+       PINCTRL_PIN(3, "TDI"),
+       PINCTRL_PIN(4, "TDO"),
+       PINCTRL_PIN(5, "JTAGX"),
+       PINCTRL_PIN(6, "CX_PREQ_B"),
+       PINCTRL_PIN(7, "CX_PRDY_B"),
+       PINCTRL_PIN(8, "GPIO_8"),
+       PINCTRL_PIN(9, "GPIO_9"),
+       PINCTRL_PIN(10, "GPIO_10"),
+       PINCTRL_PIN(11, "GPIO_11"),
+       PINCTRL_PIN(12, "GPIO_12"),
+       PINCTRL_PIN(13, "GPIO_13"),
+       PINCTRL_PIN(14, "GPIO_14"),
+       PINCTRL_PIN(15, "GPIO_15"),
+       PINCTRL_PIN(16, "GPIO_16"),
+       PINCTRL_PIN(17, "GPIO_17"),
+       PINCTRL_PIN(18, "GPIO_18"),
+       PINCTRL_PIN(19, "GPIO_19"),
+       PINCTRL_PIN(20, "GPIO_20"),
+       PINCTRL_PIN(21, "GPIO_21"),
+       PINCTRL_PIN(22, "GPIO_22"),
+       PINCTRL_PIN(23, "GPIO_23"),
+       PINCTRL_PIN(24, "GPIO_24"),
+       PINCTRL_PIN(25, "GPIO_25"),
+       PINCTRL_PIN(26, "GPIO_26"),
+       PINCTRL_PIN(27, "GPIO_27"),
+       PINCTRL_PIN(28, "GPIO_28"),
+       PINCTRL_PIN(29, "GPIO_29"),
+       PINCTRL_PIN(30, "GPIO_30"),
+       PINCTRL_PIN(31, "GPIO_31"),
+       PINCTRL_PIN(32, "GPIO_32"),
+       PINCTRL_PIN(33, "GPIO_33"),
+       PINCTRL_PIN(34, "GPIO_34"),
+       PINCTRL_PIN(35, "GPIO_35"),
+       PINCTRL_PIN(36, "GPIO_36"),
+       PINCTRL_PIN(37, "GPIO_37"),
+       PINCTRL_PIN(38, "GPIO_38"),
+       PINCTRL_PIN(39, "GPIO_39"),
+       PINCTRL_PIN(40, "GPIO_40"),
+       PINCTRL_PIN(41, "GPIO_41"),
+       PINCTRL_PIN(42, "GP_INTD_DSI_TE1"),
+       PINCTRL_PIN(43, "GP_INTD_DSI_TE2"),
+       PINCTRL_PIN(44, "USB_OC0_B"),
+       PINCTRL_PIN(45, "USB_OC1_B"),
+       PINCTRL_PIN(46, "DSI_I2C_SDA"),
+       PINCTRL_PIN(47, "DSI_I2C_SCL"),
+       PINCTRL_PIN(48, "PMC_I2C_SDA"),
+       PINCTRL_PIN(49, "PMC_I2C_SCL"),
+       PINCTRL_PIN(50, "LPSS_I2C0_SDA"),
+       PINCTRL_PIN(51, "LPSS_I2C0_SCL"),
+       PINCTRL_PIN(52, "LPSS_I2C1_SDA"),
+       PINCTRL_PIN(53, "LPSS_I2C1_SCL"),
+       PINCTRL_PIN(54, "LPSS_I2C2_SDA"),
+       PINCTRL_PIN(55, "LPSS_I2C2_SCL"),
+       PINCTRL_PIN(56, "LPSS_I2C3_SDA"),
+       PINCTRL_PIN(57, "LPSS_I2C3_SCL"),
+       PINCTRL_PIN(58, "LPSS_I2C4_SDA"),
+       PINCTRL_PIN(59, "LPSS_I2C4_SCL"),
+       PINCTRL_PIN(60, "LPSS_UART0_RXD"),
+       PINCTRL_PIN(61, "LPSS_UART0_TXD"),
+       PINCTRL_PIN(62, "LPSS_UART0_RTS_B"),
+       PINCTRL_PIN(63, "LPSS_UART0_CTS_B"),
+       PINCTRL_PIN(64, "LPSS_UART2_RXD"),
+       PINCTRL_PIN(65, "LPSS_UART2_TXD"),
+       PINCTRL_PIN(66, "LPSS_UART2_RTS_B"),
+       PINCTRL_PIN(67, "LPSS_UART2_CTS_B"),
+       PINCTRL_PIN(68, "PMC_SPI_FS0"),
+       PINCTRL_PIN(69, "PMC_SPI_FS1"),
+       PINCTRL_PIN(70, "PMC_SPI_FS2"),
+       PINCTRL_PIN(71, "PMC_SPI_RXD"),
+       PINCTRL_PIN(72, "PMC_SPI_TXD"),
+       PINCTRL_PIN(73, "PMC_SPI_CLK"),
+       PINCTRL_PIN(74, "THERMTRIP_B"),
+       PINCTRL_PIN(75, "PROCHOT_B"),
+       PINCTRL_PIN(76, "EMMC_RST_B"),
+       PINCTRL_PIN(77, "GPIO_212"),
+       PINCTRL_PIN(78, "GPIO_213"),
+       PINCTRL_PIN(79, "GPIO_214"),
+};
+
+static const unsigned int glk_northwest_uart1_pins[] = { 26, 27, 28, 29 };
+static const unsigned int glk_northwest_pwm0_pins[] = { 42 };
+static const unsigned int glk_northwest_pwm1_pins[] = { 43 };
+static const unsigned int glk_northwest_pwm2_pins[] = { 44 };
+static const unsigned int glk_northwest_pwm3_pins[] = { 45 };
+static const unsigned int glk_northwest_i2c0_pins[] = { 50, 51 };
+static const unsigned int glk_northwest_i2c1_pins[] = { 52, 53 };
+static const unsigned int glk_northwest_i2c2_pins[] = { 54, 55 };
+static const unsigned int glk_northwest_i2c3_pins[] = { 56, 57 };
+static const unsigned int glk_northwest_i2c4_pins[] = { 58, 59 };
+static const unsigned int glk_northwest_uart0_pins[] = { 60, 61, 62, 63 };
+static const unsigned int glk_northwest_uart2_pins[] = { 64, 65, 66, 67 };
+
+static const struct intel_pingroup glk_northwest_groups[] = {
+       PIN_GROUP("uart1_grp", glk_northwest_uart1_pins, 2),
+       PIN_GROUP("pwm0_grp", glk_northwest_pwm0_pins, 2),
+       PIN_GROUP("pwm1_grp", glk_northwest_pwm1_pins, 2),
+       PIN_GROUP("pwm2_grp", glk_northwest_pwm2_pins, 2),
+       PIN_GROUP("pwm3_grp", glk_northwest_pwm3_pins, 2),
+       PIN_GROUP("i2c0_grp", glk_northwest_i2c0_pins, 1),
+       PIN_GROUP("i2c1_grp", glk_northwest_i2c1_pins, 1),
+       PIN_GROUP("i2c2_grp", glk_northwest_i2c2_pins, 1),
+       PIN_GROUP("i2c3_grp", glk_northwest_i2c3_pins, 1),
+       PIN_GROUP("i2c4_grp", glk_northwest_i2c4_pins, 1),
+       PIN_GROUP("uart0_grp", glk_northwest_uart0_pins, 1),
+       PIN_GROUP("uart2_grp", glk_northwest_uart2_pins, 1),
+};
+
+static const char * const glk_northwest_uart1_groups[] = { "uart1_grp" };
+static const char * const glk_northwest_pwm0_groups[] = { "pwm0_grp" };
+static const char * const glk_northwest_pwm1_groups[] = { "pwm1_grp" };
+static const char * const glk_northwest_pwm2_groups[] = { "pwm2_grp" };
+static const char * const glk_northwest_pwm3_groups[] = { "pwm3_grp" };
+static const char * const glk_northwest_i2c0_groups[] = { "i2c0_grp" };
+static const char * const glk_northwest_i2c1_groups[] = { "i2c1_grp" };
+static const char * const glk_northwest_i2c2_groups[] = { "i2c2_grp" };
+static const char * const glk_northwest_i2c3_groups[] = { "i2c3_grp" };
+static const char * const glk_northwest_i2c4_groups[] = { "i2c4_grp" };
+static const char * const glk_northwest_uart0_groups[] = { "uart0_grp" };
+static const char * const glk_northwest_uart2_groups[] = { "uart2_grp" };
+
+static const struct intel_function glk_northwest_functions[] = {
+       FUNCTION("uart1", glk_northwest_uart1_groups),
+       FUNCTION("pmw0", glk_northwest_pwm0_groups),
+       FUNCTION("pmw1", glk_northwest_pwm1_groups),
+       FUNCTION("pmw2", glk_northwest_pwm2_groups),
+       FUNCTION("pmw3", glk_northwest_pwm3_groups),
+       FUNCTION("i2c0", glk_northwest_i2c0_groups),
+       FUNCTION("i2c1", glk_northwest_i2c1_groups),
+       FUNCTION("i2c2", glk_northwest_i2c2_groups),
+       FUNCTION("i2c3", glk_northwest_i2c3_groups),
+       FUNCTION("i2c4", glk_northwest_i2c4_groups),
+       FUNCTION("uart0", glk_northwest_uart0_groups),
+       FUNCTION("uart2", glk_northwest_uart2_groups),
+};
+
+static const struct intel_community glk_northwest_communities[] = {
+       GLK_COMMUNITY(0, 79),
+};
+
+static const struct intel_pinctrl_soc_data glk_northwest_soc_data = {
+       .uid = "1",
+       .pins = glk_northwest_pins,
+       .npins = ARRAY_SIZE(glk_northwest_pins),
+       .groups = glk_northwest_groups,
+       .ngroups = ARRAY_SIZE(glk_northwest_groups),
+       .functions = glk_northwest_functions,
+       .nfunctions = ARRAY_SIZE(glk_northwest_functions),
+       .communities = glk_northwest_communities,
+       .ncommunities = ARRAY_SIZE(glk_northwest_communities),
+};
+
+static const struct pinctrl_pin_desc glk_north_pins[] = {
+       PINCTRL_PIN(0, "SVID0_ALERT_B"),
+       PINCTRL_PIN(1, "SVID0_DATA"),
+       PINCTRL_PIN(2, "SVID0_CLK"),
+       PINCTRL_PIN(3, "LPSS_SPI_0_CLK"),
+       PINCTRL_PIN(4, "LPSS_SPI_0_FS0"),
+       PINCTRL_PIN(5, "LPSS_SPI_0_FS1"),
+       PINCTRL_PIN(6, "LPSS_SPI_0_RXD"),
+       PINCTRL_PIN(7, "LPSS_SPI_0_TXD"),
+       PINCTRL_PIN(8, "LPSS_SPI_1_CLK"),
+       PINCTRL_PIN(9, "LPSS_SPI_1_FS0"),
+       PINCTRL_PIN(10, "LPSS_SPI_1_FS1"),
+       PINCTRL_PIN(11, "LPSS_SPI_1_FS2"),
+       PINCTRL_PIN(12, "LPSS_SPI_1_RXD"),
+       PINCTRL_PIN(13, "LPSS_SPI_1_TXD"),
+       PINCTRL_PIN(14, "FST_SPI_CS0_B"),
+       PINCTRL_PIN(15, "FST_SPI_CS1_B"),
+       PINCTRL_PIN(16, "FST_SPI_MOSI_IO0"),
+       PINCTRL_PIN(17, "FST_SPI_MISO_IO1"),
+       PINCTRL_PIN(18, "FST_SPI_IO2"),
+       PINCTRL_PIN(19, "FST_SPI_IO3"),
+       PINCTRL_PIN(20, "FST_SPI_CLK"),
+       PINCTRL_PIN(21, "FST_SPI_CLK_FB"),
+       PINCTRL_PIN(22, "PMU_PLTRST_B"),
+       PINCTRL_PIN(23, "PMU_PWRBTN_B"),
+       PINCTRL_PIN(24, "PMU_SLP_S0_B"),
+       PINCTRL_PIN(25, "PMU_SLP_S3_B"),
+       PINCTRL_PIN(26, "PMU_SLP_S4_B"),
+       PINCTRL_PIN(27, "SUSPWRDNACK"),
+       PINCTRL_PIN(28, "EMMC_PWR_EN_B"),
+       PINCTRL_PIN(29, "PMU_AC_PRESENT"),
+       PINCTRL_PIN(30, "PMU_BATLOW_B"),
+       PINCTRL_PIN(31, "PMU_RESETBUTTON_B"),
+       PINCTRL_PIN(32, "PMU_SUSCLK"),
+       PINCTRL_PIN(33, "SUS_STAT_B"),
+       PINCTRL_PIN(34, "LPSS_I2C5_SDA"),
+       PINCTRL_PIN(35, "LPSS_I2C5_SCL"),
+       PINCTRL_PIN(36, "LPSS_I2C6_SDA"),
+       PINCTRL_PIN(37, "LPSS_I2C6_SCL"),
+       PINCTRL_PIN(38, "LPSS_I2C7_SDA"),
+       PINCTRL_PIN(39, "LPSS_I2C7_SCL"),
+       PINCTRL_PIN(40, "PCIE_WAKE0_B"),
+       PINCTRL_PIN(41, "PCIE_WAKE1_B"),
+       PINCTRL_PIN(42, "PCIE_WAKE2_B"),
+       PINCTRL_PIN(43, "PCIE_WAKE3_B"),
+       PINCTRL_PIN(44, "PCIE_CLKREQ0_B"),
+       PINCTRL_PIN(45, "PCIE_CLKREQ1_B"),
+       PINCTRL_PIN(46, "PCIE_CLKREQ2_B"),
+       PINCTRL_PIN(47, "PCIE_CLKREQ3_B"),
+       PINCTRL_PIN(48, "HV_DDI0_DDC_SDA"),
+       PINCTRL_PIN(49, "HV_DDI0_DDC_SCL"),
+       PINCTRL_PIN(50, "HV_DDI1_DDC_SDA"),
+       PINCTRL_PIN(51, "HV_DDI1_DDC_SCL"),
+       PINCTRL_PIN(52, "PANEL0_VDDEN"),
+       PINCTRL_PIN(53, "PANEL0_BKLTEN"),
+       PINCTRL_PIN(54, "PANEL0_BKLTCTL"),
+       PINCTRL_PIN(55, "HV_DDI0_HPD"),
+       PINCTRL_PIN(56, "HV_DDI1_HPD"),
+       PINCTRL_PIN(57, "HV_EDP_HPD"),
+       PINCTRL_PIN(58, "GPIO_134"),
+       PINCTRL_PIN(59, "GPIO_135"),
+       PINCTRL_PIN(60, "GPIO_136"),
+       PINCTRL_PIN(61, "GPIO_137"),
+       PINCTRL_PIN(62, "GPIO_138"),
+       PINCTRL_PIN(63, "GPIO_139"),
+       PINCTRL_PIN(64, "GPIO_140"),
+       PINCTRL_PIN(65, "GPIO_141"),
+       PINCTRL_PIN(66, "GPIO_142"),
+       PINCTRL_PIN(67, "GPIO_143"),
+       PINCTRL_PIN(68, "GPIO_144"),
+       PINCTRL_PIN(69, "GPIO_145"),
+       PINCTRL_PIN(70, "GPIO_146"),
+       PINCTRL_PIN(71, "LPC_ILB_SERIRQ"),
+       PINCTRL_PIN(72, "LPC_CLKOUT0"),
+       PINCTRL_PIN(73, "LPC_CLKOUT1"),
+       PINCTRL_PIN(74, "LPC_AD0"),
+       PINCTRL_PIN(75, "LPC_AD1"),
+       PINCTRL_PIN(76, "LPC_AD2"),
+       PINCTRL_PIN(77, "LPC_AD3"),
+       PINCTRL_PIN(78, "LPC_CLKRUNB"),
+       PINCTRL_PIN(79, "LPC_FRAMEB"),
+};
+
+static const unsigned int glk_north_spi0_pins[] = { 3, 4, 5, 6, 7 };
+static const unsigned int glk_north_spi1_pins[] = { 8, 9, 10, 11, 12, 13 };
+static const unsigned int glk_north_i2c5_pins[] = { 34, 35 };
+static const unsigned int glk_north_i2c6_pins[] = { 36, 37 };
+static const unsigned int glk_north_i2c7_pins[] = { 38, 39 };
+static const unsigned int glk_north_uart0_pins[] = { 62, 63, 64, 65 };
+static const unsigned int glk_north_spi0b_pins[] = { 66, 67, 68, 69, 70 };
+
+static const struct intel_pingroup glk_north_groups[] = {
+       PIN_GROUP("spi0_grp", glk_north_spi0_pins, 1),
+       PIN_GROUP("spi1_grp", glk_north_spi1_pins, 1),
+       PIN_GROUP("i2c5_grp", glk_north_i2c5_pins, 1),
+       PIN_GROUP("i2c6_grp", glk_north_i2c6_pins, 1),
+       PIN_GROUP("i2c7_grp", glk_north_i2c7_pins, 1),
+       PIN_GROUP("uart0_grp", glk_north_uart0_pins, 2),
+       PIN_GROUP("spi0b_grp", glk_north_spi0b_pins, 2),
+};
+
+static const char * const glk_north_spi0_groups[] = { "spi0_grp", "spi0b_grp" };
+static const char * const glk_north_spi1_groups[] = { "spi1_grp" };
+static const char * const glk_north_i2c5_groups[] = { "i2c5_grp" };
+static const char * const glk_north_i2c6_groups[] = { "i2c6_grp" };
+static const char * const glk_north_i2c7_groups[] = { "i2c7_grp" };
+static const char * const glk_north_uart0_groups[] = { "uart0_grp" };
+
+static const struct intel_function glk_north_functions[] = {
+       FUNCTION("spi0", glk_north_spi0_groups),
+       FUNCTION("spi1", glk_north_spi1_groups),
+       FUNCTION("i2c5", glk_north_i2c5_groups),
+       FUNCTION("i2c6", glk_north_i2c6_groups),
+       FUNCTION("i2c7", glk_north_i2c7_groups),
+       FUNCTION("uart0", glk_north_uart0_groups),
+};
+
+static const struct intel_community glk_north_communities[] = {
+       GLK_COMMUNITY(0, 79),
+};
+
+static const struct intel_pinctrl_soc_data glk_north_soc_data = {
+       .uid = "2",
+       .pins = glk_north_pins,
+       .npins = ARRAY_SIZE(glk_north_pins),
+       .groups = glk_north_groups,
+       .ngroups = ARRAY_SIZE(glk_north_groups),
+       .functions = glk_north_functions,
+       .nfunctions = ARRAY_SIZE(glk_north_functions),
+       .communities = glk_north_communities,
+       .ncommunities = ARRAY_SIZE(glk_north_communities),
+};
+
+static const struct pinctrl_pin_desc glk_audio_pins[] = {
+       PINCTRL_PIN(0, "AVS_I2S0_MCLK"),
+       PINCTRL_PIN(1, "AVS_I2S0_BCLK"),
+       PINCTRL_PIN(2, "AVS_I2S0_WS_SYNC"),
+       PINCTRL_PIN(3, "AVS_I2S0_SDI"),
+       PINCTRL_PIN(4, "AVS_I2S0_SDO"),
+       PINCTRL_PIN(5, "AVS_I2S1_MCLK"),
+       PINCTRL_PIN(6, "AVS_I2S1_BCLK"),
+       PINCTRL_PIN(7, "AVS_I2S1_WS_SYNC"),
+       PINCTRL_PIN(8, "AVS_I2S1_SDI"),
+       PINCTRL_PIN(9, "AVS_I2S1_SDO"),
+       PINCTRL_PIN(10, "AVS_HDA_BCLK"),
+       PINCTRL_PIN(11, "AVS_HDA_WS_SYNC"),
+       PINCTRL_PIN(12, "AVS_HDA_SDI"),
+       PINCTRL_PIN(13, "AVS_HDA_SDO"),
+       PINCTRL_PIN(14, "AVS_HDA_RSTB"),
+       PINCTRL_PIN(15, "AVS_M_CLK_A1"),
+       PINCTRL_PIN(16, "AVS_M_CLK_B1"),
+       PINCTRL_PIN(17, "AVS_M_DATA_1"),
+       PINCTRL_PIN(18, "AVS_M_CLK_AB2"),
+       PINCTRL_PIN(19, "AVS_M_DATA_2"),
+};
+
+static const struct intel_community glk_audio_communities[] = {
+       GLK_COMMUNITY(0, 19),
+};
+
+static const struct intel_pinctrl_soc_data glk_audio_soc_data = {
+       .uid = "3",
+       .pins = glk_audio_pins,
+       .npins = ARRAY_SIZE(glk_audio_pins),
+       .communities = glk_audio_communities,
+       .ncommunities = ARRAY_SIZE(glk_audio_communities),
+};
+
+static const struct pinctrl_pin_desc glk_scc_pins[] = {
+       PINCTRL_PIN(0, "SMB_ALERTB"),
+       PINCTRL_PIN(1, "SMB_CLK"),
+       PINCTRL_PIN(2, "SMB_DATA"),
+       PINCTRL_PIN(3, "SDCARD_LVL_WP"),
+       PINCTRL_PIN(4, "SDCARD_CLK"),
+       PINCTRL_PIN(5, "SDCARD_CLK_FB"),
+       PINCTRL_PIN(6, "SDCARD_D0"),
+       PINCTRL_PIN(7, "SDCARD_D1"),
+       PINCTRL_PIN(8, "SDCARD_D2"),
+       PINCTRL_PIN(9, "SDCARD_D3"),
+       PINCTRL_PIN(10, "SDCARD_CMD"),
+       PINCTRL_PIN(11, "SDCARD_CD_B"),
+       PINCTRL_PIN(12, "SDCARD_PWR_DOWN_B"),
+       PINCTRL_PIN(13, "GPIO_210"),
+       PINCTRL_PIN(14, "OSC_CLK_OUT_0"),
+       PINCTRL_PIN(15, "OSC_CLK_OUT_1"),
+       PINCTRL_PIN(16, "CNV_BRI_DT"),
+       PINCTRL_PIN(17, "CNV_BRI_RSP"),
+       PINCTRL_PIN(18, "CNV_RGI_DT"),
+       PINCTRL_PIN(19, "CNV_RGI_RSP"),
+       PINCTRL_PIN(20, "CNV_RF_RESET_B"),
+       PINCTRL_PIN(21, "XTAL_CLKREQ"),
+       PINCTRL_PIN(22, "SDIO_CLK_FB"),
+       PINCTRL_PIN(23, "EMMC0_CLK"),
+       PINCTRL_PIN(24, "EMMC0_CLK_FB"),
+       PINCTRL_PIN(25, "EMMC0_D0"),
+       PINCTRL_PIN(26, "EMMC0_D1"),
+       PINCTRL_PIN(27, "EMMC0_D2"),
+       PINCTRL_PIN(28, "EMMC0_D3"),
+       PINCTRL_PIN(29, "EMMC0_D4"),
+       PINCTRL_PIN(30, "EMMC0_D5"),
+       PINCTRL_PIN(31, "EMMC0_D6"),
+       PINCTRL_PIN(32, "EMMC0_D7"),
+       PINCTRL_PIN(33, "EMMC0_CMD"),
+       PINCTRL_PIN(34, "EMMC0_STROBE"),
+};
+
+static const unsigned int glk_scc_i2c7_pins[] = { 1, 2 };
+static const unsigned int glk_scc_sdcard_pins[] = {
+       3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+};
+static const unsigned int glk_scc_sdio_pins[] = { 16, 17, 18, 19, 20, 21, 22 };
+static const unsigned int glk_scc_uart1_pins[] = { 16, 17, 18, 19 };
+static const unsigned int glk_scc_emmc_pins[] = {
+       23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+};
+
+static const struct intel_pingroup glk_scc_groups[] = {
+       PIN_GROUP("i2c7_grp", glk_scc_i2c7_pins, 2),
+       PIN_GROUP("sdcard_grp", glk_scc_sdcard_pins, 1),
+       PIN_GROUP("sdio_grp", glk_scc_sdio_pins, 2),
+       PIN_GROUP("uart1_grp", glk_scc_uart1_pins, 3),
+       PIN_GROUP("emmc_grp", glk_scc_emmc_pins, 1),
+};
+
+static const char * const glk_scc_i2c7_groups[] = { "i2c7_grp" };
+static const char * const glk_scc_sdcard_groups[] = { "sdcard_grp" };
+static const char * const glk_scc_sdio_groups[] = { "sdio_grp" };
+static const char * const glk_scc_uart1_groups[] = { "uart1_grp" };
+static const char * const glk_scc_emmc_groups[] = { "emmc_grp" };
+
+static const struct intel_function glk_scc_functions[] = {
+       FUNCTION("i2c7", glk_scc_i2c7_groups),
+       FUNCTION("sdcard", glk_scc_sdcard_groups),
+       FUNCTION("sdio", glk_scc_sdio_groups),
+       FUNCTION("uart1", glk_scc_uart1_groups),
+       FUNCTION("emmc", glk_scc_emmc_groups),
+};
+
+static const struct intel_community glk_scc_communities[] = {
+       GLK_COMMUNITY(0, 34),
+};
+
+static const struct intel_pinctrl_soc_data glk_scc_soc_data = {
+       .uid = "4",
+       .pins = glk_scc_pins,
+       .npins = ARRAY_SIZE(glk_scc_pins),
+       .groups = glk_scc_groups,
+       .ngroups = ARRAY_SIZE(glk_scc_groups),
+       .functions = glk_scc_functions,
+       .nfunctions = ARRAY_SIZE(glk_scc_functions),
+       .communities = glk_scc_communities,
+       .ncommunities = ARRAY_SIZE(glk_scc_communities),
+};
+
+static const struct intel_pinctrl_soc_data *glk_pinctrl_soc_data[] = {
+       &glk_northwest_soc_data,
+       &glk_north_soc_data,
+       &glk_audio_soc_data,
+       &glk_scc_soc_data,
+       NULL,
+};
+
+static const struct acpi_device_id glk_pinctrl_acpi_match[] = {
+       { "INT3453" },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, glk_pinctrl_acpi_match);
+
+static int glk_pinctrl_probe(struct platform_device *pdev)
+{
+       const struct intel_pinctrl_soc_data *soc_data = NULL;
+       struct acpi_device *adev;
+       int i;
+
+       adev = ACPI_COMPANION(&pdev->dev);
+       if (!adev)
+               return -ENODEV;
+
+       for (i = 0; glk_pinctrl_soc_data[i]; i++) {
+               if (!strcmp(adev->pnp.unique_id,
+                           glk_pinctrl_soc_data[i]->uid)) {
+                       soc_data = glk_pinctrl_soc_data[i];
+                       break;
+               }
+       }
+
+       if (!soc_data)
+               return -ENODEV;
+
+       return intel_pinctrl_probe(pdev, soc_data);
+}
+
+static const struct dev_pm_ops glk_pinctrl_pm_ops = {
+       SET_LATE_SYSTEM_SLEEP_PM_OPS(intel_pinctrl_suspend,
+                                    intel_pinctrl_resume)
+};
+
+static struct platform_driver glk_pinctrl_driver = {
+       .probe = glk_pinctrl_probe,
+       .driver = {
+               .name = "geminilake-pinctrl",
+               .acpi_match_table = glk_pinctrl_acpi_match,
+               .pm = &glk_pinctrl_pm_ops,
+       },
+};
+
+static int __init glk_pinctrl_init(void)
+{
+       return platform_driver_register(&glk_pinctrl_driver);
+}
+subsys_initcall(glk_pinctrl_init);
+
+static void __exit glk_pinctrl_exit(void)
+{
+       platform_driver_unregister(&glk_pinctrl_driver);
+}
+module_exit(glk_pinctrl_exit);
+
+MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");
+MODULE_DESCRIPTION("Intel Gemini Lake SoC pinctrl/GPIO driver");
+MODULE_LICENSE("GPL v2");
index 6df35dcb29aea68c0ddec6cbd29bb1c9a3abd56c..592b465e981ef85ecd55c0ce1112f55831aa7f4c 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/gpio/driver.h>
+#include <linux/log2.h>
 #include <linux/platform_device.h>
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/pinctrl/pinmux.h>
 #include "pinctrl-intel.h"
 
 /* Offset from regs */
+#define REVID                          0x000
+#define REVID_SHIFT                    16
+#define REVID_MASK                     GENMASK(31, 16)
+
 #define PADBAR                         0x00c
 #define GPI_IS                         0x100
 #define GPI_GPE_STS                    0x140
@@ -41,6 +46,7 @@
 #define PADCFG0_RXEVCFG_EDGE           1
 #define PADCFG0_RXEVCFG_DISABLED       2
 #define PADCFG0_RXEVCFG_EDGE_BOTH      3
+#define PADCFG0_PREGFRXSEL             BIT(24)
 #define PADCFG0_RXINV                  BIT(23)
 #define PADCFG0_GPIROUTIOXAPIC         BIT(20)
 #define PADCFG0_GPIROUTSCI             BIT(19)
 #define PADCFG1_TERM_5K                        2
 #define PADCFG1_TERM_1K                        1
 
+#define PADCFG2                                0x008
+#define PADCFG2_DEBEN                  BIT(0)
+#define PADCFG2_DEBOUNCE_SHIFT         1
+#define PADCFG2_DEBOUNCE_MASK          GENMASK(4, 1)
+
+#define DEBOUNCE_PERIOD                        31250 /* ns */
+
 struct intel_pad_context {
        u32 padcfg0;
        u32 padcfg1;
+       u32 padcfg2;
 };
 
 struct intel_community_context {
@@ -126,13 +140,19 @@ static void __iomem *intel_get_padcfg(struct intel_pinctrl *pctrl, unsigned pin,
 {
        const struct intel_community *community;
        unsigned padno;
+       size_t nregs;
 
        community = intel_get_community(pctrl, pin);
        if (!community)
                return NULL;
 
        padno = pin_to_padno(community, pin);
-       return community->pad_regs + reg + padno * 8;
+       nregs = (community->features & PINCTRL_FEATURE_DEBOUNCE) ? 4 : 2;
+
+       if (reg == PADCFG2 && !(community->features & PINCTRL_FEATURE_DEBOUNCE))
+               return NULL;
+
+       return community->pad_regs + reg + padno * nregs * 4;
 }
 
 static bool intel_pad_owned_by_host(struct intel_pinctrl *pctrl, unsigned pin)
@@ -244,6 +264,7 @@ static void intel_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
                               unsigned pin)
 {
        struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+       void __iomem *padcfg;
        u32 cfg0, cfg1, mode;
        bool locked, acpi;
 
@@ -263,6 +284,11 @@ static void intel_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
 
        seq_printf(s, "0x%08x 0x%08x", cfg0, cfg1);
 
+       /* Dump the additional PADCFG registers if available */
+       padcfg = intel_get_padcfg(pctrl, pin, PADCFG2);
+       if (padcfg)
+               seq_printf(s, " 0x%08x", readl(padcfg));
+
        locked = intel_pad_locked(pctrl, pin);
        acpi = intel_pad_acpi_mode(pctrl, pin);
 
@@ -432,12 +458,14 @@ static int intel_config_get(struct pinctrl_dev *pctldev, unsigned pin,
 {
        struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
        enum pin_config_param param = pinconf_to_config_param(*config);
+       const struct intel_community *community;
        u32 value, term;
-       u16 arg = 0;
+       u32 arg = 0;
 
        if (!intel_pad_owned_by_host(pctrl, pin))
                return -ENOTSUPP;
 
+       community = intel_get_community(pctrl, pin);
        value = readl(intel_get_padcfg(pctrl, pin, PADCFG1));
        term = (value & PADCFG1_TERM_MASK) >> PADCFG1_TERM_SHIFT;
 
@@ -473,6 +501,11 @@ static int intel_config_get(struct pinctrl_dev *pctldev, unsigned pin,
                        return -EINVAL;
 
                switch (term) {
+               case PADCFG1_TERM_1K:
+                       if (!(community->features & PINCTRL_FEATURE_1K_PD))
+                               return -EINVAL;
+                       arg = 1000;
+                       break;
                case PADCFG1_TERM_5K:
                        arg = 5000;
                        break;
@@ -483,6 +516,24 @@ static int intel_config_get(struct pinctrl_dev *pctldev, unsigned pin,
 
                break;
 
+       case PIN_CONFIG_INPUT_DEBOUNCE: {
+               void __iomem *padcfg2;
+               u32 v;
+
+               padcfg2 = intel_get_padcfg(pctrl, pin, PADCFG2);
+               if (!padcfg2)
+                       return -ENOTSUPP;
+
+               v = readl(padcfg2);
+               if (!(v & PADCFG2_DEBEN))
+                       return -EINVAL;
+
+               v = (v & PADCFG2_DEBOUNCE_MASK) >> PADCFG2_DEBOUNCE_SHIFT;
+               arg = BIT(v) * DEBOUNCE_PERIOD / 1000;
+
+               break;
+       }
+
        default:
                return -ENOTSUPP;
        }
@@ -496,6 +547,7 @@ static int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned pin,
 {
        unsigned param = pinconf_to_config_param(config);
        unsigned arg = pinconf_to_config_argument(config);
+       const struct intel_community *community;
        void __iomem *padcfg1;
        unsigned long flags;
        int ret = 0;
@@ -503,6 +555,7 @@ static int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned pin,
 
        raw_spin_lock_irqsave(&pctrl->lock, flags);
 
+       community = intel_get_community(pctrl, pin);
        padcfg1 = intel_get_padcfg(pctrl, pin, PADCFG1);
        value = readl(padcfg1);
 
@@ -545,6 +598,13 @@ static int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned pin,
                case 5000:
                        value |= PADCFG1_TERM_5K << PADCFG1_TERM_SHIFT;
                        break;
+               case 1000:
+                       if (!(community->features & PINCTRL_FEATURE_1K_PD)) {
+                               ret = -EINVAL;
+                               break;
+                       }
+                       value |= PADCFG1_TERM_1K << PADCFG1_TERM_SHIFT;
+                       break;
                default:
                        ret = -EINVAL;
                }
@@ -560,6 +620,53 @@ static int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned pin,
        return ret;
 }
 
+static int intel_config_set_debounce(struct intel_pinctrl *pctrl, unsigned pin,
+                                    unsigned debounce)
+{
+       void __iomem *padcfg0, *padcfg2;
+       unsigned long flags;
+       u32 value0, value2;
+       int ret = 0;
+
+       padcfg2 = intel_get_padcfg(pctrl, pin, PADCFG2);
+       if (!padcfg2)
+               return -ENOTSUPP;
+
+       padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0);
+
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
+
+       value0 = readl(padcfg0);
+       value2 = readl(padcfg2);
+
+       /* Disable glitch filter and debouncer */
+       value0 &= ~PADCFG0_PREGFRXSEL;
+       value2 &= ~(PADCFG2_DEBEN | PADCFG2_DEBOUNCE_MASK);
+
+       if (debounce) {
+               unsigned long v;
+
+               v = order_base_2(debounce * 1000 / DEBOUNCE_PERIOD);
+               if (v < 3 || v > 15) {
+                       ret = -EINVAL;
+                       goto exit_unlock;
+               } else {
+                       /* Enable glitch filter and debouncer */
+                       value0 |= PADCFG0_PREGFRXSEL;
+                       value2 |= v << PADCFG2_DEBOUNCE_SHIFT;
+                       value2 |= PADCFG2_DEBEN;
+               }
+       }
+
+       writel(value0, padcfg0);
+       writel(value2, padcfg2);
+
+exit_unlock:
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+
+       return ret;
+}
+
 static int intel_config_set(struct pinctrl_dev *pctldev, unsigned pin,
                          unsigned long *configs, unsigned nconfigs)
 {
@@ -579,6 +686,13 @@ static int intel_config_set(struct pinctrl_dev *pctldev, unsigned pin,
                                return ret;
                        break;
 
+               case PIN_CONFIG_INPUT_DEBOUNCE:
+                       ret = intel_config_set_debounce(pctrl, pin,
+                               pinconf_to_config_argument(configs[i]));
+                       if (ret)
+                               return ret;
+                       break;
+
                default:
                        return -ENOTSUPP;
                }
@@ -653,6 +767,7 @@ static const struct gpio_chip intel_gpio_chip = {
        .direction_output = intel_gpio_direction_output,
        .get = intel_gpio_get,
        .set = intel_gpio_set,
+       .set_config = gpiochip_generic_config,
 };
 
 static void intel_gpio_irq_ack(struct irq_data *d)
@@ -892,7 +1007,7 @@ static int intel_gpio_probe(struct intel_pinctrl *pctrl, int irq)
        pctrl->chip.base = -1;
        pctrl->irq = irq;
 
-       ret = gpiochip_add_data(&pctrl->chip, pctrl);
+       ret = devm_gpiochip_add_data(pctrl->dev, &pctrl->chip, pctrl);
        if (ret) {
                dev_err(pctrl->dev, "failed to register gpiochip\n");
                return ret;
@@ -902,7 +1017,7 @@ static int intel_gpio_probe(struct intel_pinctrl *pctrl, int irq)
                                     0, 0, pctrl->soc->npins);
        if (ret) {
                dev_err(pctrl->dev, "failed to add GPIO pin range\n");
-               goto fail;
+               return ret;
        }
 
        /*
@@ -915,24 +1030,19 @@ static int intel_gpio_probe(struct intel_pinctrl *pctrl, int irq)
                               dev_name(pctrl->dev), pctrl);
        if (ret) {
                dev_err(pctrl->dev, "failed to request interrupt\n");
-               goto fail;
+               return ret;
        }
 
        ret = gpiochip_irqchip_add(&pctrl->chip, &intel_gpio_irqchip, 0,
                                   handle_bad_irq, IRQ_TYPE_NONE);
        if (ret) {
                dev_err(pctrl->dev, "failed to add irqchip\n");
-               goto fail;
+               return ret;
        }
 
        gpiochip_set_chained_irqchip(&pctrl->chip, &intel_gpio_irqchip, irq,
                                     NULL);
        return 0;
-
-fail:
-       gpiochip_remove(&pctrl->chip);
-
-       return ret;
 }
 
 static int intel_pinctrl_pm_init(struct intel_pinctrl *pctrl)
@@ -1013,6 +1123,20 @@ int intel_pinctrl_probe(struct platform_device *pdev,
                if (IS_ERR(regs))
                        return PTR_ERR(regs);
 
+               /*
+                * Determine community features based on the revision if
+                * not specified already.
+                */
+               if (!community->features) {
+                       u32 rev;
+
+                       rev = (readl(regs + REVID) & REVID_MASK) >> REVID_SHIFT;
+                       if (rev >= 0x94) {
+                               community->features |= PINCTRL_FEATURE_DEBOUNCE;
+                               community->features |= PINCTRL_FEATURE_1K_PD;
+                       }
+               }
+
                /* Read offset of the pad configuration registers */
                padbar = readl(regs + PADBAR);
 
@@ -1054,16 +1178,6 @@ int intel_pinctrl_probe(struct platform_device *pdev,
 }
 EXPORT_SYMBOL_GPL(intel_pinctrl_probe);
 
-int intel_pinctrl_remove(struct platform_device *pdev)
-{
-       struct intel_pinctrl *pctrl = platform_get_drvdata(pdev);
-
-       gpiochip_remove(&pctrl->chip);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(intel_pinctrl_remove);
-
 #ifdef CONFIG_PM_SLEEP
 static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned pin)
 {
@@ -1096,6 +1210,7 @@ int intel_pinctrl_suspend(struct device *dev)
        pads = pctrl->context.pads;
        for (i = 0; i < pctrl->soc->npins; i++) {
                const struct pinctrl_pin_desc *desc = &pctrl->soc->pins[i];
+               void __iomem *padcfg;
                u32 val;
 
                if (!intel_pinctrl_should_save(pctrl, desc->number))
@@ -1105,6 +1220,10 @@ int intel_pinctrl_suspend(struct device *dev)
                pads[i].padcfg0 = val & ~PADCFG0_GPIORXSTATE;
                val = readl(intel_get_padcfg(pctrl, desc->number, PADCFG1));
                pads[i].padcfg1 = val;
+
+               padcfg = intel_get_padcfg(pctrl, desc->number, PADCFG2);
+               if (padcfg)
+                       pads[i].padcfg2 = readl(padcfg);
        }
 
        communities = pctrl->context.communities;
@@ -1177,6 +1296,16 @@ int intel_pinctrl_resume(struct device *dev)
                        dev_dbg(dev, "restored pin %u padcfg1 %#08x\n",
                                desc->number, readl(padcfg));
                }
+
+               padcfg = intel_get_padcfg(pctrl, desc->number, PADCFG2);
+               if (padcfg) {
+                       val = readl(padcfg);
+                       if (val != pads[i].padcfg2) {
+                               writel(pads[i].padcfg2, padcfg);
+                               dev_dbg(dev, "restored pin %u padcfg2 %#08x\n",
+                                       desc->number, readl(padcfg));
+                       }
+               }
        }
 
        communities = pctrl->context.communities;
index b60215793017bb95b42d39692020aa2f4c41ac0d..fe9521f345b5782fd466b3d06516d2c4d82d80df 100644 (file)
@@ -58,6 +58,7 @@ struct intel_function {
  * @gpp_size: Maximum number of pads in each group, such as PADCFGLOCK,
  *            HOSTSW_OWN,  GPI_IS, GPI_IE, etc.
  * @npins: Number of pins in this community
+ * @features: Additional features supported by the hardware
  * @regs: Community specific common registers (reserved for core driver)
  * @pad_regs: Community specific pad registers (reserved for core driver)
  * @ngpps: Number of groups (hw groups) in this community (reserved for
@@ -72,11 +73,16 @@ struct intel_community {
        unsigned pin_base;
        unsigned gpp_size;
        size_t npins;
+       unsigned features;
        void __iomem *regs;
        void __iomem *pad_regs;
        size_t ngpps;
 };
 
+/* Additional features supported by the hardware */
+#define PINCTRL_FEATURE_DEBOUNCE       BIT(0)
+#define PINCTRL_FEATURE_1K_PD          BIT(1)
+
 #define PIN_GROUP(n, p, m)                     \
        {                                       \
                .name = (n),                    \
@@ -121,8 +127,6 @@ struct intel_pinctrl_soc_data {
 
 int intel_pinctrl_probe(struct platform_device *pdev,
                        const struct intel_pinctrl_soc_data *soc_data);
-int intel_pinctrl_remove(struct platform_device *pdev);
-
 #ifdef CONFIG_PM_SLEEP
 int intel_pinctrl_suspend(struct device *dev);
 int intel_pinctrl_resume(struct device *dev);
index c725a5313b4e692df92630535237e4b8374658a7..9877526c0807132d58872fcde68483dffcde103e 100644 (file)
@@ -574,7 +574,6 @@ static const struct dev_pm_ops spt_pinctrl_pm_ops = {
 
 static struct platform_driver spt_pinctrl_driver = {
        .probe = spt_pinctrl_probe,
-       .remove = intel_pinctrl_remove,
        .driver = {
                .name = "sunrisepoint-pinctrl",
                .acpi_match_table = spt_pinctrl_acpi_match,
index 4f0bc8a103f4ae273d34cc6bc05d94656e34a420..80fe3b48796cf96fa50dbbb4f65267d26800b736 100644 (file)
@@ -10,25 +10,29 @@ config PINCTRL_MTK
 
 # For ARMv7 SoCs
 config PINCTRL_MT2701
-       bool "Mediatek MT2701 pin control" if COMPILE_TEST && !MACH_MT2701
+       bool "Mediatek MT2701 pin control"
+       depends on MACH_MT2701 || COMPILE_TEST
        depends on OF
        default MACH_MT2701
        select PINCTRL_MTK
 
 config PINCTRL_MT7623
-       bool "Mediatek MT7623 pin control" if COMPILE_TEST && !MACH_MT7623
+       bool "Mediatek MT7623 pin control"
+       depends on MACH_MT7623 || COMPILE_TEST
        depends on OF
        default MACH_MT7623
        select PINCTRL_MTK_COMMON
 
 config PINCTRL_MT8135
-       bool "Mediatek MT8135 pin control" if COMPILE_TEST && !MACH_MT8135
+       bool "Mediatek MT8135 pin control"
+       depends on MACH_MT8135 || COMPILE_TEST
        depends on OF
        default MACH_MT8135
        select PINCTRL_MTK
 
 config PINCTRL_MT8127
-       bool "Mediatek MT8127 pin control" if COMPILE_TEST && !MACH_MT8127
+       bool "Mediatek MT8127 pin control"
+       depends on MACH_MT8127 || COMPILE_TEST
        depends on OF
        default MACH_MT8127
        select PINCTRL_MTK
@@ -43,7 +47,8 @@ config PINCTRL_MT8173
 
 # For PMIC
 config PINCTRL_MT6397
-       bool "Mediatek MT6397 pin control" if COMPILE_TEST && !MFD_MT6397
+       bool "Mediatek MT6397 pin control"
+       depends on MFD_MT6397 || COMPILE_TEST
        depends on OF
        default MFD_MT6397
        select PINCTRL_MTK
index 67895f8234e3ff49b7d24b0d3bff3e837e8792d4..fa28dd6b871bee336419ca8152cd48a0c0bf7456 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 John Crispin <blogic@openwrt.org>
+ * Copyright (c) 2016 John Crispin <john@phrozen.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
index f9aef2ac03a1e8b7533b9abf0b349aba21b0dc0e..3cf384f8b122879722e1b377379ecadcb73da77b 100644 (file)
@@ -1054,6 +1054,18 @@ static int mtk_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
        return 0;
 }
 
+static int mtk_gpio_set_config(struct gpio_chip *chip, unsigned offset,
+                              unsigned long config)
+{
+       u32 debounce;
+
+       if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
+               return -ENOTSUPP;
+
+       debounce = pinconf_to_config_argument(config);
+       return mtk_gpio_set_debounce(chip, offset, debounce);
+}
+
 static const struct gpio_chip mtk_gpio_chip = {
        .owner                  = THIS_MODULE,
        .request                = gpiochip_generic_request,
@@ -1064,7 +1076,7 @@ static const struct gpio_chip mtk_gpio_chip = {
        .get                    = mtk_gpio_get,
        .set                    = mtk_gpio_set,
        .to_irq                 = mtk_gpio_to_irq,
-       .set_debounce           = mtk_gpio_set_debounce,
+       .set_config             = mtk_gpio_set_config,
        .of_gpio_n_cells        = 2,
 };
 
index 3472a76ad422c9c58a6e3e89cde5ebf4fc6fe537..e06cfc40da0f9ceb5625b397f410f96ca8635322 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 John Crispin <blogic@openwrt.org>
+ * Copyright (c) 2016 John Crispin <john@phrozen.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
index e0bca4df2a2f3188da0d559a29013893a5bea528..7671424d46cbe0a5628caee0615cde2d79b8d478 100644 (file)
@@ -232,6 +232,10 @@ static const unsigned int pwm_e_pins[]             = { PIN(GPIOX_19, EE_OFF) };
 static const unsigned int pwm_f_x_pins[]       = { PIN(GPIOX_7, EE_OFF) };
 static const unsigned int pwm_f_y_pins[]       = { PIN(GPIOY_15, EE_OFF) };
 
+static const unsigned int hdmi_hpd_pins[]      = { PIN(GPIOH_0, EE_OFF) };
+static const unsigned int hdmi_sda_pins[]      = { PIN(GPIOH_1, EE_OFF) };
+static const unsigned int hdmi_scl_pins[]      = { PIN(GPIOH_2, EE_OFF) };
+
 static const struct pinctrl_pin_desc meson_gxbb_aobus_pins[] = {
        MESON_PIN(GPIOAO_0, 0),
        MESON_PIN(GPIOAO_1, 0),
@@ -439,6 +443,11 @@ static struct meson_pmx_group meson_gxbb_periphs_groups[] = {
        GROUP(eth_txd2,         6,      3),
        GROUP(eth_txd3,         6,      2),
 
+       /* Bank H */
+       GROUP(hdmi_hpd,         1,      26),
+       GROUP(hdmi_sda,         1,      25),
+       GROUP(hdmi_scl,         1,      24),
+
        /* Bank DV */
        GROUP(uart_tx_b,        2,      29),
        GROUP(uart_rx_b,        2,      28),
@@ -635,6 +644,14 @@ static const char * const pwm_f_y_groups[] = {
        "pwm_f_y",
 };
 
+static const char * const hdmi_hpd_groups[] = {
+       "hdmi_hpd",
+};
+
+static const char * const hdmi_i2c_groups[] = {
+       "hdmi_sda", "hdmi_scl",
+};
+
 static const char * const gpio_aobus_groups[] = {
        "GPIOAO_0", "GPIOAO_1", "GPIOAO_2", "GPIOAO_3", "GPIOAO_4",
        "GPIOAO_5", "GPIOAO_6", "GPIOAO_7", "GPIOAO_8", "GPIOAO_9",
@@ -698,6 +715,8 @@ static struct meson_pmx_func meson_gxbb_periphs_functions[] = {
        FUNCTION(pwm_e),
        FUNCTION(pwm_f_x),
        FUNCTION(pwm_f_y),
+       FUNCTION(hdmi_hpd),
+       FUNCTION(hdmi_i2c),
 };
 
 static struct meson_pmx_func meson_gxbb_aobus_functions[] = {
index b69743b07a1d591ace36d410583231319234d4f0..4ab94a85e30642e7bc73c5c2c9a10aeffdb8eec2 100644 (file)
@@ -197,6 +197,10 @@ static const unsigned int eth_txd3_pins[]  = { PIN(GPIOZ_13, EE_OFF) };
 
 static const unsigned int pwm_e_pins[]         = { PIN(GPIOX_16, EE_OFF) };
 
+static const unsigned int hdmi_hpd_pins[]      = { PIN(GPIOH_0, EE_OFF) };
+static const unsigned int hdmi_sda_pins[]      = { PIN(GPIOH_1, EE_OFF) };
+static const unsigned int hdmi_scl_pins[]      = { PIN(GPIOH_2, EE_OFF) };
+
 static const struct pinctrl_pin_desc meson_gxl_aobus_pins[] = {
        MESON_PIN(GPIOAO_0, 0),
        MESON_PIN(GPIOAO_1, 0),
@@ -221,6 +225,8 @@ static const unsigned int uart_rts_ao_b_pins[]      = { PIN(GPIOAO_3, 0) };
 
 static const unsigned int remote_input_ao_pins[] = {PIN(GPIOAO_7, 0) };
 
+static const unsigned int pwm_ao_b_pins[]      = { PIN(GPIOAO_9, 0) };
+
 static struct meson_pmx_group meson_gxl_periphs_groups[] = {
        GPIO_GROUP(GPIOZ_0, EE_OFF),
        GPIO_GROUP(GPIOZ_1, EE_OFF),
@@ -362,6 +368,11 @@ static struct meson_pmx_group meson_gxl_periphs_groups[] = {
        GROUP(eth_txd2,         4,      11),
        GROUP(eth_txd3,         4,      10),
 
+       /* Bank H */
+       GROUP(hdmi_hpd,         6,      31),
+       GROUP(hdmi_sda,         6,      30),
+       GROUP(hdmi_scl,         6,      29),
+
        /* Bank DV */
        GROUP(uart_tx_b,        2,      16),
        GROUP(uart_rx_b,        2,      15),
@@ -417,6 +428,7 @@ static struct meson_pmx_group meson_gxl_aobus_groups[] = {
        GROUP(uart_cts_ao_b,    0,      8),
        GROUP(uart_rts_ao_b,    0,      7),
        GROUP(remote_input_ao,  0,      0),
+       GROUP(pwm_ao_b,         0,      3),
 };
 
 static const char * const gpio_periphs_groups[] = {
@@ -505,6 +517,14 @@ static const char * const pwm_e_groups[] = {
        "pwm_e",
 };
 
+static const char * const hdmi_hpd_groups[] = {
+       "hdmi_hpd",
+};
+
+static const char * const hdmi_i2c_groups[] = {
+       "hdmi_sda", "hdmi_scl",
+};
+
 static const char * const gpio_aobus_groups[] = {
        "GPIOAO_0", "GPIOAO_1", "GPIOAO_2", "GPIOAO_3", "GPIOAO_4",
        "GPIOAO_5", "GPIOAO_6", "GPIOAO_7", "GPIOAO_8", "GPIOAO_9",
@@ -522,6 +542,10 @@ static const char * const remote_input_ao_groups[] = {
        "remote_input_ao",
 };
 
+static const char * const pwm_ao_b_groups[] = {
+       "pwm_ao_b",
+};
+
 static struct meson_pmx_func meson_gxl_periphs_functions[] = {
        FUNCTION(gpio_periphs),
        FUNCTION(emmc),
@@ -536,6 +560,8 @@ static struct meson_pmx_func meson_gxl_periphs_functions[] = {
        FUNCTION(i2c_c),
        FUNCTION(eth),
        FUNCTION(pwm_e),
+       FUNCTION(hdmi_hpd),
+       FUNCTION(hdmi_i2c),
 };
 
 static struct meson_pmx_func meson_gxl_aobus_functions[] = {
@@ -543,6 +569,7 @@ static struct meson_pmx_func meson_gxl_aobus_functions[] = {
        FUNCTION(uart_ao),
        FUNCTION(uart_ao_b),
        FUNCTION(remote_input_ao),
+       FUNCTION(pwm_ao_b),
 };
 
 static struct meson_bank meson_gxl_periphs_banks[] = {
index 620c231a2889ef6879269a80ccbfaa3e4493958f..cf1686e04378683cd3907c30fa97f838df0acc99 100644 (file)
@@ -260,7 +260,6 @@ static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin,
        enum pin_config_param param;
        unsigned int reg, bit;
        int i, ret;
-       u16 arg;
 
        ret = meson_get_bank(pc, pin, &bank);
        if (ret)
@@ -268,7 +267,6 @@ static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin,
 
        for (i = 0; i < num_configs; i++) {
                param = pinconf_to_config_param(configs[i]);
-               arg = pinconf_to_config_argument(configs[i]);
 
                switch (param) {
                case PIN_CONFIG_BIAS_DISABLE:
index 9cc1cc3f5c347d470d88cdf1d69d83fa2f4b736f..9feba9a5ccb7eaa93deef96943b435be8ddd3ff7 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/of.h>
 
 #include "pinctrl-mvebu.h"
 
-static void __iomem *mpp_base;
-
-static int armada_370_mpp_ctrl_get(unsigned pid, unsigned long *config)
-{
-       return default_mpp_ctrl_get(mpp_base, pid, config);
-}
-
-static int armada_370_mpp_ctrl_set(unsigned pid, unsigned long config)
-{
-       return default_mpp_ctrl_set(mpp_base, pid, config);
-}
-
 static struct mvebu_mpp_mode mv88f6710_mpp_modes[] = {
        MPP_MODE(0,
           MPP_FUNCTION(0x0, "gpio", NULL),
@@ -384,8 +371,8 @@ static const struct of_device_id armada_370_pinctrl_of_match[] = {
        { },
 };
 
-static struct mvebu_mpp_ctrl mv88f6710_mpp_controls[] = {
-       MPP_FUNC_CTRL(0, 65, NULL, armada_370_mpp_ctrl),
+static const struct mvebu_mpp_ctrl mv88f6710_mpp_controls[] = {
+       MPP_FUNC_CTRL(0, 65, NULL, mvebu_mmio_mpp_ctrl),
 };
 
 static struct pinctrl_gpio_range mv88f6710_mpp_gpio_ranges[] = {
@@ -397,12 +384,6 @@ static struct pinctrl_gpio_range mv88f6710_mpp_gpio_ranges[] = {
 static int armada_370_pinctrl_probe(struct platform_device *pdev)
 {
        struct mvebu_pinctrl_soc_info *soc = &armada_370_pinctrl_info;
-       struct resource *res;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       mpp_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(mpp_base))
-               return PTR_ERR(mpp_base);
 
        soc->variant = 0; /* no variants for Armada 370 */
        soc->controls = mv88f6710_mpp_controls;
@@ -414,7 +395,7 @@ static int armada_370_pinctrl_probe(struct platform_device *pdev)
 
        pdev->dev.platform_data = soc;
 
-       return mvebu_pinctrl_probe(pdev);
+       return mvebu_pinctrl_simple_mmio_probe(pdev);
 }
 
 static struct platform_driver armada_370_pinctrl_driver = {
@@ -424,9 +405,4 @@ static struct platform_driver armada_370_pinctrl_driver = {
        },
        .probe = armada_370_pinctrl_probe,
 };
-
-module_platform_driver(armada_370_pinctrl_driver);
-
-MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
-MODULE_DESCRIPTION("Marvell Armada 370 pinctrl driver");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver(armada_370_pinctrl_driver);
index 070651431ca4eea719bfa524d645fc1813210200..b7de8abccd482486a9fb9e22ae02190489ba3d05 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/of.h>
 
 #include "pinctrl-mvebu.h"
 
-static void __iomem *mpp_base;
-
-static int armada_375_mpp_ctrl_get(unsigned pid, unsigned long *config)
-{
-       return default_mpp_ctrl_get(mpp_base, pid, config);
-}
-
-static int armada_375_mpp_ctrl_set(unsigned pid, unsigned long config)
-{
-       return default_mpp_ctrl_set(mpp_base, pid, config);
-}
-
 static struct mvebu_mpp_mode mv88f6720_mpp_modes[] = {
        MPP_MODE(0,
                 MPP_FUNCTION(0x0, "gpio", NULL),
@@ -402,8 +389,8 @@ static const struct of_device_id armada_375_pinctrl_of_match[] = {
        { },
 };
 
-static struct mvebu_mpp_ctrl mv88f6720_mpp_controls[] = {
-       MPP_FUNC_CTRL(0, 69, NULL, armada_375_mpp_ctrl),
+static const struct mvebu_mpp_ctrl mv88f6720_mpp_controls[] = {
+       MPP_FUNC_CTRL(0, 69, NULL, mvebu_mmio_mpp_ctrl),
 };
 
 static struct pinctrl_gpio_range mv88f6720_mpp_gpio_ranges[] = {
@@ -415,12 +402,6 @@ static struct pinctrl_gpio_range mv88f6720_mpp_gpio_ranges[] = {
 static int armada_375_pinctrl_probe(struct platform_device *pdev)
 {
        struct mvebu_pinctrl_soc_info *soc = &armada_375_pinctrl_info;
-       struct resource *res;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       mpp_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(mpp_base))
-               return PTR_ERR(mpp_base);
 
        soc->variant = 0; /* no variants for Armada 375 */
        soc->controls = mv88f6720_mpp_controls;
@@ -432,7 +413,7 @@ static int armada_375_pinctrl_probe(struct platform_device *pdev)
 
        pdev->dev.platform_data = soc;
 
-       return mvebu_pinctrl_probe(pdev);
+       return mvebu_pinctrl_simple_mmio_probe(pdev);
 }
 
 static struct platform_driver armada_375_pinctrl_driver = {
@@ -442,9 +423,4 @@ static struct platform_driver armada_375_pinctrl_driver = {
        },
        .probe = armada_375_pinctrl_probe,
 };
-
-module_platform_driver(armada_375_pinctrl_driver);
-
-MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
-MODULE_DESCRIPTION("Marvell Armada 375 pinctrl driver");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver(armada_375_pinctrl_driver);
index 4e84c8e4938c52970d83cd7a5ec6a016f326297d..de2e1538a26fc7f9a77f25a48e90f7a96a319017 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 
 #include "pinctrl-mvebu.h"
 
-static void __iomem *mpp_base;
-
-static int armada_38x_mpp_ctrl_get(unsigned pid, unsigned long *config)
-{
-       return default_mpp_ctrl_get(mpp_base, pid, config);
-}
-
-static int armada_38x_mpp_ctrl_set(unsigned pid, unsigned long config)
-{
-       return default_mpp_ctrl_set(mpp_base, pid, config);
-}
-
 enum {
        V_88F6810 = BIT(0),
        V_88F6820 = BIT(1),
@@ -409,8 +396,8 @@ static const struct of_device_id armada_38x_pinctrl_of_match[] = {
        { },
 };
 
-static struct mvebu_mpp_ctrl armada_38x_mpp_controls[] = {
-       MPP_FUNC_CTRL(0, 59, NULL, armada_38x_mpp_ctrl),
+static const struct mvebu_mpp_ctrl armada_38x_mpp_controls[] = {
+       MPP_FUNC_CTRL(0, 59, NULL, mvebu_mmio_mpp_ctrl),
 };
 
 static struct pinctrl_gpio_range armada_38x_mpp_gpio_ranges[] = {
@@ -423,16 +410,10 @@ static int armada_38x_pinctrl_probe(struct platform_device *pdev)
        struct mvebu_pinctrl_soc_info *soc = &armada_38x_pinctrl_info;
        const struct of_device_id *match =
                of_match_device(armada_38x_pinctrl_of_match, &pdev->dev);
-       struct resource *res;
 
        if (!match)
                return -ENODEV;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       mpp_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(mpp_base))
-               return PTR_ERR(mpp_base);
-
        soc->variant = (unsigned) match->data & 0xff;
        soc->controls = armada_38x_mpp_controls;
        soc->ncontrols = ARRAY_SIZE(armada_38x_mpp_controls);
@@ -443,7 +424,7 @@ static int armada_38x_pinctrl_probe(struct platform_device *pdev)
 
        pdev->dev.platform_data = soc;
 
-       return mvebu_pinctrl_probe(pdev);
+       return mvebu_pinctrl_simple_mmio_probe(pdev);
 }
 
 static struct platform_driver armada_38x_pinctrl_driver = {
@@ -453,9 +434,4 @@ static struct platform_driver armada_38x_pinctrl_driver = {
        },
        .probe = armada_38x_pinctrl_probe,
 };
-
-module_platform_driver(armada_38x_pinctrl_driver);
-
-MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
-MODULE_DESCRIPTION("Marvell Armada 38x pinctrl driver");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver(armada_38x_pinctrl_driver);
index e288f8ba0bf13cb9ebdf8d6a3a0c60155390a6f4..627f57c88372a44e398808ce4df3f3b9a4513f0e 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 
 #include "pinctrl-mvebu.h"
 
-static void __iomem *mpp_base;
-
-static int armada_39x_mpp_ctrl_get(unsigned pid, unsigned long *config)
-{
-       return default_mpp_ctrl_get(mpp_base, pid, config);
-}
-
-static int armada_39x_mpp_ctrl_set(unsigned pid, unsigned long config)
-{
-       return default_mpp_ctrl_set(mpp_base, pid, config);
-}
-
 enum {
        V_88F6920 = BIT(0),
        V_88F6925 = BIT(1),
@@ -391,8 +378,8 @@ static const struct of_device_id armada_39x_pinctrl_of_match[] = {
        { },
 };
 
-static struct mvebu_mpp_ctrl armada_39x_mpp_controls[] = {
-       MPP_FUNC_CTRL(0, 59, NULL, armada_39x_mpp_ctrl),
+static const struct mvebu_mpp_ctrl armada_39x_mpp_controls[] = {
+       MPP_FUNC_CTRL(0, 59, NULL, mvebu_mmio_mpp_ctrl),
 };
 
 static struct pinctrl_gpio_range armada_39x_mpp_gpio_ranges[] = {
@@ -405,16 +392,10 @@ static int armada_39x_pinctrl_probe(struct platform_device *pdev)
        struct mvebu_pinctrl_soc_info *soc = &armada_39x_pinctrl_info;
        const struct of_device_id *match =
                of_match_device(armada_39x_pinctrl_of_match, &pdev->dev);
-       struct resource *res;
 
        if (!match)
                return -ENODEV;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       mpp_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(mpp_base))
-               return PTR_ERR(mpp_base);
-
        soc->variant = (unsigned) match->data & 0xff;
        soc->controls = armada_39x_mpp_controls;
        soc->ncontrols = ARRAY_SIZE(armada_39x_mpp_controls);
@@ -425,7 +406,7 @@ static int armada_39x_pinctrl_probe(struct platform_device *pdev)
 
        pdev->dev.platform_data = soc;
 
-       return mvebu_pinctrl_probe(pdev);
+       return mvebu_pinctrl_simple_mmio_probe(pdev);
 }
 
 static struct platform_driver armada_39x_pinctrl_driver = {
@@ -435,9 +416,4 @@ static struct platform_driver armada_39x_pinctrl_driver = {
        },
        .probe = armada_39x_pinctrl_probe,
 };
-
-module_platform_driver(armada_39x_pinctrl_driver);
-
-MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
-MODULE_DESCRIPTION("Marvell Armada 39x pinctrl driver");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver(armada_39x_pinctrl_driver);
index e4ea71a9d98546d3a24f5ee28309474b79fccebd..b854f1ee5de579b3fb4934de30ff0bf3272d2b9c 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/of.h>
 
 #include "pinctrl-mvebu.h"
 
-static void __iomem *mpp_base;
 static u32 *mpp_saved_regs;
 
-static int armada_xp_mpp_ctrl_get(unsigned pid, unsigned long *config)
-{
-       return default_mpp_ctrl_get(mpp_base, pid, config);
-}
-
-static int armada_xp_mpp_ctrl_set(unsigned pid, unsigned long config)
-{
-       return default_mpp_ctrl_set(mpp_base, pid, config);
-}
-
 enum armada_xp_variant {
        V_MV78230       = BIT(0),
        V_MV78260       = BIT(1),
        V_MV78460       = BIT(2),
        V_MV78230_PLUS  = (V_MV78230 | V_MV78260 | V_MV78460),
        V_MV78260_PLUS  = (V_MV78260 | V_MV78460),
+       V_98DX3236      = BIT(3),
+       V_98DX3336      = BIT(4),
+       V_98DX4251      = BIT(5),
+       V_98DX3236_PLUS = (V_98DX3236 | V_98DX3336 | V_98DX4251),
 };
 
 static struct mvebu_mpp_mode armada_xp_mpp_modes[] = {
@@ -360,6 +352,131 @@ static struct mvebu_mpp_mode armada_xp_mpp_modes[] = {
                 MPP_VAR_FUNCTION(0x1, "dev", "ad31",       V_MV78260_PLUS)),
 };
 
+static struct mvebu_mpp_mode mv98dx3236_mpp_modes[] = {
+       MPP_MODE(0,
+                MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x2, "spi0", "mosi",       V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x4, "dev", "ad8",         V_98DX3236_PLUS)),
+       MPP_MODE(1,
+                MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x2, "spi0", "miso",       V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x4, "dev", "ad9",         V_98DX3236_PLUS)),
+       MPP_MODE(2,
+                MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x2, "spi0", "sck",        V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x4, "dev", "ad10",        V_98DX3236_PLUS)),
+       MPP_MODE(3,
+                MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x2, "spi0", "cs0",        V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x4, "dev", "ad11",        V_98DX3236_PLUS)),
+       MPP_MODE(4,
+                MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x2, "spi0", "cs1",        V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x3, "smi", "mdc",         V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x4, "dev", "cs0",         V_98DX3236_PLUS)),
+       MPP_MODE(5,
+                MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x1, "pex", "rsto",        V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x2, "sd0", "cmd",         V_98DX4251),
+                MPP_VAR_FUNCTION(0x4, "dev", "bootcs",      V_98DX3236_PLUS)),
+       MPP_MODE(6,
+                MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x2, "sd0", "clk",         V_98DX4251),
+                MPP_VAR_FUNCTION(0x4, "dev", "a2",          V_98DX3236_PLUS)),
+       MPP_MODE(7,
+                MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x2, "sd0", "d0",          V_98DX4251),
+                MPP_VAR_FUNCTION(0x4, "dev", "ale0",        V_98DX3236_PLUS)),
+       MPP_MODE(8,
+                MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x2, "sd0", "d1",          V_98DX4251),
+                MPP_VAR_FUNCTION(0x4, "dev", "ale1",        V_98DX3236_PLUS)),
+       MPP_MODE(9,
+                MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x2, "sd0", "d2",          V_98DX4251),
+                MPP_VAR_FUNCTION(0x4, "dev", "ready0",      V_98DX3236_PLUS)),
+       MPP_MODE(10,
+                MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x2, "sd0", "d3",          V_98DX4251),
+                MPP_VAR_FUNCTION(0x4, "dev", "ad12",        V_98DX3236_PLUS)),
+       MPP_MODE(11,
+                MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x2, "uart1", "rxd",       V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x3, "uart0", "cts",       V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x4, "dev", "ad13",        V_98DX3236_PLUS)),
+       MPP_MODE(12,
+                MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x2, "uart1", "txd",       V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x3, "uart0", "rts",       V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x4, "dev", "ad14",        V_98DX3236_PLUS)),
+       MPP_MODE(13,
+                MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x1, "intr", "out",        V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x4, "dev", "ad15",        V_98DX3236_PLUS)),
+       MPP_MODE(14,
+                MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x1, "i2c0", "sck",        V_98DX3236_PLUS)),
+       MPP_MODE(15,
+                MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x4, "i2c0", "sda",        V_98DX3236_PLUS)),
+       MPP_MODE(16,
+                MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x4, "dev", "oe",          V_98DX3236_PLUS)),
+       MPP_MODE(17,
+                MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x4, "dev", "clkout",      V_98DX3236_PLUS)),
+       MPP_MODE(18,
+                MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x3, "uart1", "txd",       V_98DX3236_PLUS)),
+       MPP_MODE(19,
+                MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x3, "uart1", "rxd",       V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x4, "dev", "rb",          V_98DX3236_PLUS)),
+       MPP_MODE(20,
+                MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x4, "dev", "we0",         V_98DX3236_PLUS)),
+       MPP_MODE(21,
+                MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x1, "dev", "ad0",         V_98DX3236_PLUS)),
+       MPP_MODE(22,
+                MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x1, "dev", "ad1",         V_98DX3236_PLUS)),
+       MPP_MODE(23,
+                MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x1, "dev", "ad2",         V_98DX3236_PLUS)),
+       MPP_MODE(24,
+                MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x1, "dev", "ad3",         V_98DX3236_PLUS)),
+       MPP_MODE(25,
+                MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x1, "dev", "ad4",         V_98DX3236_PLUS)),
+       MPP_MODE(26,
+                MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x1, "dev", "ad5",         V_98DX3236_PLUS)),
+       MPP_MODE(27,
+                MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x1, "dev", "ad6",         V_98DX3236_PLUS)),
+       MPP_MODE(28,
+                MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x1, "dev", "ad7",         V_98DX3236_PLUS)),
+       MPP_MODE(29,
+                MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x1, "dev", "a0",          V_98DX3236_PLUS)),
+       MPP_MODE(30,
+                MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x1, "dev", "a1",          V_98DX3236_PLUS)),
+       MPP_MODE(31,
+                MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x1, "slv_smi", "mdc",     V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x3, "smi", "mdc",         V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x4, "dev", "we1",         V_98DX3236_PLUS)),
+       MPP_MODE(32,
+                MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x1, "slv_smi", "mdio",    V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x3, "smi", "mdio",        V_98DX3236_PLUS),
+                MPP_VAR_FUNCTION(0x4, "dev", "cs1",         V_98DX3236_PLUS)),
+};
+
 static struct mvebu_pinctrl_soc_info armada_xp_pinctrl_info;
 
 static const struct of_device_id armada_xp_pinctrl_of_match[] = {
@@ -375,11 +492,19 @@ static const struct of_device_id armada_xp_pinctrl_of_match[] = {
                .compatible = "marvell,mv78460-pinctrl",
                .data       = (void *) V_MV78460,
        },
+       {
+               .compatible = "marvell,98dx3236-pinctrl",
+               .data       = (void *) V_98DX3236,
+       },
+       {
+               .compatible = "marvell,98dx4251-pinctrl",
+               .data       = (void *) V_98DX4251,
+       },
        { },
 };
 
-static struct mvebu_mpp_ctrl mv78230_mpp_controls[] = {
-       MPP_FUNC_CTRL(0, 48, NULL, armada_xp_mpp_ctrl),
+static const struct mvebu_mpp_ctrl mv78230_mpp_controls[] = {
+       MPP_FUNC_CTRL(0, 48, NULL, mvebu_mmio_mpp_ctrl),
 };
 
 static struct pinctrl_gpio_range mv78230_mpp_gpio_ranges[] = {
@@ -387,8 +512,8 @@ static struct pinctrl_gpio_range mv78230_mpp_gpio_ranges[] = {
        MPP_GPIO_RANGE(1,  32, 32, 17),
 };
 
-static struct mvebu_mpp_ctrl mv78260_mpp_controls[] = {
-       MPP_FUNC_CTRL(0, 66, NULL, armada_xp_mpp_ctrl),
+static const struct mvebu_mpp_ctrl mv78260_mpp_controls[] = {
+       MPP_FUNC_CTRL(0, 66, NULL, mvebu_mmio_mpp_ctrl),
 };
 
 static struct pinctrl_gpio_range mv78260_mpp_gpio_ranges[] = {
@@ -397,8 +522,8 @@ static struct pinctrl_gpio_range mv78260_mpp_gpio_ranges[] = {
        MPP_GPIO_RANGE(2,  64, 64,  3),
 };
 
-static struct mvebu_mpp_ctrl mv78460_mpp_controls[] = {
-       MPP_FUNC_CTRL(0, 66, NULL, armada_xp_mpp_ctrl),
+static const struct mvebu_mpp_ctrl mv78460_mpp_controls[] = {
+       MPP_FUNC_CTRL(0, 66, NULL, mvebu_mmio_mpp_ctrl),
 };
 
 static struct pinctrl_gpio_range mv78460_mpp_gpio_ranges[] = {
@@ -407,6 +532,14 @@ static struct pinctrl_gpio_range mv78460_mpp_gpio_ranges[] = {
        MPP_GPIO_RANGE(2,  64, 64,  3),
 };
 
+static struct mvebu_mpp_ctrl mv98dx3236_mpp_controls[] = {
+       MPP_FUNC_CTRL(0, 32, NULL, mvebu_mmio_mpp_ctrl),
+};
+
+static struct pinctrl_gpio_range mv98dx3236_mpp_gpio_ranges[] = {
+       MPP_GPIO_RANGE(0, 0, 0, 32),
+};
+
 static int armada_xp_pinctrl_suspend(struct platform_device *pdev,
                                     pm_message_t state)
 {
@@ -417,7 +550,7 @@ static int armada_xp_pinctrl_suspend(struct platform_device *pdev,
        nregs = DIV_ROUND_UP(soc->nmodes, MVEBU_MPPS_PER_REG);
 
        for (i = 0; i < nregs; i++)
-               mpp_saved_regs[i] = readl(mpp_base + i * 4);
+               mpp_saved_regs[i] = readl(soc->control_data[0].base + i * 4);
 
        return 0;
 }
@@ -431,7 +564,7 @@ static int armada_xp_pinctrl_resume(struct platform_device *pdev)
        nregs = DIV_ROUND_UP(soc->nmodes, MVEBU_MPPS_PER_REG);
 
        for (i = 0; i < nregs; i++)
-               writel(mpp_saved_regs[i], mpp_base + i * 4);
+               writel(mpp_saved_regs[i], soc->control_data[0].base + i * 4);
 
        return 0;
 }
@@ -441,17 +574,11 @@ static int armada_xp_pinctrl_probe(struct platform_device *pdev)
        struct mvebu_pinctrl_soc_info *soc = &armada_xp_pinctrl_info;
        const struct of_device_id *match =
                of_match_device(armada_xp_pinctrl_of_match, &pdev->dev);
-       struct resource *res;
        int nregs;
 
        if (!match)
                return -ENODEV;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       mpp_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(mpp_base))
-               return PTR_ERR(mpp_base);
-
        soc->variant = (unsigned) match->data & 0xff;
 
        switch (soc->variant) {
@@ -488,6 +615,17 @@ static int armada_xp_pinctrl_probe(struct platform_device *pdev)
                soc->gpioranges = mv78460_mpp_gpio_ranges;
                soc->ngpioranges = ARRAY_SIZE(mv78460_mpp_gpio_ranges);
                break;
+       case V_98DX3236:
+       case V_98DX3336:
+       case V_98DX4251:
+               /* fall-through */
+               soc->controls = mv98dx3236_mpp_controls;
+               soc->ncontrols = ARRAY_SIZE(mv98dx3236_mpp_controls);
+               soc->modes = mv98dx3236_mpp_modes;
+               soc->nmodes = mv98dx3236_mpp_controls[0].npins;
+               soc->gpioranges = mv98dx3236_mpp_gpio_ranges;
+               soc->ngpioranges = ARRAY_SIZE(mv98dx3236_mpp_gpio_ranges);
+               break;
        }
 
        nregs = DIV_ROUND_UP(soc->nmodes, MVEBU_MPPS_PER_REG);
@@ -499,7 +637,7 @@ static int armada_xp_pinctrl_probe(struct platform_device *pdev)
 
        pdev->dev.platform_data = soc;
 
-       return mvebu_pinctrl_probe(pdev);
+       return mvebu_pinctrl_simple_mmio_probe(pdev);
 }
 
 static struct platform_driver armada_xp_pinctrl_driver = {
@@ -511,9 +649,4 @@ static struct platform_driver armada_xp_pinctrl_driver = {
        .suspend = armada_xp_pinctrl_suspend,
        .resume = armada_xp_pinctrl_resume,
 };
-
-module_platform_driver(armada_xp_pinctrl_driver);
-
-MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
-MODULE_DESCRIPTION("Marvell Armada XP pinctrl driver");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver(armada_xp_pinctrl_driver);
index f93ae0dcef9caabdfdeb5635401f233c2b108bb3..8472f61f2bbe73a35e3410eed9a6999d15c19794 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/bitops.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 
 #define CONFIG_PMU     BIT(4)
 
-static void __iomem *mpp_base;
 static void __iomem *mpp4_base;
 static void __iomem *pmu_base;
 static struct regmap *gconfmap;
 
-static int dove_mpp_ctrl_get(unsigned pid, unsigned long *config)
-{
-       return default_mpp_ctrl_get(mpp_base, pid, config);
-}
-
-static int dove_mpp_ctrl_set(unsigned pid, unsigned long config)
-{
-       return default_mpp_ctrl_set(mpp_base, pid, config);
-}
-
-static int dove_pmu_mpp_ctrl_get(unsigned pid, unsigned long *config)
+static int dove_pmu_mpp_ctrl_get(struct mvebu_mpp_ctrl_data *data,
+                                unsigned pid, unsigned long *config)
 {
        unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
        unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
-       unsigned long pmu = readl(mpp_base + PMU_MPP_GENERAL_CTRL);
+       unsigned long pmu = readl(data->base + PMU_MPP_GENERAL_CTRL);
        unsigned long func;
 
        if ((pmu & BIT(pid)) == 0)
-               return default_mpp_ctrl_get(mpp_base, pid, config);
+               return mvebu_mmio_mpp_ctrl_get(data, pid, config);
 
        func = readl(pmu_base + PMU_SIGNAL_SELECT_0 + off);
        *config = (func >> shift) & MVEBU_MPP_MASK;
@@ -93,19 +82,20 @@ static int dove_pmu_mpp_ctrl_get(unsigned pid, unsigned long *config)
        return 0;
 }
 
-static int dove_pmu_mpp_ctrl_set(unsigned pid, unsigned long config)
+static int dove_pmu_mpp_ctrl_set(struct mvebu_mpp_ctrl_data *data,
+                                unsigned pid, unsigned long config)
 {
        unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
        unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
-       unsigned long pmu = readl(mpp_base + PMU_MPP_GENERAL_CTRL);
+       unsigned long pmu = readl(data->base + PMU_MPP_GENERAL_CTRL);
        unsigned long func;
 
        if ((config & CONFIG_PMU) == 0) {
-               writel(pmu & ~BIT(pid), mpp_base + PMU_MPP_GENERAL_CTRL);
-               return default_mpp_ctrl_set(mpp_base, pid, config);
+               writel(pmu & ~BIT(pid), data->base + PMU_MPP_GENERAL_CTRL);
+               return mvebu_mmio_mpp_ctrl_set(data, pid, config);
        }
 
-       writel(pmu | BIT(pid), mpp_base + PMU_MPP_GENERAL_CTRL);
+       writel(pmu | BIT(pid), data->base + PMU_MPP_GENERAL_CTRL);
        func = readl(pmu_base + PMU_SIGNAL_SELECT_0 + off);
        func &= ~(MVEBU_MPP_MASK << shift);
        func |= (config & MVEBU_MPP_MASK) << shift;
@@ -114,7 +104,8 @@ static int dove_pmu_mpp_ctrl_set(unsigned pid, unsigned long config)
        return 0;
 }
 
-static int dove_mpp4_ctrl_get(unsigned pid, unsigned long *config)
+static int dove_mpp4_ctrl_get(struct mvebu_mpp_ctrl_data *data, unsigned pid,
+                             unsigned long *config)
 {
        unsigned long mpp4 = readl(mpp4_base);
        unsigned long mask;
@@ -144,7 +135,8 @@ static int dove_mpp4_ctrl_get(unsigned pid, unsigned long *config)
        return 0;
 }
 
-static int dove_mpp4_ctrl_set(unsigned pid, unsigned long config)
+static int dove_mpp4_ctrl_set(struct mvebu_mpp_ctrl_data *data, unsigned pid,
+                             unsigned long config)
 {
        unsigned long mpp4 = readl(mpp4_base);
        unsigned long mask;
@@ -178,7 +170,8 @@ static int dove_mpp4_ctrl_set(unsigned pid, unsigned long config)
        return 0;
 }
 
-static int dove_nand_ctrl_get(unsigned pid, unsigned long *config)
+static int dove_nand_ctrl_get(struct mvebu_mpp_ctrl_data *data, unsigned pid,
+                             unsigned long *config)
 {
        unsigned int gmpp;
 
@@ -188,7 +181,8 @@ static int dove_nand_ctrl_get(unsigned pid, unsigned long *config)
        return 0;
 }
 
-static int dove_nand_ctrl_set(unsigned pid, unsigned long config)
+static int dove_nand_ctrl_set(struct mvebu_mpp_ctrl_data *data, unsigned pid,
+                             unsigned long config)
 {
        regmap_update_bits(gconfmap, MPP_GENERAL_CONFIG,
                           NAND_GPIO_EN,
@@ -196,28 +190,31 @@ static int dove_nand_ctrl_set(unsigned pid, unsigned long config)
        return 0;
 }
 
-static int dove_audio0_ctrl_get(unsigned pid, unsigned long *config)
+static int dove_audio0_ctrl_get(struct mvebu_mpp_ctrl_data *data, unsigned pid,
+                               unsigned long *config)
 {
-       unsigned long pmu = readl(mpp_base + PMU_MPP_GENERAL_CTRL);
+       unsigned long pmu = readl(data->base + PMU_MPP_GENERAL_CTRL);
 
        *config = ((pmu & AU0_AC97_SEL) != 0);
 
        return 0;
 }
 
-static int dove_audio0_ctrl_set(unsigned pid, unsigned long config)
+static int dove_audio0_ctrl_set(struct mvebu_mpp_ctrl_data *data, unsigned pid,
+                               unsigned long config)
 {
-       unsigned long pmu = readl(mpp_base + PMU_MPP_GENERAL_CTRL);
+       unsigned long pmu = readl(data->base + PMU_MPP_GENERAL_CTRL);
 
        pmu &= ~AU0_AC97_SEL;
        if (config)
                pmu |= AU0_AC97_SEL;
-       writel(pmu, mpp_base + PMU_MPP_GENERAL_CTRL);
+       writel(pmu, data->base + PMU_MPP_GENERAL_CTRL);
 
        return 0;
 }
 
-static int dove_audio1_ctrl_get(unsigned pid, unsigned long *config)
+static int dove_audio1_ctrl_get(struct mvebu_mpp_ctrl_data *data, unsigned pid,
+                               unsigned long *config)
 {
        unsigned int mpp4 = readl(mpp4_base);
        unsigned int sspc1;
@@ -247,7 +244,8 @@ static int dove_audio1_ctrl_get(unsigned pid, unsigned long *config)
        return 0;
 }
 
-static int dove_audio1_ctrl_set(unsigned pid, unsigned long config)
+static int dove_audio1_ctrl_set(struct mvebu_mpp_ctrl_data *data, unsigned pid,
+                               unsigned long config)
 {
        unsigned int mpp4 = readl(mpp4_base);
 
@@ -274,11 +272,12 @@ static int dove_audio1_ctrl_set(unsigned pid, unsigned long config)
  * break other functions. If you require all mpps as gpio
  * enforce gpio setting by pinctrl mapping.
  */
-static int dove_audio1_ctrl_gpio_req(unsigned pid)
+static int dove_audio1_ctrl_gpio_req(struct mvebu_mpp_ctrl_data *data,
+                                    unsigned pid)
 {
        unsigned long config;
 
-       dove_audio1_ctrl_get(pid, &config);
+       dove_audio1_ctrl_get(data, pid, &config);
 
        switch (config) {
        case 0x02: /* i2s1 : gpio[56:57] */
@@ -301,14 +300,16 @@ static int dove_audio1_ctrl_gpio_req(unsigned pid)
 }
 
 /* mpp[52:57] has gpio pins capable of in and out */
-static int dove_audio1_ctrl_gpio_dir(unsigned pid, bool input)
+static int dove_audio1_ctrl_gpio_dir(struct mvebu_mpp_ctrl_data *data,
+                                    unsigned pid, bool input)
 {
        if (pid < 52 || pid > 57)
                return -ENOTSUPP;
        return 0;
 }
 
-static int dove_twsi_ctrl_get(unsigned pid, unsigned long *config)
+static int dove_twsi_ctrl_get(struct mvebu_mpp_ctrl_data *data, unsigned pid,
+                             unsigned long *config)
 {
        unsigned int gcfg1;
        unsigned int gcfg2;
@@ -327,7 +328,8 @@ static int dove_twsi_ctrl_get(unsigned pid, unsigned long *config)
        return 0;
 }
 
-static int dove_twsi_ctrl_set(unsigned pid, unsigned long config)
+static int dove_twsi_ctrl_set(struct mvebu_mpp_ctrl_data *data, unsigned pid,
+                             unsigned long config)
 {
        unsigned int gcfg1 = 0;
        unsigned int gcfg2 = 0;
@@ -354,9 +356,9 @@ static int dove_twsi_ctrl_set(unsigned pid, unsigned long config)
        return 0;
 }
 
-static struct mvebu_mpp_ctrl dove_mpp_controls[] = {
+static const struct mvebu_mpp_ctrl dove_mpp_controls[] = {
        MPP_FUNC_CTRL(0, 15, NULL, dove_pmu_mpp_ctrl),
-       MPP_FUNC_CTRL(16, 23, NULL, dove_mpp_ctrl),
+       MPP_FUNC_CTRL(16, 23, NULL, mvebu_mmio_mpp_ctrl),
        MPP_FUNC_CTRL(24, 39, "mpp_camera", dove_mpp4_ctrl),
        MPP_FUNC_CTRL(40, 45, "mpp_sdio0", dove_mpp4_ctrl),
        MPP_FUNC_CTRL(46, 51, "mpp_sdio1", dove_mpp4_ctrl),
@@ -769,6 +771,10 @@ static int dove_pinctrl_probe(struct platform_device *pdev)
        struct resource fb_res;
        const struct of_device_id *match =
                of_match_device(dove_pinctrl_of_match, &pdev->dev);
+       struct mvebu_mpp_ctrl_data *mpp_data;
+       void __iomem *base;
+       int i;
+
        pdev->dev.platform_data = (void *)match->data;
 
        /*
@@ -783,9 +789,18 @@ static int dove_pinctrl_probe(struct platform_device *pdev)
        clk_prepare_enable(clk);
 
        mpp_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       mpp_base = devm_ioremap_resource(&pdev->dev, mpp_res);
-       if (IS_ERR(mpp_base))
-               return PTR_ERR(mpp_base);
+       base = devm_ioremap_resource(&pdev->dev, mpp_res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       mpp_data = devm_kcalloc(&pdev->dev, dove_pinctrl_info.ncontrols,
+                               sizeof(*mpp_data), GFP_KERNEL);
+       if (!mpp_data)
+               return -ENOMEM;
+
+       dove_pinctrl_info.control_data = mpp_data;
+       for (i = 0; i < ARRAY_SIZE(dove_mpp_controls); i++)
+               mpp_data[i].base = base;
 
        /* prepare fallback resource */
        memcpy(&fb_res, mpp_res, sizeof(struct resource));
@@ -838,24 +853,12 @@ static int dove_pinctrl_probe(struct platform_device *pdev)
        return mvebu_pinctrl_probe(pdev);
 }
 
-static int dove_pinctrl_remove(struct platform_device *pdev)
-{
-       if (!IS_ERR(clk))
-               clk_disable_unprepare(clk);
-       return 0;
-}
-
 static struct platform_driver dove_pinctrl_driver = {
        .driver = {
                .name = "dove-pinctrl",
+               .suppress_bind_attrs = true,
                .of_match_table = dove_pinctrl_of_match,
        },
        .probe = dove_pinctrl_probe,
-       .remove = dove_pinctrl_remove,
 };
-
-module_platform_driver(dove_pinctrl_driver);
-
-MODULE_AUTHOR("Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>");
-MODULE_DESCRIPTION("Marvell Dove pinctrl driver");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver(dove_pinctrl_driver);
index 5f89c26f3292c87c094922a314a45452478c17e5..5995a19abde5abc5e1034f2734d48400bdf6b885 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/of.h>
 
 #include "pinctrl-mvebu.h"
 
-static void __iomem *mpp_base;
-
-static int kirkwood_mpp_ctrl_get(unsigned pid, unsigned long *config)
-{
-       return default_mpp_ctrl_get(mpp_base, pid, config);
-}
-
-static int kirkwood_mpp_ctrl_set(unsigned pid, unsigned long config)
-{
-       return default_mpp_ctrl_set(mpp_base, pid, config);
-}
-
 #define V(f6180, f6190, f6192, f6281, f6282, dx4122)   \
        ((f6180 << 0) | (f6190 << 1) | (f6192 << 2) |   \
         (f6281 << 3) | (f6282 << 4) | (dx4122 << 5))
@@ -370,8 +357,8 @@ static struct mvebu_mpp_mode mv88f6xxx_mpp_modes[] = {
                MPP_VAR_FUNCTION(0xb, "lcd", "d17",      V(0, 0, 0, 0, 1, 0))),
 };
 
-static struct mvebu_mpp_ctrl mv88f6180_mpp_controls[] = {
-       MPP_FUNC_CTRL(0, 44, NULL, kirkwood_mpp_ctrl),
+static const struct mvebu_mpp_ctrl mv88f6180_mpp_controls[] = {
+       MPP_FUNC_CTRL(0, 44, NULL, mvebu_mmio_mpp_ctrl),
 };
 
 static struct pinctrl_gpio_range mv88f6180_gpio_ranges[] = {
@@ -379,8 +366,8 @@ static struct pinctrl_gpio_range mv88f6180_gpio_ranges[] = {
        MPP_GPIO_RANGE(1, 35, 35, 10),
 };
 
-static struct mvebu_mpp_ctrl mv88f619x_mpp_controls[] = {
-       MPP_FUNC_CTRL(0, 35, NULL, kirkwood_mpp_ctrl),
+static const struct mvebu_mpp_ctrl mv88f619x_mpp_controls[] = {
+       MPP_FUNC_CTRL(0, 35, NULL, mvebu_mmio_mpp_ctrl),
 };
 
 static struct pinctrl_gpio_range mv88f619x_gpio_ranges[] = {
@@ -388,8 +375,8 @@ static struct pinctrl_gpio_range mv88f619x_gpio_ranges[] = {
        MPP_GPIO_RANGE(1, 32, 32,  4),
 };
 
-static struct mvebu_mpp_ctrl mv88f628x_mpp_controls[] = {
-       MPP_FUNC_CTRL(0, 49, NULL, kirkwood_mpp_ctrl),
+static const struct mvebu_mpp_ctrl mv88f628x_mpp_controls[] = {
+       MPP_FUNC_CTRL(0, 49, NULL, mvebu_mmio_mpp_ctrl),
 };
 
 static struct pinctrl_gpio_range mv88f628x_gpio_ranges[] = {
@@ -469,17 +456,12 @@ static const struct of_device_id kirkwood_pinctrl_of_match[] = {
 
 static int kirkwood_pinctrl_probe(struct platform_device *pdev)
 {
-       struct resource *res;
        const struct of_device_id *match =
                of_match_device(kirkwood_pinctrl_of_match, &pdev->dev);
-       pdev->dev.platform_data = (void *)match->data;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       mpp_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(mpp_base))
-               return PTR_ERR(mpp_base);
+       pdev->dev.platform_data = (void *)match->data;
 
-       return mvebu_pinctrl_probe(pdev);
+       return mvebu_pinctrl_simple_mmio_probe(pdev);
 }
 
 static struct platform_driver kirkwood_pinctrl_driver = {
@@ -489,9 +471,4 @@ static struct platform_driver kirkwood_pinctrl_driver = {
        },
        .probe = kirkwood_pinctrl_probe,
 };
-
-module_platform_driver(kirkwood_pinctrl_driver);
-
-MODULE_AUTHOR("Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>");
-MODULE_DESCRIPTION("Marvell Kirkwood pinctrl driver");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver(kirkwood_pinctrl_driver);
index b6ec6db783517a01a0e2daebcdfe5b4924716061..e4dda12d371a473faa1c6aa48bfcc01280ec0b18 100644 (file)
@@ -11,7 +11,6 @@
  */
 
 #include <linux/platform_device.h>
-#include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/io.h>
 #include <linux/of.h>
@@ -23,6 +22,8 @@
 #include <linux/pinctrl/pinconf.h>
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/pinctrl/pinmux.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
 
 #include "pinctrl-mvebu.h"
 
@@ -38,7 +39,8 @@ struct mvebu_pinctrl_function {
 
 struct mvebu_pinctrl_group {
        const char *name;
-       struct mvebu_mpp_ctrl *ctrl;
+       const struct mvebu_mpp_ctrl *ctrl;
+       struct mvebu_mpp_ctrl_data *data;
        struct mvebu_mpp_ctrl_setting *settings;
        unsigned num_settings;
        unsigned gid;
@@ -57,6 +59,30 @@ struct mvebu_pinctrl {
        u8 variant;
 };
 
+int mvebu_mmio_mpp_ctrl_get(struct mvebu_mpp_ctrl_data *data,
+                            unsigned int pid, unsigned long *config)
+{
+       unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+       unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+
+       *config = (readl(data->base + off) >> shift) & MVEBU_MPP_MASK;
+
+       return 0;
+}
+
+int mvebu_mmio_mpp_ctrl_set(struct mvebu_mpp_ctrl_data *data,
+                            unsigned int pid, unsigned long config)
+{
+       unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+       unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+       unsigned long reg;
+
+       reg = readl(data->base + off) & ~(MVEBU_MPP_MASK << shift);
+       writel(reg | (config << shift), data->base + off);
+
+       return 0;
+}
+
 static struct mvebu_pinctrl_group *mvebu_pinctrl_find_group_by_pid(
        struct mvebu_pinctrl *pctl, unsigned pid)
 {
@@ -146,7 +172,7 @@ static int mvebu_pinconf_group_get(struct pinctrl_dev *pctldev,
        if (!grp->ctrl)
                return -EINVAL;
 
-       return grp->ctrl->mpp_get(grp->pins[0], config);
+       return grp->ctrl->mpp_get(grp->data, grp->pins[0], config);
 }
 
 static int mvebu_pinconf_group_set(struct pinctrl_dev *pctldev,
@@ -161,7 +187,7 @@ static int mvebu_pinconf_group_set(struct pinctrl_dev *pctldev,
                return -EINVAL;
 
        for (i = 0; i < num_configs; i++) {
-               ret = grp->ctrl->mpp_set(grp->pins[0], configs[i]);
+               ret = grp->ctrl->mpp_set(grp->data, grp->pins[0], configs[i]);
                if (ret)
                        return ret;
        } /* for each config */
@@ -188,18 +214,19 @@ static void mvebu_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
                if (curr->subname)
                        seq_printf(s, "(%s)", curr->subname);
                if (curr->flags & (MVEBU_SETTING_GPO | MVEBU_SETTING_GPI)) {
-                       seq_printf(s, "(");
+                       seq_putc(s, '(');
                        if (curr->flags & MVEBU_SETTING_GPI)
-                               seq_printf(s, "i");
+                               seq_putc(s, 'i');
                        if (curr->flags & MVEBU_SETTING_GPO)
-                               seq_printf(s, "o");
-                       seq_printf(s, ")");
+                               seq_putc(s, 'o');
+                       seq_putc(s, ')');
                }
-       } else
-               seq_printf(s, "current: UNKNOWN");
+       } else {
+               seq_puts(s, "current: UNKNOWN");
+       }
 
        if (grp->num_settings > 1) {
-               seq_printf(s, ", available = [");
+               seq_puts(s, ", available = [");
                for (n = 0; n < grp->num_settings; n++) {
                        if (curr == &grp->settings[n])
                                continue;
@@ -214,17 +241,16 @@ static void mvebu_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
                                seq_printf(s, "(%s)", grp->settings[n].subname);
                        if (grp->settings[n].flags &
                                (MVEBU_SETTING_GPO | MVEBU_SETTING_GPI)) {
-                               seq_printf(s, "(");
+                               seq_putc(s, '(');
                                if (grp->settings[n].flags & MVEBU_SETTING_GPI)
-                                       seq_printf(s, "i");
+                                       seq_putc(s, 'i');
                                if (grp->settings[n].flags & MVEBU_SETTING_GPO)
-                                       seq_printf(s, "o");
-                               seq_printf(s, ")");
+                                       seq_putc(s, 'o');
+                               seq_putc(s, ')');
                        }
                }
-               seq_printf(s, " ]");
+               seq_puts(s, " ]");
        }
-       return;
 }
 
 static const struct pinconf_ops mvebu_pinconf_ops = {
@@ -302,7 +328,7 @@ static int mvebu_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev,
                return -EINVAL;
 
        if (grp->ctrl->mpp_gpio_req)
-               return grp->ctrl->mpp_gpio_req(offset);
+               return grp->ctrl->mpp_gpio_req(grp->data, offset);
 
        setting = mvebu_pinctrl_find_gpio_setting(pctl, grp);
        if (!setting)
@@ -325,7 +351,7 @@ static int mvebu_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
                return -EINVAL;
 
        if (grp->ctrl->mpp_gpio_dir)
-               return grp->ctrl->mpp_gpio_dir(offset, input);
+               return grp->ctrl->mpp_gpio_dir(grp->data, offset, input);
 
        setting = mvebu_pinctrl_find_gpio_setting(pctl, grp);
        if (!setting)
@@ -398,13 +424,9 @@ static int mvebu_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
                return 0;
        }
 
-       *map = kmalloc(nmaps * sizeof(struct pinctrl_map), GFP_KERNEL);
-       if (*map == NULL) {
-               dev_err(pctl->dev,
-                       "cannot allocate pinctrl_map memory for %s\n",
-                       np->name);
+       *map = kmalloc_array(nmaps, sizeof(**map), GFP_KERNEL);
+       if (!*map)
                return -ENOMEM;
-       }
 
        n = 0;
        of_property_for_each_string(np, "marvell,pins", prop, group) {
@@ -563,10 +585,8 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
 
        pctl = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_pinctrl),
                        GFP_KERNEL);
-       if (!pctl) {
-               dev_err(&pdev->dev, "unable to alloc driver\n");
+       if (!pctl)
                return -ENOMEM;
-       }
 
        pctl->desc.name = dev_name(&pdev->dev);
        pctl->desc.owner = THIS_MODULE;
@@ -582,7 +602,7 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
        pctl->num_groups = 0;
        pctl->desc.npins = 0;
        for (n = 0; n < soc->ncontrols; n++) {
-               struct mvebu_mpp_ctrl *ctrl = &soc->controls[n];
+               const struct mvebu_mpp_ctrl *ctrl = &soc->controls[n];
 
                pctl->desc.npins += ctrl->npins;
                /* initialize control's pins[] array */
@@ -604,10 +624,8 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
 
        pdesc = devm_kzalloc(&pdev->dev, pctl->desc.npins *
                             sizeof(struct pinctrl_pin_desc), GFP_KERNEL);
-       if (!pdesc) {
-               dev_err(&pdev->dev, "failed to alloc pinctrl pins\n");
+       if (!pdesc)
                return -ENOMEM;
-       }
 
        for (n = 0; n < pctl->desc.npins; n++)
                pdesc[n].number = n;
@@ -628,9 +646,13 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
        /* assign mpp controls to groups */
        gid = 0;
        for (n = 0; n < soc->ncontrols; n++) {
-               struct mvebu_mpp_ctrl *ctrl = &soc->controls[n];
+               const struct mvebu_mpp_ctrl *ctrl = &soc->controls[n];
+               struct mvebu_mpp_ctrl_data *data = soc->control_data ?
+                                                  &soc->control_data[n] : NULL;
+
                pctl->groups[gid].gid = gid;
                pctl->groups[gid].ctrl = ctrl;
+               pctl->groups[gid].data = data;
                pctl->groups[gid].name = ctrl->name;
                pctl->groups[gid].pins = ctrl->pins;
                pctl->groups[gid].npins = ctrl->npins;
@@ -650,6 +672,7 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
                                gid++;
                                pctl->groups[gid].gid = gid;
                                pctl->groups[gid].ctrl = ctrl;
+                               pctl->groups[gid].data = data;
                                pctl->groups[gid].name = noname_buf;
                                pctl->groups[gid].pins = &ctrl->pins[k];
                                pctl->groups[gid].npins = 1;
@@ -725,3 +748,94 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
 
        return 0;
 }
+
+/*
+ * mvebu_pinctrl_simple_mmio_probe - probe a simple mmio pinctrl
+ * @pdev: platform device (with platform data already attached)
+ *
+ * Initialise a simple (single base address) mmio pinctrl driver,
+ * assigning the MMIO base address to all mvebu mpp ctrl instances.
+ */
+int mvebu_pinctrl_simple_mmio_probe(struct platform_device *pdev)
+{
+       struct mvebu_pinctrl_soc_info *soc = dev_get_platdata(&pdev->dev);
+       struct mvebu_mpp_ctrl_data *mpp_data;
+       struct resource *res;
+       void __iomem *base;
+       int i;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       mpp_data = devm_kcalloc(&pdev->dev, soc->ncontrols, sizeof(*mpp_data),
+                               GFP_KERNEL);
+       if (!mpp_data)
+               return -ENOMEM;
+
+       for (i = 0; i < soc->ncontrols; i++)
+               mpp_data[i].base = base;
+
+       soc->control_data = mpp_data;
+
+       return mvebu_pinctrl_probe(pdev);
+}
+
+int mvebu_regmap_mpp_ctrl_get(struct mvebu_mpp_ctrl_data *data,
+                             unsigned int pid, unsigned long *config)
+{
+       unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+       unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+       unsigned int val;
+       int err;
+
+       err = regmap_read(data->regmap.map, data->regmap.offset + off, &val);
+       if (err)
+               return err;
+
+       *config = (val >> shift) & MVEBU_MPP_MASK;
+
+       return 0;
+}
+
+int mvebu_regmap_mpp_ctrl_set(struct mvebu_mpp_ctrl_data *data,
+                             unsigned int pid, unsigned long config)
+{
+       unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+       unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
+
+       return regmap_update_bits(data->regmap.map, data->regmap.offset + off,
+                                 MVEBU_MPP_MASK << shift, config << shift);
+}
+
+int mvebu_pinctrl_simple_regmap_probe(struct platform_device *pdev,
+                                     struct device *syscon_dev)
+{
+       struct mvebu_pinctrl_soc_info *soc = dev_get_platdata(&pdev->dev);
+       struct mvebu_mpp_ctrl_data *mpp_data;
+       struct regmap *regmap;
+       u32 offset;
+       int i;
+
+       regmap = syscon_node_to_regmap(syscon_dev->of_node);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       if (of_property_read_u32(pdev->dev.of_node, "offset", &offset))
+               return -EINVAL;
+
+       mpp_data = devm_kcalloc(&pdev->dev, soc->ncontrols, sizeof(*mpp_data),
+                               GFP_KERNEL);
+       if (!mpp_data)
+               return -ENOMEM;
+
+       for (i = 0; i < soc->ncontrols; i++) {
+               mpp_data[i].regmap.map = regmap;
+               mpp_data[i].regmap.offset = offset;
+       }
+
+       soc->control_data = mpp_data;
+
+       return mvebu_pinctrl_probe(pdev);
+}
index b75a5f4adf3b1fce09c200e8bc585c51c1e791d4..c90704e74884c525fffd21fd921f768bb5455dd2 100644 (file)
 #ifndef __PINCTRL_MVEBU_H__
 #define __PINCTRL_MVEBU_H__
 
+/**
+ * struct mvebu_mpp_ctrl_data - private data for the mpp ctrl operations
+ * @base: base address of pinctrl hardware
+ * @regmap.map: regmap structure
+ * @regmap.offset: regmap offset
+ */
+struct mvebu_mpp_ctrl_data {
+       union {
+               void __iomem *base;
+               struct {
+                       struct regmap *map;
+                       u32 offset;
+               } regmap;
+       };
+};
+
 /**
  * struct mvebu_mpp_ctrl - describe a mpp control
  * @name: name of the control group
@@ -37,10 +53,13 @@ struct mvebu_mpp_ctrl {
        u8 pid;
        u8 npins;
        unsigned *pins;
-       int (*mpp_get)(unsigned pid, unsigned long *config);
-       int (*mpp_set)(unsigned pid, unsigned long config);
-       int (*mpp_gpio_req)(unsigned pid);
-       int (*mpp_gpio_dir)(unsigned pid, bool input);
+       int (*mpp_get)(struct mvebu_mpp_ctrl_data *data, unsigned pid,
+                      unsigned long *config);
+       int (*mpp_set)(struct mvebu_mpp_ctrl_data *data, unsigned pid,
+                      unsigned long config);
+       int (*mpp_gpio_req)(struct mvebu_mpp_ctrl_data *data, unsigned pid);
+       int (*mpp_gpio_dir)(struct mvebu_mpp_ctrl_data *data, unsigned pid,
+                           bool input);
 };
 
 /**
@@ -93,6 +112,7 @@ struct mvebu_mpp_mode {
  * struct mvebu_pinctrl_soc_info - SoC specific info passed to pinctrl-mvebu
  * @variant: variant mask of soc_info
  * @controls: list of available mvebu_mpp_ctrls
+ * @control_data: optional array, one entry for each control
  * @ncontrols: number of available mvebu_mpp_ctrls
  * @modes: list of available mvebu_mpp_modes
  * @nmodes: number of available mvebu_mpp_modes
@@ -105,7 +125,8 @@ struct mvebu_mpp_mode {
  */
 struct mvebu_pinctrl_soc_info {
        u8 variant;
-       struct mvebu_mpp_ctrl *controls;
+       const struct mvebu_mpp_ctrl *controls;
+       struct mvebu_mpp_ctrl_data *control_data;
        int ncontrols;
        struct mvebu_mpp_mode *modes;
        int nmodes;
@@ -177,30 +198,18 @@ struct mvebu_pinctrl_soc_info {
 #define MVEBU_MPP_BITS         4
 #define MVEBU_MPP_MASK         0xf
 
-static inline int default_mpp_ctrl_get(void __iomem *base, unsigned int pid,
-                                      unsigned long *config)
-{
-       unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
-       unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
-
-       *config = (readl(base + off) >> shift) & MVEBU_MPP_MASK;
-
-       return 0;
-}
-
-static inline int default_mpp_ctrl_set(void __iomem *base, unsigned int pid,
-                                      unsigned long config)
-{
-       unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
-       unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
-       unsigned long reg;
-
-       reg = readl(base + off) & ~(MVEBU_MPP_MASK << shift);
-       writel(reg | (config << shift), base + off);
-
-       return 0;
-}
+int mvebu_mmio_mpp_ctrl_get(struct mvebu_mpp_ctrl_data *data, unsigned pid,
+                              unsigned long *config);
+int mvebu_mmio_mpp_ctrl_set(struct mvebu_mpp_ctrl_data *data, unsigned pid,
+                              unsigned long config);
+int mvebu_regmap_mpp_ctrl_get(struct mvebu_mpp_ctrl_data *data, unsigned pid,
+                             unsigned long *config);
+int mvebu_regmap_mpp_ctrl_set(struct mvebu_mpp_ctrl_data *data, unsigned pid,
+                             unsigned long config);
 
 int mvebu_pinctrl_probe(struct platform_device *pdev);
+int mvebu_pinctrl_simple_mmio_probe(struct platform_device *pdev);
+int mvebu_pinctrl_simple_regmap_probe(struct platform_device *pdev,
+                                     struct device *syscon_dev);
 
 #endif
index 84e144167b44d37777fe1f7062e19a9d28b83131..69cb4d9f0114d0857ec99da5c763e0c42b4bb22f 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/of.h>
@@ -32,7 +31,8 @@
 static void __iomem *mpp_base;
 static void __iomem *high_mpp_base;
 
-static int orion_mpp_ctrl_get(unsigned pid, unsigned long *config)
+static int orion_mpp_ctrl_get(struct mvebu_mpp_ctrl_data *data,
+                             unsigned pid, unsigned long *config)
 {
        unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
 
@@ -47,7 +47,8 @@ static int orion_mpp_ctrl_get(unsigned pid, unsigned long *config)
        return 0;
 }
 
-static int orion_mpp_ctrl_set(unsigned pid, unsigned long config)
+static int orion_mpp_ctrl_set(struct mvebu_mpp_ctrl_data *data,
+                             unsigned pid, unsigned long config)
 {
        unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
 
@@ -161,7 +162,7 @@ static struct mvebu_mpp_mode orion_mpp_modes[] = {
                 MPP_VAR_FUNCTION(0x5, "gpio", NULL,        V_5182)),
 };
 
-static struct mvebu_mpp_ctrl orion_mpp_controls[] = {
+static const struct mvebu_mpp_ctrl orion_mpp_controls[] = {
        MPP_FUNC_CTRL(0, 19, NULL, orion_mpp_ctrl),
 };
 
@@ -247,9 +248,4 @@ static struct platform_driver orion_pinctrl_driver = {
        },
        .probe = orion_pinctrl_probe,
 };
-
-module_platform_driver(orion_pinctrl_driver);
-
-MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
-MODULE_DESCRIPTION("Marvell Orion pinctrl driver");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver(orion_pinctrl_driver);
index 799048f3c8d4ec271c5c8849d3a8f17c8ac4e1ff..c1c1ccc58267f58c95ef83f028ce7880c9975d65 100644 (file)
@@ -200,6 +200,18 @@ int pinconf_apply_setting(struct pinctrl_setting const *setting)
        return 0;
 }
 
+int pinconf_set_config(struct pinctrl_dev *pctldev, unsigned pin,
+                      unsigned long *configs, size_t nconfigs)
+{
+       const struct pinconf_ops *ops;
+
+       ops = pctldev->desc->confops;
+       if (!ops)
+               return -ENOTSUPP;
+
+       return ops->pin_config_set(pctldev, pin, configs, nconfigs);
+}
+
 #ifdef CONFIG_DEBUG_FS
 
 static void pinconf_show_config(struct seq_file *s, struct pinctrl_dev *pctldev,
index 55c75780b3b29e2dbefcefba6c9ff5556e70f21c..bf8aff9abf32338eafb783b1ffb62e2742084481 100644 (file)
@@ -20,6 +20,9 @@ int pinconf_map_to_setting(struct pinctrl_map const *map,
 void pinconf_free_setting(struct pinctrl_setting const *setting);
 int pinconf_apply_setting(struct pinctrl_setting const *setting);
 
+int pinconf_set_config(struct pinctrl_dev *pctldev, unsigned pin,
+                      unsigned long *configs, size_t nconfigs);
+
 /*
  * You will only be interested in these if you're using PINCONF
  * so don't supply any stubs for these.
@@ -56,6 +59,12 @@ static inline int pinconf_apply_setting(struct pinctrl_setting const *setting)
        return 0;
 }
 
+static inline int pinconf_set_config(struct pinctrl_dev *pctldev, unsigned pin,
+                                    unsigned long *configs, size_t nconfigs)
+{
+       return -ENOTSUPP;
+}
+
 #endif
 
 #if defined(CONFIG_PINCONF) && defined(CONFIG_DEBUG_FS)
index 537b52055756645a8f225dd7e96b191d7d841e96..d69e357a7a98fe0467917e6a87a8b45145a2e4c3 100644 (file)
@@ -164,6 +164,18 @@ static int amd_gpio_set_debounce(struct gpio_chip *gc, unsigned offset,
        return ret;
 }
 
+static int amd_gpio_set_config(struct gpio_chip *gc, unsigned offset,
+                              unsigned long config)
+{
+       u32 debounce;
+
+       if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
+               return -ENOTSUPP;
+
+       debounce = pinconf_to_config_argument(config);
+       return amd_gpio_set_debounce(gc, offset, debounce);
+}
+
 #ifdef CONFIG_DEBUG_FS
 static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc)
 {
@@ -186,7 +198,7 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc)
        char *output_value;
        char *output_enable;
 
-       for (bank = 0; bank < AMD_GPIO_TOTAL_BANKS; bank++) {
+       for (bank = 0; bank < gpio_dev->hwbank_num; bank++) {
                seq_printf(s, "GPIO bank%d\t", bank);
 
                switch (bank) {
@@ -202,10 +214,14 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc)
                        i = 128;
                        pin_num = AMD_GPIO_PINS_BANK2 + i;
                        break;
+               case 3:
+                       i = 192;
+                       pin_num = AMD_GPIO_PINS_BANK3 + i;
+                       break;
                default:
-                       return;
+                       /* Illegal bank number, ignore */
+                       continue;
                }
-
                for (; i < pin_num; i++) {
                        seq_printf(s, "pin%d\t", i);
                        spin_lock_irqsave(&gpio_dev->lock, flags);
@@ -215,14 +231,14 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc)
                        if (pin_reg & BIT(INTERRUPT_ENABLE_OFF)) {
                                interrupt_enable = "interrupt is enabled|";
 
-                               if (!(pin_reg & BIT(ACTIVE_LEVEL_OFF))
-                               && !(pin_reg & BIT(ACTIVE_LEVEL_OFF+1)))
+                               if (!(pin_reg & BIT(ACTIVE_LEVEL_OFF)) &&
+                                   !(pin_reg & BIT(ACTIVE_LEVEL_OFF + 1)))
                                        active_level = "Active low|";
-                               else if (pin_reg & BIT(ACTIVE_LEVEL_OFF)
-                               && !(pin_reg & BIT(ACTIVE_LEVEL_OFF+1)))
+                               else if (pin_reg & BIT(ACTIVE_LEVEL_OFF) &&
+                                        !(pin_reg & BIT(ACTIVE_LEVEL_OFF + 1)))
                                        active_level = "Active high|";
-                               else if (!(pin_reg & BIT(ACTIVE_LEVEL_OFF))
-                                       && pin_reg & BIT(ACTIVE_LEVEL_OFF+1))
+                               else if (!(pin_reg & BIT(ACTIVE_LEVEL_OFF)) &&
+                                        pin_reg & BIT(ACTIVE_LEVEL_OFF + 1))
                                        active_level = "Active on both|";
                                else
                                        active_level = "Unknow Active level|";
@@ -246,17 +262,17 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc)
                                interrupt_mask =
                                        "interrupt is masked|";
 
-                       if (pin_reg & BIT(WAKE_CNTRL_OFF))
+                       if (pin_reg & BIT(WAKE_CNTRL_OFF_S0I3))
                                wake_cntrl0 = "enable wakeup in S0i3 state|";
                        else
                                wake_cntrl0 = "disable wakeup in S0i3 state|";
 
-                       if (pin_reg & BIT(WAKE_CNTRL_OFF))
+                       if (pin_reg & BIT(WAKE_CNTRL_OFF_S3))
                                wake_cntrl1 = "enable wakeup in S3 state|";
                        else
                                wake_cntrl1 = "disable wakeup in S3 state|";
 
-                       if (pin_reg & BIT(WAKE_CNTRL_OFF))
+                       if (pin_reg & BIT(WAKE_CNTRL_OFF_S4))
                                wake_cntrl2 = "enable wakeup in S4/S5 state|";
                        else
                                wake_cntrl2 = "disable wakeup in S4/S5 state|";
@@ -476,6 +492,7 @@ static struct irq_chip amd_gpio_irqchip = {
        .irq_unmask   = amd_gpio_irq_unmask,
        .irq_eoi      = amd_gpio_irq_eoi,
        .irq_set_type = amd_gpio_irq_set_type,
+       .flags        = IRQCHIP_SKIP_SET_WAKE,
 };
 
 static void amd_gpio_irq_handler(struct irq_desc *desc)
@@ -758,18 +775,19 @@ static int amd_gpio_probe(struct platform_device *pdev)
        gpio_dev->gc.direction_output   = amd_gpio_direction_output;
        gpio_dev->gc.get                        = amd_gpio_get_value;
        gpio_dev->gc.set                        = amd_gpio_set_value;
-       gpio_dev->gc.set_debounce       = amd_gpio_set_debounce;
+       gpio_dev->gc.set_config         = amd_gpio_set_config;
        gpio_dev->gc.dbg_show           = amd_gpio_dbg_show;
 
-       gpio_dev->gc.base                       = 0;
+       gpio_dev->gc.base               = -1;
        gpio_dev->gc.label                      = pdev->name;
        gpio_dev->gc.owner                      = THIS_MODULE;
        gpio_dev->gc.parent                     = &pdev->dev;
-       gpio_dev->gc.ngpio                      = TOTAL_NUMBER_OF_PINS;
+       gpio_dev->gc.ngpio                      = resource_size(res) / 4;
 #if defined(CONFIG_OF_GPIO)
        gpio_dev->gc.of_node                    = pdev->dev.of_node;
 #endif
 
+       gpio_dev->hwbank_num = gpio_dev->gc.ngpio / 64;
        gpio_dev->groups = kerncz_groups;
        gpio_dev->ngroups = ARRAY_SIZE(kerncz_groups);
 
@@ -786,7 +804,7 @@ static int amd_gpio_probe(struct platform_device *pdev)
                return ret;
 
        ret = gpiochip_add_pin_range(&gpio_dev->gc, dev_name(&pdev->dev),
-                               0, 0, TOTAL_NUMBER_OF_PINS);
+                               0, 0, gpio_dev->gc.ngpio);
        if (ret) {
                dev_err(&pdev->dev, "Failed to add pin range\n");
                goto out2;
@@ -807,7 +825,6 @@ static int amd_gpio_probe(struct platform_device *pdev)
                                 &amd_gpio_irqchip,
                                 irq_base,
                                 amd_gpio_irq_handler);
-
        platform_set_drvdata(pdev, gpio_dev);
 
        dev_dbg(&pdev->dev, "amd gpio driver loaded\n");
index 7bfea47dbb472f6857380023873f4caf6aad25a8..c03f77822069ec01daabb36306feae98660af494 100644 (file)
 #ifndef _PINCTRL_AMD_H
 #define _PINCTRL_AMD_H
 
-#define TOTAL_NUMBER_OF_PINS   192
 #define AMD_GPIO_PINS_PER_BANK  64
-#define AMD_GPIO_TOTAL_BANKS    3
 
 #define AMD_GPIO_PINS_BANK0     63
 #define AMD_GPIO_PINS_BANK1     64
 #define AMD_GPIO_PINS_BANK2     56
+#define AMD_GPIO_PINS_BANK3     32
 
 #define WAKE_INT_MASTER_REG 0xfc
 #define EOI_MASK (1 << 29)
@@ -35,7 +34,9 @@
 #define ACTIVE_LEVEL_OFF               9
 #define INTERRUPT_ENABLE_OFF           11
 #define INTERRUPT_MASK_OFF             12
-#define WAKE_CNTRL_OFF                 13
+#define WAKE_CNTRL_OFF_S0I3             13
+#define WAKE_CNTRL_OFF_S3               14
+#define WAKE_CNTRL_OFF_S4               15
 #define PIN_STS_OFF                    16
 #define DRV_STRENGTH_SEL_OFF           17
 #define PULL_UP_SEL_OFF                        19
@@ -93,6 +94,7 @@ struct amd_gpio {
        u32 ngroups;
        struct pinctrl_dev *pctrl;
        struct gpio_chip        gc;
+       unsigned int            hwbank_num;
        struct resource         *res;
        struct platform_device  *pdev;
 };
index b36a90a3f3e492493b41c5c61c61582e7d35a091..f41d3d948dd8178d1b6b7074a4da734eb3484e2d 100644 (file)
@@ -113,7 +113,6 @@ static int da850_pupd_pin_config_group_set(struct pinctrl_dev *pctldev,
        struct da850_pupd_data *data = pinctrl_dev_get_drvdata(pctldev);
        u32 ena, sel;
        enum pin_config_param param;
-       u16 arg;
        int i;
 
        ena = readl(data->base + DA850_PUPD_ENA);
@@ -121,7 +120,6 @@ static int da850_pupd_pin_config_group_set(struct pinctrl_dev *pctldev,
 
        for (i = 0; i < num_configs; i++) {
                param = pinconf_to_config_param(configs[i]);
-               arg = pinconf_to_config_argument(configs[i]);
 
                switch (param) {
                case PIN_CONFIG_BIAS_DISABLE:
@@ -194,6 +192,7 @@ static const struct of_device_id da850_pupd_of_match[] = {
        { .compatible = "ti,da850-pupd" },
        { }
 };
+MODULE_DEVICE_TABLE(of, da850_pupd_of_match);
 
 static struct platform_driver da850_pupd_driver = {
        .driver = {
index 0b0fc2eb48e0b190c9b947b3386478303fa86123..fb73dcbb5ef37a1d6f490d53ab77f57f7e41223d 100644 (file)
@@ -7,7 +7,7 @@
  *  by the Free Software Foundation.
  *
  *  Copyright (C) 2012 Thomas Langer <thomas.langer@lantiq.com>
- *  Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ *  Copyright (C) 2012 John Crispin <john@phrozen.org>
  */
 
 #include <linux/gpio.h>
index a4d64742460090e9ef42f9989ff2c6eff400159e..41dc39c7a7b14c700936eb38075aa440af0a1d85 100644 (file)
@@ -6,7 +6,7 @@
  *  it under the terms of the GNU General Public License version 2 as
  *  publishhed by the Free Software Foundation.
  *
- *  Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ *  Copyright (C) 2012 John Crispin <john@phrozen.org>
  */
 
 #include <linux/module.h>
index e137d139e49467071867305d4b1ec4238848fe19..0e4308b8f2356297ee9775263125193355498af7 100644 (file)
@@ -6,7 +6,7 @@
  *  it under the terms of the GNU General Public License version 2 as
  *  publishhed by the Free Software Foundation.
  *
- *  Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ *  Copyright (C) 2012 John Crispin <john@phrozen.org>
  */
 
 #ifndef __PINCTRL_LANTIQ_H
index e053f1fa551203cdf6e2fdeb2e3d8b78e75bdc0f..d090f37ca4a114683d69e203532b20dc653c1d35 100644 (file)
@@ -904,7 +904,7 @@ static int lpc18xx_pconf_get(struct pinctrl_dev *pctldev, unsigned pin,
 
 static int lpc18xx_pconf_set_usb1(struct pinctrl_dev *pctldev,
                                  enum pin_config_param param,
-                                 u16 param_val, u32 *reg)
+                                 u32 param_val, u32 *reg)
 {
        switch (param) {
        case PIN_CONFIG_LOW_POWER_MODE:
@@ -932,7 +932,7 @@ static int lpc18xx_pconf_set_usb1(struct pinctrl_dev *pctldev,
 
 static int lpc18xx_pconf_set_i2c0(struct pinctrl_dev *pctldev,
                                  enum pin_config_param param,
-                                 u16 param_val, u32 *reg,
+                                 u32 param_val, u32 *reg,
                                  unsigned pin)
 {
        u8 shift;
@@ -982,7 +982,7 @@ static int lpc18xx_pconf_set_i2c0(struct pinctrl_dev *pctldev,
 }
 
 static int lpc18xx_pconf_set_gpio_pin_int(struct pinctrl_dev *pctldev,
-                                         u16 param_val, unsigned pin)
+                                         u32 param_val, unsigned pin)
 {
        struct lpc18xx_scu_data *scu = pinctrl_dev_get_drvdata(pctldev);
        u32 val, reg_val, reg_offset = LPC18XX_SCU_PINTSEL0;
@@ -1008,7 +1008,7 @@ static int lpc18xx_pconf_set_gpio_pin_int(struct pinctrl_dev *pctldev,
 }
 
 static int lpc18xx_pconf_set_pin(struct pinctrl_dev *pctldev, unsigned param,
-                                u16 param_val, u32 *reg, unsigned pin,
+                                u32 param_val, u32 *reg, unsigned pin,
                                 struct lpc18xx_pin_caps *pin_cap)
 {
        switch (param) {
@@ -1088,7 +1088,7 @@ static int lpc18xx_pconf_set(struct pinctrl_dev *pctldev, unsigned pin,
        struct lpc18xx_scu_data *scu = pinctrl_dev_get_drvdata(pctldev);
        struct lpc18xx_pin_caps *pin_cap;
        enum pin_config_param param;
-       u16 param_val;
+       u32 param_val;
        u32 reg;
        int ret;
        int i;
index d9ff53e8f715a425ae563bccfe6a7fb85bcd9679..b8d2180a2bea44426b940745c5030f60073e214e 100644 (file)
@@ -402,7 +402,7 @@ static int max77620_pinconf_set(struct pinctrl_dev *pctldev,
        struct device *dev = mpci->dev;
        struct max77620_fps_config *fps_config;
        int param;
-       u16 param_val;
+       u32 param_val;
        unsigned int val;
        unsigned int pu_val;
        unsigned int pd_val;
index a30146da7ffdcb6a72513b87d692a49527a5d16c..4d6a5015b9272f335d8738c072e27cd0eec56f9b 100644 (file)
@@ -860,7 +860,7 @@ static int palmas_pinconf_set(struct pinctrl_dev *pctldev,
 {
        struct palmas_pctrl_chip_info *pci = pinctrl_dev_get_drvdata(pctldev);
        enum pin_config_param param;
-       u16 param_val;
+       u32 param_val;
        const struct palmas_pingroup *g;
        const struct palmas_pin_info *opt;
        int ret;
index 08765f58253c206b2c3d6692d19a504a7de4fbfa..7813599e43fac80634061b00d0dbb32f5ea829f6 100644 (file)
@@ -1441,7 +1441,7 @@ static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
        struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
        struct rockchip_pin_bank *bank = pin_to_bank(info, pin);
        enum pin_config_param param;
-       u16 arg;
+       u32 arg;
        int i;
        int rc;
 
index a5a0392ab8175da62001816e3f7eb7a2600f1b08..8b2d45e85baea612451812fb7cc82b88b75d8d9c 100644 (file)
 #include "core.h"
 #include "devicetree.h"
 #include "pinconf.h"
+#include "pinmux.h"
 
 #define DRIVER_NAME                    "pinctrl-single"
 #define PCS_OFF_DISABLED               ~0U
 
-/**
- * struct pcs_pingroup - pingroups for a function
- * @np:                pingroup device node pointer
- * @name:      pingroup name
- * @gpins:     array of the pins in the group
- * @ngpins:    number of pins in the group
- * @node:      list node
- */
-struct pcs_pingroup {
-       struct device_node *np;
-       const char *name;
-       int *gpins;
-       int ngpins;
-       struct list_head node;
-};
-
 /**
  * struct pcs_func_vals - mux function register offset and value pair
  * @reg:       register virtual address
@@ -176,16 +161,10 @@ struct pcs_soc_data {
  * @bits_per_mux: number of bits per mux
  * @bits_per_pin: number of bits per pin
  * @pins:      physical pins on the SoC
- * @pgtree:    pingroup index radix tree
- * @ftree:     function index radix tree
- * @pingroups: list of pingroups
- * @functions: list of functions
  * @gpiofuncs: list of gpio functions
  * @irqs:      list of interrupt registers
  * @chip:      chip container for this instance
  * @domain:    IRQ domain for this instance
- * @ngroups:   number of pingroups
- * @nfuncs:    number of functions
  * @desc:      pin controller descriptor
  * @read:      register read function to use
  * @write:     register write function to use
@@ -213,16 +192,10 @@ struct pcs_device {
        bool bits_per_mux;
        unsigned bits_per_pin;
        struct pcs_data pins;
-       struct radix_tree_root pgtree;
-       struct radix_tree_root ftree;
-       struct list_head pingroups;
-       struct list_head functions;
        struct list_head gpiofuncs;
        struct list_head irqs;
        struct irq_chip chip;
        struct irq_domain *domain;
-       unsigned ngroups;
-       unsigned nfuncs;
        struct pinctrl_desc desc;
        unsigned (*read)(void __iomem *reg);
        void (*write)(unsigned val, void __iomem *reg);
@@ -288,54 +261,6 @@ static void __maybe_unused pcs_writel(unsigned val, void __iomem *reg)
        writel(val, reg);
 }
 
-static int pcs_get_groups_count(struct pinctrl_dev *pctldev)
-{
-       struct pcs_device *pcs;
-
-       pcs = pinctrl_dev_get_drvdata(pctldev);
-
-       return pcs->ngroups;
-}
-
-static const char *pcs_get_group_name(struct pinctrl_dev *pctldev,
-                                       unsigned gselector)
-{
-       struct pcs_device *pcs;
-       struct pcs_pingroup *group;
-
-       pcs = pinctrl_dev_get_drvdata(pctldev);
-       group = radix_tree_lookup(&pcs->pgtree, gselector);
-       if (!group) {
-               dev_err(pcs->dev, "%s could not find pingroup%i\n",
-                       __func__, gselector);
-               return NULL;
-       }
-
-       return group->name;
-}
-
-static int pcs_get_group_pins(struct pinctrl_dev *pctldev,
-                                       unsigned gselector,
-                                       const unsigned **pins,
-                                       unsigned *npins)
-{
-       struct pcs_device *pcs;
-       struct pcs_pingroup *group;
-
-       pcs = pinctrl_dev_get_drvdata(pctldev);
-       group = radix_tree_lookup(&pcs->pgtree, gselector);
-       if (!group) {
-               dev_err(pcs->dev, "%s could not find pingroup%i\n",
-                       __func__, gselector);
-               return -EINVAL;
-       }
-
-       *pins = group->gpins;
-       *npins = group->ngpins;
-
-       return 0;
-}
-
 static void pcs_pin_dbg_show(struct pinctrl_dev *pctldev,
                                        struct seq_file *s,
                                        unsigned pin)
@@ -369,67 +294,21 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev,
                                struct pinctrl_map **map, unsigned *num_maps);
 
 static const struct pinctrl_ops pcs_pinctrl_ops = {
-       .get_groups_count = pcs_get_groups_count,
-       .get_group_name = pcs_get_group_name,
-       .get_group_pins = pcs_get_group_pins,
+       .get_groups_count = pinctrl_generic_get_group_count,
+       .get_group_name = pinctrl_generic_get_group_name,
+       .get_group_pins = pinctrl_generic_get_group_pins,
        .pin_dbg_show = pcs_pin_dbg_show,
        .dt_node_to_map = pcs_dt_node_to_map,
        .dt_free_map = pcs_dt_free_map,
 };
 
-static int pcs_get_functions_count(struct pinctrl_dev *pctldev)
-{
-       struct pcs_device *pcs;
-
-       pcs = pinctrl_dev_get_drvdata(pctldev);
-
-       return pcs->nfuncs;
-}
-
-static const char *pcs_get_function_name(struct pinctrl_dev *pctldev,
-                                               unsigned fselector)
-{
-       struct pcs_device *pcs;
-       struct pcs_function *func;
-
-       pcs = pinctrl_dev_get_drvdata(pctldev);
-       func = radix_tree_lookup(&pcs->ftree, fselector);
-       if (!func) {
-               dev_err(pcs->dev, "%s could not find function%i\n",
-                       __func__, fselector);
-               return NULL;
-       }
-
-       return func->name;
-}
-
-static int pcs_get_function_groups(struct pinctrl_dev *pctldev,
-                                       unsigned fselector,
-                                       const char * const **groups,
-                                       unsigned * const ngroups)
-{
-       struct pcs_device *pcs;
-       struct pcs_function *func;
-
-       pcs = pinctrl_dev_get_drvdata(pctldev);
-       func = radix_tree_lookup(&pcs->ftree, fselector);
-       if (!func) {
-               dev_err(pcs->dev, "%s could not find function%i\n",
-                       __func__, fselector);
-               return -EINVAL;
-       }
-       *groups = func->pgnames;
-       *ngroups = func->npgnames;
-
-       return 0;
-}
-
 static int pcs_get_function(struct pinctrl_dev *pctldev, unsigned pin,
                            struct pcs_function **func)
 {
        struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
        struct pin_desc *pdesc = pin_desc_get(pctldev, pin);
        const struct pinctrl_setting_mux *setting;
+       struct function_desc *function;
        unsigned fselector;
 
        /* If pin is not described in DTS & enabled, mux_setting is NULL. */
@@ -437,7 +316,8 @@ static int pcs_get_function(struct pinctrl_dev *pctldev, unsigned pin,
        if (!setting)
                return -ENOTSUPP;
        fselector = setting->func;
-       *func = radix_tree_lookup(&pcs->ftree, fselector);
+       function = pinmux_generic_get_function(pctldev, fselector);
+       *func = function->data;
        if (!(*func)) {
                dev_err(pcs->dev, "%s could not find function%i\n",
                        __func__, fselector);
@@ -450,6 +330,7 @@ static int pcs_set_mux(struct pinctrl_dev *pctldev, unsigned fselector,
        unsigned group)
 {
        struct pcs_device *pcs;
+       struct function_desc *function;
        struct pcs_function *func;
        int i;
 
@@ -457,7 +338,8 @@ static int pcs_set_mux(struct pinctrl_dev *pctldev, unsigned fselector,
        /* If function mask is null, needn't enable it. */
        if (!pcs->fmask)
                return 0;
-       func = radix_tree_lookup(&pcs->ftree, fselector);
+       function = pinmux_generic_get_function(pctldev, fselector);
+       func = function->data;
        if (!func)
                return -EINVAL;
 
@@ -515,9 +397,9 @@ static int pcs_request_gpio(struct pinctrl_dev *pctldev,
 }
 
 static const struct pinmux_ops pcs_pinmux_ops = {
-       .get_functions_count = pcs_get_functions_count,
-       .get_function_name = pcs_get_function_name,
-       .get_function_groups = pcs_get_function_groups,
+       .get_functions_count = pinmux_generic_get_function_count,
+       .get_function_name = pinmux_generic_get_function_name,
+       .get_function_groups = pinmux_generic_get_function_groups,
        .set_mux = pcs_set_mux,
        .gpio_request_enable = pcs_request_gpio,
 };
@@ -622,7 +504,7 @@ static int pcs_pinconf_set(struct pinctrl_dev *pctldev,
        struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
        struct pcs_function *func;
        unsigned offset = 0, shift = 0, i, data, ret;
-       u16 arg;
+       u32 arg;
        int j;
 
        ret = pcs_get_function(pctldev, pin, &func);
@@ -685,7 +567,7 @@ static int pcs_pinconf_group_get(struct pinctrl_dev *pctldev,
        unsigned npins, old = 0;
        int i, ret;
 
-       ret = pcs_get_group_pins(pctldev, group, &pins, &npins);
+       ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins);
        if (ret)
                return ret;
        for (i = 0; i < npins; i++) {
@@ -707,7 +589,7 @@ static int pcs_pinconf_group_set(struct pinctrl_dev *pctldev,
        unsigned npins;
        int i, ret;
 
-       ret = pcs_get_group_pins(pctldev, group, &pins, &npins);
+       ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins);
        if (ret)
                return ret;
        for (i = 0; i < npins; i++) {
@@ -859,77 +741,24 @@ static struct pcs_function *pcs_add_function(struct pcs_device *pcs,
                                        unsigned npgnames)
 {
        struct pcs_function *function;
+       int res;
 
        function = devm_kzalloc(pcs->dev, sizeof(*function), GFP_KERNEL);
        if (!function)
                return NULL;
 
-       function->name = name;
        function->vals = vals;
        function->nvals = nvals;
-       function->pgnames = pgnames;
-       function->npgnames = npgnames;
 
-       mutex_lock(&pcs->mutex);
-       list_add_tail(&function->node, &pcs->functions);
-       radix_tree_insert(&pcs->ftree, pcs->nfuncs, function);
-       pcs->nfuncs++;
-       mutex_unlock(&pcs->mutex);
+       res = pinmux_generic_add_function(pcs->pctl, name,
+                                         pgnames, npgnames,
+                                         function);
+       if (res)
+               return NULL;
 
        return function;
 }
 
-static void pcs_remove_function(struct pcs_device *pcs,
-                               struct pcs_function *function)
-{
-       int i;
-
-       mutex_lock(&pcs->mutex);
-       for (i = 0; i < pcs->nfuncs; i++) {
-               struct pcs_function *found;
-
-               found = radix_tree_lookup(&pcs->ftree, i);
-               if (found == function)
-                       radix_tree_delete(&pcs->ftree, i);
-       }
-       list_del(&function->node);
-       mutex_unlock(&pcs->mutex);
-}
-
-/**
- * pcs_add_pingroup() - add a pingroup to the pingroup list
- * @pcs: pcs driver instance
- * @np: device node of the mux entry
- * @name: name of the pingroup
- * @gpins: array of the pins that belong to the group
- * @ngpins: number of pins in the group
- */
-static int pcs_add_pingroup(struct pcs_device *pcs,
-                                       struct device_node *np,
-                                       const char *name,
-                                       int *gpins,
-                                       int ngpins)
-{
-       struct pcs_pingroup *pingroup;
-
-       pingroup = devm_kzalloc(pcs->dev, sizeof(*pingroup), GFP_KERNEL);
-       if (!pingroup)
-               return -ENOMEM;
-
-       pingroup->name = name;
-       pingroup->np = np;
-       pingroup->gpins = gpins;
-       pingroup->ngpins = ngpins;
-
-       mutex_lock(&pcs->mutex);
-       list_add_tail(&pingroup->node, &pcs->pingroups);
-       radix_tree_insert(&pcs->pgtree, pcs->ngroups, pingroup);
-       pcs->ngroups++;
-       mutex_unlock(&pcs->mutex);
-
-       return 0;
-}
-
 /**
  * pcs_get_pin_by_offset() - get a pin index based on the register offset
  * @pcs: pcs driver instance
@@ -1100,10 +929,9 @@ static int pcs_parse_pinconf(struct pcs_device *pcs, struct device_node *np,
        return 0;
 }
 
-static void pcs_free_pingroups(struct pcs_device *pcs);
-
 /**
  * smux_parse_one_pinctrl_entry() - parses a device tree mux entry
+ * @pctldev: pin controller device
  * @pcs: pinctrl driver instance
  * @np: device node of the mux entry
  * @map: map entry
@@ -1134,7 +962,7 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
 
        rows = pinctrl_count_index_with_args(np, name);
        if (rows <= 0) {
-               dev_err(pcs->dev, "Ivalid number of rows: %d\n", rows);
+               dev_err(pcs->dev, "Invalid number of rows: %d\n", rows);
                return -EINVAL;
        }
 
@@ -1186,7 +1014,7 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
                goto free_pins;
        }
 
-       res = pcs_add_pingroup(pcs, np, np->name, pins, found);
+       res = pinctrl_generic_add_group(pcs->pctl, np->name, pins, found, pcs);
        if (res < 0)
                goto free_function;
 
@@ -1205,10 +1033,10 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
        return 0;
 
 free_pingroups:
-       pcs_free_pingroups(pcs);
+       pinctrl_generic_remove_last_group(pcs->pctl);
        *num_maps = 1;
 free_function:
-       pcs_remove_function(pcs, function);
+       pinmux_generic_remove_last_function(pcs->pctl);
 
 free_pins:
        devm_kfree(pcs->dev, pins);
@@ -1320,7 +1148,7 @@ static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs,
                goto free_pins;
        }
 
-       res = pcs_add_pingroup(pcs, np, np->name, pins, found);
+       res = pinctrl_generic_add_group(pcs->pctl, np->name, pins, found, pcs);
        if (res < 0)
                goto free_function;
 
@@ -1337,11 +1165,10 @@ static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs,
        return 0;
 
 free_pingroups:
-       pcs_free_pingroups(pcs);
+       pinctrl_generic_remove_last_group(pcs->pctl);
        *num_maps = 1;
 free_function:
-       pcs_remove_function(pcs, function);
-
+       pinmux_generic_remove_last_function(pcs->pctl);
 free_pins:
        devm_kfree(pcs->dev, pins);
 
@@ -1408,60 +1235,6 @@ free_map:
        return ret;
 }
 
-/**
- * pcs_free_funcs() - free memory used by functions
- * @pcs: pcs driver instance
- */
-static void pcs_free_funcs(struct pcs_device *pcs)
-{
-       struct list_head *pos, *tmp;
-       int i;
-
-       mutex_lock(&pcs->mutex);
-       for (i = 0; i < pcs->nfuncs; i++) {
-               struct pcs_function *func;
-
-               func = radix_tree_lookup(&pcs->ftree, i);
-               if (!func)
-                       continue;
-               radix_tree_delete(&pcs->ftree, i);
-       }
-       list_for_each_safe(pos, tmp, &pcs->functions) {
-               struct pcs_function *function;
-
-               function = list_entry(pos, struct pcs_function, node);
-               list_del(&function->node);
-       }
-       mutex_unlock(&pcs->mutex);
-}
-
-/**
- * pcs_free_pingroups() - free memory used by pingroups
- * @pcs: pcs driver instance
- */
-static void pcs_free_pingroups(struct pcs_device *pcs)
-{
-       struct list_head *pos, *tmp;
-       int i;
-
-       mutex_lock(&pcs->mutex);
-       for (i = 0; i < pcs->ngroups; i++) {
-               struct pcs_pingroup *pingroup;
-
-               pingroup = radix_tree_lookup(&pcs->pgtree, i);
-               if (!pingroup)
-                       continue;
-               radix_tree_delete(&pcs->pgtree, i);
-       }
-       list_for_each_safe(pos, tmp, &pcs->pingroups) {
-               struct pcs_pingroup *pingroup;
-
-               pingroup = list_entry(pos, struct pcs_pingroup, node);
-               list_del(&pingroup->node);
-       }
-       mutex_unlock(&pcs->mutex);
-}
-
 /**
  * pcs_irq_free() - free interrupt
  * @pcs: pcs driver instance
@@ -1490,8 +1263,7 @@ static void pcs_free_resources(struct pcs_device *pcs)
 {
        pcs_irq_free(pcs);
        pinctrl_unregister(pcs->pctl);
-       pcs_free_funcs(pcs);
-       pcs_free_pingroups(pcs);
+
 #if IS_BUILTIN(CONFIG_PINCTRL_SINGLE)
        if (pcs->missing_nr_pinctrl_cells)
                of_remove_property(pcs->np, pcs->missing_nr_pinctrl_cells);
@@ -1885,8 +1657,6 @@ static int pcs_probe(struct platform_device *pdev)
        pcs->np = np;
        raw_spin_lock_init(&pcs->lock);
        mutex_init(&pcs->mutex);
-       INIT_LIST_HEAD(&pcs->pingroups);
-       INIT_LIST_HEAD(&pcs->functions);
        INIT_LIST_HEAD(&pcs->gpiofuncs);
        soc = match->data;
        pcs->flags = soc->flags;
@@ -1947,8 +1717,6 @@ static int pcs_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       INIT_RADIX_TREE(&pcs->pgtree, GFP_KERNEL);
-       INIT_RADIX_TREE(&pcs->ftree, GFP_KERNEL);
        platform_set_drvdata(pdev, pcs);
 
        switch (pcs->width) {
@@ -1979,10 +1747,9 @@ static int pcs_probe(struct platform_device *pdev)
        if (ret < 0)
                goto free;
 
-       pcs->pctl = pinctrl_register(&pcs->desc, pcs->dev, pcs);
-       if (IS_ERR(pcs->pctl)) {
+       ret = pinctrl_register_and_init(&pcs->desc, pcs->dev, pcs, &pcs->pctl);
+       if (ret) {
                dev_err(pcs->dev, "could not register single pinctrl driver\n");
-               ret = PTR_ERR(pcs->pctl);
                goto free;
        }
 
index 29fb7403d24e1acd01eb3bb8bb9c8f40c17bf5d1..7450f511844569d32b0bda6cefa3423a1cbb5eba 100644 (file)
@@ -424,41 +424,6 @@ static int sx150x_gpio_get(struct gpio_chip *chip, unsigned int offset)
        return !!(value & BIT(offset));
 }
 
-static int sx150x_gpio_set_single_ended(struct gpio_chip *chip,
-                                       unsigned int offset,
-                                       enum single_ended_mode mode)
-{
-       struct sx150x_pinctrl *pctl = gpiochip_get_data(chip);
-       int ret;
-
-       switch (mode) {
-       case LINE_MODE_PUSH_PULL:
-               if (pctl->data->model != SX150X_789 ||
-                   sx150x_pin_is_oscio(pctl, offset))
-                       return 0;
-
-               ret = regmap_write_bits(pctl->regmap,
-                                       pctl->data->pri.x789.reg_drain,
-                                       BIT(offset), 0);
-               break;
-
-       case LINE_MODE_OPEN_DRAIN:
-               if (pctl->data->model != SX150X_789 ||
-                   sx150x_pin_is_oscio(pctl, offset))
-                       return -ENOTSUPP;
-
-               ret = regmap_write_bits(pctl->regmap,
-                                       pctl->data->pri.x789.reg_drain,
-                                       BIT(offset), BIT(offset));
-               break;
-       default:
-               ret = -ENOTSUPP;
-               break;
-       }
-
-       return ret;
-}
-
 static int __sx150x_gpio_set(struct sx150x_pinctrl *pctl, unsigned int offset,
                             int value)
 {
@@ -811,16 +776,26 @@ static int sx150x_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
                        break;
 
                case PIN_CONFIG_DRIVE_OPEN_DRAIN:
-                       ret = sx150x_gpio_set_single_ended(&pctl->gpio,
-                                               pin, LINE_MODE_OPEN_DRAIN);
+                       if (pctl->data->model != SX150X_789 ||
+                           sx150x_pin_is_oscio(pctl, pin))
+                               return -ENOTSUPP;
+
+                       ret = regmap_write_bits(pctl->regmap,
+                                               pctl->data->pri.x789.reg_drain,
+                                               BIT(pin), BIT(pin));
                        if (ret < 0)
                                return ret;
 
                        break;
 
                case PIN_CONFIG_DRIVE_PUSH_PULL:
-                       ret = sx150x_gpio_set_single_ended(&pctl->gpio,
-                                               pin, LINE_MODE_PUSH_PULL);
+                       if (pctl->data->model != SX150X_789 ||
+                           sx150x_pin_is_oscio(pctl, pin))
+                               return 0;
+
+                       ret = regmap_write_bits(pctl->regmap,
+                                               pctl->data->pri.x789.reg_drain,
+                                               BIT(pin), 0);
                        if (ret < 0)
                                return ret;
 
@@ -1178,7 +1153,7 @@ static int sx150x_probe(struct i2c_client *client,
        pctl->gpio.direction_output = sx150x_gpio_direction_output;
        pctl->gpio.get = sx150x_gpio_get;
        pctl->gpio.set = sx150x_gpio_set;
-       pctl->gpio.set_single_ended = sx150x_gpio_set_single_ended;
+       pctl->gpio.set_config = gpiochip_generic_config;
        pctl->gpio.parent = dev;
 #ifdef CONFIG_OF_GPIO
        pctl->gpio.of_node = dev->of_node;
index dd85ad1807f52f36b5ea0fa4bf1639e7f4b42622..d4167e2c173ae054d60ba7489e8db9395771e184 100644 (file)
@@ -6,7 +6,7 @@
  *  it under the terms of the GNU General Public License version 2 as
  *  publishhed by the Free Software Foundation.
  *
- *  Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ *  Copyright (C) 2012 John Crispin <john@phrozen.org>
  *  Copyright (C) 2015 Martin Schiller <mschiller@tdt.de>
  */
 
index ece702881946dd849cae2e7adf2c992697b29fdd..29ad3151abecc42e8178d249aa6d332e972345ef 100644 (file)
@@ -99,37 +99,24 @@ static int pin_request(struct pinctrl_dev *pctldev,
        dev_dbg(pctldev->dev, "request pin %d (%s) for %s\n",
                pin, desc->name, owner);
 
-       if (gpio_range) {
-               /* There's no need to support multiple GPIO requests */
-               if (desc->gpio_owner) {
-                       dev_err(pctldev->dev,
-                               "pin %s already requested by %s; cannot claim for %s\n",
-                               desc->name, desc->gpio_owner, owner);
-                       goto out;
-               }
-               if (ops->strict && desc->mux_usecount &&
-                   strcmp(desc->mux_owner, owner)) {
-                       dev_err(pctldev->dev,
-                               "pin %s already requested by %s; cannot claim for %s\n",
-                               desc->name, desc->mux_owner, owner);
-                       goto out;
-               }
+       if ((!gpio_range || ops->strict) &&
+           desc->mux_usecount && strcmp(desc->mux_owner, owner)) {
+               dev_err(pctldev->dev,
+                       "pin %s already requested by %s; cannot claim for %s\n",
+                       desc->name, desc->mux_owner, owner);
+               goto out;
+       }
 
+       if ((gpio_range || ops->strict) && desc->gpio_owner) {
+               dev_err(pctldev->dev,
+                       "pin %s already requested by %s; cannot claim for %s\n",
+                       desc->name, desc->gpio_owner, owner);
+               goto out;
+       }
+
+       if (gpio_range) {
                desc->gpio_owner = owner;
        } else {
-               if (desc->mux_usecount && strcmp(desc->mux_owner, owner)) {
-                       dev_err(pctldev->dev,
-                               "pin %s already requested by %s; cannot claim for %s\n",
-                               desc->name, desc->mux_owner, owner);
-                       goto out;
-               }
-               if (ops->strict && desc->gpio_owner) {
-                       dev_err(pctldev->dev,
-                               "pin %s already requested by %s; cannot claim for %s\n",
-                               desc->name, desc->gpio_owner, owner);
-                       goto out;
-               }
-
                desc->mux_usecount++;
                if (desc->mux_usecount > 1)
                        return 0;
@@ -695,3 +682,176 @@ void pinmux_init_device_debugfs(struct dentry *devroot,
 }
 
 #endif /* CONFIG_DEBUG_FS */
+
+#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS
+
+/**
+ * pinmux_generic_get_function_count() - returns number of functions
+ * @pctldev: pin controller device
+ */
+int pinmux_generic_get_function_count(struct pinctrl_dev *pctldev)
+{
+       return pctldev->num_functions;
+}
+EXPORT_SYMBOL_GPL(pinmux_generic_get_function_count);
+
+/**
+ * pinmux_generic_get_function_name() - returns the function name
+ * @pctldev: pin controller device
+ * @selector: function number
+ */
+const char *
+pinmux_generic_get_function_name(struct pinctrl_dev *pctldev,
+                                unsigned int selector)
+{
+       struct function_desc *function;
+
+       function = radix_tree_lookup(&pctldev->pin_function_tree,
+                                    selector);
+       if (!function)
+               return NULL;
+
+       return function->name;
+}
+EXPORT_SYMBOL_GPL(pinmux_generic_get_function_name);
+
+/**
+ * pinmux_generic_get_function_groups() - gets the function groups
+ * @pctldev: pin controller device
+ * @selector: function number
+ * @groups: array of pin groups
+ * @num_groups: number of pin groups
+ */
+int pinmux_generic_get_function_groups(struct pinctrl_dev *pctldev,
+                                      unsigned int selector,
+                                      const char * const **groups,
+                                      unsigned * const num_groups)
+{
+       struct function_desc *function;
+
+       function = radix_tree_lookup(&pctldev->pin_function_tree,
+                                    selector);
+       if (!function) {
+               dev_err(pctldev->dev, "%s could not find function%i\n",
+                       __func__, selector);
+               return -EINVAL;
+       }
+       *groups = function->group_names;
+       *num_groups = function->num_group_names;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pinmux_generic_get_function_groups);
+
+/**
+ * pinmux_generic_get_function() - returns a function based on the number
+ * @pctldev: pin controller device
+ * @group_selector: function number
+ */
+struct function_desc *pinmux_generic_get_function(struct pinctrl_dev *pctldev,
+                                                 unsigned int selector)
+{
+       struct function_desc *function;
+
+       function = radix_tree_lookup(&pctldev->pin_function_tree,
+                                    selector);
+       if (!function)
+               return NULL;
+
+       return function;
+}
+EXPORT_SYMBOL_GPL(pinmux_generic_get_function);
+
+/**
+ * pinmux_generic_get_function_groups() - gets the function groups
+ * @pctldev: pin controller device
+ * @name: name of the function
+ * @groups: array of pin groups
+ * @num_groups: number of pin groups
+ * @data: pin controller driver specific data
+ */
+int pinmux_generic_add_function(struct pinctrl_dev *pctldev,
+                               const char *name,
+                               const char **groups,
+                               const unsigned int num_groups,
+                               void *data)
+{
+       struct function_desc *function;
+
+       function = devm_kzalloc(pctldev->dev, sizeof(*function), GFP_KERNEL);
+       if (!function)
+               return -ENOMEM;
+
+       function->name = name;
+       function->group_names = groups;
+       function->num_group_names = num_groups;
+       function->data = data;
+
+       radix_tree_insert(&pctldev->pin_function_tree, pctldev->num_functions,
+                         function);
+
+       pctldev->num_functions++;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pinmux_generic_add_function);
+
+/**
+ * pinmux_generic_remove_function() - removes a numbered function
+ * @pctldev: pin controller device
+ * @selector: function number
+ *
+ * Note that the caller must take care of locking.
+ */
+int pinmux_generic_remove_function(struct pinctrl_dev *pctldev,
+                                  unsigned int selector)
+{
+       struct function_desc *function;
+
+       function = radix_tree_lookup(&pctldev->pin_function_tree,
+                                    selector);
+       if (!function)
+               return -ENOENT;
+
+       radix_tree_delete(&pctldev->pin_function_tree, selector);
+       devm_kfree(pctldev->dev, function);
+
+       pctldev->num_functions--;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pinmux_generic_remove_function);
+
+/**
+ * pinmux_generic_free_functions() - removes all functions
+ * @pctldev: pin controller device
+ *
+ * Note that the caller must take care of locking.
+ */
+void pinmux_generic_free_functions(struct pinctrl_dev *pctldev)
+{
+       struct radix_tree_iter iter;
+       struct function_desc *function;
+       unsigned long *indices;
+       void **slot;
+       int i = 0;
+
+       indices = devm_kzalloc(pctldev->dev, sizeof(*indices) *
+                              pctldev->num_functions, GFP_KERNEL);
+       if (!indices)
+               return;
+
+       radix_tree_for_each_slot(slot, &pctldev->pin_function_tree, &iter, 0)
+               indices[i++] = iter.index;
+
+       for (i = 0; i < pctldev->num_functions; i++) {
+               function = radix_tree_lookup(&pctldev->pin_function_tree,
+                                            indices[i]);
+               radix_tree_delete(&pctldev->pin_function_tree, indices[i]);
+               devm_kfree(pctldev->dev, function);
+       }
+
+       pctldev->num_functions = 0;
+}
+
+#endif /* CONFIG_GENERIC_PINMUX_FUNCTIONS */
index d1a98b1c9fcea6541b90683c377f76107539302f..248d8ea30e260b4212d08535104a6043371de858 100644 (file)
@@ -111,3 +111,59 @@ static inline void pinmux_init_device_debugfs(struct dentry *devroot,
 }
 
 #endif
+
+#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS
+
+/**
+ * struct function_desc - generic function descriptor
+ * @name: name of the function
+ * @group_names: array of pin group names
+ * @num_group_names: number of pin group names
+ * @data: pin controller driver specific data
+ */
+struct function_desc {
+       const char *name;
+       const char **group_names;
+       int num_group_names;
+       void *data;
+};
+
+int pinmux_generic_get_function_count(struct pinctrl_dev *pctldev);
+
+const char *
+pinmux_generic_get_function_name(struct pinctrl_dev *pctldev,
+                                unsigned int selector);
+
+int pinmux_generic_get_function_groups(struct pinctrl_dev *pctldev,
+                                      unsigned int selector,
+                                      const char * const **groups,
+                                      unsigned * const num_groups);
+
+struct function_desc *pinmux_generic_get_function(struct pinctrl_dev *pctldev,
+                                                 unsigned int selector);
+
+int pinmux_generic_add_function(struct pinctrl_dev *pctldev,
+                               const char *name,
+                               const char **groups,
+                               unsigned const num_groups,
+                               void *data);
+
+int pinmux_generic_remove_function(struct pinctrl_dev *pctldev,
+                                  unsigned int selector);
+
+static inline int
+pinmux_generic_remove_last_function(struct pinctrl_dev *pctldev)
+{
+       return pinmux_generic_remove_function(pctldev,
+                                             pctldev->num_functions - 1);
+}
+
+void pinmux_generic_free_functions(struct pinctrl_dev *pctldev);
+
+#else
+
+static inline void pinmux_generic_free_functions(struct pinctrl_dev *pctldev)
+{
+}
+
+#endif /* CONFIG_GENERIC_PINMUX_FUNCTIONS */
index 775c883030175320553bf087b64a545f634f86fe..f8e9e1c2b2f6f45078aa2fe9a3356b450d60fd58 100644 (file)
@@ -61,7 +61,7 @@ struct msm_pinctrl {
        struct notifier_block restart_nb;
        int irq;
 
-       spinlock_t lock;
+       raw_spinlock_t lock;
 
        DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO);
        DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO);
@@ -153,14 +153,14 @@ static int msm_pinmux_set_mux(struct pinctrl_dev *pctldev,
        if (WARN_ON(i == g->nfuncs))
                return -EINVAL;
 
-       spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
 
        val = readl(pctrl->regs + g->ctl_reg);
        val &= ~mask;
        val |= i << g->mux_bit;
        writel(val, pctrl->regs + g->ctl_reg);
 
-       spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 
        return 0;
 }
@@ -323,14 +323,14 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev,
                        break;
                case PIN_CONFIG_OUTPUT:
                        /* set output value */
-                       spin_lock_irqsave(&pctrl->lock, flags);
+                       raw_spin_lock_irqsave(&pctrl->lock, flags);
                        val = readl(pctrl->regs + g->io_reg);
                        if (arg)
                                val |= BIT(g->out_bit);
                        else
                                val &= ~BIT(g->out_bit);
                        writel(val, pctrl->regs + g->io_reg);
-                       spin_unlock_irqrestore(&pctrl->lock, flags);
+                       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 
                        /* enable output */
                        arg = 1;
@@ -351,12 +351,12 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev,
                        return -EINVAL;
                }
 
-               spin_lock_irqsave(&pctrl->lock, flags);
+               raw_spin_lock_irqsave(&pctrl->lock, flags);
                val = readl(pctrl->regs + g->ctl_reg);
                val &= ~(mask << bit);
                val |= arg << bit;
                writel(val, pctrl->regs + g->ctl_reg);
-               spin_unlock_irqrestore(&pctrl->lock, flags);
+               raw_spin_unlock_irqrestore(&pctrl->lock, flags);
        }
 
        return 0;
@@ -384,13 +384,13 @@ static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 
        g = &pctrl->soc->groups[offset];
 
-       spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
 
        val = readl(pctrl->regs + g->ctl_reg);
        val &= ~BIT(g->oe_bit);
        writel(val, pctrl->regs + g->ctl_reg);
 
-       spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 
        return 0;
 }
@@ -404,7 +404,7 @@ static int msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, in
 
        g = &pctrl->soc->groups[offset];
 
-       spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
 
        val = readl(pctrl->regs + g->io_reg);
        if (value)
@@ -417,7 +417,7 @@ static int msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, in
        val |= BIT(g->oe_bit);
        writel(val, pctrl->regs + g->ctl_reg);
 
-       spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 
        return 0;
 }
@@ -443,7 +443,7 @@ static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 
        g = &pctrl->soc->groups[offset];
 
-       spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
 
        val = readl(pctrl->regs + g->io_reg);
        if (value)
@@ -452,7 +452,7 @@ static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
                val &= ~BIT(g->out_bit);
        writel(val, pctrl->regs + g->io_reg);
 
-       spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 }
 
 #ifdef CONFIG_DEBUG_FS
@@ -571,7 +571,7 @@ static void msm_gpio_irq_mask(struct irq_data *d)
 
        g = &pctrl->soc->groups[d->hwirq];
 
-       spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
 
        val = readl(pctrl->regs + g->intr_cfg_reg);
        val &= ~BIT(g->intr_enable_bit);
@@ -579,7 +579,7 @@ static void msm_gpio_irq_mask(struct irq_data *d)
 
        clear_bit(d->hwirq, pctrl->enabled_irqs);
 
-       spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 }
 
 static void msm_gpio_irq_unmask(struct irq_data *d)
@@ -592,7 +592,7 @@ static void msm_gpio_irq_unmask(struct irq_data *d)
 
        g = &pctrl->soc->groups[d->hwirq];
 
-       spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
 
        val = readl(pctrl->regs + g->intr_status_reg);
        val &= ~BIT(g->intr_status_bit);
@@ -604,7 +604,7 @@ static void msm_gpio_irq_unmask(struct irq_data *d)
 
        set_bit(d->hwirq, pctrl->enabled_irqs);
 
-       spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 }
 
 static void msm_gpio_irq_ack(struct irq_data *d)
@@ -617,7 +617,7 @@ static void msm_gpio_irq_ack(struct irq_data *d)
 
        g = &pctrl->soc->groups[d->hwirq];
 
-       spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
 
        val = readl(pctrl->regs + g->intr_status_reg);
        if (g->intr_ack_high)
@@ -629,7 +629,7 @@ static void msm_gpio_irq_ack(struct irq_data *d)
        if (test_bit(d->hwirq, pctrl->dual_edge_irqs))
                msm_gpio_update_dual_edge_pos(pctrl, g, d);
 
-       spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 }
 
 static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)
@@ -642,7 +642,7 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)
 
        g = &pctrl->soc->groups[d->hwirq];
 
-       spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
 
        /*
         * For hw without possibility of detecting both edges
@@ -716,7 +716,7 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)
        if (test_bit(d->hwirq, pctrl->dual_edge_irqs))
                msm_gpio_update_dual_edge_pos(pctrl, g, d);
 
-       spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 
        if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
                irq_set_handler_locked(d, handle_level_irq);
@@ -732,11 +732,11 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
        struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
        unsigned long flags;
 
-       spin_lock_irqsave(&pctrl->lock, flags);
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
 
        irq_set_irq_wake(pctrl->irq, on);
 
-       spin_unlock_irqrestore(&pctrl->lock, flags);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
 
        return 0;
 }
@@ -882,7 +882,7 @@ int msm_pinctrl_probe(struct platform_device *pdev,
        pctrl->soc = soc_data;
        pctrl->chip = msm_gpio_template;
 
-       spin_lock_init(&pctrl->lock);
+       raw_spin_lock_init(&pctrl->lock);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        pctrl->regs = devm_ioremap_resource(&pdev->dev, res);
index 5591d093bf7804560b79631ab716b29fd46ac33e..bb71dd1e62796bb54f22ea44840766b7f6f040b6 100644 (file)
@@ -193,9 +193,9 @@ static const struct pinctrl_pin_desc msm8660_pins[] = {
        PINCTRL_PIN(171, "GPIO_171"),
        PINCTRL_PIN(172, "GPIO_172"),
 
-       PINCTRL_PIN(173, "SDC1_CLK"),
-       PINCTRL_PIN(174, "SDC1_CMD"),
-       PINCTRL_PIN(175, "SDC1_DATA"),
+       PINCTRL_PIN(173, "SDC4_CLK"),
+       PINCTRL_PIN(174, "SDC4_CMD"),
+       PINCTRL_PIN(175, "SDC4_DATA"),
        PINCTRL_PIN(176, "SDC3_CLK"),
        PINCTRL_PIN(177, "SDC3_CMD"),
        PINCTRL_PIN(178, "SDC3_DATA"),
index 07409fde02b23f85005c0403ba146fce50cde970..f9b49967f512b52cec5447ae0baee9e146745d1b 100644 (file)
 #include <linux/irqdomain.h>
 #include <linux/irq.h>
 #include <linux/irqchip/chained_irq.h>
+#include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/regmap.h>
 #include <linux/err.h>
+#include <linux/soc/samsung/exynos-pmu.h>
+#include <linux/soc/samsung/exynos-regs-pmu.h>
 
 #include "pinctrl-samsung.h"
 #include "pinctrl-exynos.h"
@@ -528,10 +532,8 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d)
 
                weint_data = devm_kzalloc(dev, bank->nr_pins
                                        * sizeof(*weint_data), GFP_KERNEL);
-               if (!weint_data) {
-                       dev_err(dev, "could not allocate memory for weint_data\n");
+               if (!weint_data)
                        return -ENOMEM;
-               }
 
                for (idx = 0; idx < bank->nr_pins; ++idx) {
                        irq = irq_of_parse_and_map(bank->of_node, idx);
@@ -559,10 +561,8 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d)
 
        muxed_data = devm_kzalloc(dev, sizeof(*muxed_data)
                + muxed_banks*sizeof(struct samsung_pin_bank *), GFP_KERNEL);
-       if (!muxed_data) {
-               dev_err(dev, "could not allocate memory for muxed_data\n");
+       if (!muxed_data)
                return -ENOMEM;
-       }
 
        irq_set_chained_handler_and_data(irq, exynos_irq_demux_eint16_31,
                                         muxed_data);
@@ -644,6 +644,60 @@ static void exynos_pinctrl_resume(struct samsung_pinctrl_drv_data *drvdata)
                        exynos_pinctrl_resume_bank(drvdata, bank);
 }
 
+/* Retention control for S5PV210 are located at the end of clock controller */
+#define S5P_OTHERS 0xE000
+
+#define S5P_OTHERS_RET_IO              (1 << 31)
+#define S5P_OTHERS_RET_CF              (1 << 30)
+#define S5P_OTHERS_RET_MMC             (1 << 29)
+#define S5P_OTHERS_RET_UART            (1 << 28)
+
+static void s5pv210_retention_disable(struct samsung_pinctrl_drv_data *drvdata)
+{
+       void *clk_base = drvdata->retention_ctrl->priv;
+       u32 tmp;
+
+       tmp = __raw_readl(clk_base + S5P_OTHERS);
+       tmp |= (S5P_OTHERS_RET_IO | S5P_OTHERS_RET_CF | S5P_OTHERS_RET_MMC |
+               S5P_OTHERS_RET_UART);
+       __raw_writel(tmp, clk_base + S5P_OTHERS);
+}
+
+static struct samsung_retention_ctrl *
+s5pv210_retention_init(struct samsung_pinctrl_drv_data *drvdata,
+                      const struct samsung_retention_data *data)
+{
+       struct samsung_retention_ctrl *ctrl;
+       struct device_node *np;
+       void *clk_base;
+
+       ctrl = devm_kzalloc(drvdata->dev, sizeof(*ctrl), GFP_KERNEL);
+       if (!ctrl)
+               return ERR_PTR(-ENOMEM);
+
+       np = of_find_compatible_node(NULL, NULL, "samsung,s5pv210-clock");
+       if (!np) {
+               pr_err("%s: failed to find clock controller DT node\n",
+                       __func__);
+               return ERR_PTR(-ENODEV);
+       }
+
+       clk_base = of_iomap(np, 0);
+       if (!clk_base) {
+               pr_err("%s: failed to map clock registers\n", __func__);
+               return ERR_PTR(-EINVAL);
+       }
+
+       ctrl->priv = clk_base;
+       ctrl->disable = s5pv210_retention_disable;
+
+       return ctrl;
+}
+
+static const struct samsung_retention_data s5pv210_retention_data __initconst = {
+       .init    = s5pv210_retention_init,
+};
+
 /* pin banks of s5pv210 pin-controller */
 static const struct samsung_pin_bank_data s5pv210_pin_bank[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
@@ -691,9 +745,58 @@ const struct samsung_pin_ctrl s5pv210_pin_ctrl[] __initconst = {
                .eint_wkup_init = exynos_eint_wkup_init,
                .suspend        = exynos_pinctrl_suspend,
                .resume         = exynos_pinctrl_resume,
+               .retention_data = &s5pv210_retention_data,
        },
 };
 
+/* Pad retention control code for accessing PMU regmap */
+static atomic_t exynos_shared_retention_refcnt;
+
+static void exynos_retention_enable(struct samsung_pinctrl_drv_data *drvdata)
+{
+       if (drvdata->retention_ctrl->refcnt)
+               atomic_inc(drvdata->retention_ctrl->refcnt);
+}
+
+static void exynos_retention_disable(struct samsung_pinctrl_drv_data *drvdata)
+{
+       struct samsung_retention_ctrl *ctrl = drvdata->retention_ctrl;
+       struct regmap *pmu_regs = ctrl->priv;
+       int i;
+
+       if (ctrl->refcnt && !atomic_dec_and_test(ctrl->refcnt))
+               return;
+
+       for (i = 0; i < ctrl->nr_regs; i++)
+               regmap_write(pmu_regs, ctrl->regs[i], ctrl->value);
+}
+
+static struct samsung_retention_ctrl *
+exynos_retention_init(struct samsung_pinctrl_drv_data *drvdata,
+                     const struct samsung_retention_data *data)
+{
+       struct samsung_retention_ctrl *ctrl;
+       struct regmap *pmu_regs;
+
+       ctrl = devm_kzalloc(drvdata->dev, sizeof(*ctrl), GFP_KERNEL);
+       if (!ctrl)
+               return ERR_PTR(-ENOMEM);
+
+       pmu_regs = exynos_get_pmu_regmap();
+       if (IS_ERR(pmu_regs))
+               return ERR_CAST(pmu_regs);
+
+       ctrl->priv = pmu_regs;
+       ctrl->regs = data->regs;
+       ctrl->nr_regs = data->nr_regs;
+       ctrl->value = data->value;
+       ctrl->refcnt = data->refcnt;
+       ctrl->enable = exynos_retention_enable;
+       ctrl->disable = exynos_retention_disable;
+
+       return ctrl;
+}
+
 /* pin banks of exynos3250 pin-controller 0 */
 static const struct samsung_pin_bank_data exynos3250_pin_banks0[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
@@ -725,6 +828,30 @@ static const struct samsung_pin_bank_data exynos3250_pin_banks1[] __initconst =
        EXYNOS_PIN_BANK_EINTW(8, 0xc60, "gpx3", 0x0c),
 };
 
+/*
+ * PMU pad retention groups for Exynos3250 doesn't match pin banks, so handle
+ * them all together
+ */
+static const u32 exynos3250_retention_regs[] = {
+       S5P_PAD_RET_MAUDIO_OPTION,
+       S5P_PAD_RET_GPIO_OPTION,
+       S5P_PAD_RET_UART_OPTION,
+       S5P_PAD_RET_MMCA_OPTION,
+       S5P_PAD_RET_MMCB_OPTION,
+       S5P_PAD_RET_EBIA_OPTION,
+       S5P_PAD_RET_EBIB_OPTION,
+       S5P_PAD_RET_MMC2_OPTION,
+       S5P_PAD_RET_SPI_OPTION,
+};
+
+static const struct samsung_retention_data exynos3250_retention_data __initconst = {
+       .regs    = exynos3250_retention_regs,
+       .nr_regs = ARRAY_SIZE(exynos3250_retention_regs),
+       .value   = EXYNOS_WAKEUP_FROM_LOWPWR,
+       .refcnt  = &exynos_shared_retention_refcnt,
+       .init    = exynos_retention_init,
+};
+
 /*
  * Samsung pinctrl driver data for Exynos3250 SoC. Exynos3250 SoC includes
  * two gpio/pin-mux/pinconfig controllers.
@@ -737,6 +864,7 @@ const struct samsung_pin_ctrl exynos3250_pin_ctrl[] __initconst = {
                .eint_gpio_init = exynos_eint_gpio_init,
                .suspend        = exynos_pinctrl_suspend,
                .resume         = exynos_pinctrl_resume,
+               .retention_data = &exynos3250_retention_data,
        }, {
                /* pin-controller instance 1 data */
                .pin_banks      = exynos3250_pin_banks1,
@@ -745,6 +873,7 @@ const struct samsung_pin_ctrl exynos3250_pin_ctrl[] __initconst = {
                .eint_wkup_init = exynos_eint_wkup_init,
                .suspend        = exynos_pinctrl_suspend,
                .resume         = exynos_pinctrl_resume,
+               .retention_data = &exynos3250_retention_data,
        },
 };
 
@@ -797,6 +926,36 @@ static const struct samsung_pin_bank_data exynos4210_pin_banks2[] __initconst =
        EXYNOS_PIN_BANK_EINTN(7, 0x000, "gpz"),
 };
 
+/* PMU pad retention groups registers for Exynos4 (without audio) */
+static const u32 exynos4_retention_regs[] = {
+       S5P_PAD_RET_GPIO_OPTION,
+       S5P_PAD_RET_UART_OPTION,
+       S5P_PAD_RET_MMCA_OPTION,
+       S5P_PAD_RET_MMCB_OPTION,
+       S5P_PAD_RET_EBIA_OPTION,
+       S5P_PAD_RET_EBIB_OPTION,
+};
+
+static const struct samsung_retention_data exynos4_retention_data __initconst = {
+       .regs    = exynos4_retention_regs,
+       .nr_regs = ARRAY_SIZE(exynos4_retention_regs),
+       .value   = EXYNOS_WAKEUP_FROM_LOWPWR,
+       .refcnt  = &exynos_shared_retention_refcnt,
+       .init    = exynos_retention_init,
+};
+
+/* PMU retention control for audio pins can be tied to audio pin bank */
+static const u32 exynos4_audio_retention_regs[] = {
+       S5P_PAD_RET_MAUDIO_OPTION,
+};
+
+static const struct samsung_retention_data exynos4_audio_retention_data __initconst = {
+       .regs    = exynos4_audio_retention_regs,
+       .nr_regs = ARRAY_SIZE(exynos4_audio_retention_regs),
+       .value   = EXYNOS_WAKEUP_FROM_LOWPWR,
+       .init    = exynos_retention_init,
+};
+
 /*
  * Samsung pinctrl driver data for Exynos4210 SoC. Exynos4210 SoC includes
  * three gpio/pin-mux/pinconfig controllers.
@@ -809,6 +968,7 @@ const struct samsung_pin_ctrl exynos4210_pin_ctrl[] __initconst = {
                .eint_gpio_init = exynos_eint_gpio_init,
                .suspend        = exynos_pinctrl_suspend,
                .resume         = exynos_pinctrl_resume,
+               .retention_data = &exynos4_retention_data,
        }, {
                /* pin-controller instance 1 data */
                .pin_banks      = exynos4210_pin_banks1,
@@ -817,10 +977,12 @@ const struct samsung_pin_ctrl exynos4210_pin_ctrl[] __initconst = {
                .eint_wkup_init = exynos_eint_wkup_init,
                .suspend        = exynos_pinctrl_suspend,
                .resume         = exynos_pinctrl_resume,
+               .retention_data = &exynos4_retention_data,
        }, {
                /* pin-controller instance 2 data */
                .pin_banks      = exynos4210_pin_banks2,
                .nr_banks       = ARRAY_SIZE(exynos4210_pin_banks2),
+               .retention_data = &exynos4_audio_retention_data,
        },
 };
 
@@ -894,6 +1056,7 @@ const struct samsung_pin_ctrl exynos4x12_pin_ctrl[] __initconst = {
                .eint_gpio_init = exynos_eint_gpio_init,
                .suspend        = exynos_pinctrl_suspend,
                .resume         = exynos_pinctrl_resume,
+               .retention_data = &exynos4_retention_data,
        }, {
                /* pin-controller instance 1 data */
                .pin_banks      = exynos4x12_pin_banks1,
@@ -902,6 +1065,7 @@ const struct samsung_pin_ctrl exynos4x12_pin_ctrl[] __initconst = {
                .eint_wkup_init = exynos_eint_wkup_init,
                .suspend        = exynos_pinctrl_suspend,
                .resume         = exynos_pinctrl_resume,
+               .retention_data = &exynos4_retention_data,
        }, {
                /* pin-controller instance 2 data */
                .pin_banks      = exynos4x12_pin_banks2,
@@ -909,6 +1073,7 @@ const struct samsung_pin_ctrl exynos4x12_pin_ctrl[] __initconst = {
                .eint_gpio_init = exynos_eint_gpio_init,
                .suspend        = exynos_pinctrl_suspend,
                .resume         = exynos_pinctrl_resume,
+               .retention_data = &exynos4_audio_retention_data,
        }, {
                /* pin-controller instance 3 data */
                .pin_banks      = exynos4x12_pin_banks3,
@@ -919,81 +1084,6 @@ const struct samsung_pin_ctrl exynos4x12_pin_ctrl[] __initconst = {
        },
 };
 
-/* pin banks of exynos4415 pin-controller 0 */
-static const struct samsung_pin_bank_data exynos4415_pin_banks0[] = {
-       EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
-       EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04),
-       EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb", 0x08),
-       EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpc0", 0x0c),
-       EXYNOS_PIN_BANK_EINTG(5, 0x080, "gpc1", 0x10),
-       EXYNOS_PIN_BANK_EINTG(4, 0x0A0, "gpd0", 0x14),
-       EXYNOS_PIN_BANK_EINTG(4, 0x0C0, "gpd1", 0x18),
-       EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpf0", 0x30),
-       EXYNOS_PIN_BANK_EINTG(8, 0x1A0, "gpf1", 0x34),
-       EXYNOS_PIN_BANK_EINTG(1, 0x1C0, "gpf2", 0x38),
-};
-
-/* pin banks of exynos4415 pin-controller 1 */
-static const struct samsung_pin_bank_data exynos4415_pin_banks1[] = {
-       EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpk0", 0x08),
-       EXYNOS_PIN_BANK_EINTG(7, 0x060, "gpk1", 0x0c),
-       EXYNOS_PIN_BANK_EINTG(7, 0x080, "gpk2", 0x10),
-       EXYNOS_PIN_BANK_EINTG(7, 0x0A0, "gpk3", 0x14),
-       EXYNOS_PIN_BANK_EINTG(4, 0x0C0, "gpl0", 0x18),
-       EXYNOS_PIN_BANK_EINTN(6, 0x120, "mp00"),
-       EXYNOS_PIN_BANK_EINTN(4, 0x140, "mp01"),
-       EXYNOS_PIN_BANK_EINTN(6, 0x160, "mp02"),
-       EXYNOS_PIN_BANK_EINTN(8, 0x180, "mp03"),
-       EXYNOS_PIN_BANK_EINTN(8, 0x1A0, "mp04"),
-       EXYNOS_PIN_BANK_EINTN(8, 0x1C0, "mp05"),
-       EXYNOS_PIN_BANK_EINTN(8, 0x1E0, "mp06"),
-       EXYNOS_PIN_BANK_EINTG(8, 0x260, "gpm0", 0x24),
-       EXYNOS_PIN_BANK_EINTG(7, 0x280, "gpm1", 0x28),
-       EXYNOS_PIN_BANK_EINTG(5, 0x2A0, "gpm2", 0x2c),
-       EXYNOS_PIN_BANK_EINTG(8, 0x2C0, "gpm3", 0x30),
-       EXYNOS_PIN_BANK_EINTG(8, 0x2E0, "gpm4", 0x34),
-       EXYNOS_PIN_BANK_EINTW(8, 0xC00, "gpx0", 0x00),
-       EXYNOS_PIN_BANK_EINTW(8, 0xC20, "gpx1", 0x04),
-       EXYNOS_PIN_BANK_EINTW(8, 0xC40, "gpx2", 0x08),
-       EXYNOS_PIN_BANK_EINTW(8, 0xC60, "gpx3", 0x0c),
-};
-
-/* pin banks of exynos4415 pin-controller 2 */
-static const struct samsung_pin_bank_data exynos4415_pin_banks2[] = {
-       EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00),
-       EXYNOS_PIN_BANK_EINTN(2, 0x000, "etc1"),
-};
-
-/*
- * Samsung pinctrl driver data for Exynos4415 SoC. Exynos4415 SoC includes
- * three gpio/pin-mux/pinconfig controllers.
- */
-const struct samsung_pin_ctrl exynos4415_pin_ctrl[] = {
-       {
-               /* pin-controller instance 0 data */
-               .pin_banks      = exynos4415_pin_banks0,
-               .nr_banks       = ARRAY_SIZE(exynos4415_pin_banks0),
-               .eint_gpio_init = exynos_eint_gpio_init,
-               .suspend        = exynos_pinctrl_suspend,
-               .resume         = exynos_pinctrl_resume,
-       }, {
-               /* pin-controller instance 1 data */
-               .pin_banks      = exynos4415_pin_banks1,
-               .nr_banks       = ARRAY_SIZE(exynos4415_pin_banks1),
-               .eint_gpio_init = exynos_eint_gpio_init,
-               .eint_wkup_init = exynos_eint_wkup_init,
-               .suspend        = exynos_pinctrl_suspend,
-               .resume         = exynos_pinctrl_resume,
-       }, {
-               /* pin-controller instance 2 data */
-               .pin_banks      = exynos4415_pin_banks2,
-               .nr_banks       = ARRAY_SIZE(exynos4415_pin_banks2),
-               .eint_gpio_init = exynos_eint_gpio_init,
-               .suspend        = exynos_pinctrl_suspend,
-               .resume         = exynos_pinctrl_resume,
-       },
-};
-
 /* pin banks of exynos5250 pin-controller 0 */
 static const struct samsung_pin_bank_data exynos5250_pin_banks0[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
@@ -1063,6 +1153,7 @@ const struct samsung_pin_ctrl exynos5250_pin_ctrl[] __initconst = {
                .eint_wkup_init = exynos_eint_wkup_init,
                .suspend        = exynos_pinctrl_suspend,
                .resume         = exynos_pinctrl_resume,
+               .retention_data = &exynos4_retention_data,
        }, {
                /* pin-controller instance 1 data */
                .pin_banks      = exynos5250_pin_banks1,
@@ -1070,6 +1161,7 @@ const struct samsung_pin_ctrl exynos5250_pin_ctrl[] __initconst = {
                .eint_gpio_init = exynos_eint_gpio_init,
                .suspend        = exynos_pinctrl_suspend,
                .resume         = exynos_pinctrl_resume,
+               .retention_data = &exynos4_retention_data,
        }, {
                /* pin-controller instance 2 data */
                .pin_banks      = exynos5250_pin_banks2,
@@ -1084,6 +1176,7 @@ const struct samsung_pin_ctrl exynos5250_pin_ctrl[] __initconst = {
                .eint_gpio_init = exynos_eint_gpio_init,
                .suspend        = exynos_pinctrl_suspend,
                .resume         = exynos_pinctrl_resume,
+               .retention_data = &exynos4_audio_retention_data,
        },
 };
 
@@ -1310,6 +1403,30 @@ static const struct samsung_pin_bank_data exynos5420_pin_banks4[] __initconst =
        EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00),
 };
 
+/* PMU pad retention groups registers for Exynos5420 (without audio) */
+static const u32 exynos5420_retention_regs[] = {
+       EXYNOS_PAD_RET_DRAM_OPTION,
+       EXYNOS_PAD_RET_JTAG_OPTION,
+       EXYNOS5420_PAD_RET_GPIO_OPTION,
+       EXYNOS5420_PAD_RET_UART_OPTION,
+       EXYNOS5420_PAD_RET_MMCA_OPTION,
+       EXYNOS5420_PAD_RET_MMCB_OPTION,
+       EXYNOS5420_PAD_RET_MMCC_OPTION,
+       EXYNOS5420_PAD_RET_HSI_OPTION,
+       EXYNOS_PAD_RET_EBIA_OPTION,
+       EXYNOS_PAD_RET_EBIB_OPTION,
+       EXYNOS5420_PAD_RET_SPI_OPTION,
+       EXYNOS5420_PAD_RET_DRAM_COREBLK_OPTION,
+};
+
+static const struct samsung_retention_data exynos5420_retention_data __initconst = {
+       .regs    = exynos5420_retention_regs,
+       .nr_regs = ARRAY_SIZE(exynos5420_retention_regs),
+       .value   = EXYNOS_WAKEUP_FROM_LOWPWR,
+       .refcnt  = &exynos_shared_retention_refcnt,
+       .init    = exynos_retention_init,
+};
+
 /*
  * Samsung pinctrl driver data for Exynos5420 SoC. Exynos5420 SoC includes
  * four gpio/pin-mux/pinconfig controllers.
@@ -1321,114 +1438,119 @@ const struct samsung_pin_ctrl exynos5420_pin_ctrl[] __initconst = {
                .nr_banks       = ARRAY_SIZE(exynos5420_pin_banks0),
                .eint_gpio_init = exynos_eint_gpio_init,
                .eint_wkup_init = exynos_eint_wkup_init,
+               .retention_data = &exynos5420_retention_data,
        }, {
                /* pin-controller instance 1 data */
                .pin_banks      = exynos5420_pin_banks1,
                .nr_banks       = ARRAY_SIZE(exynos5420_pin_banks1),
                .eint_gpio_init = exynos_eint_gpio_init,
+               .retention_data = &exynos5420_retention_data,
        }, {
                /* pin-controller instance 2 data */
                .pin_banks      = exynos5420_pin_banks2,
                .nr_banks       = ARRAY_SIZE(exynos5420_pin_banks2),
                .eint_gpio_init = exynos_eint_gpio_init,
+               .retention_data = &exynos5420_retention_data,
        }, {
                /* pin-controller instance 3 data */
                .pin_banks      = exynos5420_pin_banks3,
                .nr_banks       = ARRAY_SIZE(exynos5420_pin_banks3),
                .eint_gpio_init = exynos_eint_gpio_init,
+               .retention_data = &exynos5420_retention_data,
        }, {
                /* pin-controller instance 4 data */
                .pin_banks      = exynos5420_pin_banks4,
                .nr_banks       = ARRAY_SIZE(exynos5420_pin_banks4),
                .eint_gpio_init = exynos_eint_gpio_init,
+               .retention_data = &exynos4_audio_retention_data,
        },
 };
 
 /* pin banks of exynos5433 pin-controller - ALIVE */
-static const struct samsung_pin_bank_data exynos5433_pin_banks0[] = {
-       EXYNOS5433_PIN_BANK_EINTW(8, 0x000, "gpa0", 0x00),
-       EXYNOS5433_PIN_BANK_EINTW(8, 0x020, "gpa1", 0x04),
-       EXYNOS5433_PIN_BANK_EINTW(8, 0x040, "gpa2", 0x08),
-       EXYNOS5433_PIN_BANK_EINTW(8, 0x060, "gpa3", 0x0c),
-       EXYNOS5433_PIN_BANK_EINTW_EXT(8, 0x020, "gpf1", 0x1004, 1),
-       EXYNOS5433_PIN_BANK_EINTW_EXT(4, 0x040, "gpf2", 0x1008, 1),
-       EXYNOS5433_PIN_BANK_EINTW_EXT(4, 0x060, "gpf3", 0x100c, 1),
-       EXYNOS5433_PIN_BANK_EINTW_EXT(8, 0x080, "gpf4", 0x1010, 1),
-       EXYNOS5433_PIN_BANK_EINTW_EXT(8, 0x0a0, "gpf5", 0x1014, 1),
+static const struct samsung_pin_bank_data exynos5433_pin_banks0[] __initconst = {
+       EXYNOS_PIN_BANK_EINTW(8, 0x000, "gpa0", 0x00),
+       EXYNOS_PIN_BANK_EINTW(8, 0x020, "gpa1", 0x04),
+       EXYNOS_PIN_BANK_EINTW(8, 0x040, "gpa2", 0x08),
+       EXYNOS_PIN_BANK_EINTW(8, 0x060, "gpa3", 0x0c),
+       EXYNOS_PIN_BANK_EINTW_EXT(8, 0x020, "gpf1", 0x1004, 1),
+       EXYNOS_PIN_BANK_EINTW_EXT(4, 0x040, "gpf2", 0x1008, 1),
+       EXYNOS_PIN_BANK_EINTW_EXT(4, 0x060, "gpf3", 0x100c, 1),
+       EXYNOS_PIN_BANK_EINTW_EXT(8, 0x080, "gpf4", 0x1010, 1),
+       EXYNOS_PIN_BANK_EINTW_EXT(8, 0x0a0, "gpf5", 0x1014, 1),
 };
 
 /* pin banks of exynos5433 pin-controller - AUD */
-static const struct samsung_pin_bank_data exynos5433_pin_banks1[] = {
-       EXYNOS5433_PIN_BANK_EINTG(7, 0x000, "gpz0", 0x00),
-       EXYNOS5433_PIN_BANK_EINTG(4, 0x020, "gpz1", 0x04),
+static const struct samsung_pin_bank_data exynos5433_pin_banks1[] __initconst = {
+       EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz0", 0x00),
+       EXYNOS_PIN_BANK_EINTG(4, 0x020, "gpz1", 0x04),
 };
 
 /* pin banks of exynos5433 pin-controller - CPIF */
-static const struct samsung_pin_bank_data exynos5433_pin_banks2[] = {
-       EXYNOS5433_PIN_BANK_EINTG(2, 0x000, "gpv6", 0x00),
+static const struct samsung_pin_bank_data exynos5433_pin_banks2[] __initconst = {
+       EXYNOS_PIN_BANK_EINTG(2, 0x000, "gpv6", 0x00),
 };
 
 /* pin banks of exynos5433 pin-controller - eSE */
-static const struct samsung_pin_bank_data exynos5433_pin_banks3[] = {
-       EXYNOS5433_PIN_BANK_EINTG(3, 0x000, "gpj2", 0x00),
+static const struct samsung_pin_bank_data exynos5433_pin_banks3[] __initconst = {
+       EXYNOS_PIN_BANK_EINTG(3, 0x000, "gpj2", 0x00),
 };
 
 /* pin banks of exynos5433 pin-controller - FINGER */
-static const struct samsung_pin_bank_data exynos5433_pin_banks4[] = {
-       EXYNOS5433_PIN_BANK_EINTG(4, 0x000, "gpd5", 0x00),
+static const struct samsung_pin_bank_data exynos5433_pin_banks4[] __initconst = {
+       EXYNOS_PIN_BANK_EINTG(4, 0x000, "gpd5", 0x00),
 };
 
 /* pin banks of exynos5433 pin-controller - FSYS */
-static const struct samsung_pin_bank_data exynos5433_pin_banks5[] = {
-       EXYNOS5433_PIN_BANK_EINTG(6, 0x000, "gph1", 0x00),
-       EXYNOS5433_PIN_BANK_EINTG(7, 0x020, "gpr4", 0x04),
-       EXYNOS5433_PIN_BANK_EINTG(5, 0x040, "gpr0", 0x08),
-       EXYNOS5433_PIN_BANK_EINTG(8, 0x060, "gpr1", 0x0c),
-       EXYNOS5433_PIN_BANK_EINTG(2, 0x080, "gpr2", 0x10),
-       EXYNOS5433_PIN_BANK_EINTG(8, 0x0a0, "gpr3", 0x14),
+static const struct samsung_pin_bank_data exynos5433_pin_banks5[] __initconst = {
+       EXYNOS_PIN_BANK_EINTG(6, 0x000, "gph1", 0x00),
+       EXYNOS_PIN_BANK_EINTG(7, 0x020, "gpr4", 0x04),
+       EXYNOS_PIN_BANK_EINTG(5, 0x040, "gpr0", 0x08),
+       EXYNOS_PIN_BANK_EINTG(8, 0x060, "gpr1", 0x0c),
+       EXYNOS_PIN_BANK_EINTG(2, 0x080, "gpr2", 0x10),
+       EXYNOS_PIN_BANK_EINTG(8, 0x0a0, "gpr3", 0x14),
 };
 
 /* pin banks of exynos5433 pin-controller - IMEM */
-static const struct samsung_pin_bank_data exynos5433_pin_banks6[] = {
-       EXYNOS5433_PIN_BANK_EINTG(8, 0x000, "gpf0", 0x00),
+static const struct samsung_pin_bank_data exynos5433_pin_banks6[] __initconst = {
+       EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpf0", 0x00),
 };
 
 /* pin banks of exynos5433 pin-controller - NFC */
-static const struct samsung_pin_bank_data exynos5433_pin_banks7[] = {
-       EXYNOS5433_PIN_BANK_EINTG(3, 0x000, "gpj0", 0x00),
+static const struct samsung_pin_bank_data exynos5433_pin_banks7[] __initconst = {
+       EXYNOS_PIN_BANK_EINTG(3, 0x000, "gpj0", 0x00),
 };
 
 /* pin banks of exynos5433 pin-controller - PERIC */
-static const struct samsung_pin_bank_data exynos5433_pin_banks8[] = {
-       EXYNOS5433_PIN_BANK_EINTG(6, 0x000, "gpv7", 0x00),
-       EXYNOS5433_PIN_BANK_EINTG(5, 0x020, "gpb0", 0x04),
-       EXYNOS5433_PIN_BANK_EINTG(8, 0x040, "gpc0", 0x08),
-       EXYNOS5433_PIN_BANK_EINTG(2, 0x060, "gpc1", 0x0c),
-       EXYNOS5433_PIN_BANK_EINTG(6, 0x080, "gpc2", 0x10),
-       EXYNOS5433_PIN_BANK_EINTG(8, 0x0a0, "gpc3", 0x14),
-       EXYNOS5433_PIN_BANK_EINTG(2, 0x0c0, "gpg0", 0x18),
-       EXYNOS5433_PIN_BANK_EINTG(4, 0x0e0, "gpd0", 0x1c),
-       EXYNOS5433_PIN_BANK_EINTG(6, 0x100, "gpd1", 0x20),
-       EXYNOS5433_PIN_BANK_EINTG(8, 0x120, "gpd2", 0x24),
-       EXYNOS5433_PIN_BANK_EINTG(5, 0x140, "gpd4", 0x28),
-       EXYNOS5433_PIN_BANK_EINTG(2, 0x160, "gpd8", 0x2c),
-       EXYNOS5433_PIN_BANK_EINTG(7, 0x180, "gpd6", 0x30),
-       EXYNOS5433_PIN_BANK_EINTG(3, 0x1a0, "gpd7", 0x34),
-       EXYNOS5433_PIN_BANK_EINTG(5, 0x1c0, "gpg1", 0x38),
-       EXYNOS5433_PIN_BANK_EINTG(2, 0x1e0, "gpg2", 0x3c),
-       EXYNOS5433_PIN_BANK_EINTG(8, 0x200, "gpg3", 0x40),
+static const struct samsung_pin_bank_data exynos5433_pin_banks8[] __initconst = {
+       EXYNOS_PIN_BANK_EINTG(6, 0x000, "gpv7", 0x00),
+       EXYNOS_PIN_BANK_EINTG(5, 0x020, "gpb0", 0x04),
+       EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpc0", 0x08),
+       EXYNOS_PIN_BANK_EINTG(2, 0x060, "gpc1", 0x0c),
+       EXYNOS_PIN_BANK_EINTG(6, 0x080, "gpc2", 0x10),
+       EXYNOS_PIN_BANK_EINTG(8, 0x0a0, "gpc3", 0x14),
+       EXYNOS_PIN_BANK_EINTG(2, 0x0c0, "gpg0", 0x18),
+       EXYNOS_PIN_BANK_EINTG(4, 0x0e0, "gpd0", 0x1c),
+       EXYNOS_PIN_BANK_EINTG(6, 0x100, "gpd1", 0x20),
+       EXYNOS_PIN_BANK_EINTG(8, 0x120, "gpd2", 0x24),
+       EXYNOS_PIN_BANK_EINTG(5, 0x140, "gpd4", 0x28),
+       EXYNOS_PIN_BANK_EINTG(2, 0x160, "gpd8", 0x2c),
+       EXYNOS_PIN_BANK_EINTG(7, 0x180, "gpd6", 0x30),
+       EXYNOS_PIN_BANK_EINTG(3, 0x1a0, "gpd7", 0x34),
+       EXYNOS_PIN_BANK_EINTG(5, 0x1c0, "gpg1", 0x38),
+       EXYNOS_PIN_BANK_EINTG(2, 0x1e0, "gpg2", 0x3c),
+       EXYNOS_PIN_BANK_EINTG(8, 0x200, "gpg3", 0x40),
 };
 
 /* pin banks of exynos5433 pin-controller - TOUCH */
-static const struct samsung_pin_bank_data exynos5433_pin_banks9[] = {
-       EXYNOS5433_PIN_BANK_EINTG(3, 0x000, "gpj1", 0x00),
+static const struct samsung_pin_bank_data exynos5433_pin_banks9[] __initconst = {
+       EXYNOS_PIN_BANK_EINTG(3, 0x000, "gpj1", 0x00),
 };
 
 /*
  * Samsung pinctrl driver data for Exynos5433 SoC. Exynos5433 SoC includes
  * ten gpio/pin-mux/pinconfig controllers.
  */
-const struct samsung_pin_ctrl exynos5433_pin_ctrl[] = {
+const struct samsung_pin_ctrl exynos5433_pin_ctrl[] __initconst = {
        {
                /* pin-controller instance 0 data */
                .pin_banks      = exynos5433_pin_banks0,
index 4c632812ccff2dbd8086b0640f58774edf23e0fb..f17890aa6e25c2ec45d6f49d1e9c42fbaaacc91e 100644 (file)
@@ -489,10 +489,8 @@ static int s3c64xx_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
 
        data = devm_kzalloc(dev, sizeof(*data)
                        + nr_domains * sizeof(*data->domains), GFP_KERNEL);
-       if (!data) {
-               dev_err(dev, "failed to allocate handler data\n");
+       if (!data)
                return -ENOMEM;
-       }
        data->drvdata = d;
 
        bank = d->pin_banks;
@@ -715,10 +713,8 @@ static int s3c64xx_eint_eint0_init(struct samsung_pinctrl_drv_data *d)
                return -ENODEV;
 
        data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
-       if (!data) {
-               dev_err(dev, "could not allocate memory for wkup eint data\n");
+       if (!data)
                return -ENOMEM;
-       }
        data->drvdata = d;
 
        for (i = 0; i < NUM_EINT0_IRQ; ++i) {
@@ -751,10 +747,8 @@ static int s3c64xx_eint_eint0_init(struct samsung_pinctrl_drv_data *d)
 
                ddata = devm_kzalloc(dev,
                                sizeof(*ddata) + nr_eints, GFP_KERNEL);
-               if (!ddata) {
-                       dev_err(dev, "failed to allocate domain data\n");
+               if (!ddata)
                        return -ENOMEM;
-               }
                ddata->bank = bank;
 
                bank->irq_domain = irq_domain_add_linear(bank->of_node,
index 41e62391c33ca10e34e9322780926fb7637ebe39..f9ddba7decc18563916d5adc118958fad46f0073 100644 (file)
@@ -27,8 +27,8 @@
 #include <linux/err.h>
 #include <linux/gpio.h>
 #include <linux/irqdomain.h>
+#include <linux/of_device.h>
 #include <linux/spinlock.h>
-#include <linux/syscore_ops.h>
 
 #include "../core.h"
 #include "pinctrl-samsung.h"
@@ -48,9 +48,6 @@ static struct pin_config {
        { "samsung,pin-val", PINCFG_TYPE_DAT },
 };
 
-/* Global list of devices (struct samsung_pinctrl_drv_data) */
-static LIST_HEAD(drvdata_list);
-
 static unsigned int pin_base;
 
 static int samsung_get_group_count(struct pinctrl_dev *pctldev)
@@ -93,10 +90,8 @@ static int reserve_map(struct device *dev, struct pinctrl_map **map,
                return 0;
 
        new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL);
-       if (!new_map) {
-               dev_err(dev, "krealloc(map) failed\n");
+       if (!new_map)
                return -ENOMEM;
-       }
 
        memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map));
 
@@ -133,10 +128,8 @@ static int add_map_configs(struct device *dev, struct pinctrl_map **map,
 
        dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs),
                              GFP_KERNEL);
-       if (!dup_configs) {
-               dev_err(dev, "kmemdup(configs) failed\n");
+       if (!dup_configs)
                return -ENOMEM;
-       }
 
        (*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_GROUP;
        (*map)[*num_maps].data.configs.group_or_pin = group;
@@ -156,10 +149,8 @@ static int add_config(struct device *dev, unsigned long **configs,
 
        new_configs = krealloc(*configs, sizeof(*new_configs) * new_num,
                               GFP_KERNEL);
-       if (!new_configs) {
-               dev_err(dev, "krealloc(configs) failed\n");
+       if (!new_configs)
                return -ENOMEM;
-       }
 
        new_configs[old_num] = config;
 
@@ -356,7 +347,7 @@ static void pin_to_reg_bank(struct samsung_pinctrl_drv_data *drvdata,
 
 /* enable or disable a pinmux function */
 static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector,
-                                       unsigned group, bool enable)
+                                       unsigned group)
 {
        struct samsung_pinctrl_drv_data *drvdata;
        const struct samsung_pin_bank_type *type;
@@ -386,8 +377,7 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector,
 
        data = readl(reg + type->reg_offset[PINCFG_TYPE_FUNC]);
        data &= ~(mask << shift);
-       if (enable)
-               data |= func->val << shift;
+       data |= func->val << shift;
        writel(data, reg + type->reg_offset[PINCFG_TYPE_FUNC]);
 
        spin_unlock_irqrestore(&bank->slock, flags);
@@ -398,7 +388,7 @@ static int samsung_pinmux_set_mux(struct pinctrl_dev *pctldev,
                                  unsigned selector,
                                  unsigned group)
 {
-       samsung_pinmux_setup(pctldev, selector, group, true);
+       samsung_pinmux_setup(pctldev, selector, group);
        return 0;
 }
 
@@ -756,10 +746,8 @@ static struct samsung_pmx_func *samsung_pinctrl_create_functions(
 
        functions = devm_kzalloc(dev, func_cnt * sizeof(*functions),
                                        GFP_KERNEL);
-       if (!functions) {
-               dev_err(dev, "failed to allocate memory for function list\n");
-               return ERR_PTR(-EINVAL);
-       }
+       if (!functions)
+               return ERR_PTR(-ENOMEM);
        func = functions;
 
        /*
@@ -850,10 +838,8 @@ static int samsung_pinctrl_register(struct platform_device *pdev,
 
        pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) *
                        drvdata->nr_pins, GFP_KERNEL);
-       if (!pindesc) {
-               dev_err(&pdev->dev, "mem alloc for pin descriptors failed\n");
+       if (!pindesc)
                return -ENOMEM;
-       }
        ctrldesc->pins = pindesc;
        ctrldesc->npins = drvdata->nr_pins;
 
@@ -867,10 +853,8 @@ static int samsung_pinctrl_register(struct platform_device *pdev,
         */
        pin_names = devm_kzalloc(&pdev->dev, sizeof(char) * PIN_NAME_LENGTH *
                                        drvdata->nr_pins, GFP_KERNEL);
-       if (!pin_names) {
-               dev_err(&pdev->dev, "mem alloc for pin names failed\n");
+       if (!pin_names)
                return -ENOMEM;
-       }
 
        /* for each pin, the name of the pin is pin-bank name + pin number */
        for (bank = 0; bank < drvdata->nr_banks; bank++) {
@@ -968,15 +952,12 @@ static int samsung_gpiolib_unregister(struct platform_device *pdev,
        return 0;
 }
 
-static const struct of_device_id samsung_pinctrl_dt_match[];
-
 /* retrieve the soc specific data */
 static const struct samsung_pin_ctrl *
 samsung_pinctrl_get_soc_data(struct samsung_pinctrl_drv_data *d,
                             struct platform_device *pdev)
 {
        int id;
-       const struct of_device_id *match;
        struct device_node *node = pdev->dev.of_node;
        struct device_node *np;
        const struct samsung_pin_bank_data *bdata;
@@ -991,8 +972,8 @@ samsung_pinctrl_get_soc_data(struct samsung_pinctrl_drv_data *d,
                dev_err(&pdev->dev, "failed to get alias id\n");
                return ERR_PTR(-ENOENT);
        }
-       match = of_match_node(samsung_pinctrl_dt_match, node);
-       ctrl = (struct samsung_pin_ctrl *)match->data + id;
+       ctrl = of_device_get_match_data(&pdev->dev);
+       ctrl += id;
 
        d->suspend = ctrl->suspend;
        d->resume = ctrl->resume;
@@ -1007,10 +988,9 @@ samsung_pinctrl_get_soc_data(struct samsung_pinctrl_drv_data *d,
 
        for (i = 0; i < ctrl->nr_ext_resources + 1; i++) {
                res = platform_get_resource(pdev, IORESOURCE_MEM, i);
-               virt_base[i] = devm_ioremap(&pdev->dev, res->start,
-                                               resource_size(res));
+               virt_base[i] = devm_ioremap_resource(&pdev->dev, res);
                if (IS_ERR(virt_base[i]))
-                       return ERR_PTR(-EIO);
+                       return ERR_CAST(virt_base[i]);
        }
 
        bank = d->pin_banks;
@@ -1075,6 +1055,13 @@ static int samsung_pinctrl_probe(struct platform_device *pdev)
        if (res)
                drvdata->irq = res->start;
 
+       if (ctrl->retention_data) {
+               drvdata->retention_ctrl = ctrl->retention_data->init(drvdata,
+                                                         ctrl->retention_data);
+               if (IS_ERR(drvdata->retention_ctrl))
+                       return PTR_ERR(drvdata->retention_ctrl);
+       }
+
        ret = samsung_gpiolib_register(pdev, drvdata);
        if (ret)
                return ret;
@@ -1092,22 +1079,17 @@ static int samsung_pinctrl_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, drvdata);
 
-       /* Add to the global list */
-       list_add_tail(&drvdata->node, &drvdata_list);
-
        return 0;
 }
 
-#ifdef CONFIG_PM
-
 /**
- * samsung_pinctrl_suspend_dev - save pinctrl state for suspend for a device
+ * samsung_pinctrl_suspend - save pinctrl state for suspend
  *
  * Save data for all banks handled by this device.
  */
-static void samsung_pinctrl_suspend_dev(
-       struct samsung_pinctrl_drv_data *drvdata)
+static int __maybe_unused samsung_pinctrl_suspend(struct device *dev)
 {
+       struct samsung_pinctrl_drv_data *drvdata = dev_get_drvdata(dev);
        int i;
 
        for (i = 0; i < drvdata->nr_banks; i++) {
@@ -1141,18 +1123,23 @@ static void samsung_pinctrl_suspend_dev(
 
        if (drvdata->suspend)
                drvdata->suspend(drvdata);
+       if (drvdata->retention_ctrl && drvdata->retention_ctrl->enable)
+               drvdata->retention_ctrl->enable(drvdata);
+
+       return 0;
 }
 
 /**
- * samsung_pinctrl_resume_dev - restore pinctrl state from suspend for a device
+ * samsung_pinctrl_resume - restore pinctrl state from suspend
  *
  * Restore one of the banks that was saved during suspend.
  *
  * We don't bother doing anything complicated to avoid glitching lines since
  * we're called before pad retention is turned off.
  */
-static void samsung_pinctrl_resume_dev(struct samsung_pinctrl_drv_data *drvdata)
+static int __maybe_unused samsung_pinctrl_resume(struct device *dev)
 {
+       struct samsung_pinctrl_drv_data *drvdata = dev_get_drvdata(dev);
        int i;
 
        if (drvdata->resume)
@@ -1188,48 +1175,13 @@ static void samsung_pinctrl_resume_dev(struct samsung_pinctrl_drv_data *drvdata)
                        if (widths[type])
                                writel(bank->pm_save[type], reg + offs[type]);
        }
-}
-
-/**
- * samsung_pinctrl_suspend - save pinctrl state for suspend
- *
- * Save data for all banks across all devices.
- */
-static int samsung_pinctrl_suspend(void)
-{
-       struct samsung_pinctrl_drv_data *drvdata;
 
-       list_for_each_entry(drvdata, &drvdata_list, node) {
-               samsung_pinctrl_suspend_dev(drvdata);
-       }
+       if (drvdata->retention_ctrl && drvdata->retention_ctrl->disable)
+               drvdata->retention_ctrl->disable(drvdata);
 
        return 0;
 }
 
-/**
- * samsung_pinctrl_resume - restore pinctrl state for suspend
- *
- * Restore data for all banks across all devices.
- */
-static void samsung_pinctrl_resume(void)
-{
-       struct samsung_pinctrl_drv_data *drvdata;
-
-       list_for_each_entry_reverse(drvdata, &drvdata_list, node) {
-               samsung_pinctrl_resume_dev(drvdata);
-       }
-}
-
-#else
-#define samsung_pinctrl_suspend                NULL
-#define samsung_pinctrl_resume         NULL
-#endif
-
-static struct syscore_ops samsung_pinctrl_syscore_ops = {
-       .suspend        = samsung_pinctrl_suspend,
-       .resume         = samsung_pinctrl_resume,
-};
-
 static const struct of_device_id samsung_pinctrl_dt_match[] = {
 #ifdef CONFIG_PINCTRL_EXYNOS
        { .compatible = "samsung,exynos3250-pinctrl",
@@ -1238,8 +1190,6 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = {
                .data = (void *)exynos4210_pin_ctrl },
        { .compatible = "samsung,exynos4x12-pinctrl",
                .data = (void *)exynos4x12_pin_ctrl },
-       { .compatible = "samsung,exynos4415-pinctrl",
-               .data = (void *)exynos4415_pin_ctrl },
        { .compatible = "samsung,exynos5250-pinctrl",
                .data = (void *)exynos5250_pin_ctrl },
        { .compatible = "samsung,exynos5260-pinctrl",
@@ -1273,25 +1223,23 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = {
 };
 MODULE_DEVICE_TABLE(of, samsung_pinctrl_dt_match);
 
+static const struct dev_pm_ops samsung_pinctrl_pm_ops = {
+       SET_LATE_SYSTEM_SLEEP_PM_OPS(samsung_pinctrl_suspend,
+                                    samsung_pinctrl_resume)
+};
+
 static struct platform_driver samsung_pinctrl_driver = {
        .probe          = samsung_pinctrl_probe,
        .driver = {
                .name   = "samsung-pinctrl",
                .of_match_table = samsung_pinctrl_dt_match,
                .suppress_bind_attrs = true,
+               .pm = &samsung_pinctrl_pm_ops,
        },
 };
 
 static int __init samsung_pinctrl_drv_register(void)
 {
-       /*
-        * Register syscore ops for save/restore of registers across suspend.
-        * It's important to ensure that this driver is running at an earlier
-        * initcall level than any arch-specific init calls that install syscore
-        * ops that turn off pad retention (like exynos_pm_resume).
-        */
-       register_syscore_ops(&samsung_pinctrl_syscore_ops);
-
        return platform_driver_register(&samsung_pinctrl_driver);
 }
 postcore_initcall(samsung_pinctrl_drv_register);
index 043cb6c11180e5c8241d47feddbbd0f74fe4d31c..515a61035e54a5415b6a3d142319b59377b9bd88 100644 (file)
@@ -184,11 +184,49 @@ struct samsung_pin_bank {
        u32 pm_save[PINCFG_TYPE_NUM + 1]; /* +1 to handle double CON registers*/
 };
 
+/**
+ * struct samsung_retention_data: runtime pin-bank retention control data.
+ * @regs: array of PMU registers to control pad retention.
+ * @nr_regs: number of registers in @regs array.
+ * @value: value to store to registers to turn off retention.
+ * @refcnt: atomic counter if retention control affects more than one bank.
+ * @priv: retention control code private data
+ * @enable: platform specific callback to enter retention mode.
+ * @disable: platform specific callback to exit retention mode.
+ **/
+struct samsung_retention_ctrl {
+       const u32       *regs;
+       int             nr_regs;
+       u32             value;
+       atomic_t        *refcnt;
+       void            *priv;
+       void            (*enable)(struct samsung_pinctrl_drv_data *);
+       void            (*disable)(struct samsung_pinctrl_drv_data *);
+};
+
+/**
+ * struct samsung_retention_data: represent a pin-bank retention control data.
+ * @regs: array of PMU registers to control pad retention.
+ * @nr_regs: number of registers in @regs array.
+ * @value: value to store to registers to turn off retention.
+ * @refcnt: atomic counter if retention control affects more than one bank.
+ * @init: platform specific callback to initialize retention control.
+ **/
+struct samsung_retention_data {
+       const u32       *regs;
+       int             nr_regs;
+       u32             value;
+       atomic_t        *refcnt;
+       struct samsung_retention_ctrl *(*init)(struct samsung_pinctrl_drv_data *,
+                                       const struct samsung_retention_data *);
+};
+
 /**
  * struct samsung_pin_ctrl: represent a pin controller.
  * @pin_banks: list of pin banks included in this controller.
  * @nr_banks: number of pin banks.
  * @nr_ext_resources: number of the extra base address for pin banks.
+ * @retention_data: configuration data for retention control.
  * @eint_gpio_init: platform specific callback to setup the external gpio
  *     interrupts for the controller.
  * @eint_wkup_init: platform specific callback to setup the external wakeup
@@ -198,6 +236,7 @@ struct samsung_pin_ctrl {
        const struct samsung_pin_bank_data *pin_banks;
        u32             nr_banks;
        int             nr_ext_resources;
+       const struct samsung_retention_data *retention_data;
 
        int             (*eint_gpio_init)(struct samsung_pinctrl_drv_data *);
        int             (*eint_wkup_init)(struct samsung_pinctrl_drv_data *);
@@ -219,6 +258,7 @@ struct samsung_pin_ctrl {
  * @nr_function: number of such pin functions.
  * @pin_base: starting system wide pin number.
  * @nr_pins: number of pins supported by the controller.
+ * @retention_ctrl: retention control runtime data.
  */
 struct samsung_pinctrl_drv_data {
        struct list_head                node;
@@ -238,6 +278,8 @@ struct samsung_pinctrl_drv_data {
        unsigned int                    pin_base;
        unsigned int                    nr_pins;
 
+       struct samsung_retention_ctrl   *retention_ctrl;
+
        void (*suspend)(struct samsung_pinctrl_drv_data *);
        void (*resume)(struct samsung_pinctrl_drv_data *);
 };
@@ -273,7 +315,6 @@ struct samsung_pmx_func {
 extern const struct samsung_pin_ctrl exynos3250_pin_ctrl[];
 extern const struct samsung_pin_ctrl exynos4210_pin_ctrl[];
 extern const struct samsung_pin_ctrl exynos4x12_pin_ctrl[];
-extern const struct samsung_pin_ctrl exynos4415_pin_ctrl[];
 extern const struct samsung_pin_ctrl exynos5250_pin_ctrl[];
 extern const struct samsung_pin_ctrl exynos5260_pin_ctrl[];
 extern const struct samsung_pin_ctrl exynos5410_pin_ctrl[];
index 7ca37c3019abb1dc66b9ecc3dc12f1dc49abbe09..841cecdca7ea34c49c0245519b5a4cd86c4bf3da 100644 (file)
@@ -1691,6 +1691,72 @@ static const struct sh_pfc_pin pinmux_pins[] = {
        PINMUX_GPIO_GP_ALL(),
 };
 
+/* - ADI -------------------------------------------------------------------- */
+static const unsigned int adi_common_pins[] = {
+       /* ADIDATA, ADICS/SAMP, ADICLK */
+       RCAR_GP_PIN(6, 24), RCAR_GP_PIN(6, 25), RCAR_GP_PIN(6, 26),
+};
+static const unsigned int adi_common_mux[] = {
+       /* ADIDATA, ADICS/SAMP, ADICLK */
+       ADIDATA_MARK, ADICS_SAMP_MARK, ADICLK_MARK,
+};
+static const unsigned int adi_chsel0_pins[] = {
+       /* ADICHS 0 */
+       RCAR_GP_PIN(6, 27),
+};
+static const unsigned int adi_chsel0_mux[] = {
+       /* ADICHS 0 */
+       ADICHS0_MARK,
+};
+static const unsigned int adi_chsel1_pins[] = {
+       /* ADICHS 1 */
+       RCAR_GP_PIN(6, 28),
+};
+static const unsigned int adi_chsel1_mux[] = {
+       /* ADICHS 1 */
+       ADICHS1_MARK,
+};
+static const unsigned int adi_chsel2_pins[] = {
+       /* ADICHS 2 */
+       RCAR_GP_PIN(6, 29),
+};
+static const unsigned int adi_chsel2_mux[] = {
+       /* ADICHS 2 */
+       ADICHS2_MARK,
+};
+static const unsigned int adi_common_b_pins[] = {
+       /* ADIDATA B, ADICS/SAMP B, ADICLK B */
+       RCAR_GP_PIN(5, 25), RCAR_GP_PIN(5, 26), RCAR_GP_PIN(5, 27),
+};
+static const unsigned int adi_common_b_mux[] = {
+       /* ADIDATA B, ADICS/SAMP B, ADICLK B */
+       ADIDATA_B_MARK, ADICS_SAMP_B_MARK, ADICLK_B_MARK,
+};
+static const unsigned int adi_chsel0_b_pins[] = {
+       /* ADICHS B 0 */
+       RCAR_GP_PIN(5, 28),
+};
+static const unsigned int adi_chsel0_b_mux[] = {
+       /* ADICHS B 0 */
+       ADICHS0_B_MARK,
+};
+static const unsigned int adi_chsel1_b_pins[] = {
+       /* ADICHS B 1 */
+       RCAR_GP_PIN(5, 29),
+};
+static const unsigned int adi_chsel1_b_mux[] = {
+       /* ADICHS B 1 */
+       ADICHS1_B_MARK,
+};
+static const unsigned int adi_chsel2_b_pins[] = {
+       /* ADICHS B 2 */
+       RCAR_GP_PIN(5, 30),
+};
+static const unsigned int adi_chsel2_b_mux[] = {
+       /* ADICHS B 2 */
+       ADICHS2_B_MARK,
+};
+
 /* - Audio Clock ------------------------------------------------------------ */
 static const unsigned int audio_clk_a_pins[] = {
        /* CLK */
@@ -4343,6 +4409,14 @@ static const unsigned int vin2_clk_mux[] = {
 };
 
 static const struct sh_pfc_pin_group pinmux_groups[] = {
+       SH_PFC_PIN_GROUP(adi_common),
+       SH_PFC_PIN_GROUP(adi_chsel0),
+       SH_PFC_PIN_GROUP(adi_chsel1),
+       SH_PFC_PIN_GROUP(adi_chsel2),
+       SH_PFC_PIN_GROUP(adi_common_b),
+       SH_PFC_PIN_GROUP(adi_chsel0_b),
+       SH_PFC_PIN_GROUP(adi_chsel1_b),
+       SH_PFC_PIN_GROUP(adi_chsel2_b),
        SH_PFC_PIN_GROUP(audio_clk_a),
        SH_PFC_PIN_GROUP(audio_clk_b),
        SH_PFC_PIN_GROUP(audio_clk_b_b),
@@ -4687,6 +4761,17 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
        SH_PFC_PIN_GROUP(vin2_clk),
 };
 
+static const char * const adi_groups[] = {
+       "adi_common",
+       "adi_chsel0",
+       "adi_chsel1",
+       "adi_chsel2",
+       "adi_common_b",
+       "adi_chsel0_b",
+       "adi_chsel1_b",
+       "adi_chsel2_b",
+};
+
 static const char * const audio_clk_groups[] = {
        "audio_clk_a",
        "audio_clk_b",
@@ -5192,6 +5277,7 @@ static const char * const vin2_groups[] = {
 };
 
 static const struct sh_pfc_function pinmux_functions[] = {
+       SH_PFC_FUNCTION(adi),
        SH_PFC_FUNCTION(audio_clk),
        SH_PFC_FUNCTION(avb),
        SH_PFC_FUNCTION(can0),
@@ -6455,6 +6541,7 @@ const struct sh_pfc_soc_info r8a7791_pinmux_info = {
 #ifdef CONFIG_PINCTRL_PFC_R8A7793
 const struct sh_pfc_soc_info r8a7793_pinmux_info = {
        .name = "r8a77930_pfc",
+       .ops = &r8a7791_pinmux_ops,
        .unlock_reg = 0xe6060000, /* PMMR */
 
        .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
index 135ed5cbeb44c5e6aaf76ca30a96e5c52751f7b3..504d0c3d7f741849191dc88f2e12adb0d119944c 100644 (file)
@@ -538,7 +538,7 @@ MOD_SEL0_2_1                MOD_SEL1_2 \
        FM(AVB_TXCREFCLK) FM(AVB_MDIO) \
        FM(CLKOUT) FM(PRESETOUT) \
        FM(DU_DOTCLKIN0) FM(DU_DOTCLKIN1) FM(DU_DOTCLKIN2) FM(DU_DOTCLKIN3) \
-       FM(TMS) FM(TDO) FM(ASEBRK) FM(MLB_REF)
+       FM(TMS) FM(TDO) FM(ASEBRK) FM(MLB_REF) FM(TDI) FM(TCK) FM(TRST) FM(EXTALR)
 
 enum {
        PINMUX_RESERVED = 0,
@@ -1461,46 +1461,50 @@ static const struct sh_pfc_pin pinmux_pins[] = {
         * number for each pin. To this end use the pin layout from
         * R-Car H3SiP to calculate a unique number for each pin.
         */
-       SH_PFC_PIN_NAMED_CFG('A',  8, AVB_TX_CTL, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG('A',  9, AVB_MDIO, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG('A', 12, AVB_TXCREFCLK, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG('A', 13, AVB_RD0, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG('A', 14, AVB_RD2, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG('A', 16, AVB_RX_CTL, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG('A', 17, AVB_TD2, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG('A', 18, AVB_TD0, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG('A', 19, AVB_TXC, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG('B', 13, AVB_RD1, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG('B', 14, AVB_RD3, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG('B', 17, AVB_TD3, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG('B', 18, AVB_TD1, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG('B', 19, AVB_RXC, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG('C',  1, PRESETOUT#, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG('F',  1, CLKOUT, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG('H', 37, MLB_REF, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG('V',  3, QSPI1_SPCLK, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG('V',  5, QSPI1_SSL, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG('V',  6, RPC_WP#, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG('V',  7, RPC_RESET#, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG('W',  3, QSPI0_SPCLK, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG('Y',  3, QSPI0_SSL, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG('Y',  6, QSPI0_IO2, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG('Y',  7, RPC_INT#, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'),  4, QSPI0_MISO_IO1, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'),  6, QSPI0_IO3, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'),  3, QSPI1_IO3, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'),  5, QSPI0_MOSI_IO0, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'),  7, QSPI1_MOSI_IO0, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 38, FSCLKST#, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'),  4, QSPI1_IO2, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'),  5, QSPI1_MISO_IO1, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'),  7, DU_DOTCLKIN0, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'),  8, DU_DOTCLKIN1, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'),  7, DU_DOTCLKIN2, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'),  8, DU_DOTCLKIN3, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 30, TMS, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
+       SH_PFC_PIN_NAMED_CFG('A',  8, AVB_TX_CTL, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('A',  9, AVB_MDIO, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('A', 12, AVB_TXCREFCLK, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('A', 13, AVB_RD0, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('A', 14, AVB_RD2, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('A', 16, AVB_RX_CTL, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('A', 17, AVB_TD2, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('A', 18, AVB_TD0, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('A', 19, AVB_TXC, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('B', 13, AVB_RD1, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('B', 14, AVB_RD3, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('B', 17, AVB_TD3, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('B', 18, AVB_TD1, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('B', 19, AVB_RXC, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('C',  1, PRESETOUT#, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('F',  1, CLKOUT, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('H', 37, MLB_REF, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('V',  3, QSPI1_SPCLK, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('V',  5, QSPI1_SSL, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('V',  6, RPC_WP#, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('V',  7, RPC_RESET#, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('W',  3, QSPI0_SPCLK, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('Y',  3, QSPI0_SSL, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('Y',  6, QSPI0_IO2, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('Y',  7, RPC_INT#, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'),  4, QSPI0_MISO_IO1, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'),  6, QSPI0_IO3, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'),  3, QSPI1_IO3, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'),  5, QSPI0_MOSI_IO0, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'),  7, QSPI1_MOSI_IO0, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 38, FSCLKST#, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 39, EXTALR, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'),  4, QSPI1_IO2, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'),  5, QSPI1_MISO_IO1, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'),  7, DU_DOTCLKIN0, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'),  8, DU_DOTCLKIN1, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'),  7, DU_DOTCLKIN2, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'),  8, DU_DOTCLKIN3, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 26, TRST#, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 29, TDI, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 30, TMS, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 27, TCK, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
        SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 28, TDO, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
-       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 30, ASEBRK, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 30, ASEBRK, CFG_FLAGS),
 };
 
 /* - AUDIO CLOCK ------------------------------------------------------------ */
@@ -5415,167 +5419,211 @@ static int r8a7795_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin, u32 *poc
 #define PU6    0x18
 
 static const struct sh_pfc_bias_info bias_info[] = {
-       { RCAR_GP_PIN(2, 11), PU0, 31 },        /* AVB_PHY_INT */
-       { RCAR_GP_PIN(2, 10), PU0, 30 },        /* AVB_MAGIC */
-       { RCAR_GP_PIN(2,  9), PU0, 29 },        /* AVB_MDC */
-
-       { RCAR_GP_PIN(1, 19), PU1, 31 },        /* A19 */
-       { RCAR_GP_PIN(1, 18), PU1, 30 },        /* A18 */
-       { RCAR_GP_PIN(1, 17), PU1, 29 },        /* A17 */
-       { RCAR_GP_PIN(1, 16), PU1, 28 },        /* A16 */
-       { RCAR_GP_PIN(1, 15), PU1, 27 },        /* A15 */
-       { RCAR_GP_PIN(1, 14), PU1, 26 },        /* A14 */
-       { RCAR_GP_PIN(1, 13), PU1, 25 },        /* A13 */
-       { RCAR_GP_PIN(1, 12), PU1, 24 },        /* A12 */
-       { RCAR_GP_PIN(1, 11), PU1, 23 },        /* A11 */
-       { RCAR_GP_PIN(1, 10), PU1, 22 },        /* A10 */
-       { RCAR_GP_PIN(1,  9), PU1, 21 },        /* A9 */
-       { RCAR_GP_PIN(1,  8), PU1, 20 },        /* A8 */
-       { RCAR_GP_PIN(1,  7), PU1, 19 },        /* A7 */
-       { RCAR_GP_PIN(1,  6), PU1, 18 },        /* A6 */
-       { RCAR_GP_PIN(1,  5), PU1, 17 },        /* A5 */
-       { RCAR_GP_PIN(1,  4), PU1, 16 },        /* A4 */
-       { RCAR_GP_PIN(1,  3), PU1, 15 },        /* A3 */
-       { RCAR_GP_PIN(1,  2), PU1, 14 },        /* A2 */
-       { RCAR_GP_PIN(1,  1), PU1, 13 },        /* A1 */
-       { RCAR_GP_PIN(1,  0), PU1, 12 },        /* A0 */
-       { RCAR_GP_PIN(2,  8), PU1, 11 },        /* PWM2_A */
-       { RCAR_GP_PIN(2,  7), PU1, 10 },        /* PWM1_A */
-       { RCAR_GP_PIN(2,  6), PU1,  9 },        /* PWM0 */
-       { RCAR_GP_PIN(2,  5), PU1,  8 },        /* IRQ5 */
-       { RCAR_GP_PIN(2,  4), PU1,  7 },        /* IRQ4 */
-       { RCAR_GP_PIN(2,  3), PU1,  6 },        /* IRQ3 */
-       { RCAR_GP_PIN(2,  2), PU1,  5 },        /* IRQ2 */
-       { RCAR_GP_PIN(2,  1), PU1,  4 },        /* IRQ1 */
-       { RCAR_GP_PIN(2,  0), PU1,  3 },        /* IRQ0 */
-       { RCAR_GP_PIN(2, 14), PU1,  2 },        /* AVB_AVTP_CAPTURE_A */
-       { RCAR_GP_PIN(2, 13), PU1,  1 },        /* AVB_AVTP_MATCH_A */
-       { RCAR_GP_PIN(2, 12), PU1,  0 },        /* AVB_LINK */
-
-       { RCAR_GP_PIN(7,  3), PU2, 29 },        /* HDMI1_CEC */
-       { RCAR_GP_PIN(7,  2), PU2, 28 },        /* HDMI0_CEC */
-       { RCAR_GP_PIN(7,  1), PU2, 27 },        /* AVS2 */
-       { RCAR_GP_PIN(7,  0), PU2, 26 },        /* AVS1 */
-       { RCAR_GP_PIN(0, 15), PU2, 25 },        /* D15 */
-       { RCAR_GP_PIN(0, 14), PU2, 24 },        /* D14 */
-       { RCAR_GP_PIN(0, 13), PU2, 23 },        /* D13 */
-       { RCAR_GP_PIN(0, 12), PU2, 22 },        /* D12 */
-       { RCAR_GP_PIN(0, 11), PU2, 21 },        /* D11 */
-       { RCAR_GP_PIN(0, 10), PU2, 20 },        /* D10 */
-       { RCAR_GP_PIN(0,  9), PU2, 19 },        /* D9 */
-       { RCAR_GP_PIN(0,  8), PU2, 18 },        /* D8 */
-       { RCAR_GP_PIN(0,  7), PU2, 17 },        /* D7 */
-       { RCAR_GP_PIN(0,  6), PU2, 16 },        /* D6 */
-       { RCAR_GP_PIN(0,  5), PU2, 15 },        /* D5 */
-       { RCAR_GP_PIN(0,  4), PU2, 14 },        /* D4 */
-       { RCAR_GP_PIN(0,  3), PU2, 13 },        /* D3 */
-       { RCAR_GP_PIN(0,  2), PU2, 12 },        /* D2 */
-       { RCAR_GP_PIN(0,  1), PU2, 11 },        /* D1 */
-       { RCAR_GP_PIN(0,  0), PU2, 10 },        /* D0 */
-       { RCAR_GP_PIN(1, 27), PU2,  8 },        /* EX_WAIT0_A */
-       { RCAR_GP_PIN(1, 26), PU2,  7 },        /* WE1_N */
-       { RCAR_GP_PIN(1, 25), PU2,  6 },        /* WE0_N */
-       { RCAR_GP_PIN(1, 24), PU2,  5 },        /* RD_WR_N */
-       { RCAR_GP_PIN(1, 23), PU2,  4 },        /* RD_N */
-       { RCAR_GP_PIN(1, 22), PU2,  3 },        /* BS_N */
-       { RCAR_GP_PIN(1, 21), PU2,  2 },        /* CS1_N_A26 */
-       { RCAR_GP_PIN(1, 20), PU2,  1 },        /* CS0_N */
-
-       { RCAR_GP_PIN(4,  9), PU3, 31 },        /* SD3_DAT0 */
-       { RCAR_GP_PIN(4,  8), PU3, 30 },        /* SD3_CMD */
-       { RCAR_GP_PIN(4,  7), PU3, 29 },        /* SD3_CLK */
-       { RCAR_GP_PIN(4,  6), PU3, 28 },        /* SD2_DS */
-       { RCAR_GP_PIN(4,  5), PU3, 27 },        /* SD2_DAT3 */
-       { RCAR_GP_PIN(4,  4), PU3, 26 },        /* SD2_DAT2 */
-       { RCAR_GP_PIN(4,  3), PU3, 25 },        /* SD2_DAT1 */
-       { RCAR_GP_PIN(4,  2), PU3, 24 },        /* SD2_DAT0 */
-       { RCAR_GP_PIN(4,  1), PU3, 23 },        /* SD2_CMD */
-       { RCAR_GP_PIN(4,  0), PU3, 22 },        /* SD2_CLK */
-       { RCAR_GP_PIN(3, 11), PU3, 21 },        /* SD1_DAT3 */
-       { RCAR_GP_PIN(3, 10), PU3, 20 },        /* SD1_DAT2 */
-       { RCAR_GP_PIN(3,  9), PU3, 19 },        /* SD1_DAT1 */
-       { RCAR_GP_PIN(3,  8), PU3, 18 },        /* SD1_DAT0 */
-       { RCAR_GP_PIN(3,  7), PU3, 17 },        /* SD1_CMD */
-       { RCAR_GP_PIN(3,  6), PU3, 16 },        /* SD1_CLK */
-       { RCAR_GP_PIN(3,  5), PU3, 15 },        /* SD0_DAT3 */
-       { RCAR_GP_PIN(3,  4), PU3, 14 },        /* SD0_DAT2 */
-       { RCAR_GP_PIN(3,  3), PU3, 13 },        /* SD0_DAT1 */
-       { RCAR_GP_PIN(3,  2), PU3, 12 },        /* SD0_DAT0 */
-       { RCAR_GP_PIN(3,  1), PU3, 11 },        /* SD0_CMD */
-       { RCAR_GP_PIN(3,  0), PU3, 10 },        /* SD0_CLK */
-
-       { RCAR_GP_PIN(5, 19), PU4, 31 },        /* MSIOF0_SS1 */
-       { RCAR_GP_PIN(5, 18), PU4, 30 },        /* MSIOF0_SYNC */
-       { RCAR_GP_PIN(5, 17), PU4, 29 },        /* MSIOF0_SCK */
-       { RCAR_GP_PIN(5, 16), PU4, 28 },        /* HRTS0_N */
-       { RCAR_GP_PIN(5, 15), PU4, 27 },        /* HCTS0_N */
-       { RCAR_GP_PIN(5, 14), PU4, 26 },        /* HTX0 */
-       { RCAR_GP_PIN(5, 13), PU4, 25 },        /* HRX0 */
-       { RCAR_GP_PIN(5, 12), PU4, 24 },        /* HSCK0 */
-       { RCAR_GP_PIN(5, 11), PU4, 23 },        /* RX2_A */
-       { RCAR_GP_PIN(5, 10), PU4, 22 },        /* TX2_A */
-       { RCAR_GP_PIN(5,  9), PU4, 21 },        /* SCK2 */
-       { RCAR_GP_PIN(5,  8), PU4, 20 },        /* RTS1_N_TANS */
-       { RCAR_GP_PIN(5,  7), PU4, 19 },        /* CTS1_N */
-       { RCAR_GP_PIN(5,  6), PU4, 18 },        /* TX1_A */
-       { RCAR_GP_PIN(5,  5), PU4, 17 },        /* RX1_A */
-       { RCAR_GP_PIN(5,  4), PU4, 16 },        /* RTS0_N_TANS */
-       { RCAR_GP_PIN(5,  3), PU4, 15 },        /* CTS0_N */
-       { RCAR_GP_PIN(5,  2), PU4, 14 },        /* TX0 */
-       { RCAR_GP_PIN(5,  1), PU4, 13 },        /* RX0 */
-       { RCAR_GP_PIN(5,  0), PU4, 12 },        /* SCK0 */
-       { RCAR_GP_PIN(3, 15), PU4, 11 },        /* SD1_WP */
-       { RCAR_GP_PIN(3, 14), PU4, 10 },        /* SD1_CD */
-       { RCAR_GP_PIN(3, 13), PU4,  9 },        /* SD0_WP */
-       { RCAR_GP_PIN(3, 12), PU4,  8 },        /* SD0_CD */
-       { RCAR_GP_PIN(4, 17), PU4,  7 },        /* SD3_DS */
-       { RCAR_GP_PIN(4, 16), PU4,  6 },        /* SD3_DAT7 */
-       { RCAR_GP_PIN(4, 15), PU4,  5 },        /* SD3_DAT6 */
-       { RCAR_GP_PIN(4, 14), PU4,  4 },        /* SD3_DAT5 */
-       { RCAR_GP_PIN(4, 13), PU4,  3 },        /* SD3_DAT4 */
-       { RCAR_GP_PIN(4, 12), PU4,  2 },        /* SD3_DAT3 */
-       { RCAR_GP_PIN(4, 11), PU4,  1 },        /* SD3_DAT2 */
-       { RCAR_GP_PIN(4, 10), PU4,  0 },        /* SD3_DAT1 */
-
-       { RCAR_GP_PIN(6, 24), PU5, 31 },        /* USB0_PWEN */
-       { RCAR_GP_PIN(6, 23), PU5, 30 },        /* AUDIO_CLKB_B */
-       { RCAR_GP_PIN(6, 22), PU5, 29 },        /* AUDIO_CLKA_A */
-       { RCAR_GP_PIN(6, 21), PU5, 28 },        /* SSI_SDATA9_A */
-       { RCAR_GP_PIN(6, 20), PU5, 27 },        /* SSI_SDATA8 */
-       { RCAR_GP_PIN(6, 19), PU5, 26 },        /* SSI_SDATA7 */
-       { RCAR_GP_PIN(6, 18), PU5, 25 },        /* SSI_WS78 */
-       { RCAR_GP_PIN(6, 17), PU5, 24 },        /* SSI_SCK78 */
-       { RCAR_GP_PIN(6, 16), PU5, 23 },        /* SSI_SDATA6 */
-       { RCAR_GP_PIN(6, 15), PU5, 22 },        /* SSI_WS6 */
-       { RCAR_GP_PIN(6, 14), PU5, 21 },        /* SSI_SCK6 */
-       { RCAR_GP_PIN(6, 13), PU5, 20 },        /* SSI_SDATA5 */
-       { RCAR_GP_PIN(6, 12), PU5, 19 },        /* SSI_WS5 */
-       { RCAR_GP_PIN(6, 11), PU5, 18 },        /* SSI_SCK5 */
-       { RCAR_GP_PIN(6, 10), PU5, 17 },        /* SSI_SDATA4 */
-       { RCAR_GP_PIN(6,  9), PU5, 16 },        /* SSI_WS4 */
-       { RCAR_GP_PIN(6,  8), PU5, 15 },        /* SSI_SCK4 */
-       { RCAR_GP_PIN(6,  7), PU5, 14 },        /* SSI_SDATA3 */
-       { RCAR_GP_PIN(6,  6), PU5, 13 },        /* SSI_WS34 */
-       { RCAR_GP_PIN(6,  5), PU5, 12 },        /* SSI_SCK34 */
-       { RCAR_GP_PIN(6,  4), PU5, 11 },        /* SSI_SDATA2_A */
-       { RCAR_GP_PIN(6,  3), PU5, 10 },        /* SSI_SDATA1_A */
-       { RCAR_GP_PIN(6,  2), PU5,  9 },        /* SSI_SDATA0 */
-       { RCAR_GP_PIN(6,  1), PU5,  8 },        /* SSI_WS01239 */
-       { RCAR_GP_PIN(6,  0), PU5,  7 },        /* SSI_SCK01239 */
-       { RCAR_GP_PIN(5, 25), PU5,  5 },        /* MLB_DAT */
-       { RCAR_GP_PIN(5, 24), PU5,  4 },        /* MLB_SIG */
-       { RCAR_GP_PIN(5, 23), PU5,  3 },        /* MLB_CLK */
-       { RCAR_GP_PIN(5, 22), PU5,  2 },        /* MSIOF0_RXD */
-       { RCAR_GP_PIN(5, 21), PU5,  1 },        /* MSIOF0_SS2 */
-       { RCAR_GP_PIN(5, 20), PU5,  0 },        /* MSIOF0_TXD */
-
-       { RCAR_GP_PIN(6, 31), PU6,  6 },        /* USB31_OVC */
-       { RCAR_GP_PIN(6, 30), PU6,  5 },        /* USB31_PWEN */
-       { RCAR_GP_PIN(6, 29), PU6,  4 },        /* USB30_OVC */
-       { RCAR_GP_PIN(6, 28), PU6,  3 },        /* USB30_PWEN */
-       { RCAR_GP_PIN(6, 27), PU6,  2 },        /* USB1_OVC */
-       { RCAR_GP_PIN(6, 26), PU6,  1 },        /* USB1_PWEN */
-       { RCAR_GP_PIN(6, 25), PU6,  0 },        /* USB0_OVC */
+       { RCAR_GP_PIN(2, 11),    PU0, 31 },     /* AVB_PHY_INT */
+       { RCAR_GP_PIN(2, 10),    PU0, 30 },     /* AVB_MAGIC */
+       { RCAR_GP_PIN(2,  9),    PU0, 29 },     /* AVB_MDC */
+       { PIN_NUMBER('A', 9),    PU0, 28 },     /* AVB_MDIO */
+       { PIN_NUMBER('A', 12),   PU0, 27 },     /* AVB_TXCREFCLK */
+       { PIN_NUMBER('B', 17),   PU0, 26 },     /* AVB_TD3 */
+       { PIN_NUMBER('A', 17),   PU0, 25 },     /* AVB_TD2 */
+       { PIN_NUMBER('B', 18),   PU0, 24 },     /* AVB_TD1 */
+       { PIN_NUMBER('A', 18),   PU0, 23 },     /* AVB_TD0 */
+       { PIN_NUMBER('A', 19),   PU0, 22 },     /* AVB_TXC */
+       { PIN_NUMBER('A', 8),    PU0, 21 },     /* AVB_TX_CTL */
+       { PIN_NUMBER('B', 14),   PU0, 20 },     /* AVB_RD3 */
+       { PIN_NUMBER('A', 14),   PU0, 19 },     /* AVB_RD2 */
+       { PIN_NUMBER('B', 13),   PU0, 18 },     /* AVB_RD1 */
+       { PIN_NUMBER('A', 13),   PU0, 17 },     /* AVB_RD0 */
+       { PIN_NUMBER('B', 19),   PU0, 16 },     /* AVB_RXC */
+       { PIN_NUMBER('A', 16),   PU0, 15 },     /* AVB_RX_CTL */
+       { PIN_NUMBER('V', 7),    PU0, 14 },     /* RPC_RESET# */
+       { PIN_NUMBER('V', 6),    PU0, 13 },     /* RPC_WP# */
+       { PIN_NUMBER('Y', 7),    PU0, 12 },     /* RPC_INT# */
+       { PIN_NUMBER('V', 5),    PU0, 11 },     /* QSPI1_SSL */
+       { PIN_A_NUMBER('C', 3),  PU0, 10 },     /* QSPI1_IO3 */
+       { PIN_A_NUMBER('E', 4),  PU0,  9 },     /* QSPI1_IO2 */
+       { PIN_A_NUMBER('E', 5),  PU0,  8 },     /* QSPI1_MISO_IO1 */
+       { PIN_A_NUMBER('C', 7),  PU0,  7 },     /* QSPI1_MOSI_IO0 */
+       { PIN_NUMBER('V', 3),    PU0,  6 },     /* QSPI1_SPCLK */
+       { PIN_NUMBER('Y', 3),    PU0,  5 },     /* QSPI0_SSL */
+       { PIN_A_NUMBER('B', 6),  PU0,  4 },     /* QSPI0_IO3 */
+       { PIN_NUMBER('Y', 6),    PU0,  3 },     /* QSPI0_IO2 */
+       { PIN_A_NUMBER('B', 4),  PU0,  2 },     /* QSPI0_MISO_IO1 */
+       { PIN_A_NUMBER('C', 5),  PU0,  1 },     /* QSPI0_MOSI_IO0 */
+       { PIN_NUMBER('W', 3),    PU0,  0 },     /* QSPI0_SPCLK */
+
+       { RCAR_GP_PIN(1, 19),    PU1, 31 },     /* A19 */
+       { RCAR_GP_PIN(1, 18),    PU1, 30 },     /* A18 */
+       { RCAR_GP_PIN(1, 17),    PU1, 29 },     /* A17 */
+       { RCAR_GP_PIN(1, 16),    PU1, 28 },     /* A16 */
+       { RCAR_GP_PIN(1, 15),    PU1, 27 },     /* A15 */
+       { RCAR_GP_PIN(1, 14),    PU1, 26 },     /* A14 */
+       { RCAR_GP_PIN(1, 13),    PU1, 25 },     /* A13 */
+       { RCAR_GP_PIN(1, 12),    PU1, 24 },     /* A12 */
+       { RCAR_GP_PIN(1, 11),    PU1, 23 },     /* A11 */
+       { RCAR_GP_PIN(1, 10),    PU1, 22 },     /* A10 */
+       { RCAR_GP_PIN(1,  9),    PU1, 21 },     /* A9 */
+       { RCAR_GP_PIN(1,  8),    PU1, 20 },     /* A8 */
+       { RCAR_GP_PIN(1,  7),    PU1, 19 },     /* A7 */
+       { RCAR_GP_PIN(1,  6),    PU1, 18 },     /* A6 */
+       { RCAR_GP_PIN(1,  5),    PU1, 17 },     /* A5 */
+       { RCAR_GP_PIN(1,  4),    PU1, 16 },     /* A4 */
+       { RCAR_GP_PIN(1,  3),    PU1, 15 },     /* A3 */
+       { RCAR_GP_PIN(1,  2),    PU1, 14 },     /* A2 */
+       { RCAR_GP_PIN(1,  1),    PU1, 13 },     /* A1 */
+       { RCAR_GP_PIN(1,  0),    PU1, 12 },     /* A0 */
+       { RCAR_GP_PIN(2,  8),    PU1, 11 },     /* PWM2_A */
+       { RCAR_GP_PIN(2,  7),    PU1, 10 },     /* PWM1_A */
+       { RCAR_GP_PIN(2,  6),    PU1,  9 },     /* PWM0 */
+       { RCAR_GP_PIN(2,  5),    PU1,  8 },     /* IRQ5 */
+       { RCAR_GP_PIN(2,  4),    PU1,  7 },     /* IRQ4 */
+       { RCAR_GP_PIN(2,  3),    PU1,  6 },     /* IRQ3 */
+       { RCAR_GP_PIN(2,  2),    PU1,  5 },     /* IRQ2 */
+       { RCAR_GP_PIN(2,  1),    PU1,  4 },     /* IRQ1 */
+       { RCAR_GP_PIN(2,  0),    PU1,  3 },     /* IRQ0 */
+       { RCAR_GP_PIN(2, 14),    PU1,  2 },     /* AVB_AVTP_CAPTURE_A */
+       { RCAR_GP_PIN(2, 13),    PU1,  1 },     /* AVB_AVTP_MATCH_A */
+       { RCAR_GP_PIN(2, 12),    PU1,  0 },     /* AVB_LINK */
+
+       { PIN_A_NUMBER('P', 8),  PU2, 31 },     /* DU_DOTCLKIN1 */
+       { PIN_A_NUMBER('P', 7),  PU2, 30 },     /* DU_DOTCLKIN0 */
+       { RCAR_GP_PIN(7,  3),    PU2, 29 },     /* HDMI1_CEC */
+       { RCAR_GP_PIN(7,  2),    PU2, 28 },     /* HDMI0_CEC */
+       { RCAR_GP_PIN(7,  1),    PU2, 27 },     /* AVS2 */
+       { RCAR_GP_PIN(7,  0),    PU2, 26 },     /* AVS1 */
+       { RCAR_GP_PIN(0, 15),    PU2, 25 },     /* D15 */
+       { RCAR_GP_PIN(0, 14),    PU2, 24 },     /* D14 */
+       { RCAR_GP_PIN(0, 13),    PU2, 23 },     /* D13 */
+       { RCAR_GP_PIN(0, 12),    PU2, 22 },     /* D12 */
+       { RCAR_GP_PIN(0, 11),    PU2, 21 },     /* D11 */
+       { RCAR_GP_PIN(0, 10),    PU2, 20 },     /* D10 */
+       { RCAR_GP_PIN(0,  9),    PU2, 19 },     /* D9 */
+       { RCAR_GP_PIN(0,  8),    PU2, 18 },     /* D8 */
+       { RCAR_GP_PIN(0,  7),    PU2, 17 },     /* D7 */
+       { RCAR_GP_PIN(0,  6),    PU2, 16 },     /* D6 */
+       { RCAR_GP_PIN(0,  5),    PU2, 15 },     /* D5 */
+       { RCAR_GP_PIN(0,  4),    PU2, 14 },     /* D4 */
+       { RCAR_GP_PIN(0,  3),    PU2, 13 },     /* D3 */
+       { RCAR_GP_PIN(0,  2),    PU2, 12 },     /* D2 */
+       { RCAR_GP_PIN(0,  1),    PU2, 11 },     /* D1 */
+       { RCAR_GP_PIN(0,  0),    PU2, 10 },     /* D0 */
+       { PIN_NUMBER('C', 1),    PU2,  9 },     /* PRESETOUT# */
+       { RCAR_GP_PIN(1, 27),    PU2,  8 },     /* EX_WAIT0_A */
+       { RCAR_GP_PIN(1, 26),    PU2,  7 },     /* WE1_N */
+       { RCAR_GP_PIN(1, 25),    PU2,  6 },     /* WE0_N */
+       { RCAR_GP_PIN(1, 24),    PU2,  5 },     /* RD_WR_N */
+       { RCAR_GP_PIN(1, 23),    PU2,  4 },     /* RD_N */
+       { RCAR_GP_PIN(1, 22),    PU2,  3 },     /* BS_N */
+       { RCAR_GP_PIN(1, 21),    PU2,  2 },     /* CS1_N_A26 */
+       { RCAR_GP_PIN(1, 20),    PU2,  1 },     /* CS0_N */
+       { PIN_NUMBER('F', 1),    PU2,  0 },     /* CLKOUT */
+
+       { RCAR_GP_PIN(4,  9),    PU3, 31 },     /* SD3_DAT0 */
+       { RCAR_GP_PIN(4,  8),    PU3, 30 },     /* SD3_CMD */
+       { RCAR_GP_PIN(4,  7),    PU3, 29 },     /* SD3_CLK */
+       { RCAR_GP_PIN(4,  6),    PU3, 28 },     /* SD2_DS */
+       { RCAR_GP_PIN(4,  5),    PU3, 27 },     /* SD2_DAT3 */
+       { RCAR_GP_PIN(4,  4),    PU3, 26 },     /* SD2_DAT2 */
+       { RCAR_GP_PIN(4,  3),    PU3, 25 },     /* SD2_DAT1 */
+       { RCAR_GP_PIN(4,  2),    PU3, 24 },     /* SD2_DAT0 */
+       { RCAR_GP_PIN(4,  1),    PU3, 23 },     /* SD2_CMD */
+       { RCAR_GP_PIN(4,  0),    PU3, 22 },     /* SD2_CLK */
+       { RCAR_GP_PIN(3, 11),    PU3, 21 },     /* SD1_DAT3 */
+       { RCAR_GP_PIN(3, 10),    PU3, 20 },     /* SD1_DAT2 */
+       { RCAR_GP_PIN(3,  9),    PU3, 19 },     /* SD1_DAT1 */
+       { RCAR_GP_PIN(3,  8),    PU3, 18 },     /* SD1_DAT0 */
+       { RCAR_GP_PIN(3,  7),    PU3, 17 },     /* SD1_CMD */
+       { RCAR_GP_PIN(3,  6),    PU3, 16 },     /* SD1_CLK */
+       { RCAR_GP_PIN(3,  5),    PU3, 15 },     /* SD0_DAT3 */
+       { RCAR_GP_PIN(3,  4),    PU3, 14 },     /* SD0_DAT2 */
+       { RCAR_GP_PIN(3,  3),    PU3, 13 },     /* SD0_DAT1 */
+       { RCAR_GP_PIN(3,  2),    PU3, 12 },     /* SD0_DAT0 */
+       { RCAR_GP_PIN(3,  1),    PU3, 11 },     /* SD0_CMD */
+       { RCAR_GP_PIN(3,  0),    PU3, 10 },     /* SD0_CLK */
+       { PIN_A_NUMBER('T', 30), PU3,  9 },     /* ASEBRK */
+       /* bit 8 n/a */
+       { PIN_A_NUMBER('R', 29), PU3,  7 },     /* TDI */
+       { PIN_A_NUMBER('R', 30), PU3,  6 },     /* TMS */
+       { PIN_A_NUMBER('T', 27), PU3,  5 },     /* TCK */
+       { PIN_A_NUMBER('R', 26), PU3,  4 },     /* TRST# */
+       { PIN_A_NUMBER('D', 39), PU3,  3 },     /* EXTALR*/
+       { PIN_A_NUMBER('D', 38), PU3,  2 },     /* FSCLKST# */
+       { PIN_A_NUMBER('R', 8),  PU3,  1 },     /* DU_DOTCLKIN3 */
+       { PIN_A_NUMBER('R', 7),  PU3,  0 },     /* DU_DOTCLKIN2 */
+
+       { RCAR_GP_PIN(5, 19),    PU4, 31 },     /* MSIOF0_SS1 */
+       { RCAR_GP_PIN(5, 18),    PU4, 30 },     /* MSIOF0_SYNC */
+       { RCAR_GP_PIN(5, 17),    PU4, 29 },     /* MSIOF0_SCK */
+       { RCAR_GP_PIN(5, 16),    PU4, 28 },     /* HRTS0_N */
+       { RCAR_GP_PIN(5, 15),    PU4, 27 },     /* HCTS0_N */
+       { RCAR_GP_PIN(5, 14),    PU4, 26 },     /* HTX0 */
+       { RCAR_GP_PIN(5, 13),    PU4, 25 },     /* HRX0 */
+       { RCAR_GP_PIN(5, 12),    PU4, 24 },     /* HSCK0 */
+       { RCAR_GP_PIN(5, 11),    PU4, 23 },     /* RX2_A */
+       { RCAR_GP_PIN(5, 10),    PU4, 22 },     /* TX2_A */
+       { RCAR_GP_PIN(5,  9),    PU4, 21 },     /* SCK2 */
+       { RCAR_GP_PIN(5,  8),    PU4, 20 },     /* RTS1_N_TANS */
+       { RCAR_GP_PIN(5,  7),    PU4, 19 },     /* CTS1_N */
+       { RCAR_GP_PIN(5,  6),    PU4, 18 },     /* TX1_A */
+       { RCAR_GP_PIN(5,  5),    PU4, 17 },     /* RX1_A */
+       { RCAR_GP_PIN(5,  4),    PU4, 16 },     /* RTS0_N_TANS */
+       { RCAR_GP_PIN(5,  3),    PU4, 15 },     /* CTS0_N */
+       { RCAR_GP_PIN(5,  2),    PU4, 14 },     /* TX0 */
+       { RCAR_GP_PIN(5,  1),    PU4, 13 },     /* RX0 */
+       { RCAR_GP_PIN(5,  0),    PU4, 12 },     /* SCK0 */
+       { RCAR_GP_PIN(3, 15),    PU4, 11 },     /* SD1_WP */
+       { RCAR_GP_PIN(3, 14),    PU4, 10 },     /* SD1_CD */
+       { RCAR_GP_PIN(3, 13),    PU4,  9 },     /* SD0_WP */
+       { RCAR_GP_PIN(3, 12),    PU4,  8 },     /* SD0_CD */
+       { RCAR_GP_PIN(4, 17),    PU4,  7 },     /* SD3_DS */
+       { RCAR_GP_PIN(4, 16),    PU4,  6 },     /* SD3_DAT7 */
+       { RCAR_GP_PIN(4, 15),    PU4,  5 },     /* SD3_DAT6 */
+       { RCAR_GP_PIN(4, 14),    PU4,  4 },     /* SD3_DAT5 */
+       { RCAR_GP_PIN(4, 13),    PU4,  3 },     /* SD3_DAT4 */
+       { RCAR_GP_PIN(4, 12),    PU4,  2 },     /* SD3_DAT3 */
+       { RCAR_GP_PIN(4, 11),    PU4,  1 },     /* SD3_DAT2 */
+       { RCAR_GP_PIN(4, 10),    PU4,  0 },     /* SD3_DAT1 */
+
+       { RCAR_GP_PIN(6, 24),    PU5, 31 },     /* USB0_PWEN */
+       { RCAR_GP_PIN(6, 23),    PU5, 30 },     /* AUDIO_CLKB_B */
+       { RCAR_GP_PIN(6, 22),    PU5, 29 },     /* AUDIO_CLKA_A */
+       { RCAR_GP_PIN(6, 21),    PU5, 28 },     /* SSI_SDATA9_A */
+       { RCAR_GP_PIN(6, 20),    PU5, 27 },     /* SSI_SDATA8 */
+       { RCAR_GP_PIN(6, 19),    PU5, 26 },     /* SSI_SDATA7 */
+       { RCAR_GP_PIN(6, 18),    PU5, 25 },     /* SSI_WS78 */
+       { RCAR_GP_PIN(6, 17),    PU5, 24 },     /* SSI_SCK78 */
+       { RCAR_GP_PIN(6, 16),    PU5, 23 },     /* SSI_SDATA6 */
+       { RCAR_GP_PIN(6, 15),    PU5, 22 },     /* SSI_WS6 */
+       { RCAR_GP_PIN(6, 14),    PU5, 21 },     /* SSI_SCK6 */
+       { RCAR_GP_PIN(6, 13),    PU5, 20 },     /* SSI_SDATA5 */
+       { RCAR_GP_PIN(6, 12),    PU5, 19 },     /* SSI_WS5 */
+       { RCAR_GP_PIN(6, 11),    PU5, 18 },     /* SSI_SCK5 */
+       { RCAR_GP_PIN(6, 10),    PU5, 17 },     /* SSI_SDATA4 */
+       { RCAR_GP_PIN(6,  9),    PU5, 16 },     /* SSI_WS4 */
+       { RCAR_GP_PIN(6,  8),    PU5, 15 },     /* SSI_SCK4 */
+       { RCAR_GP_PIN(6,  7),    PU5, 14 },     /* SSI_SDATA3 */
+       { RCAR_GP_PIN(6,  6),    PU5, 13 },     /* SSI_WS34 */
+       { RCAR_GP_PIN(6,  5),    PU5, 12 },     /* SSI_SCK34 */
+       { RCAR_GP_PIN(6,  4),    PU5, 11 },     /* SSI_SDATA2_A */
+       { RCAR_GP_PIN(6,  3),    PU5, 10 },     /* SSI_SDATA1_A */
+       { RCAR_GP_PIN(6,  2),    PU5,  9 },     /* SSI_SDATA0 */
+       { RCAR_GP_PIN(6,  1),    PU5,  8 },     /* SSI_WS01239 */
+       { RCAR_GP_PIN(6,  0),    PU5,  7 },     /* SSI_SCK01239 */
+       { PIN_NUMBER('H', 37),   PU5,  6 },     /* MLB_REF */
+       { RCAR_GP_PIN(5, 25),    PU5,  5 },     /* MLB_DAT */
+       { RCAR_GP_PIN(5, 24),    PU5,  4 },     /* MLB_SIG */
+       { RCAR_GP_PIN(5, 23),    PU5,  3 },     /* MLB_CLK */
+       { RCAR_GP_PIN(5, 22),    PU5,  2 },     /* MSIOF0_RXD */
+       { RCAR_GP_PIN(5, 21),    PU5,  1 },     /* MSIOF0_SS2 */
+       { RCAR_GP_PIN(5, 20),    PU5,  0 },     /* MSIOF0_TXD */
+
+       { RCAR_GP_PIN(6, 31),    PU6,  6 },     /* USB31_OVC */
+       { RCAR_GP_PIN(6, 30),    PU6,  5 },     /* USB31_PWEN */
+       { RCAR_GP_PIN(6, 29),    PU6,  4 },     /* USB30_OVC */
+       { RCAR_GP_PIN(6, 28),    PU6,  3 },     /* USB30_PWEN */
+       { RCAR_GP_PIN(6, 27),    PU6,  2 },     /* USB1_OVC */
+       { RCAR_GP_PIN(6, 26),    PU6,  1 },     /* USB1_PWEN */
+       { RCAR_GP_PIN(6, 25),    PU6,  0 },     /* USB0_OVC */
 };
 
 static unsigned int r8a7795_pinmux_get_bias(struct sh_pfc *pfc,
index 7e16545a2c3c9db82d4f8777ecca5b733af9a21f..b0362ae707e2e59a11bdc938bddba72fd678f9aa 100644 (file)
 #include "core.h"
 #include "sh_pfc.h"
 
+#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | \
+                  SH_PFC_PIN_CFG_PULL_UP | \
+                  SH_PFC_PIN_CFG_PULL_DOWN)
+
 #define CPU_ALL_PORT(fn, sfx)                                          \
-       PORT_GP_16(0, fn, sfx),                                         \
-       PORT_GP_29(1, fn, sfx),                                         \
-       PORT_GP_15(2, fn, sfx),                                         \
-       PORT_GP_CFG_12(3, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE),          \
-       PORT_GP_1(3, 12, fn, sfx),                                      \
-       PORT_GP_1(3, 13, fn, sfx),                                      \
-       PORT_GP_1(3, 14, fn, sfx),                                      \
-       PORT_GP_1(3, 15, fn, sfx),                                      \
-       PORT_GP_CFG_18(4, fn, sfx, SH_PFC_PIN_CFG_IO_VOLTAGE),          \
-       PORT_GP_26(5, fn, sfx),                                         \
-       PORT_GP_32(6, fn, sfx),                                         \
-       PORT_GP_4(7, fn, sfx)
+       PORT_GP_CFG_16(0, fn, sfx, CFG_FLAGS),  \
+       PORT_GP_CFG_29(1, fn, sfx, CFG_FLAGS),  \
+       PORT_GP_CFG_15(2, fn, sfx, CFG_FLAGS),  \
+       PORT_GP_CFG_12(3, fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE),      \
+       PORT_GP_CFG_1(3, 12, fn, sfx, CFG_FLAGS),       \
+       PORT_GP_CFG_1(3, 13, fn, sfx, CFG_FLAGS),       \
+       PORT_GP_CFG_1(3, 14, fn, sfx, CFG_FLAGS),       \
+       PORT_GP_CFG_1(3, 15, fn, sfx, CFG_FLAGS),       \
+       PORT_GP_CFG_18(4, fn, sfx, CFG_FLAGS | SH_PFC_PIN_CFG_IO_VOLTAGE),      \
+       PORT_GP_CFG_26(5, fn, sfx, CFG_FLAGS),  \
+       PORT_GP_CFG_32(6, fn, sfx, CFG_FLAGS),  \
+       PORT_GP_CFG_4(7, fn, sfx, CFG_FLAGS)
 /*
  * F_() : just information
  * FM() : macro for FN_xxx / xxx_MARK
@@ -541,6 +545,23 @@ MOD_SEL0_2         MOD_SEL1_2 \
                        MOD_SEL1_1 \
                        MOD_SEL1_0              MOD_SEL2_0
 
+/*
+ * These pins are not able to be muxed but have other properties
+ * that can be set, such as drive-strength or pull-up/pull-down enable.
+ */
+#define PINMUX_STATIC \
+       FM(QSPI0_SPCLK) FM(QSPI0_SSL) FM(QSPI0_MOSI_IO0) FM(QSPI0_MISO_IO1) \
+       FM(QSPI0_IO2) FM(QSPI0_IO3) \
+       FM(QSPI1_SPCLK) FM(QSPI1_SSL) FM(QSPI1_MOSI_IO0) FM(QSPI1_MISO_IO1) \
+       FM(QSPI1_IO2) FM(QSPI1_IO3) \
+       FM(RPC_INT) FM(RPC_WP) FM(RPC_RESET) \
+       FM(AVB_TX_CTL) FM(AVB_TXC) FM(AVB_TD0) FM(AVB_TD1) FM(AVB_TD2) FM(AVB_TD3) \
+       FM(AVB_RX_CTL) FM(AVB_RXC) FM(AVB_RD0) FM(AVB_RD1) FM(AVB_RD2) FM(AVB_RD3) \
+       FM(AVB_TXCREFCLK) FM(AVB_MDIO) \
+       FM(PRESETOUT) \
+       FM(DU_DOTCLKIN0) FM(DU_DOTCLKIN1) FM(DU_DOTCLKIN2) \
+       FM(TMS) FM(TDO) FM(ASEBRK) FM(MLB_REF) FM(TDI) FM(TCK) FM(TRST) FM(EXTALR)
+
 enum {
        PINMUX_RESERVED = 0,
 
@@ -565,6 +586,7 @@ enum {
        PINMUX_GPSR
        PINMUX_IPSR
        PINMUX_MOD_SELS
+       PINMUX_STATIC
        PINMUX_MARK_END,
 #undef F_
 #undef FM
@@ -1484,10 +1506,80 @@ static const u16 pinmux_data[] = {
        PINMUX_IPSR_NOGP(0,             I2C_SEL_0_1),
        PINMUX_IPSR_NOGP(0,             I2C_SEL_3_1),
        PINMUX_IPSR_NOGP(0,             I2C_SEL_5_1),
+
+/*
+ * Static pins can not be muxed between different functions but
+ * still needs a mark entry in the pinmux list. Add each static
+ * pin to the list without an associated function. The sh-pfc
+ * core will do the right thing and skip trying to mux then pin
+ * while still applying configuration to it
+ */
+#define FM(x)   PINMUX_DATA(x##_MARK, 0),
+       PINMUX_STATIC
+#undef FM
 };
 
+/*
+ * R8A7796 has 8 banks with 32 GPIOs in each => 256 GPIOs.
+ * Physical layout rows: A - AW, cols: 1 - 39.
+ */
+#define ROW_GROUP_A(r) ('Z' - 'A' + 1 + (r))
+#define PIN_NUMBER(r, c) (((r) - 'A') * 39 + (c) + 300)
+#define PIN_A_NUMBER(r, c) PIN_NUMBER(ROW_GROUP_A(r), c)
+
 static const struct sh_pfc_pin pinmux_pins[] = {
        PINMUX_GPIO_GP_ALL(),
+
+       /*
+        * Pins not associated with a GPIO port.
+        *
+        * The pin positions are different between different r8a7796
+        * packages, all that is needed for the pfc driver is a unique
+        * number for each pin. To this end use the pin layout from
+        * R-Car M3SiP to calculate a unique number for each pin.
+        */
+       SH_PFC_PIN_NAMED_CFG('A',  8, AVB_TX_CTL, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('A',  9, AVB_MDIO, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('A', 12, AVB_TXCREFCLK, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('A', 13, AVB_RD0, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('A', 14, AVB_RD2, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('A', 16, AVB_RX_CTL, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('A', 17, AVB_TD2, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('A', 18, AVB_TD0, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('A', 19, AVB_TXC, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('B', 13, AVB_RD1, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('B', 14, AVB_RD3, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('B', 17, AVB_TD3, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('B', 18, AVB_TD1, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('B', 19, AVB_RXC, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('C',  1, PRESETOUT#, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('H', 37, MLB_REF, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('V',  3, QSPI1_SPCLK, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('V',  5, QSPI1_SSL, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('V',  6, RPC_WP#, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('V',  7, RPC_RESET#, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('W',  3, QSPI0_SPCLK, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('Y',  3, QSPI0_SSL, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('Y',  6, QSPI0_IO2, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG('Y',  7, RPC_INT#, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'),  4, QSPI0_MISO_IO1, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('B'),  6, QSPI0_IO3, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'),  3, QSPI1_IO3, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'),  5, QSPI0_MOSI_IO0, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('C'),  7, QSPI1_MOSI_IO0, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 38, FSCLKST, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('D'), 39, EXTALR, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'),  4, QSPI1_IO2, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('E'),  5, QSPI1_MISO_IO1, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'),  7, DU_DOTCLKIN0, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('P'),  8, DU_DOTCLKIN1, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'),  8, DU_DOTCLKIN2, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 26, TRST#, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 29, TDI, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('R'), 30, TMS, CFG_FLAGS),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 27, TCK, SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 28, TDO, SH_PFC_PIN_CFG_DRIVE_STRENGTH),
+       SH_PFC_PIN_NAMED_CFG(ROW_GROUP_A('T'), 30, ASEBRK, CFG_FLAGS),
 };
 
 /* - EtherAVB --------------------------------------------------------------- */
@@ -1555,6 +1647,61 @@ static const unsigned int avb_avtp_capture_b_mux[] = {
        AVB_AVTP_CAPTURE_B_MARK,
 };
 
+/* - CAN ------------------------------------------------------------------ */
+static const unsigned int can0_data_a_pins[] = {
+       /* TX, RX */
+       RCAR_GP_PIN(1, 23),     RCAR_GP_PIN(1, 24),
+};
+static const unsigned int can0_data_a_mux[] = {
+       CAN0_TX_A_MARK,         CAN0_RX_A_MARK,
+};
+static const unsigned int can0_data_b_pins[] = {
+       /* TX, RX */
+       RCAR_GP_PIN(2, 0),      RCAR_GP_PIN(2, 1),
+};
+static const unsigned int can0_data_b_mux[] = {
+       CAN0_TX_B_MARK,         CAN0_RX_B_MARK,
+};
+static const unsigned int can1_data_pins[] = {
+       /* TX, RX */
+       RCAR_GP_PIN(1, 22),     RCAR_GP_PIN(1, 26),
+};
+static const unsigned int can1_data_mux[] = {
+       CAN1_TX_MARK,           CAN1_RX_MARK,
+};
+
+/* - CAN Clock -------------------------------------------------------------- */
+static const unsigned int can_clk_pins[] = {
+       /* CLK */
+       RCAR_GP_PIN(1, 25),
+};
+static const unsigned int can_clk_mux[] = {
+       CAN_CLK_MARK,
+};
+
+/* - CAN FD --------------------------------------------------------------- */
+static const unsigned int canfd0_data_a_pins[] = {
+       /* TX, RX */
+       RCAR_GP_PIN(1, 23),     RCAR_GP_PIN(1, 24),
+};
+static const unsigned int canfd0_data_a_mux[] = {
+       CANFD0_TX_A_MARK,       CANFD0_RX_A_MARK,
+};
+static const unsigned int canfd0_data_b_pins[] = {
+       /* TX, RX */
+       RCAR_GP_PIN(2, 0),      RCAR_GP_PIN(2, 1),
+};
+static const unsigned int canfd0_data_b_mux[] = {
+       CANFD0_TX_B_MARK,       CANFD0_RX_B_MARK,
+};
+static const unsigned int canfd1_data_pins[] = {
+       /* TX, RX */
+       RCAR_GP_PIN(1, 22),     RCAR_GP_PIN(1, 26),
+};
+static const unsigned int canfd1_data_mux[] = {
+       CANFD1_TX_MARK,         CANFD1_RX_MARK,
+};
+
 /* - DRIF0 --------------------------------------------------------------- */
 static const unsigned int drif0_ctrl_a_pins[] = {
        /* CLK, SYNC */
@@ -1851,6 +1998,213 @@ static const unsigned int du_disp_mux[] = {
        DU_DISP_MARK,
 };
 
+/* - HSCIF0 ----------------------------------------------------------------- */
+static const unsigned int hscif0_data_pins[] = {
+       /* RX, TX */
+       RCAR_GP_PIN(5, 13), RCAR_GP_PIN(5, 14),
+};
+static const unsigned int hscif0_data_mux[] = {
+       HRX0_MARK, HTX0_MARK,
+};
+static const unsigned int hscif0_clk_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(5, 12),
+};
+static const unsigned int hscif0_clk_mux[] = {
+       HSCK0_MARK,
+};
+static const unsigned int hscif0_ctrl_pins[] = {
+       /* RTS, CTS */
+       RCAR_GP_PIN(5, 16), RCAR_GP_PIN(5, 15),
+};
+static const unsigned int hscif0_ctrl_mux[] = {
+       HRTS0_N_MARK, HCTS0_N_MARK,
+};
+/* - HSCIF1 ----------------------------------------------------------------- */
+static const unsigned int hscif1_data_a_pins[] = {
+       /* RX, TX */
+       RCAR_GP_PIN(5, 5), RCAR_GP_PIN(5, 6),
+};
+static const unsigned int hscif1_data_a_mux[] = {
+       HRX1_A_MARK, HTX1_A_MARK,
+};
+static const unsigned int hscif1_clk_a_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(6, 21),
+};
+static const unsigned int hscif1_clk_a_mux[] = {
+       HSCK1_A_MARK,
+};
+static const unsigned int hscif1_ctrl_a_pins[] = {
+       /* RTS, CTS */
+       RCAR_GP_PIN(5, 8), RCAR_GP_PIN(5, 7),
+};
+static const unsigned int hscif1_ctrl_a_mux[] = {
+       HRTS1_N_A_MARK, HCTS1_N_A_MARK,
+};
+
+static const unsigned int hscif1_data_b_pins[] = {
+       /* RX, TX */
+       RCAR_GP_PIN(5, 1), RCAR_GP_PIN(5, 2),
+};
+static const unsigned int hscif1_data_b_mux[] = {
+       HRX1_B_MARK, HTX1_B_MARK,
+};
+static const unsigned int hscif1_clk_b_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(5, 0),
+};
+static const unsigned int hscif1_clk_b_mux[] = {
+       HSCK1_B_MARK,
+};
+static const unsigned int hscif1_ctrl_b_pins[] = {
+       /* RTS, CTS */
+       RCAR_GP_PIN(5, 4), RCAR_GP_PIN(5, 3),
+};
+static const unsigned int hscif1_ctrl_b_mux[] = {
+       HRTS1_N_B_MARK, HCTS1_N_B_MARK,
+};
+/* - HSCIF2 ----------------------------------------------------------------- */
+static const unsigned int hscif2_data_a_pins[] = {
+       /* RX, TX */
+       RCAR_GP_PIN(6, 8), RCAR_GP_PIN(6, 9),
+};
+static const unsigned int hscif2_data_a_mux[] = {
+       HRX2_A_MARK, HTX2_A_MARK,
+};
+static const unsigned int hscif2_clk_a_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(6, 10),
+};
+static const unsigned int hscif2_clk_a_mux[] = {
+       HSCK2_A_MARK,
+};
+static const unsigned int hscif2_ctrl_a_pins[] = {
+       /* RTS, CTS */
+       RCAR_GP_PIN(6, 7), RCAR_GP_PIN(6, 6),
+};
+static const unsigned int hscif2_ctrl_a_mux[] = {
+       HRTS2_N_A_MARK, HCTS2_N_A_MARK,
+};
+
+static const unsigned int hscif2_data_b_pins[] = {
+       /* RX, TX */
+       RCAR_GP_PIN(6, 17), RCAR_GP_PIN(6, 18),
+};
+static const unsigned int hscif2_data_b_mux[] = {
+       HRX2_B_MARK, HTX2_B_MARK,
+};
+static const unsigned int hscif2_clk_b_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(6, 21),
+};
+static const unsigned int hscif2_clk_b_mux[] = {
+       HSCK2_B_MARK,
+};
+static const unsigned int hscif2_ctrl_b_pins[] = {
+       /* RTS, CTS */
+       RCAR_GP_PIN(6, 20), RCAR_GP_PIN(6, 19),
+};
+static const unsigned int hscif2_ctrl_b_mux[] = {
+       HRTS2_N_B_MARK, HCTS2_N_B_MARK,
+};
+
+static const unsigned int hscif2_data_c_pins[] = {
+       /* RX, TX */
+       RCAR_GP_PIN(6, 25), RCAR_GP_PIN(6, 26),
+};
+static const unsigned int hscif2_data_c_mux[] = {
+       HRX2_C_MARK, HTX2_C_MARK,
+};
+static const unsigned int hscif2_clk_c_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(6, 24),
+};
+static const unsigned int hscif2_clk_c_mux[] = {
+       HSCK2_C_MARK,
+};
+static const unsigned int hscif2_ctrl_c_pins[] = {
+       /* RTS, CTS */
+       RCAR_GP_PIN(6, 28), RCAR_GP_PIN(6, 27),
+};
+static const unsigned int hscif2_ctrl_c_mux[] = {
+       HRTS2_N_C_MARK, HCTS2_N_C_MARK,
+};
+/* - HSCIF3 ----------------------------------------------------------------- */
+static const unsigned int hscif3_data_a_pins[] = {
+       /* RX, TX */
+       RCAR_GP_PIN(1, 23), RCAR_GP_PIN(1, 24),
+};
+static const unsigned int hscif3_data_a_mux[] = {
+       HRX3_A_MARK, HTX3_A_MARK,
+};
+static const unsigned int hscif3_clk_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(1, 22),
+};
+static const unsigned int hscif3_clk_mux[] = {
+       HSCK3_MARK,
+};
+static const unsigned int hscif3_ctrl_pins[] = {
+       /* RTS, CTS */
+       RCAR_GP_PIN(1, 26), RCAR_GP_PIN(1, 25),
+};
+static const unsigned int hscif3_ctrl_mux[] = {
+       HRTS3_N_MARK, HCTS3_N_MARK,
+};
+
+static const unsigned int hscif3_data_b_pins[] = {
+       /* RX, TX */
+       RCAR_GP_PIN(0, 10), RCAR_GP_PIN(0, 11),
+};
+static const unsigned int hscif3_data_b_mux[] = {
+       HRX3_B_MARK, HTX3_B_MARK,
+};
+static const unsigned int hscif3_data_c_pins[] = {
+       /* RX, TX */
+       RCAR_GP_PIN(0, 14), RCAR_GP_PIN(0, 15),
+};
+static const unsigned int hscif3_data_c_mux[] = {
+       HRX3_C_MARK, HTX3_C_MARK,
+};
+static const unsigned int hscif3_data_d_pins[] = {
+       /* RX, TX */
+       RCAR_GP_PIN(2, 7), RCAR_GP_PIN(2, 8),
+};
+static const unsigned int hscif3_data_d_mux[] = {
+       HRX3_D_MARK, HTX3_D_MARK,
+};
+/* - HSCIF4 ----------------------------------------------------------------- */
+static const unsigned int hscif4_data_a_pins[] = {
+       /* RX, TX */
+       RCAR_GP_PIN(1, 12), RCAR_GP_PIN(1, 13),
+};
+static const unsigned int hscif4_data_a_mux[] = {
+       HRX4_A_MARK, HTX4_A_MARK,
+};
+static const unsigned int hscif4_clk_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(1, 11),
+};
+static const unsigned int hscif4_clk_mux[] = {
+       HSCK4_MARK,
+};
+static const unsigned int hscif4_ctrl_pins[] = {
+       /* RTS, CTS */
+       RCAR_GP_PIN(1, 15), RCAR_GP_PIN(1, 14),
+};
+static const unsigned int hscif4_ctrl_mux[] = {
+       HRTS4_N_MARK, HCTS4_N_MARK,
+};
+
+static const unsigned int hscif4_data_b_pins[] = {
+       /* RX, TX */
+       RCAR_GP_PIN(1, 8), RCAR_GP_PIN(1, 11),
+};
+static const unsigned int hscif4_data_b_mux[] = {
+       HRX4_B_MARK, HTX4_B_MARK,
+};
+
 /* - I2C -------------------------------------------------------------------- */
 static const unsigned int i2c1_a_pins[] = {
        /* SDA, SCL */
@@ -1902,6 +2256,705 @@ static const unsigned int i2c6_c_mux[] = {
        SDA6_C_MARK, SCL6_C_MARK,
 };
 
+/* - MSIOF0 ----------------------------------------------------------------- */
+static const unsigned int msiof0_clk_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(5, 17),
+};
+static const unsigned int msiof0_clk_mux[] = {
+       MSIOF0_SCK_MARK,
+};
+static const unsigned int msiof0_sync_pins[] = {
+       /* SYNC */
+       RCAR_GP_PIN(5, 18),
+};
+static const unsigned int msiof0_sync_mux[] = {
+       MSIOF0_SYNC_MARK,
+};
+static const unsigned int msiof0_ss1_pins[] = {
+       /* SS1 */
+       RCAR_GP_PIN(5, 19),
+};
+static const unsigned int msiof0_ss1_mux[] = {
+       MSIOF0_SS1_MARK,
+};
+static const unsigned int msiof0_ss2_pins[] = {
+       /* SS2 */
+       RCAR_GP_PIN(5, 21),
+};
+static const unsigned int msiof0_ss2_mux[] = {
+       MSIOF0_SS2_MARK,
+};
+static const unsigned int msiof0_txd_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(5, 20),
+};
+static const unsigned int msiof0_txd_mux[] = {
+       MSIOF0_TXD_MARK,
+};
+static const unsigned int msiof0_rxd_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(5, 22),
+};
+static const unsigned int msiof0_rxd_mux[] = {
+       MSIOF0_RXD_MARK,
+};
+/* - MSIOF1 ----------------------------------------------------------------- */
+static const unsigned int msiof1_clk_a_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(6, 8),
+};
+static const unsigned int msiof1_clk_a_mux[] = {
+       MSIOF1_SCK_A_MARK,
+};
+static const unsigned int msiof1_sync_a_pins[] = {
+       /* SYNC */
+       RCAR_GP_PIN(6, 9),
+};
+static const unsigned int msiof1_sync_a_mux[] = {
+       MSIOF1_SYNC_A_MARK,
+};
+static const unsigned int msiof1_ss1_a_pins[] = {
+       /* SS1 */
+       RCAR_GP_PIN(6, 5),
+};
+static const unsigned int msiof1_ss1_a_mux[] = {
+       MSIOF1_SS1_A_MARK,
+};
+static const unsigned int msiof1_ss2_a_pins[] = {
+       /* SS2 */
+       RCAR_GP_PIN(6, 6),
+};
+static const unsigned int msiof1_ss2_a_mux[] = {
+       MSIOF1_SS2_A_MARK,
+};
+static const unsigned int msiof1_txd_a_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(6, 7),
+};
+static const unsigned int msiof1_txd_a_mux[] = {
+       MSIOF1_TXD_A_MARK,
+};
+static const unsigned int msiof1_rxd_a_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(6, 10),
+};
+static const unsigned int msiof1_rxd_a_mux[] = {
+       MSIOF1_RXD_A_MARK,
+};
+static const unsigned int msiof1_clk_b_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(5, 9),
+};
+static const unsigned int msiof1_clk_b_mux[] = {
+       MSIOF1_SCK_B_MARK,
+};
+static const unsigned int msiof1_sync_b_pins[] = {
+       /* SYNC */
+       RCAR_GP_PIN(5, 3),
+};
+static const unsigned int msiof1_sync_b_mux[] = {
+       MSIOF1_SYNC_B_MARK,
+};
+static const unsigned int msiof1_ss1_b_pins[] = {
+       /* SS1 */
+       RCAR_GP_PIN(5, 4),
+};
+static const unsigned int msiof1_ss1_b_mux[] = {
+       MSIOF1_SS1_B_MARK,
+};
+static const unsigned int msiof1_ss2_b_pins[] = {
+       /* SS2 */
+       RCAR_GP_PIN(5, 0),
+};
+static const unsigned int msiof1_ss2_b_mux[] = {
+       MSIOF1_SS2_B_MARK,
+};
+static const unsigned int msiof1_txd_b_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(5, 8),
+};
+static const unsigned int msiof1_txd_b_mux[] = {
+       MSIOF1_TXD_B_MARK,
+};
+static const unsigned int msiof1_rxd_b_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(5, 7),
+};
+static const unsigned int msiof1_rxd_b_mux[] = {
+       MSIOF1_RXD_B_MARK,
+};
+static const unsigned int msiof1_clk_c_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(6, 17),
+};
+static const unsigned int msiof1_clk_c_mux[] = {
+       MSIOF1_SCK_C_MARK,
+};
+static const unsigned int msiof1_sync_c_pins[] = {
+       /* SYNC */
+       RCAR_GP_PIN(6, 18),
+};
+static const unsigned int msiof1_sync_c_mux[] = {
+       MSIOF1_SYNC_C_MARK,
+};
+static const unsigned int msiof1_ss1_c_pins[] = {
+       /* SS1 */
+       RCAR_GP_PIN(6, 21),
+};
+static const unsigned int msiof1_ss1_c_mux[] = {
+       MSIOF1_SS1_C_MARK,
+};
+static const unsigned int msiof1_ss2_c_pins[] = {
+       /* SS2 */
+       RCAR_GP_PIN(6, 27),
+};
+static const unsigned int msiof1_ss2_c_mux[] = {
+       MSIOF1_SS2_C_MARK,
+};
+static const unsigned int msiof1_txd_c_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(6, 20),
+};
+static const unsigned int msiof1_txd_c_mux[] = {
+       MSIOF1_TXD_C_MARK,
+};
+static const unsigned int msiof1_rxd_c_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(6, 19),
+};
+static const unsigned int msiof1_rxd_c_mux[] = {
+       MSIOF1_RXD_C_MARK,
+};
+static const unsigned int msiof1_clk_d_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(5, 12),
+};
+static const unsigned int msiof1_clk_d_mux[] = {
+       MSIOF1_SCK_D_MARK,
+};
+static const unsigned int msiof1_sync_d_pins[] = {
+       /* SYNC */
+       RCAR_GP_PIN(5, 15),
+};
+static const unsigned int msiof1_sync_d_mux[] = {
+       MSIOF1_SYNC_D_MARK,
+};
+static const unsigned int msiof1_ss1_d_pins[] = {
+       /* SS1 */
+       RCAR_GP_PIN(5, 16),
+};
+static const unsigned int msiof1_ss1_d_mux[] = {
+       MSIOF1_SS1_D_MARK,
+};
+static const unsigned int msiof1_ss2_d_pins[] = {
+       /* SS2 */
+       RCAR_GP_PIN(5, 21),
+};
+static const unsigned int msiof1_ss2_d_mux[] = {
+       MSIOF1_SS2_D_MARK,
+};
+static const unsigned int msiof1_txd_d_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(5, 14),
+};
+static const unsigned int msiof1_txd_d_mux[] = {
+       MSIOF1_TXD_D_MARK,
+};
+static const unsigned int msiof1_rxd_d_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(5, 13),
+};
+static const unsigned int msiof1_rxd_d_mux[] = {
+       MSIOF1_RXD_D_MARK,
+};
+static const unsigned int msiof1_clk_e_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(3, 0),
+};
+static const unsigned int msiof1_clk_e_mux[] = {
+       MSIOF1_SCK_E_MARK,
+};
+static const unsigned int msiof1_sync_e_pins[] = {
+       /* SYNC */
+       RCAR_GP_PIN(3, 1),
+};
+static const unsigned int msiof1_sync_e_mux[] = {
+       MSIOF1_SYNC_E_MARK,
+};
+static const unsigned int msiof1_ss1_e_pins[] = {
+       /* SS1 */
+       RCAR_GP_PIN(3, 4),
+};
+static const unsigned int msiof1_ss1_e_mux[] = {
+       MSIOF1_SS1_E_MARK,
+};
+static const unsigned int msiof1_ss2_e_pins[] = {
+       /* SS2 */
+       RCAR_GP_PIN(3, 5),
+};
+static const unsigned int msiof1_ss2_e_mux[] = {
+       MSIOF1_SS2_E_MARK,
+};
+static const unsigned int msiof1_txd_e_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(3, 3),
+};
+static const unsigned int msiof1_txd_e_mux[] = {
+       MSIOF1_TXD_E_MARK,
+};
+static const unsigned int msiof1_rxd_e_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(3, 2),
+};
+static const unsigned int msiof1_rxd_e_mux[] = {
+       MSIOF1_RXD_E_MARK,
+};
+static const unsigned int msiof1_clk_f_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(5, 23),
+};
+static const unsigned int msiof1_clk_f_mux[] = {
+       MSIOF1_SCK_F_MARK,
+};
+static const unsigned int msiof1_sync_f_pins[] = {
+       /* SYNC */
+       RCAR_GP_PIN(5, 24),
+};
+static const unsigned int msiof1_sync_f_mux[] = {
+       MSIOF1_SYNC_F_MARK,
+};
+static const unsigned int msiof1_ss1_f_pins[] = {
+       /* SS1 */
+       RCAR_GP_PIN(6, 1),
+};
+static const unsigned int msiof1_ss1_f_mux[] = {
+       MSIOF1_SS1_F_MARK,
+};
+static const unsigned int msiof1_ss2_f_pins[] = {
+       /* SS2 */
+       RCAR_GP_PIN(6, 2),
+};
+static const unsigned int msiof1_ss2_f_mux[] = {
+       MSIOF1_SS2_F_MARK,
+};
+static const unsigned int msiof1_txd_f_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(6, 0),
+};
+static const unsigned int msiof1_txd_f_mux[] = {
+       MSIOF1_TXD_F_MARK,
+};
+static const unsigned int msiof1_rxd_f_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(5, 25),
+};
+static const unsigned int msiof1_rxd_f_mux[] = {
+       MSIOF1_RXD_F_MARK,
+};
+static const unsigned int msiof1_clk_g_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(3, 6),
+};
+static const unsigned int msiof1_clk_g_mux[] = {
+       MSIOF1_SCK_G_MARK,
+};
+static const unsigned int msiof1_sync_g_pins[] = {
+       /* SYNC */
+       RCAR_GP_PIN(3, 7),
+};
+static const unsigned int msiof1_sync_g_mux[] = {
+       MSIOF1_SYNC_G_MARK,
+};
+static const unsigned int msiof1_ss1_g_pins[] = {
+       /* SS1 */
+       RCAR_GP_PIN(3, 10),
+};
+static const unsigned int msiof1_ss1_g_mux[] = {
+       MSIOF1_SS1_G_MARK,
+};
+static const unsigned int msiof1_ss2_g_pins[] = {
+       /* SS2 */
+       RCAR_GP_PIN(3, 11),
+};
+static const unsigned int msiof1_ss2_g_mux[] = {
+       MSIOF1_SS2_G_MARK,
+};
+static const unsigned int msiof1_txd_g_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(3, 9),
+};
+static const unsigned int msiof1_txd_g_mux[] = {
+       MSIOF1_TXD_G_MARK,
+};
+static const unsigned int msiof1_rxd_g_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(3, 8),
+};
+static const unsigned int msiof1_rxd_g_mux[] = {
+       MSIOF1_RXD_G_MARK,
+};
+/* - MSIOF2 ----------------------------------------------------------------- */
+static const unsigned int msiof2_clk_a_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(1, 9),
+};
+static const unsigned int msiof2_clk_a_mux[] = {
+       MSIOF2_SCK_A_MARK,
+};
+static const unsigned int msiof2_sync_a_pins[] = {
+       /* SYNC */
+       RCAR_GP_PIN(1, 8),
+};
+static const unsigned int msiof2_sync_a_mux[] = {
+       MSIOF2_SYNC_A_MARK,
+};
+static const unsigned int msiof2_ss1_a_pins[] = {
+       /* SS1 */
+       RCAR_GP_PIN(1, 6),
+};
+static const unsigned int msiof2_ss1_a_mux[] = {
+       MSIOF2_SS1_A_MARK,
+};
+static const unsigned int msiof2_ss2_a_pins[] = {
+       /* SS2 */
+       RCAR_GP_PIN(1, 7),
+};
+static const unsigned int msiof2_ss2_a_mux[] = {
+       MSIOF2_SS2_A_MARK,
+};
+static const unsigned int msiof2_txd_a_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(1, 11),
+};
+static const unsigned int msiof2_txd_a_mux[] = {
+       MSIOF2_TXD_A_MARK,
+};
+static const unsigned int msiof2_rxd_a_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(1, 10),
+};
+static const unsigned int msiof2_rxd_a_mux[] = {
+       MSIOF2_RXD_A_MARK,
+};
+static const unsigned int msiof2_clk_b_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(0, 4),
+};
+static const unsigned int msiof2_clk_b_mux[] = {
+       MSIOF2_SCK_B_MARK,
+};
+static const unsigned int msiof2_sync_b_pins[] = {
+       /* SYNC */
+       RCAR_GP_PIN(0, 5),
+};
+static const unsigned int msiof2_sync_b_mux[] = {
+       MSIOF2_SYNC_B_MARK,
+};
+static const unsigned int msiof2_ss1_b_pins[] = {
+       /* SS1 */
+       RCAR_GP_PIN(0, 0),
+};
+static const unsigned int msiof2_ss1_b_mux[] = {
+       MSIOF2_SS1_B_MARK,
+};
+static const unsigned int msiof2_ss2_b_pins[] = {
+       /* SS2 */
+       RCAR_GP_PIN(0, 1),
+};
+static const unsigned int msiof2_ss2_b_mux[] = {
+       MSIOF2_SS2_B_MARK,
+};
+static const unsigned int msiof2_txd_b_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(0, 7),
+};
+static const unsigned int msiof2_txd_b_mux[] = {
+       MSIOF2_TXD_B_MARK,
+};
+static const unsigned int msiof2_rxd_b_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(0, 6),
+};
+static const unsigned int msiof2_rxd_b_mux[] = {
+       MSIOF2_RXD_B_MARK,
+};
+static const unsigned int msiof2_clk_c_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(2, 12),
+};
+static const unsigned int msiof2_clk_c_mux[] = {
+       MSIOF2_SCK_C_MARK,
+};
+static const unsigned int msiof2_sync_c_pins[] = {
+       /* SYNC */
+       RCAR_GP_PIN(2, 11),
+};
+static const unsigned int msiof2_sync_c_mux[] = {
+       MSIOF2_SYNC_C_MARK,
+};
+static const unsigned int msiof2_ss1_c_pins[] = {
+       /* SS1 */
+       RCAR_GP_PIN(2, 10),
+};
+static const unsigned int msiof2_ss1_c_mux[] = {
+       MSIOF2_SS1_C_MARK,
+};
+static const unsigned int msiof2_ss2_c_pins[] = {
+       /* SS2 */
+       RCAR_GP_PIN(2, 9),
+};
+static const unsigned int msiof2_ss2_c_mux[] = {
+       MSIOF2_SS2_C_MARK,
+};
+static const unsigned int msiof2_txd_c_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(2, 14),
+};
+static const unsigned int msiof2_txd_c_mux[] = {
+       MSIOF2_TXD_C_MARK,
+};
+static const unsigned int msiof2_rxd_c_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(2, 13),
+};
+static const unsigned int msiof2_rxd_c_mux[] = {
+       MSIOF2_RXD_C_MARK,
+};
+static const unsigned int msiof2_clk_d_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(0, 8),
+};
+static const unsigned int msiof2_clk_d_mux[] = {
+       MSIOF2_SCK_D_MARK,
+};
+static const unsigned int msiof2_sync_d_pins[] = {
+       /* SYNC */
+       RCAR_GP_PIN(0, 9),
+};
+static const unsigned int msiof2_sync_d_mux[] = {
+       MSIOF2_SYNC_D_MARK,
+};
+static const unsigned int msiof2_ss1_d_pins[] = {
+       /* SS1 */
+       RCAR_GP_PIN(0, 12),
+};
+static const unsigned int msiof2_ss1_d_mux[] = {
+       MSIOF2_SS1_D_MARK,
+};
+static const unsigned int msiof2_ss2_d_pins[] = {
+       /* SS2 */
+       RCAR_GP_PIN(0, 13),
+};
+static const unsigned int msiof2_ss2_d_mux[] = {
+       MSIOF2_SS2_D_MARK,
+};
+static const unsigned int msiof2_txd_d_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(0, 11),
+};
+static const unsigned int msiof2_txd_d_mux[] = {
+       MSIOF2_TXD_D_MARK,
+};
+static const unsigned int msiof2_rxd_d_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(0, 10),
+};
+static const unsigned int msiof2_rxd_d_mux[] = {
+       MSIOF2_RXD_D_MARK,
+};
+/* - MSIOF3 ----------------------------------------------------------------- */
+static const unsigned int msiof3_clk_a_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(0, 0),
+};
+static const unsigned int msiof3_clk_a_mux[] = {
+       MSIOF3_SCK_A_MARK,
+};
+static const unsigned int msiof3_sync_a_pins[] = {
+       /* SYNC */
+       RCAR_GP_PIN(0, 1),
+};
+static const unsigned int msiof3_sync_a_mux[] = {
+       MSIOF3_SYNC_A_MARK,
+};
+static const unsigned int msiof3_ss1_a_pins[] = {
+       /* SS1 */
+       RCAR_GP_PIN(0, 14),
+};
+static const unsigned int msiof3_ss1_a_mux[] = {
+       MSIOF3_SS1_A_MARK,
+};
+static const unsigned int msiof3_ss2_a_pins[] = {
+       /* SS2 */
+       RCAR_GP_PIN(0, 15),
+};
+static const unsigned int msiof3_ss2_a_mux[] = {
+       MSIOF3_SS2_A_MARK,
+};
+static const unsigned int msiof3_txd_a_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(0, 3),
+};
+static const unsigned int msiof3_txd_a_mux[] = {
+       MSIOF3_TXD_A_MARK,
+};
+static const unsigned int msiof3_rxd_a_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(0, 2),
+};
+static const unsigned int msiof3_rxd_a_mux[] = {
+       MSIOF3_RXD_A_MARK,
+};
+static const unsigned int msiof3_clk_b_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(1, 2),
+};
+static const unsigned int msiof3_clk_b_mux[] = {
+       MSIOF3_SCK_B_MARK,
+};
+static const unsigned int msiof3_sync_b_pins[] = {
+       /* SYNC */
+       RCAR_GP_PIN(1, 0),
+};
+static const unsigned int msiof3_sync_b_mux[] = {
+       MSIOF3_SYNC_B_MARK,
+};
+static const unsigned int msiof3_ss1_b_pins[] = {
+       /* SS1 */
+       RCAR_GP_PIN(1, 4),
+};
+static const unsigned int msiof3_ss1_b_mux[] = {
+       MSIOF3_SS1_B_MARK,
+};
+static const unsigned int msiof3_ss2_b_pins[] = {
+       /* SS2 */
+       RCAR_GP_PIN(1, 5),
+};
+static const unsigned int msiof3_ss2_b_mux[] = {
+       MSIOF3_SS2_B_MARK,
+};
+static const unsigned int msiof3_txd_b_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(1, 1),
+};
+static const unsigned int msiof3_txd_b_mux[] = {
+       MSIOF3_TXD_B_MARK,
+};
+static const unsigned int msiof3_rxd_b_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(1, 3),
+};
+static const unsigned int msiof3_rxd_b_mux[] = {
+       MSIOF3_RXD_B_MARK,
+};
+static const unsigned int msiof3_clk_c_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(1, 12),
+};
+static const unsigned int msiof3_clk_c_mux[] = {
+       MSIOF3_SCK_C_MARK,
+};
+static const unsigned int msiof3_sync_c_pins[] = {
+       /* SYNC */
+       RCAR_GP_PIN(1, 13),
+};
+static const unsigned int msiof3_sync_c_mux[] = {
+       MSIOF3_SYNC_C_MARK,
+};
+static const unsigned int msiof3_txd_c_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(1, 15),
+};
+static const unsigned int msiof3_txd_c_mux[] = {
+       MSIOF3_TXD_C_MARK,
+};
+static const unsigned int msiof3_rxd_c_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(1, 14),
+};
+static const unsigned int msiof3_rxd_c_mux[] = {
+       MSIOF3_RXD_C_MARK,
+};
+static const unsigned int msiof3_clk_d_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(1, 22),
+};
+static const unsigned int msiof3_clk_d_mux[] = {
+       MSIOF3_SCK_D_MARK,
+};
+static const unsigned int msiof3_sync_d_pins[] = {
+       /* SYNC */
+       RCAR_GP_PIN(1, 23),
+};
+static const unsigned int msiof3_sync_d_mux[] = {
+       MSIOF3_SYNC_D_MARK,
+};
+static const unsigned int msiof3_ss1_d_pins[] = {
+       /* SS1 */
+       RCAR_GP_PIN(1, 26),
+};
+static const unsigned int msiof3_ss1_d_mux[] = {
+       MSIOF3_SS1_D_MARK,
+};
+static const unsigned int msiof3_txd_d_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(1, 25),
+};
+static const unsigned int msiof3_txd_d_mux[] = {
+       MSIOF3_TXD_D_MARK,
+};
+static const unsigned int msiof3_rxd_d_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(1, 24),
+};
+static const unsigned int msiof3_rxd_d_mux[] = {
+       MSIOF3_RXD_D_MARK,
+};
+
+static const unsigned int msiof3_clk_e_pins[] = {
+       /* SCK */
+       RCAR_GP_PIN(2, 3),
+};
+static const unsigned int msiof3_clk_e_mux[] = {
+       MSIOF3_SCK_E_MARK,
+};
+static const unsigned int msiof3_sync_e_pins[] = {
+       /* SYNC */
+       RCAR_GP_PIN(2, 2),
+};
+static const unsigned int msiof3_sync_e_mux[] = {
+       MSIOF3_SYNC_E_MARK,
+};
+static const unsigned int msiof3_ss1_e_pins[] = {
+       /* SS1 */
+       RCAR_GP_PIN(2, 1),
+};
+static const unsigned int msiof3_ss1_e_mux[] = {
+       MSIOF3_SS1_E_MARK,
+};
+static const unsigned int msiof3_ss2_e_pins[] = {
+       /* SS1 */
+       RCAR_GP_PIN(2, 0),
+};
+static const unsigned int msiof3_ss2_e_mux[] = {
+       MSIOF3_SS1_E_MARK,
+};
+static const unsigned int msiof3_txd_e_pins[] = {
+       /* TXD */
+       RCAR_GP_PIN(2, 5),
+};
+static const unsigned int msiof3_txd_e_mux[] = {
+       MSIOF3_TXD_E_MARK,
+};
+static const unsigned int msiof3_rxd_e_pins[] = {
+       /* RXD */
+       RCAR_GP_PIN(2, 4),
+};
+static const unsigned int msiof3_rxd_e_mux[] = {
+       MSIOF3_RXD_E_MARK,
+};
+
 /* - SCIF0 ------------------------------------------------------------------ */
 static const unsigned int scif0_data_pins[] = {
        /* RX, TX */
@@ -2333,6 +3386,13 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
        SH_PFC_PIN_GROUP(avb_avtp_capture_a),
        SH_PFC_PIN_GROUP(avb_avtp_match_b),
        SH_PFC_PIN_GROUP(avb_avtp_capture_b),
+       SH_PFC_PIN_GROUP(can0_data_a),
+       SH_PFC_PIN_GROUP(can0_data_b),
+       SH_PFC_PIN_GROUP(can1_data),
+       SH_PFC_PIN_GROUP(can_clk),
+       SH_PFC_PIN_GROUP(canfd0_data_a),
+       SH_PFC_PIN_GROUP(canfd0_data_b),
+       SH_PFC_PIN_GROUP(canfd1_data),
        SH_PFC_PIN_GROUP(drif0_ctrl_a),
        SH_PFC_PIN_GROUP(drif0_data0_a),
        SH_PFC_PIN_GROUP(drif0_data1_a),
@@ -2371,6 +3431,34 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
        SH_PFC_PIN_GROUP(du_oddf),
        SH_PFC_PIN_GROUP(du_cde),
        SH_PFC_PIN_GROUP(du_disp),
+       SH_PFC_PIN_GROUP(hscif0_data),
+       SH_PFC_PIN_GROUP(hscif0_clk),
+       SH_PFC_PIN_GROUP(hscif0_ctrl),
+       SH_PFC_PIN_GROUP(hscif1_data_a),
+       SH_PFC_PIN_GROUP(hscif1_clk_a),
+       SH_PFC_PIN_GROUP(hscif1_ctrl_a),
+       SH_PFC_PIN_GROUP(hscif1_data_b),
+       SH_PFC_PIN_GROUP(hscif1_clk_b),
+       SH_PFC_PIN_GROUP(hscif1_ctrl_b),
+       SH_PFC_PIN_GROUP(hscif2_data_a),
+       SH_PFC_PIN_GROUP(hscif2_clk_a),
+       SH_PFC_PIN_GROUP(hscif2_ctrl_a),
+       SH_PFC_PIN_GROUP(hscif2_data_b),
+       SH_PFC_PIN_GROUP(hscif2_clk_b),
+       SH_PFC_PIN_GROUP(hscif2_ctrl_b),
+       SH_PFC_PIN_GROUP(hscif2_data_c),
+       SH_PFC_PIN_GROUP(hscif2_clk_c),
+       SH_PFC_PIN_GROUP(hscif2_ctrl_c),
+       SH_PFC_PIN_GROUP(hscif3_data_a),
+       SH_PFC_PIN_GROUP(hscif3_clk),
+       SH_PFC_PIN_GROUP(hscif3_ctrl),
+       SH_PFC_PIN_GROUP(hscif3_data_b),
+       SH_PFC_PIN_GROUP(hscif3_data_c),
+       SH_PFC_PIN_GROUP(hscif3_data_d),
+       SH_PFC_PIN_GROUP(hscif4_data_a),
+       SH_PFC_PIN_GROUP(hscif4_clk),
+       SH_PFC_PIN_GROUP(hscif4_ctrl),
+       SH_PFC_PIN_GROUP(hscif4_data_b),
        SH_PFC_PIN_GROUP(i2c1_a),
        SH_PFC_PIN_GROUP(i2c1_b),
        SH_PFC_PIN_GROUP(i2c2_a),
@@ -2378,6 +3466,105 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
        SH_PFC_PIN_GROUP(i2c6_a),
        SH_PFC_PIN_GROUP(i2c6_b),
        SH_PFC_PIN_GROUP(i2c6_c),
+       SH_PFC_PIN_GROUP(msiof0_clk),
+       SH_PFC_PIN_GROUP(msiof0_sync),
+       SH_PFC_PIN_GROUP(msiof0_ss1),
+       SH_PFC_PIN_GROUP(msiof0_ss2),
+       SH_PFC_PIN_GROUP(msiof0_txd),
+       SH_PFC_PIN_GROUP(msiof0_rxd),
+       SH_PFC_PIN_GROUP(msiof1_clk_a),
+       SH_PFC_PIN_GROUP(msiof1_sync_a),
+       SH_PFC_PIN_GROUP(msiof1_ss1_a),
+       SH_PFC_PIN_GROUP(msiof1_ss2_a),
+       SH_PFC_PIN_GROUP(msiof1_txd_a),
+       SH_PFC_PIN_GROUP(msiof1_rxd_a),
+       SH_PFC_PIN_GROUP(msiof1_clk_b),
+       SH_PFC_PIN_GROUP(msiof1_sync_b),
+       SH_PFC_PIN_GROUP(msiof1_ss1_b),
+       SH_PFC_PIN_GROUP(msiof1_ss2_b),
+       SH_PFC_PIN_GROUP(msiof1_txd_b),
+       SH_PFC_PIN_GROUP(msiof1_rxd_b),
+       SH_PFC_PIN_GROUP(msiof1_clk_c),
+       SH_PFC_PIN_GROUP(msiof1_sync_c),
+       SH_PFC_PIN_GROUP(msiof1_ss1_c),
+       SH_PFC_PIN_GROUP(msiof1_ss2_c),
+       SH_PFC_PIN_GROUP(msiof1_txd_c),
+       SH_PFC_PIN_GROUP(msiof1_rxd_c),
+       SH_PFC_PIN_GROUP(msiof1_clk_d),
+       SH_PFC_PIN_GROUP(msiof1_sync_d),
+       SH_PFC_PIN_GROUP(msiof1_ss1_d),
+       SH_PFC_PIN_GROUP(msiof1_ss2_d),
+       SH_PFC_PIN_GROUP(msiof1_txd_d),
+       SH_PFC_PIN_GROUP(msiof1_rxd_d),
+       SH_PFC_PIN_GROUP(msiof1_clk_e),
+       SH_PFC_PIN_GROUP(msiof1_sync_e),
+       SH_PFC_PIN_GROUP(msiof1_ss1_e),
+       SH_PFC_PIN_GROUP(msiof1_ss2_e),
+       SH_PFC_PIN_GROUP(msiof1_txd_e),
+       SH_PFC_PIN_GROUP(msiof1_rxd_e),
+       SH_PFC_PIN_GROUP(msiof1_clk_f),
+       SH_PFC_PIN_GROUP(msiof1_sync_f),
+       SH_PFC_PIN_GROUP(msiof1_ss1_f),
+       SH_PFC_PIN_GROUP(msiof1_ss2_f),
+       SH_PFC_PIN_GROUP(msiof1_txd_f),
+       SH_PFC_PIN_GROUP(msiof1_rxd_f),
+       SH_PFC_PIN_GROUP(msiof1_clk_g),
+       SH_PFC_PIN_GROUP(msiof1_sync_g),
+       SH_PFC_PIN_GROUP(msiof1_ss1_g),
+       SH_PFC_PIN_GROUP(msiof1_ss2_g),
+       SH_PFC_PIN_GROUP(msiof1_txd_g),
+       SH_PFC_PIN_GROUP(msiof1_rxd_g),
+       SH_PFC_PIN_GROUP(msiof2_clk_a),
+       SH_PFC_PIN_GROUP(msiof2_sync_a),
+       SH_PFC_PIN_GROUP(msiof2_ss1_a),
+       SH_PFC_PIN_GROUP(msiof2_ss2_a),
+       SH_PFC_PIN_GROUP(msiof2_txd_a),
+       SH_PFC_PIN_GROUP(msiof2_rxd_a),
+       SH_PFC_PIN_GROUP(msiof2_clk_b),
+       SH_PFC_PIN_GROUP(msiof2_sync_b),
+       SH_PFC_PIN_GROUP(msiof2_ss1_b),
+       SH_PFC_PIN_GROUP(msiof2_ss2_b),
+       SH_PFC_PIN_GROUP(msiof2_txd_b),
+       SH_PFC_PIN_GROUP(msiof2_rxd_b),
+       SH_PFC_PIN_GROUP(msiof2_clk_c),
+       SH_PFC_PIN_GROUP(msiof2_sync_c),
+       SH_PFC_PIN_GROUP(msiof2_ss1_c),
+       SH_PFC_PIN_GROUP(msiof2_ss2_c),
+       SH_PFC_PIN_GROUP(msiof2_txd_c),
+       SH_PFC_PIN_GROUP(msiof2_rxd_c),
+       SH_PFC_PIN_GROUP(msiof2_clk_d),
+       SH_PFC_PIN_GROUP(msiof2_sync_d),
+       SH_PFC_PIN_GROUP(msiof2_ss1_d),
+       SH_PFC_PIN_GROUP(msiof2_ss2_d),
+       SH_PFC_PIN_GROUP(msiof2_txd_d),
+       SH_PFC_PIN_GROUP(msiof2_rxd_d),
+       SH_PFC_PIN_GROUP(msiof3_clk_a),
+       SH_PFC_PIN_GROUP(msiof3_sync_a),
+       SH_PFC_PIN_GROUP(msiof3_ss1_a),
+       SH_PFC_PIN_GROUP(msiof3_ss2_a),
+       SH_PFC_PIN_GROUP(msiof3_txd_a),
+       SH_PFC_PIN_GROUP(msiof3_rxd_a),
+       SH_PFC_PIN_GROUP(msiof3_clk_b),
+       SH_PFC_PIN_GROUP(msiof3_sync_b),
+       SH_PFC_PIN_GROUP(msiof3_ss1_b),
+       SH_PFC_PIN_GROUP(msiof3_ss2_b),
+       SH_PFC_PIN_GROUP(msiof3_txd_b),
+       SH_PFC_PIN_GROUP(msiof3_rxd_b),
+       SH_PFC_PIN_GROUP(msiof3_clk_c),
+       SH_PFC_PIN_GROUP(msiof3_sync_c),
+       SH_PFC_PIN_GROUP(msiof3_txd_c),
+       SH_PFC_PIN_GROUP(msiof3_rxd_c),
+       SH_PFC_PIN_GROUP(msiof3_clk_d),
+       SH_PFC_PIN_GROUP(msiof3_sync_d),
+       SH_PFC_PIN_GROUP(msiof3_ss1_d),
+       SH_PFC_PIN_GROUP(msiof3_txd_d),
+       SH_PFC_PIN_GROUP(msiof3_rxd_d),
+       SH_PFC_PIN_GROUP(msiof3_clk_e),
+       SH_PFC_PIN_GROUP(msiof3_sync_e),
+       SH_PFC_PIN_GROUP(msiof3_ss1_e),
+       SH_PFC_PIN_GROUP(msiof3_ss2_e),
+       SH_PFC_PIN_GROUP(msiof3_txd_e),
+       SH_PFC_PIN_GROUP(msiof3_rxd_e),
        SH_PFC_PIN_GROUP(scif0_data),
        SH_PFC_PIN_GROUP(scif0_clk),
        SH_PFC_PIN_GROUP(scif0_ctrl),
@@ -2447,6 +3634,28 @@ static const char * const avb_groups[] = {
        "avb_avtp_capture_b",
 };
 
+static const char * const can0_groups[] = {
+       "can0_data_a",
+       "can0_data_b",
+};
+
+static const char * const can1_groups[] = {
+       "can1_data",
+};
+
+static const char * const can_clk_groups[] = {
+       "can_clk",
+};
+
+static const char * const canfd0_groups[] = {
+       "canfd0_data_a",
+       "canfd0_data_b",
+};
+
+static const char * const canfd1_groups[] = {
+       "canfd1_data",
+};
+
 static const char * const drif0_groups[] = {
        "drif0_ctrl_a",
        "drif0_data0_a",
@@ -2500,6 +3709,49 @@ static const char * const du_groups[] = {
        "du_disp",
 };
 
+static const char * const hscif0_groups[] = {
+       "hscif0_data",
+       "hscif0_clk",
+       "hscif0_ctrl",
+};
+
+static const char * const hscif1_groups[] = {
+       "hscif1_data_a",
+       "hscif1_clk_a",
+       "hscif1_ctrl_a",
+       "hscif1_data_b",
+       "hscif1_clk_b",
+       "hscif1_ctrl_b",
+};
+
+static const char * const hscif2_groups[] = {
+       "hscif2_data_a",
+       "hscif2_clk_a",
+       "hscif2_ctrl_a",
+       "hscif2_data_b",
+       "hscif2_clk_b",
+       "hscif2_ctrl_b",
+       "hscif2_data_c",
+       "hscif2_clk_c",
+       "hscif2_ctrl_c",
+};
+
+static const char * const hscif3_groups[] = {
+       "hscif3_data_a",
+       "hscif3_clk",
+       "hscif3_ctrl",
+       "hscif3_data_b",
+       "hscif3_data_c",
+       "hscif3_data_d",
+};
+
+static const char * const hscif4_groups[] = {
+       "hscif4_data_a",
+       "hscif4_clk",
+       "hscif4_ctrl",
+       "hscif4_data_b",
+};
+
 static const char * const i2c1_groups[] = {
        "i2c1_a",
        "i2c1_b",
@@ -2516,6 +3768,117 @@ static const char * const i2c6_groups[] = {
        "i2c6_c",
 };
 
+static const char * const msiof0_groups[] = {
+       "msiof0_clk",
+       "msiof0_sync",
+       "msiof0_ss1",
+       "msiof0_ss2",
+       "msiof0_txd",
+       "msiof0_rxd",
+};
+
+static const char * const msiof1_groups[] = {
+       "msiof1_clk_a",
+       "msiof1_sync_a",
+       "msiof1_ss1_a",
+       "msiof1_ss2_a",
+       "msiof1_txd_a",
+       "msiof1_rxd_a",
+       "msiof1_clk_b",
+       "msiof1_sync_b",
+       "msiof1_ss1_b",
+       "msiof1_ss2_b",
+       "msiof1_txd_b",
+       "msiof1_rxd_b",
+       "msiof1_clk_c",
+       "msiof1_sync_c",
+       "msiof1_ss1_c",
+       "msiof1_ss2_c",
+       "msiof1_txd_c",
+       "msiof1_rxd_c",
+       "msiof1_clk_d",
+       "msiof1_sync_d",
+       "msiof1_ss1_d",
+       "msiof1_ss2_d",
+       "msiof1_txd_d",
+       "msiof1_rxd_d",
+       "msiof1_clk_e",
+       "msiof1_sync_e",
+       "msiof1_ss1_e",
+       "msiof1_ss2_e",
+       "msiof1_txd_e",
+       "msiof1_rxd_e",
+       "msiof1_clk_f",
+       "msiof1_sync_f",
+       "msiof1_ss1_f",
+       "msiof1_ss2_f",
+       "msiof1_txd_f",
+       "msiof1_rxd_f",
+       "msiof1_clk_g",
+       "msiof1_sync_g",
+       "msiof1_ss1_g",
+       "msiof1_ss2_g",
+       "msiof1_txd_g",
+       "msiof1_rxd_g",
+};
+
+static const char * const msiof2_groups[] = {
+       "msiof2_clk_a",
+       "msiof2_sync_a",
+       "msiof2_ss1_a",
+       "msiof2_ss2_a",
+       "msiof2_txd_a",
+       "msiof2_rxd_a",
+       "msiof2_clk_b",
+       "msiof2_sync_b",
+       "msiof2_ss1_b",
+       "msiof2_ss2_b",
+       "msiof2_txd_b",
+       "msiof2_rxd_b",
+       "msiof2_clk_c",
+       "msiof2_sync_c",
+       "msiof2_ss1_c",
+       "msiof2_ss2_c",
+       "msiof2_txd_c",
+       "msiof2_rxd_c",
+       "msiof2_clk_d",
+       "msiof2_sync_d",
+       "msiof2_ss1_d",
+       "msiof2_ss2_d",
+       "msiof2_txd_d",
+       "msiof2_rxd_d",
+};
+
+static const char * const msiof3_groups[] = {
+       "msiof3_clk_a",
+       "msiof3_sync_a",
+       "msiof3_ss1_a",
+       "msiof3_ss2_a",
+       "msiof3_txd_a",
+       "msiof3_rxd_a",
+       "msiof3_clk_b",
+       "msiof3_sync_b",
+       "msiof3_ss1_b",
+       "msiof3_ss2_b",
+       "msiof3_txd_b",
+       "msiof3_rxd_b",
+       "msiof3_clk_c",
+       "msiof3_sync_c",
+       "msiof3_txd_c",
+       "msiof3_rxd_c",
+       "msiof3_clk_d",
+       "msiof3_sync_d",
+       "msiof3_ss1_d",
+       "msiof3_txd_d",
+       "msiof3_rxd_d",
+       "msiof3_clk_e",
+       "msiof3_sync_e",
+       "msiof3_ss1_e",
+       "msiof3_ss2_e",
+       "msiof3_txd_e",
+       "msiof3_rxd_e",
+};
+
 static const char * const scif0_groups[] = {
        "scif0_data",
        "scif0_clk",
@@ -2606,14 +3969,28 @@ static const char * const sdhi3_groups[] = {
 
 static const struct sh_pfc_function pinmux_functions[] = {
        SH_PFC_FUNCTION(avb),
+       SH_PFC_FUNCTION(can0),
+       SH_PFC_FUNCTION(can1),
+       SH_PFC_FUNCTION(can_clk),
+       SH_PFC_FUNCTION(canfd0),
+       SH_PFC_FUNCTION(canfd1),
        SH_PFC_FUNCTION(drif0),
        SH_PFC_FUNCTION(drif1),
        SH_PFC_FUNCTION(drif2),
        SH_PFC_FUNCTION(drif3),
        SH_PFC_FUNCTION(du),
+       SH_PFC_FUNCTION(hscif0),
+       SH_PFC_FUNCTION(hscif1),
+       SH_PFC_FUNCTION(hscif2),
+       SH_PFC_FUNCTION(hscif3),
+       SH_PFC_FUNCTION(hscif4),
        SH_PFC_FUNCTION(i2c1),
        SH_PFC_FUNCTION(i2c2),
        SH_PFC_FUNCTION(i2c6),
+       SH_PFC_FUNCTION(msiof0),
+       SH_PFC_FUNCTION(msiof1),
+       SH_PFC_FUNCTION(msiof2),
+       SH_PFC_FUNCTION(msiof3),
        SH_PFC_FUNCTION(scif0),
        SH_PFC_FUNCTION(scif1),
        SH_PFC_FUNCTION(scif2),
@@ -3187,6 +4564,254 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
        { },
 };
 
+static const struct pinmux_drive_reg pinmux_drive_regs[] = {
+       { PINMUX_DRIVE_REG("DRVCTRL0", 0xe6060300) {
+               { PIN_NUMBER('W', 3),   28, 2 },        /* QSPI0_SPCLK */
+               { PIN_A_NUMBER('C', 5), 24, 2 },        /* QSPI0_MOSI_IO0 */
+               { PIN_A_NUMBER('B', 4), 20, 2 },        /* QSPI0_MISO_IO1 */
+               { PIN_NUMBER('Y', 6),   16, 2 },        /* QSPI0_IO2 */
+               { PIN_A_NUMBER('B', 6), 12, 2 },        /* QSPI0_IO3 */
+               { PIN_NUMBER('Y', 3),    8, 2 },        /* QSPI0_SSL */
+               { PIN_NUMBER('V', 3),    4, 2 },        /* QSPI1_SPCLK */
+               { PIN_A_NUMBER('C', 7),  0, 2 },        /* QSPI1_MOSI_IO0 */
+       } },
+       { PINMUX_DRIVE_REG("DRVCTRL1", 0xe6060304) {
+               { PIN_A_NUMBER('E', 5), 28, 2 },        /* QSPI1_MISO_IO1 */
+               { PIN_A_NUMBER('E', 4), 24, 2 },        /* QSPI1_IO2 */
+               { PIN_A_NUMBER('C', 3), 20, 2 },        /* QSPI1_IO3 */
+               { PIN_NUMBER('V', 5),   16, 2 },        /* QSPI1_SSL */
+               { PIN_NUMBER('Y', 7),   12, 2 },        /* RPC_INT# */
+               { PIN_NUMBER('V', 6),    8, 2 },        /* RPC_WP# */
+               { PIN_NUMBER('V', 7),    4, 2 },        /* RPC_RESET# */
+               { PIN_NUMBER('A', 16),   0, 3 },        /* AVB_RX_CTL */
+       } },
+       { PINMUX_DRIVE_REG("DRVCTRL2", 0xe6060308) {
+               { PIN_NUMBER('B', 19),  28, 3 },        /* AVB_RXC */
+               { PIN_NUMBER('A', 13),  24, 3 },        /* AVB_RD0 */
+               { PIN_NUMBER('B', 13),  20, 3 },        /* AVB_RD1 */
+               { PIN_NUMBER('A', 14),  16, 3 },        /* AVB_RD2 */
+               { PIN_NUMBER('B', 14),  12, 3 },        /* AVB_RD3 */
+               { PIN_NUMBER('A', 8),    8, 3 },        /* AVB_TX_CTL */
+               { PIN_NUMBER('A', 19),   4, 3 },        /* AVB_TXC */
+               { PIN_NUMBER('A', 18),   0, 3 },        /* AVB_TD0 */
+       } },
+       { PINMUX_DRIVE_REG("DRVCTRL3", 0xe606030c) {
+               { PIN_NUMBER('B', 18),  28, 3 },        /* AVB_TD1 */
+               { PIN_NUMBER('A', 17),  24, 3 },        /* AVB_TD2 */
+               { PIN_NUMBER('B', 17),  20, 3 },        /* AVB_TD3 */
+               { PIN_NUMBER('A', 12),  16, 3 },        /* AVB_TXCREFCLK */
+               { PIN_NUMBER('A', 9),   12, 3 },        /* AVB_MDIO */
+               { RCAR_GP_PIN(2,  9),    8, 3 },        /* AVB_MDC */
+               { RCAR_GP_PIN(2, 10),    4, 3 },        /* AVB_MAGIC */
+               { RCAR_GP_PIN(2, 11),    0, 3 },        /* AVB_PHY_INT */
+       } },
+       { PINMUX_DRIVE_REG("DRVCTRL4", 0xe6060310) {
+               { RCAR_GP_PIN(2, 12), 28, 3 },  /* AVB_LINK */
+               { RCAR_GP_PIN(2, 13), 24, 3 },  /* AVB_AVTP_MATCH */
+               { RCAR_GP_PIN(2, 14), 20, 3 },  /* AVB_AVTP_CAPTURE */
+               { RCAR_GP_PIN(2,  0), 16, 3 },  /* IRQ0 */
+               { RCAR_GP_PIN(2,  1), 12, 3 },  /* IRQ1 */
+               { RCAR_GP_PIN(2,  2),  8, 3 },  /* IRQ2 */
+               { RCAR_GP_PIN(2,  3),  4, 3 },  /* IRQ3 */
+               { RCAR_GP_PIN(2,  4),  0, 3 },  /* IRQ4 */
+       } },
+       { PINMUX_DRIVE_REG("DRVCTRL5", 0xe6060314) {
+               { RCAR_GP_PIN(2,  5), 28, 3 },  /* IRQ5 */
+               { RCAR_GP_PIN(2,  6), 24, 3 },  /* PWM0 */
+               { RCAR_GP_PIN(2,  7), 20, 3 },  /* PWM1 */
+               { RCAR_GP_PIN(2,  8), 16, 3 },  /* PWM2 */
+               { RCAR_GP_PIN(1,  0), 12, 3 },  /* A0 */
+               { RCAR_GP_PIN(1,  1),  8, 3 },  /* A1 */
+               { RCAR_GP_PIN(1,  2),  4, 3 },  /* A2 */
+               { RCAR_GP_PIN(1,  3),  0, 3 },  /* A3 */
+       } },
+       { PINMUX_DRIVE_REG("DRVCTRL6", 0xe6060318) {
+               { RCAR_GP_PIN(1,  4), 28, 3 },  /* A4 */
+               { RCAR_GP_PIN(1,  5), 24, 3 },  /* A5 */
+               { RCAR_GP_PIN(1,  6), 20, 3 },  /* A6 */
+               { RCAR_GP_PIN(1,  7), 16, 3 },  /* A7 */
+               { RCAR_GP_PIN(1,  8), 12, 3 },  /* A8 */
+               { RCAR_GP_PIN(1,  9),  8, 3 },  /* A9 */
+               { RCAR_GP_PIN(1, 10),  4, 3 },  /* A10 */
+               { RCAR_GP_PIN(1, 11),  0, 3 },  /* A11 */
+       } },
+       { PINMUX_DRIVE_REG("DRVCTRL7", 0xe606031c) {
+               { RCAR_GP_PIN(1, 12), 28, 3 },  /* A12 */
+               { RCAR_GP_PIN(1, 13), 24, 3 },  /* A13 */
+               { RCAR_GP_PIN(1, 14), 20, 3 },  /* A14 */
+               { RCAR_GP_PIN(1, 15), 16, 3 },  /* A15 */
+               { RCAR_GP_PIN(1, 16), 12, 3 },  /* A16 */
+               { RCAR_GP_PIN(1, 17),  8, 3 },  /* A17 */
+               { RCAR_GP_PIN(1, 18),  4, 3 },  /* A18 */
+               { RCAR_GP_PIN(1, 19),  0, 3 },  /* A19 */
+       } },
+       { PINMUX_DRIVE_REG("DRVCTRL8", 0xe6060320) {
+               { RCAR_GP_PIN(1, 28), 28, 3 },  /* CLKOUT */
+               { RCAR_GP_PIN(1, 20), 24, 3 },  /* CS0 */
+               { RCAR_GP_PIN(1, 21), 20, 3 },  /* CS1_A26 */
+               { RCAR_GP_PIN(1, 22), 16, 3 },  /* BS */
+               { RCAR_GP_PIN(1, 23), 12, 3 },  /* RD */
+               { RCAR_GP_PIN(1, 24),  8, 3 },  /* RD_WR */
+               { RCAR_GP_PIN(1, 25),  4, 3 },  /* WE0 */
+               { RCAR_GP_PIN(1, 26),  0, 3 },  /* WE1 */
+       } },
+       { PINMUX_DRIVE_REG("DRVCTRL9", 0xe6060324) {
+               { RCAR_GP_PIN(1, 27), 28, 3 },  /* EX_WAIT0 */
+               { PIN_NUMBER('C', 1), 24, 3 },  /* PRESETOUT# */
+               { RCAR_GP_PIN(0,  0), 20, 3 },  /* D0 */
+               { RCAR_GP_PIN(0,  1), 16, 3 },  /* D1 */
+               { RCAR_GP_PIN(0,  2), 12, 3 },  /* D2 */
+               { RCAR_GP_PIN(0,  3),  8, 3 },  /* D3 */
+               { RCAR_GP_PIN(0,  4),  4, 3 },  /* D4 */
+               { RCAR_GP_PIN(0,  5),  0, 3 },  /* D5 */
+       } },
+       { PINMUX_DRIVE_REG("DRVCTRL10", 0xe6060328) {
+               { RCAR_GP_PIN(0,  6), 28, 3 },  /* D6 */
+               { RCAR_GP_PIN(0,  7), 24, 3 },  /* D7 */
+               { RCAR_GP_PIN(0,  8), 20, 3 },  /* D8 */
+               { RCAR_GP_PIN(0,  9), 16, 3 },  /* D9 */
+               { RCAR_GP_PIN(0, 10), 12, 3 },  /* D10 */
+               { RCAR_GP_PIN(0, 11),  8, 3 },  /* D11 */
+               { RCAR_GP_PIN(0, 12),  4, 3 },  /* D12 */
+               { RCAR_GP_PIN(0, 13),  0, 3 },  /* D13 */
+       } },
+       { PINMUX_DRIVE_REG("DRVCTRL11", 0xe606032c) {
+               { RCAR_GP_PIN(0, 14),   28, 3 },        /* D14 */
+               { RCAR_GP_PIN(0, 15),   24, 3 },        /* D15 */
+               { RCAR_GP_PIN(7,  0),   20, 3 },        /* AVS1 */
+               { RCAR_GP_PIN(7,  1),   16, 3 },        /* AVS2 */
+               { RCAR_GP_PIN(7,  2),   12, 3 },        /* HDMI0_CEC */
+               { RCAR_GP_PIN(7,  3),    8, 3 },        /* GP7_03 */
+               { PIN_A_NUMBER('P', 7),  4, 2 },        /* DU_DOTCLKIN0 */
+               { PIN_A_NUMBER('P', 8),  0, 2 },        /* DU_DOTCLKIN1 */
+       } },
+       { PINMUX_DRIVE_REG("DRVCTRL12", 0xe6060330) {
+               { PIN_A_NUMBER('R', 8),  28, 2 },       /* DU_DOTCLKIN2 */
+               { PIN_A_NUMBER('D', 38), 20, 2 },       /* FSCLKST */
+               { PIN_A_NUMBER('R', 30),  4, 2 },       /* TMS */
+       } },
+       { PINMUX_DRIVE_REG("DRVCTRL13", 0xe6060334) {
+               { PIN_A_NUMBER('T', 28), 28, 2 },       /* TDO */
+               { PIN_A_NUMBER('T', 30), 24, 2 },       /* ASEBRK */
+               { RCAR_GP_PIN(3,  0),    20, 3 },       /* SD0_CLK */
+               { RCAR_GP_PIN(3,  1),    16, 3 },       /* SD0_CMD */
+               { RCAR_GP_PIN(3,  2),    12, 3 },       /* SD0_DAT0 */
+               { RCAR_GP_PIN(3,  3),     8, 3 },       /* SD0_DAT1 */
+               { RCAR_GP_PIN(3,  4),     4, 3 },       /* SD0_DAT2 */
+               { RCAR_GP_PIN(3,  5),     0, 3 },       /* SD0_DAT3 */
+       } },
+       { PINMUX_DRIVE_REG("DRVCTRL14", 0xe6060338) {
+               { RCAR_GP_PIN(3,  6), 28, 3 },  /* SD1_CLK */
+               { RCAR_GP_PIN(3,  7), 24, 3 },  /* SD1_CMD */
+               { RCAR_GP_PIN(3,  8), 20, 3 },  /* SD1_DAT0 */
+               { RCAR_GP_PIN(3,  9), 16, 3 },  /* SD1_DAT1 */
+               { RCAR_GP_PIN(3, 10), 12, 3 },  /* SD1_DAT2 */
+               { RCAR_GP_PIN(3, 11),  8, 3 },  /* SD1_DAT3 */
+               { RCAR_GP_PIN(4,  0),  4, 3 },  /* SD2_CLK */
+               { RCAR_GP_PIN(4,  1),  0, 3 },  /* SD2_CMD */
+       } },
+       { PINMUX_DRIVE_REG("DRVCTRL15", 0xe606033c) {
+               { RCAR_GP_PIN(4,  2), 28, 3 },  /* SD2_DAT0 */
+               { RCAR_GP_PIN(4,  3), 24, 3 },  /* SD2_DAT1 */
+               { RCAR_GP_PIN(4,  4), 20, 3 },  /* SD2_DAT2 */
+               { RCAR_GP_PIN(4,  5), 16, 3 },  /* SD2_DAT3 */
+               { RCAR_GP_PIN(4,  6), 12, 3 },  /* SD2_DS */
+               { RCAR_GP_PIN(4,  7),  8, 3 },  /* SD3_CLK */
+               { RCAR_GP_PIN(4,  8),  4, 3 },  /* SD3_CMD */
+               { RCAR_GP_PIN(4,  9),  0, 3 },  /* SD3_DAT0 */
+       } },
+       { PINMUX_DRIVE_REG("DRVCTRL16", 0xe6060340) {
+               { RCAR_GP_PIN(4, 10), 28, 3 },  /* SD3_DAT1 */
+               { RCAR_GP_PIN(4, 11), 24, 3 },  /* SD3_DAT2 */
+               { RCAR_GP_PIN(4, 12), 20, 3 },  /* SD3_DAT3 */
+               { RCAR_GP_PIN(4, 13), 16, 3 },  /* SD3_DAT4 */
+               { RCAR_GP_PIN(4, 14), 12, 3 },  /* SD3_DAT5 */
+               { RCAR_GP_PIN(4, 15),  8, 3 },  /* SD3_DAT6 */
+               { RCAR_GP_PIN(4, 16),  4, 3 },  /* SD3_DAT7 */
+               { RCAR_GP_PIN(4, 17),  0, 3 },  /* SD3_DS */
+       } },
+       { PINMUX_DRIVE_REG("DRVCTRL17", 0xe6060344) {
+               { RCAR_GP_PIN(3, 12), 28, 3 },  /* SD0_CD */
+               { RCAR_GP_PIN(3, 13), 24, 3 },  /* SD0_WP */
+               { RCAR_GP_PIN(3, 14), 20, 3 },  /* SD1_CD */
+               { RCAR_GP_PIN(3, 15), 16, 3 },  /* SD1_WP */
+               { RCAR_GP_PIN(5,  0), 12, 3 },  /* SCK0 */
+               { RCAR_GP_PIN(5,  1),  8, 3 },  /* RX0 */
+               { RCAR_GP_PIN(5,  2),  4, 3 },  /* TX0 */
+               { RCAR_GP_PIN(5,  3),  0, 3 },  /* CTS0 */
+       } },
+       { PINMUX_DRIVE_REG("DRVCTRL18", 0xe6060348) {
+               { RCAR_GP_PIN(5,  4), 28, 3 },  /* RTS0_TANS */
+               { RCAR_GP_PIN(5,  5), 24, 3 },  /* RX1 */
+               { RCAR_GP_PIN(5,  6), 20, 3 },  /* TX1 */
+               { RCAR_GP_PIN(5,  7), 16, 3 },  /* CTS1 */
+               { RCAR_GP_PIN(5,  8), 12, 3 },  /* RTS1_TANS */
+               { RCAR_GP_PIN(5,  9),  8, 3 },  /* SCK2 */
+               { RCAR_GP_PIN(5, 10),  4, 3 },  /* TX2 */
+               { RCAR_GP_PIN(5, 11),  0, 3 },  /* RX2 */
+       } },
+       { PINMUX_DRIVE_REG("DRVCTRL19", 0xe606034c) {
+               { RCAR_GP_PIN(5, 12), 28, 3 },  /* HSCK0 */
+               { RCAR_GP_PIN(5, 13), 24, 3 },  /* HRX0 */
+               { RCAR_GP_PIN(5, 14), 20, 3 },  /* HTX0 */
+               { RCAR_GP_PIN(5, 15), 16, 3 },  /* HCTS0 */
+               { RCAR_GP_PIN(5, 16), 12, 3 },  /* HRTS0 */
+               { RCAR_GP_PIN(5, 17),  8, 3 },  /* MSIOF0_SCK */
+               { RCAR_GP_PIN(5, 18),  4, 3 },  /* MSIOF0_SYNC */
+               { RCAR_GP_PIN(5, 19),  0, 3 },  /* MSIOF0_SS1 */
+       } },
+       { PINMUX_DRIVE_REG("DRVCTRL20", 0xe6060350) {
+               { RCAR_GP_PIN(5, 20), 28, 3 },  /* MSIOF0_TXD */
+               { RCAR_GP_PIN(5, 21), 24, 3 },  /* MSIOF0_SS2 */
+               { RCAR_GP_PIN(5, 22), 20, 3 },  /* MSIOF0_RXD */
+               { RCAR_GP_PIN(5, 23), 16, 3 },  /* MLB_CLK */
+               { RCAR_GP_PIN(5, 24), 12, 3 },  /* MLB_SIG */
+               { RCAR_GP_PIN(5, 25),  8, 3 },  /* MLB_DAT */
+               { PIN_NUMBER('H', 37),  4, 3 }, /* MLB_REF */
+               { RCAR_GP_PIN(6,  0),  0, 3 },  /* SSI_SCK01239 */
+       } },
+       { PINMUX_DRIVE_REG("DRVCTRL21", 0xe6060354) {
+               { RCAR_GP_PIN(6,  1), 28, 3 },  /* SSI_WS01239 */
+               { RCAR_GP_PIN(6,  2), 24, 3 },  /* SSI_SDATA0 */
+               { RCAR_GP_PIN(6,  3), 20, 3 },  /* SSI_SDATA1 */
+               { RCAR_GP_PIN(6,  4), 16, 3 },  /* SSI_SDATA2 */
+               { RCAR_GP_PIN(6,  5), 12, 3 },  /* SSI_SCK34 */
+               { RCAR_GP_PIN(6,  6),  8, 3 },  /* SSI_WS34 */
+               { RCAR_GP_PIN(6,  7),  4, 3 },  /* SSI_SDATA3 */
+               { RCAR_GP_PIN(6,  8),  0, 3 },  /* SSI_SCK4 */
+       } },
+       { PINMUX_DRIVE_REG("DRVCTRL22", 0xe6060358) {
+               { RCAR_GP_PIN(6,  9), 28, 3 },  /* SSI_WS4 */
+               { RCAR_GP_PIN(6, 10), 24, 3 },  /* SSI_SDATA4 */
+               { RCAR_GP_PIN(6, 11), 20, 3 },  /* SSI_SCK5 */
+               { RCAR_GP_PIN(6, 12), 16, 3 },  /* SSI_WS5 */
+               { RCAR_GP_PIN(6, 13), 12, 3 },  /* SSI_SDATA5 */
+               { RCAR_GP_PIN(6, 14),  8, 3 },  /* SSI_SCK6 */
+               { RCAR_GP_PIN(6, 15),  4, 3 },  /* SSI_WS6 */
+               { RCAR_GP_PIN(6, 16),  0, 3 },  /* SSI_SDATA6 */
+       } },
+       { PINMUX_DRIVE_REG("DRVCTRL23", 0xe606035c) {
+               { RCAR_GP_PIN(6, 17), 28, 3 },  /* SSI_SCK78 */
+               { RCAR_GP_PIN(6, 18), 24, 3 },  /* SSI_WS78 */
+               { RCAR_GP_PIN(6, 19), 20, 3 },  /* SSI_SDATA7 */
+               { RCAR_GP_PIN(6, 20), 16, 3 },  /* SSI_SDATA8 */
+               { RCAR_GP_PIN(6, 21), 12, 3 },  /* SSI_SDATA9 */
+               { RCAR_GP_PIN(6, 22),  8, 3 },  /* AUDIO_CLKA */
+               { RCAR_GP_PIN(6, 23),  4, 3 },  /* AUDIO_CLKB */
+               { RCAR_GP_PIN(6, 24),  0, 3 },  /* USB0_PWEN */
+       } },
+       { PINMUX_DRIVE_REG("DRVCTRL24", 0xe6060360) {
+               { RCAR_GP_PIN(6, 25), 28, 3 },  /* USB0_OVC */
+               { RCAR_GP_PIN(6, 26), 24, 3 },  /* USB1_PWEN */
+               { RCAR_GP_PIN(6, 27), 20, 3 },  /* USB1_OVC */
+               { RCAR_GP_PIN(6, 28), 16, 3 },  /* USB30_PWEN */
+               { RCAR_GP_PIN(6, 29), 12, 3 },  /* USB30_OVC */
+               { RCAR_GP_PIN(6, 30),  8, 3 },  /* GP6_30 */
+               { RCAR_GP_PIN(6, 31),  4, 3 },  /* GP6_31 */
+       } },
+       { },
+};
+
 static int r8a7796_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin, u32 *pocctrl)
 {
        int bit = -EINVAL;
@@ -3202,8 +4827,278 @@ static int r8a7796_pin_to_pocctrl(struct sh_pfc *pfc, unsigned int pin, u32 *poc
        return bit;
 }
 
+#define PUEN   0xe6060400
+#define PUD    0xe6060440
+
+#define PU0    0x00
+#define PU1    0x04
+#define PU2    0x08
+#define PU3    0x0c
+#define PU4    0x10
+#define PU5    0x14
+#define PU6    0x18
+
+static const struct sh_pfc_bias_info bias_info[] = {
+       { RCAR_GP_PIN(2, 11),    PU0, 31 },     /* AVB_PHY_INT */
+       { RCAR_GP_PIN(2, 10),    PU0, 30 },     /* AVB_MAGIC */
+       { RCAR_GP_PIN(2,  9),    PU0, 29 },     /* AVB_MDC */
+       { PIN_NUMBER('A', 9),    PU0, 28 },     /* AVB_MDIO */
+       { PIN_NUMBER('A', 12),   PU0, 27 },     /* AVB_TXCREFCLK */
+       { PIN_NUMBER('B', 17),   PU0, 26 },     /* AVB_TD3 */
+       { PIN_NUMBER('A', 17),   PU0, 25 },     /* AVB_TD2 */
+       { PIN_NUMBER('B', 18),   PU0, 24 },     /* AVB_TD1 */
+       { PIN_NUMBER('A', 18),   PU0, 23 },     /* AVB_TD0 */
+       { PIN_NUMBER('A', 19),   PU0, 22 },     /* AVB_TXC */
+       { PIN_NUMBER('A', 8),    PU0, 21 },     /* AVB_TX_CTL */
+       { PIN_NUMBER('B', 14),   PU0, 20 },     /* AVB_RD3 */
+       { PIN_NUMBER('A', 14),   PU0, 19 },     /* AVB_RD2 */
+       { PIN_NUMBER('B', 13),   PU0, 18 },     /* AVB_RD1 */
+       { PIN_NUMBER('A', 13),   PU0, 17 },     /* AVB_RD0 */
+       { PIN_NUMBER('B', 19),   PU0, 16 },     /* AVB_RXC */
+       { PIN_NUMBER('A', 16),   PU0, 15 },     /* AVB_RX_CTL */
+       { PIN_NUMBER('V', 7),    PU0, 14 },     /* RPC_RESET# */
+       { PIN_NUMBER('V', 6),    PU0, 13 },     /* RPC_WP# */
+       { PIN_NUMBER('Y', 7),    PU0, 12 },     /* RPC_INT# */
+       { PIN_NUMBER('V', 5),    PU0, 11 },     /* QSPI1_SSL */
+       { PIN_A_NUMBER('C', 3),  PU0, 10 },     /* QSPI1_IO3 */
+       { PIN_A_NUMBER('E', 4),  PU0,  9 },     /* QSPI1_IO2 */
+       { PIN_A_NUMBER('E', 5),  PU0,  8 },     /* QSPI1_MISO_IO1 */
+       { PIN_A_NUMBER('C', 7),  PU0,  7 },     /* QSPI1_MOSI_IO0 */
+       { PIN_NUMBER('V', 3),    PU0,  6 },     /* QSPI1_SPCLK */
+       { PIN_NUMBER('Y', 3),    PU0,  5 },     /* QSPI0_SSL */
+       { PIN_A_NUMBER('B', 6),  PU0,  4 },     /* QSPI0_IO3 */
+       { PIN_NUMBER('Y', 6),    PU0,  3 },     /* QSPI0_IO2 */
+       { PIN_A_NUMBER('B', 4),  PU0,  2 },     /* QSPI0_MISO_IO1 */
+       { PIN_A_NUMBER('C', 5),  PU0,  1 },     /* QSPI0_MOSI_IO0 */
+       { PIN_NUMBER('W', 3),    PU0,  0 },     /* QSPI0_SPCLK */
+
+       { RCAR_GP_PIN(1, 19),    PU1, 31 },     /* A19 */
+       { RCAR_GP_PIN(1, 18),    PU1, 30 },     /* A18 */
+       { RCAR_GP_PIN(1, 17),    PU1, 29 },     /* A17 */
+       { RCAR_GP_PIN(1, 16),    PU1, 28 },     /* A16 */
+       { RCAR_GP_PIN(1, 15),    PU1, 27 },     /* A15 */
+       { RCAR_GP_PIN(1, 14),    PU1, 26 },     /* A14 */
+       { RCAR_GP_PIN(1, 13),    PU1, 25 },     /* A13 */
+       { RCAR_GP_PIN(1, 12),    PU1, 24 },     /* A12 */
+       { RCAR_GP_PIN(1, 11),    PU1, 23 },     /* A11 */
+       { RCAR_GP_PIN(1, 10),    PU1, 22 },     /* A10 */
+       { RCAR_GP_PIN(1,  9),    PU1, 21 },     /* A9 */
+       { RCAR_GP_PIN(1,  8),    PU1, 20 },     /* A8 */
+       { RCAR_GP_PIN(1,  7),    PU1, 19 },     /* A7 */
+       { RCAR_GP_PIN(1,  6),    PU1, 18 },     /* A6 */
+       { RCAR_GP_PIN(1,  5),    PU1, 17 },     /* A5 */
+       { RCAR_GP_PIN(1,  4),    PU1, 16 },     /* A4 */
+       { RCAR_GP_PIN(1,  3),    PU1, 15 },     /* A3 */
+       { RCAR_GP_PIN(1,  2),    PU1, 14 },     /* A2 */
+       { RCAR_GP_PIN(1,  1),    PU1, 13 },     /* A1 */
+       { RCAR_GP_PIN(1,  0),    PU1, 12 },     /* A0 */
+       { RCAR_GP_PIN(2,  8),    PU1, 11 },     /* PWM2_A */
+       { RCAR_GP_PIN(2,  7),    PU1, 10 },     /* PWM1_A */
+       { RCAR_GP_PIN(2,  6),    PU1,  9 },     /* PWM0 */
+       { RCAR_GP_PIN(2,  5),    PU1,  8 },     /* IRQ5 */
+       { RCAR_GP_PIN(2,  4),    PU1,  7 },     /* IRQ4 */
+       { RCAR_GP_PIN(2,  3),    PU1,  6 },     /* IRQ3 */
+       { RCAR_GP_PIN(2,  2),    PU1,  5 },     /* IRQ2 */
+       { RCAR_GP_PIN(2,  1),    PU1,  4 },     /* IRQ1 */
+       { RCAR_GP_PIN(2,  0),    PU1,  3 },     /* IRQ0 */
+       { RCAR_GP_PIN(2, 14),    PU1,  2 },     /* AVB_AVTP_CAPTURE_A */
+       { RCAR_GP_PIN(2, 13),    PU1,  1 },     /* AVB_AVTP_MATCH_A */
+       { RCAR_GP_PIN(2, 12),    PU1,  0 },     /* AVB_LINK */
+
+       { PIN_A_NUMBER('P', 8),  PU2, 31 },     /* DU_DOTCLKIN1 */
+       { PIN_A_NUMBER('P', 7),  PU2, 30 },     /* DU_DOTCLKIN0 */
+       { RCAR_GP_PIN(7,  3),    PU2, 29 },     /* GP7_03 */
+       { RCAR_GP_PIN(7,  2),    PU2, 28 },     /* HDMI0_CEC */
+       { RCAR_GP_PIN(7,  1),    PU2, 27 },     /* AVS2 */
+       { RCAR_GP_PIN(7,  0),    PU2, 26 },     /* AVS1 */
+       { RCAR_GP_PIN(0, 15),    PU2, 25 },     /* D15 */
+       { RCAR_GP_PIN(0, 14),    PU2, 24 },     /* D14 */
+       { RCAR_GP_PIN(0, 13),    PU2, 23 },     /* D13 */
+       { RCAR_GP_PIN(0, 12),    PU2, 22 },     /* D12 */
+       { RCAR_GP_PIN(0, 11),    PU2, 21 },     /* D11 */
+       { RCAR_GP_PIN(0, 10),    PU2, 20 },     /* D10 */
+       { RCAR_GP_PIN(0,  9),    PU2, 19 },     /* D9 */
+       { RCAR_GP_PIN(0,  8),    PU2, 18 },     /* D8 */
+       { RCAR_GP_PIN(0,  7),    PU2, 17 },     /* D7 */
+       { RCAR_GP_PIN(0,  6),    PU2, 16 },     /* D6 */
+       { RCAR_GP_PIN(0,  5),    PU2, 15 },     /* D5 */
+       { RCAR_GP_PIN(0,  4),    PU2, 14 },     /* D4 */
+       { RCAR_GP_PIN(0,  3),    PU2, 13 },     /* D3 */
+       { RCAR_GP_PIN(0,  2),    PU2, 12 },     /* D2 */
+       { RCAR_GP_PIN(0,  1),    PU2, 11 },     /* D1 */
+       { RCAR_GP_PIN(0,  0),    PU2, 10 },     /* D0 */
+       { PIN_NUMBER('C', 1),    PU2,  9 },     /* PRESETOUT# */
+       { RCAR_GP_PIN(1, 27),    PU2,  8 },     /* EX_WAIT0_A */
+       { RCAR_GP_PIN(1, 26),    PU2,  7 },     /* WE1_N */
+       { RCAR_GP_PIN(1, 25),    PU2,  6 },     /* WE0_N */
+       { RCAR_GP_PIN(1, 24),    PU2,  5 },     /* RD_WR_N */
+       { RCAR_GP_PIN(1, 23),    PU2,  4 },     /* RD_N */
+       { RCAR_GP_PIN(1, 22),    PU2,  3 },     /* BS_N */
+       { RCAR_GP_PIN(1, 21),    PU2,  2 },     /* CS1_N_A26 */
+       { RCAR_GP_PIN(1, 20),    PU2,  1 },     /* CS0_N */
+       { RCAR_GP_PIN(1, 28),    PU2,  0 },     /* CLKOUT */
+
+       { RCAR_GP_PIN(4,  9),    PU3, 31 },     /* SD3_DAT0 */
+       { RCAR_GP_PIN(4,  8),    PU3, 30 },     /* SD3_CMD */
+       { RCAR_GP_PIN(4,  7),    PU3, 29 },     /* SD3_CLK */
+       { RCAR_GP_PIN(4,  6),    PU3, 28 },     /* SD2_DS */
+       { RCAR_GP_PIN(4,  5),    PU3, 27 },     /* SD2_DAT3 */
+       { RCAR_GP_PIN(4,  4),    PU3, 26 },     /* SD2_DAT2 */
+       { RCAR_GP_PIN(4,  3),    PU3, 25 },     /* SD2_DAT1 */
+       { RCAR_GP_PIN(4,  2),    PU3, 24 },     /* SD2_DAT0 */
+       { RCAR_GP_PIN(4,  1),    PU3, 23 },     /* SD2_CMD */
+       { RCAR_GP_PIN(4,  0),    PU3, 22 },     /* SD2_CLK */
+       { RCAR_GP_PIN(3, 11),    PU3, 21 },     /* SD1_DAT3 */
+       { RCAR_GP_PIN(3, 10),    PU3, 20 },     /* SD1_DAT2 */
+       { RCAR_GP_PIN(3,  9),    PU3, 19 },     /* SD1_DAT1 */
+       { RCAR_GP_PIN(3,  8),    PU3, 18 },     /* SD1_DAT0 */
+       { RCAR_GP_PIN(3,  7),    PU3, 17 },     /* SD1_CMD */
+       { RCAR_GP_PIN(3,  6),    PU3, 16 },     /* SD1_CLK */
+       { RCAR_GP_PIN(3,  5),    PU3, 15 },     /* SD0_DAT3 */
+       { RCAR_GP_PIN(3,  4),    PU3, 14 },     /* SD0_DAT2 */
+       { RCAR_GP_PIN(3,  3),    PU3, 13 },     /* SD0_DAT1 */
+       { RCAR_GP_PIN(3,  2),    PU3, 12 },     /* SD0_DAT0 */
+       { RCAR_GP_PIN(3,  1),    PU3, 11 },     /* SD0_CMD */
+       { RCAR_GP_PIN(3,  0),    PU3, 10 },     /* SD0_CLK */
+       { PIN_A_NUMBER('T', 30), PU3,  9 },     /* ASEBRK */
+       /* bit 8 n/a */
+       { PIN_A_NUMBER('R', 29), PU3,  7 },     /* TDI */
+       { PIN_A_NUMBER('R', 30), PU3,  6 },     /* TMS */
+       { PIN_A_NUMBER('T', 27), PU3,  5 },     /* TCK */
+       { PIN_A_NUMBER('R', 26), PU3,  4 },     /* TRST# */
+       { PIN_A_NUMBER('D', 39), PU3,  3 },     /* EXTALR*/
+       { PIN_A_NUMBER('D', 38), PU3,  2 },     /* FSCLKST */
+       /* bit 1 n/a on M3*/
+       { PIN_A_NUMBER('R', 8),  PU3,  0 },     /* DU_DOTCLKIN2 */
+
+       { RCAR_GP_PIN(5, 19),    PU4, 31 },     /* MSIOF0_SS1 */
+       { RCAR_GP_PIN(5, 18),    PU4, 30 },     /* MSIOF0_SYNC */
+       { RCAR_GP_PIN(5, 17),    PU4, 29 },     /* MSIOF0_SCK */
+       { RCAR_GP_PIN(5, 16),    PU4, 28 },     /* HRTS0_N */
+       { RCAR_GP_PIN(5, 15),    PU4, 27 },     /* HCTS0_N */
+       { RCAR_GP_PIN(5, 14),    PU4, 26 },     /* HTX0 */
+       { RCAR_GP_PIN(5, 13),    PU4, 25 },     /* HRX0 */
+       { RCAR_GP_PIN(5, 12),    PU4, 24 },     /* HSCK0 */
+       { RCAR_GP_PIN(5, 11),    PU4, 23 },     /* RX2_A */
+       { RCAR_GP_PIN(5, 10),    PU4, 22 },     /* TX2_A */
+       { RCAR_GP_PIN(5,  9),    PU4, 21 },     /* SCK2 */
+       { RCAR_GP_PIN(5,  8),    PU4, 20 },     /* RTS1_N_TANS */
+       { RCAR_GP_PIN(5,  7),    PU4, 19 },     /* CTS1_N */
+       { RCAR_GP_PIN(5,  6),    PU4, 18 },     /* TX1_A */
+       { RCAR_GP_PIN(5,  5),    PU4, 17 },     /* RX1_A */
+       { RCAR_GP_PIN(5,  4),    PU4, 16 },     /* RTS0_N_TANS */
+       { RCAR_GP_PIN(5,  3),    PU4, 15 },     /* CTS0_N */
+       { RCAR_GP_PIN(5,  2),    PU4, 14 },     /* TX0 */
+       { RCAR_GP_PIN(5,  1),    PU4, 13 },     /* RX0 */
+       { RCAR_GP_PIN(5,  0),    PU4, 12 },     /* SCK0 */
+       { RCAR_GP_PIN(3, 15),    PU4, 11 },     /* SD1_WP */
+       { RCAR_GP_PIN(3, 14),    PU4, 10 },     /* SD1_CD */
+       { RCAR_GP_PIN(3, 13),    PU4,  9 },     /* SD0_WP */
+       { RCAR_GP_PIN(3, 12),    PU4,  8 },     /* SD0_CD */
+       { RCAR_GP_PIN(4, 17),    PU4,  7 },     /* SD3_DS */
+       { RCAR_GP_PIN(4, 16),    PU4,  6 },     /* SD3_DAT7 */
+       { RCAR_GP_PIN(4, 15),    PU4,  5 },     /* SD3_DAT6 */
+       { RCAR_GP_PIN(4, 14),    PU4,  4 },     /* SD3_DAT5 */
+       { RCAR_GP_PIN(4, 13),    PU4,  3 },     /* SD3_DAT4 */
+       { RCAR_GP_PIN(4, 12),    PU4,  2 },     /* SD3_DAT3 */
+       { RCAR_GP_PIN(4, 11),    PU4,  1 },     /* SD3_DAT2 */
+       { RCAR_GP_PIN(4, 10),    PU4,  0 },     /* SD3_DAT1 */
+
+       { RCAR_GP_PIN(6, 24),    PU5, 31 },     /* USB0_PWEN */
+       { RCAR_GP_PIN(6, 23),    PU5, 30 },     /* AUDIO_CLKB_B */
+       { RCAR_GP_PIN(6, 22),    PU5, 29 },     /* AUDIO_CLKA_A */
+       { RCAR_GP_PIN(6, 21),    PU5, 28 },     /* SSI_SDATA9_A */
+       { RCAR_GP_PIN(6, 20),    PU5, 27 },     /* SSI_SDATA8 */
+       { RCAR_GP_PIN(6, 19),    PU5, 26 },     /* SSI_SDATA7 */
+       { RCAR_GP_PIN(6, 18),    PU5, 25 },     /* SSI_WS78 */
+       { RCAR_GP_PIN(6, 17),    PU5, 24 },     /* SSI_SCK78 */
+       { RCAR_GP_PIN(6, 16),    PU5, 23 },     /* SSI_SDATA6 */
+       { RCAR_GP_PIN(6, 15),    PU5, 22 },     /* SSI_WS6 */
+       { RCAR_GP_PIN(6, 14),    PU5, 21 },     /* SSI_SCK6 */
+       { RCAR_GP_PIN(6, 13),    PU5, 20 },     /* SSI_SDATA5 */
+       { RCAR_GP_PIN(6, 12),    PU5, 19 },     /* SSI_WS5 */
+       { RCAR_GP_PIN(6, 11),    PU5, 18 },     /* SSI_SCK5 */
+       { RCAR_GP_PIN(6, 10),    PU5, 17 },     /* SSI_SDATA4 */
+       { RCAR_GP_PIN(6,  9),    PU5, 16 },     /* SSI_WS4 */
+       { RCAR_GP_PIN(6,  8),    PU5, 15 },     /* SSI_SCK4 */
+       { RCAR_GP_PIN(6,  7),    PU5, 14 },     /* SSI_SDATA3 */
+       { RCAR_GP_PIN(6,  6),    PU5, 13 },     /* SSI_WS34 */
+       { RCAR_GP_PIN(6,  5),    PU5, 12 },     /* SSI_SCK34 */
+       { RCAR_GP_PIN(6,  4),    PU5, 11 },     /* SSI_SDATA2_A */
+       { RCAR_GP_PIN(6,  3),    PU5, 10 },     /* SSI_SDATA1_A */
+       { RCAR_GP_PIN(6,  2),    PU5,  9 },     /* SSI_SDATA0 */
+       { RCAR_GP_PIN(6,  1),    PU5,  8 },     /* SSI_WS01239 */
+       { RCAR_GP_PIN(6,  0),    PU5,  7 },     /* SSI_SCK01239 */
+       { PIN_NUMBER('H', 37),   PU5,  6 },     /* MLB_REF */
+       { RCAR_GP_PIN(5, 25),    PU5,  5 },     /* MLB_DAT */
+       { RCAR_GP_PIN(5, 24),    PU5,  4 },     /* MLB_SIG */
+       { RCAR_GP_PIN(5, 23),    PU5,  3 },     /* MLB_CLK */
+       { RCAR_GP_PIN(5, 22),    PU5,  2 },     /* MSIOF0_RXD */
+       { RCAR_GP_PIN(5, 21),    PU5,  1 },     /* MSIOF0_SS2 */
+       { RCAR_GP_PIN(5, 20),    PU5,  0 },     /* MSIOF0_TXD */
+
+       { RCAR_GP_PIN(6, 31),    PU6,  6 },     /* GP6_31 */
+       { RCAR_GP_PIN(6, 30),    PU6,  5 },     /* GP6_30 */
+       { RCAR_GP_PIN(6, 29),    PU6,  4 },     /* USB30_OVC */
+       { RCAR_GP_PIN(6, 28),    PU6,  3 },     /* USB30_PWEN */
+       { RCAR_GP_PIN(6, 27),    PU6,  2 },     /* USB1_OVC */
+       { RCAR_GP_PIN(6, 26),    PU6,  1 },     /* USB1_PWEN */
+       { RCAR_GP_PIN(6, 25),    PU6,  0 },     /* USB0_OVC */
+};
+
+static unsigned int r8a7796_pinmux_get_bias(struct sh_pfc *pfc,
+                                           unsigned int pin)
+{
+       const struct sh_pfc_bias_info *info;
+       u32 reg;
+       u32 bit;
+
+       info = sh_pfc_pin_to_bias_info(bias_info, ARRAY_SIZE(bias_info), pin);
+       if (!info)
+               return PIN_CONFIG_BIAS_DISABLE;
+
+       reg = info->reg;
+       bit = BIT(info->bit);
+
+       if (!(sh_pfc_read_reg(pfc, PUEN + reg, 32) & bit))
+               return PIN_CONFIG_BIAS_DISABLE;
+       else if (sh_pfc_read_reg(pfc, PUD + reg, 32) & bit)
+               return PIN_CONFIG_BIAS_PULL_UP;
+       else
+               return PIN_CONFIG_BIAS_PULL_DOWN;
+}
+
+static void r8a7796_pinmux_set_bias(struct sh_pfc *pfc, unsigned int pin,
+                                  unsigned int bias)
+{
+       const struct sh_pfc_bias_info *info;
+       u32 enable, updown;
+       u32 reg;
+       u32 bit;
+
+       info = sh_pfc_pin_to_bias_info(bias_info, ARRAY_SIZE(bias_info), pin);
+       if (!info)
+               return;
+
+       reg = info->reg;
+       bit = BIT(info->bit);
+
+       enable = sh_pfc_read_reg(pfc, PUEN + reg, 32) & ~bit;
+       if (bias != PIN_CONFIG_BIAS_DISABLE)
+               enable |= bit;
+
+       updown = sh_pfc_read_reg(pfc, PUD + reg, 32) & ~bit;
+       if (bias == PIN_CONFIG_BIAS_PULL_UP)
+               updown |= bit;
+
+       sh_pfc_write_reg(pfc, PUD + reg, 32, updown);
+       sh_pfc_write_reg(pfc, PUEN + reg, 32, enable);
+}
+
 static const struct sh_pfc_soc_operations r8a7796_pinmux_ops = {
        .pin_to_pocctrl = r8a7796_pin_to_pocctrl,
+       .get_bias = r8a7796_pinmux_get_bias,
+       .set_bias = r8a7796_pinmux_set_bias,
 };
 
 const struct sh_pfc_soc_info r8a7796_pinmux_info = {
@@ -3221,6 +5116,7 @@ const struct sh_pfc_soc_info r8a7796_pinmux_info = {
        .nr_functions = ARRAY_SIZE(pinmux_functions),
 
        .cfg_regs = pinmux_config_regs,
+       .drive_regs = pinmux_drive_regs,
 
        .pinmux_data = pinmux_data,
        .pinmux_data_size = ARRAY_SIZE(pinmux_data),
index fcacfa73ef6e9b657fb043186fcd6c9cd0d2dfeb..08150a321be6f1e2df11fce59745430b1ead1213 100644 (file)
@@ -816,6 +816,6 @@ int sh_pfc_register_pinctrl(struct sh_pfc *pfc)
        pmx->pctl_desc.pins = pmx->pins;
        pmx->pctl_desc.npins = pfc->info->nr_pins;
 
-       pmx->pctl = devm_pinctrl_register(pfc->dev, &pmx->pctl_desc, pmx);
-       return PTR_ERR_OR_ZERO(pmx->pctl);
+       return devm_pinctrl_register_and_init(pfc->dev, &pmx->pctl_desc, pmx,
+                                             &pmx->pctl);
 }
index 7f3041697813ebc73bd031454dbb5df3ca30bb2d..600d6427a9784c2eed5ee5ad6d7360e5dc42b86e 100644 (file)
@@ -5322,7 +5322,8 @@ static int atlas7_pin_config_set(struct pinctrl_dev *pctldev,
                                unsigned pin, unsigned long *configs,
                                unsigned num_configs)
 {
-       u16 param, arg;
+       u16 param;
+       u32 arg;
        int idx, err;
 
        for (idx = 0; idx < num_configs; idx++) {
@@ -5420,14 +5421,15 @@ static int atlas7_pinmux_probe(struct platform_device *pdev)
        sys2pci_np = of_find_node_by_name(NULL, "sys2pci");
        if (!sys2pci_np)
                return -EINVAL;
+
        ret = of_address_to_resource(sys2pci_np, 0, &res);
+       of_node_put(sys2pci_np);
        if (ret)
                return ret;
+
        pmx->sys2pci_base = devm_ioremap_resource(&pdev->dev, &res);
-       if (IS_ERR(pmx->sys2pci_base)) {
-               of_node_put(sys2pci_np);
+       if (IS_ERR(pmx->sys2pci_base))
                return -ENOMEM;
-       }
 
        pmx->dev = &pdev->dev;
 
@@ -5443,7 +5445,7 @@ static int atlas7_pinmux_probe(struct platform_device *pdev)
                pmx->regs[idx] = of_iomap(np, idx);
                if (!pmx->regs[idx]) {
                        dev_err(&pdev->dev,
-                       "can't map ioc bank#%d registers\n", idx);
+                               "can't map ioc bank#%d registers\n", idx);
                        ret = -ENOMEM;
                        goto unmap_io;
                }
@@ -6056,8 +6058,8 @@ static int atlas7_gpio_probe(struct platform_device *pdev)
        ret = gpiochip_add_data(chip, a7gc);
        if (ret) {
                dev_err(&pdev->dev,
-               "%s: error in probe function with status %d\n",
-               np->name, ret);
+                       "%s: error in probe function with status %d\n",
+                       np->name, ret);
                goto failed;
        }
 
index 4c9b863f826772f1acebb791cb5439a315491b96..cf6d68c7345be71239f85a30db164b141a451b5d 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/err.h>
 #include <linux/gpio/driver.h>
 #include <linux/io.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/pinctrl/consumer.h>
@@ -705,7 +705,6 @@ static const struct of_device_id plgpio_of_match[] = {
        { .compatible = "st,spear-plgpio" },
        {}
 };
-MODULE_DEVICE_TABLE(of, plgpio_of_match);
 
 static struct platform_driver plgpio_driver = {
        .probe = plgpio_probe,
@@ -721,7 +720,3 @@ static int __init plgpio_init(void)
        return platform_driver_register(&plgpio_driver);
 }
 subsys_initcall(plgpio_init);
-
-MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.org>");
-MODULE_DESCRIPTION("STMicroelectronics SPEAr PLGPIO driver");
-MODULE_LICENSE("GPL");
index 18210681c737a9c454583403c4772231032bbdd6..0180eb544f022462094dc1923b7f8598063d3463 100644 (file)
@@ -11,7 +11,6 @@
 
 #include <linux/err.h>
 #include <linux/init.h>
-#include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include "pinctrl-spear.h"
@@ -2717,14 +2716,3 @@ static int __init spear1310_pinctrl_init(void)
        return platform_driver_register(&spear1310_pinctrl_driver);
 }
 arch_initcall(spear1310_pinctrl_init);
-
-static void __exit spear1310_pinctrl_exit(void)
-{
-       platform_driver_unregister(&spear1310_pinctrl_driver);
-}
-module_exit(spear1310_pinctrl_exit);
-
-MODULE_AUTHOR("Viresh Kumar <vireshk@kernel.org>");
-MODULE_DESCRIPTION("ST Microelectronics SPEAr1310 pinctrl driver");
-MODULE_LICENSE("GPL v2");
-MODULE_DEVICE_TABLE(of, spear1310_pinctrl_of_match);
index c01fb23ee636cf01dfca147829a45176d49678de..0ca961219b3b0b7aedef34122613fd854bd7ddaa 100644 (file)
@@ -11,7 +11,6 @@
 
 #include <linux/err.h>
 #include <linux/init.h>
-#include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include "pinctrl-spear.h"
@@ -2033,14 +2032,3 @@ static int __init spear1340_pinctrl_init(void)
        return platform_driver_register(&spear1340_pinctrl_driver);
 }
 arch_initcall(spear1340_pinctrl_init);
-
-static void __exit spear1340_pinctrl_exit(void)
-{
-       platform_driver_unregister(&spear1340_pinctrl_driver);
-}
-module_exit(spear1340_pinctrl_exit);
-
-MODULE_AUTHOR("Viresh Kumar <vireshk@kernel.org>");
-MODULE_DESCRIPTION("ST Microelectronics SPEAr1340 pinctrl driver");
-MODULE_LICENSE("GPL v2");
-MODULE_DEVICE_TABLE(of, spear1340_pinctrl_of_match);
index 111148daa3f12593357d4b66b2dd2bc33089696e..e39913a1813955e6255567cc42f72f5403088935 100644 (file)
@@ -11,7 +11,6 @@
 
 #include <linux/err.h>
 #include <linux/init.h>
-#include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include "pinctrl-spear3xx.h"
@@ -690,14 +689,3 @@ static int __init spear300_pinctrl_init(void)
        return platform_driver_register(&spear300_pinctrl_driver);
 }
 arch_initcall(spear300_pinctrl_init);
-
-static void __exit spear300_pinctrl_exit(void)
-{
-       platform_driver_unregister(&spear300_pinctrl_driver);
-}
-module_exit(spear300_pinctrl_exit);
-
-MODULE_AUTHOR("Viresh Kumar <vireshk@kernel.org>");
-MODULE_DESCRIPTION("ST Microelectronics SPEAr300 pinctrl driver");
-MODULE_LICENSE("GPL v2");
-MODULE_DEVICE_TABLE(of, spear300_pinctrl_of_match);
index a7b000062985345cbfe31517a609c2a32ccb5110..393b2b97d527421b6d75d57602edf3da675e0df1 100644 (file)
@@ -11,7 +11,6 @@
 
 #include <linux/err.h>
 #include <linux/init.h>
-#include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include "pinctrl-spear3xx.h"
@@ -413,14 +412,3 @@ static int __init spear310_pinctrl_init(void)
        return platform_driver_register(&spear310_pinctrl_driver);
 }
 arch_initcall(spear310_pinctrl_init);
-
-static void __exit spear310_pinctrl_exit(void)
-{
-       platform_driver_unregister(&spear310_pinctrl_driver);
-}
-module_exit(spear310_pinctrl_exit);
-
-MODULE_AUTHOR("Viresh Kumar <vireshk@kernel.org>");
-MODULE_DESCRIPTION("ST Microelectronics SPEAr310 pinctrl driver");
-MODULE_LICENSE("GPL v2");
-MODULE_DEVICE_TABLE(of, spear310_pinctrl_of_match);
index e2b3817701dcbc7ccbef5abe68f8a3f5b14e26c4..99c10fc3d9b518f48286679fcb6635ed318b953a 100644 (file)
@@ -11,7 +11,6 @@
 
 #include <linux/err.h>
 #include <linux/init.h>
-#include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include "pinctrl-spear3xx.h"
@@ -3454,14 +3453,3 @@ static int __init spear320_pinctrl_init(void)
        return platform_driver_register(&spear320_pinctrl_driver);
 }
 arch_initcall(spear320_pinctrl_init);
-
-static void __exit spear320_pinctrl_exit(void)
-{
-       platform_driver_unregister(&spear320_pinctrl_driver);
-}
-module_exit(spear320_pinctrl_exit);
-
-MODULE_AUTHOR("Viresh Kumar <vireshk@kernel.org>");
-MODULE_DESCRIPTION("ST Microelectronics SPEAr320 pinctrl driver");
-MODULE_LICENSE("GPL v2");
-MODULE_DEVICE_TABLE(of, spear320_pinctrl_of_match);
index c03dce7a22df2d67bcf607fb63656fd5a4a39c1d..f5ccabd8535ef20d4d7ffbc407792635586f9b91 100644 (file)
@@ -20,4 +20,9 @@ config PINCTRL_STM32F746
        default MACH_STM32F746
        select PINCTRL_STM32
 
+config PINCTRL_STM32H743
+       bool "STMicroelectronics STM32H743 pin control" if COMPILE_TEST && !MACH_STM32H743
+       depends on OF && IRQ_DOMAIN_HIERARCHY
+       default MACH_STM32H743
+       select PINCTRL_STM32
 endif
index 4a1ee748441f1718ee5ba9d17363b499918dcd18..cb31b4d24c44919c1fe8d46bcdaf02777c34b978 100644 (file)
@@ -4,3 +4,4 @@ obj-$(CONFIG_PINCTRL_STM32) += pinctrl-stm32.o
 # SoC Drivers
 obj-$(CONFIG_PINCTRL_STM32F429)        += pinctrl-stm32f429.o
 obj-$(CONFIG_PINCTRL_STM32F746)        += pinctrl-stm32f746.o
+obj-$(CONFIG_PINCTRL_STM32H743)        += pinctrl-stm32h743.o
index efc43711ff5cbcff2c94838e06ead49623ab9118..abc405be0212be794b8d1239dac8e7b757a4c945 100644 (file)
@@ -236,6 +236,15 @@ static void stm32_gpio_domain_activate(struct irq_domain *d,
        struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
 
        regmap_field_write(pctl->irqmux[irq_data->hwirq], bank->range.id);
+       gpiochip_lock_as_irq(&bank->gpio_chip, irq_data->hwirq);
+}
+
+static void stm32_gpio_domain_deactivate(struct irq_domain *d,
+                                      struct irq_data *irq_data)
+{
+       struct stm32_gpio_bank *bank = d->host_data;
+
+       gpiochip_unlock_as_irq(&bank->gpio_chip, irq_data->hwirq);
 }
 
 static int stm32_gpio_domain_alloc(struct irq_domain *d,
@@ -243,11 +252,9 @@ static int stm32_gpio_domain_alloc(struct irq_domain *d,
                                   unsigned int nr_irqs, void *data)
 {
        struct stm32_gpio_bank *bank = d->host_data;
-       struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
        struct irq_fwspec *fwspec = data;
        struct irq_fwspec parent_fwspec;
        irq_hw_number_t hwirq;
-       int ret;
 
        hwirq = fwspec->param[0];
        parent_fwspec.fwnode = d->parent->fwnode;
@@ -258,35 +265,15 @@ static int stm32_gpio_domain_alloc(struct irq_domain *d,
        irq_domain_set_hwirq_and_chip(d, virq, hwirq, &stm32_gpio_irq_chip,
                                      bank);
 
-       ret = gpiochip_lock_as_irq(&bank->gpio_chip, hwirq);
-       if (ret) {
-               dev_err(pctl->dev, "Unable to configure STM32 %s%ld as IRQ\n",
-                       bank->gpio_chip.label, hwirq);
-               return ret;
-       }
-
-       ret = irq_domain_alloc_irqs_parent(d, virq, nr_irqs, &parent_fwspec);
-       if (ret)
-               gpiochip_unlock_as_irq(&bank->gpio_chip, hwirq);
-
-       return ret;
-}
-
-static void stm32_gpio_domain_free(struct irq_domain *d, unsigned int virq,
-                                  unsigned int nr_irqs)
-{
-       struct stm32_gpio_bank *bank = d->host_data;
-       struct irq_data *data = irq_get_irq_data(virq);
-
-       irq_domain_free_irqs_common(d, virq, nr_irqs);
-       gpiochip_unlock_as_irq(&bank->gpio_chip, data->hwirq);
+       return irq_domain_alloc_irqs_parent(d, virq, nr_irqs, &parent_fwspec);
 }
 
 static const struct irq_domain_ops stm32_gpio_domain_ops = {
        .translate      = stm32_gpio_domain_translate,
        .alloc          = stm32_gpio_domain_alloc,
-       .free           = stm32_gpio_domain_free,
+       .free           = irq_domain_free_irqs_common,
        .activate       = stm32_gpio_domain_activate,
+       .deactivate     = stm32_gpio_domain_deactivate,
 };
 
 /* Pinctrl functions */
@@ -631,6 +618,7 @@ static const struct pinmux_ops stm32_pmx_ops = {
        .get_function_groups    = stm32_pmx_get_func_groups,
        .set_mux                = stm32_pmx_set_mux,
        .gpio_set_direction     = stm32_pmx_gpio_set_direction,
+       .strict                 = true,
 };
 
 /* Pinconf functions */
diff --git a/drivers/pinctrl/stm32/pinctrl-stm32h743.c b/drivers/pinctrl/stm32/pinctrl-stm32h743.c
new file mode 100644 (file)
index 0000000..f7f9eac
--- /dev/null
@@ -0,0 +1,1980 @@
+/*
+ * Copyright (C) Alexandre Torgue 2017
+ * Author:  Alexandre Torgue <alexandre.torgue@st.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-stm32.h"
+
+static const struct stm32_desc_pin stm32h743_pins[] = {
+       STM32_PIN(
+               PINCTRL_PIN(0, "PA0"),
+               STM32_FUNCTION(0, "GPIOA0"),
+               STM32_FUNCTION(2, "TIM2_CH1 TIM2_ETR"),
+               STM32_FUNCTION(3, "TIM5_CH1"),
+               STM32_FUNCTION(4, "TIM8_ETR"),
+               STM32_FUNCTION(5, "TIM15_BKIN"),
+               STM32_FUNCTION(8, "USART2_CTS_NSS"),
+               STM32_FUNCTION(9, "UART4_TX"),
+               STM32_FUNCTION(10, "SDMMC2_CMD"),
+               STM32_FUNCTION(11, "SAI2_SD_B"),
+               STM32_FUNCTION(12, "ETH_MII_CRS"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(1, "PA1"),
+               STM32_FUNCTION(0, "GPIOA1"),
+               STM32_FUNCTION(2, "TIM2_CH2"),
+               STM32_FUNCTION(3, "TIM5_CH2"),
+               STM32_FUNCTION(4, "LPTIM3_OUT"),
+               STM32_FUNCTION(5, "TIM15_CH1N"),
+               STM32_FUNCTION(8, "USART2_RTS"),
+               STM32_FUNCTION(9, "UART4_RX"),
+               STM32_FUNCTION(10, "QUADSPI_BK1_IO3"),
+               STM32_FUNCTION(11, "SAI2_MCK_B"),
+               STM32_FUNCTION(12, "ETH_MII_RX_CLK ETH_RMII_REF_CLK"),
+               STM32_FUNCTION(15, "LCD_R2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(2, "PA2"),
+               STM32_FUNCTION(0, "GPIOA2"),
+               STM32_FUNCTION(2, "TIM2_CH3"),
+               STM32_FUNCTION(3, "TIM5_CH3"),
+               STM32_FUNCTION(4, "LPTIM4_OUT"),
+               STM32_FUNCTION(5, "TIM15_CH1"),
+               STM32_FUNCTION(8, "USART2_TX"),
+               STM32_FUNCTION(9, "SAI2_SCK_B"),
+               STM32_FUNCTION(12, "ETH_MDIO"),
+               STM32_FUNCTION(13, "MDIOS_MDIO"),
+               STM32_FUNCTION(15, "LCD_R1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(3, "PA3"),
+               STM32_FUNCTION(0, "GPIOA3"),
+               STM32_FUNCTION(2, "TIM2_CH4"),
+               STM32_FUNCTION(3, "TIM5_CH4"),
+               STM32_FUNCTION(4, "LPTIM5_OUT"),
+               STM32_FUNCTION(5, "TIM15_CH2"),
+               STM32_FUNCTION(8, "USART2_RX"),
+               STM32_FUNCTION(10, "LCD_B2"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_D0"),
+               STM32_FUNCTION(12, "ETH_MII_COL"),
+               STM32_FUNCTION(15, "LCD_B5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(4, "PA4"),
+               STM32_FUNCTION(0, "GPIOA4"),
+               STM32_FUNCTION(3, "TIM5_ETR"),
+               STM32_FUNCTION(6, "SPI1_NSS I2S1_WS"),
+               STM32_FUNCTION(7, "SPI3_NSS I2S3_WS"),
+               STM32_FUNCTION(8, "USART2_CK"),
+               STM32_FUNCTION(9, "SPI6_NSS"),
+               STM32_FUNCTION(13, "OTG_HS_SOF"),
+               STM32_FUNCTION(14, "DCMI_HSYNC"),
+               STM32_FUNCTION(15, "LCD_VSYNC"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(5, "PA5"),
+               STM32_FUNCTION(0, "GPIOA5"),
+               STM32_FUNCTION(2, "TIM2_CH1 TIM2_ETR"),
+               STM32_FUNCTION(4, "TIM8_CH1N"),
+               STM32_FUNCTION(6, "SPI1_SCK I2S1_CK"),
+               STM32_FUNCTION(9, "SPI6_SCK"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_CK"),
+               STM32_FUNCTION(15, "LCD_R4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(6, "PA6"),
+               STM32_FUNCTION(0, "GPIOA6"),
+               STM32_FUNCTION(2, "TIM1_BKIN"),
+               STM32_FUNCTION(3, "TIM3_CH1"),
+               STM32_FUNCTION(4, "TIM8_BKIN"),
+               STM32_FUNCTION(6, "SPI1_MISO I2S1_SDI"),
+               STM32_FUNCTION(9, "SPI6_MISO"),
+               STM32_FUNCTION(10, "TIM13_CH1"),
+               STM32_FUNCTION(11, "TIM8_BKIN_COMP12"),
+               STM32_FUNCTION(12, "MDIOS_MDC"),
+               STM32_FUNCTION(13, "TIM1_BKIN_COMP12"),
+               STM32_FUNCTION(14, "DCMI_PIXCLK"),
+               STM32_FUNCTION(15, "LCD_G2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(7, "PA7"),
+               STM32_FUNCTION(0, "GPIOA7"),
+               STM32_FUNCTION(2, "TIM1_CH1N"),
+               STM32_FUNCTION(3, "TIM3_CH2"),
+               STM32_FUNCTION(4, "TIM8_CH1N"),
+               STM32_FUNCTION(6, "SPI1_MOSI I2S1_SDO"),
+               STM32_FUNCTION(9, "SPI6_MOSI"),
+               STM32_FUNCTION(10, "TIM14_CH1"),
+               STM32_FUNCTION(12, "ETH_MII_RX_DV ETH_RMII_CRS_DV"),
+               STM32_FUNCTION(13, "FMC_SDNWE"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(8, "PA8"),
+               STM32_FUNCTION(0, "GPIOA8"),
+               STM32_FUNCTION(1, "MCO1"),
+               STM32_FUNCTION(2, "TIM1_CH1"),
+               STM32_FUNCTION(3, "HRTIM_CHB2"),
+               STM32_FUNCTION(4, "TIM8_BKIN2"),
+               STM32_FUNCTION(5, "I2C3_SCL"),
+               STM32_FUNCTION(8, "USART1_CK"),
+               STM32_FUNCTION(11, "OTG_FS_SOF"),
+               STM32_FUNCTION(12, "UART7_RX"),
+               STM32_FUNCTION(13, "TIM8_BKIN2_COMP12"),
+               STM32_FUNCTION(14, "LCD_B3"),
+               STM32_FUNCTION(15, "LCD_R6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(9, "PA9"),
+               STM32_FUNCTION(0, "GPIOA9"),
+               STM32_FUNCTION(2, "TIM1_CH2"),
+               STM32_FUNCTION(3, "HRTIM_CHC1"),
+               STM32_FUNCTION(4, "LPUART1_TX"),
+               STM32_FUNCTION(5, "I2C3_SMBA"),
+               STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"),
+               STM32_FUNCTION(8, "USART1_TX"),
+               STM32_FUNCTION(10, "CAN1_RXFD"),
+               STM32_FUNCTION(12, "ETH_TX_ER"),
+               STM32_FUNCTION(14, "DCMI_D0"),
+               STM32_FUNCTION(15, "LCD_R5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(10, "PA10"),
+               STM32_FUNCTION(0, "GPIOA10"),
+               STM32_FUNCTION(2, "TIM1_CH3"),
+               STM32_FUNCTION(3, "HRTIM_CHC2"),
+               STM32_FUNCTION(4, "LPUART1_RX"),
+               STM32_FUNCTION(8, "USART1_RX"),
+               STM32_FUNCTION(10, "CAN1_TXFD"),
+               STM32_FUNCTION(11, "OTG_FS_ID"),
+               STM32_FUNCTION(12, "MDIOS_MDIO"),
+               STM32_FUNCTION(13, "LCD_B4"),
+               STM32_FUNCTION(14, "DCMI_D1"),
+               STM32_FUNCTION(15, "LCD_B1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(11, "PA11"),
+               STM32_FUNCTION(0, "GPIOA11"),
+               STM32_FUNCTION(2, "TIM1_CH4"),
+               STM32_FUNCTION(3, "HRTIM_CHD1"),
+               STM32_FUNCTION(4, "LPUART1_CTS"),
+               STM32_FUNCTION(6, "SPI2_NSS I2S2_WS"),
+               STM32_FUNCTION(7, "UART4_RX"),
+               STM32_FUNCTION(8, "USART1_CTS_NSS"),
+               STM32_FUNCTION(10, "CAN1_RX"),
+               STM32_FUNCTION(11, "OTG_FS_DM"),
+               STM32_FUNCTION(15, "LCD_R4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(12, "PA12"),
+               STM32_FUNCTION(0, "GPIOA12"),
+               STM32_FUNCTION(2, "TIM1_ETR"),
+               STM32_FUNCTION(3, "HRTIM_CHD2"),
+               STM32_FUNCTION(4, "LPUART1_RTS"),
+               STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"),
+               STM32_FUNCTION(7, "UART4_TX"),
+               STM32_FUNCTION(8, "USART1_RTS"),
+               STM32_FUNCTION(9, "SAI2_FS_B"),
+               STM32_FUNCTION(10, "CAN1_TX"),
+               STM32_FUNCTION(11, "OTG_FS_DP"),
+               STM32_FUNCTION(15, "LCD_R5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(13, "PA13"),
+               STM32_FUNCTION(0, "GPIOA13"),
+               STM32_FUNCTION(1, "JTMS SWDIO"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(14, "PA14"),
+               STM32_FUNCTION(0, "GPIOA14"),
+               STM32_FUNCTION(1, "JTCK SWCLK"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(15, "PA15"),
+               STM32_FUNCTION(0, "GPIOA15"),
+               STM32_FUNCTION(1, "JTDI"),
+               STM32_FUNCTION(2, "TIM2_CH1 TIM2_ETR"),
+               STM32_FUNCTION(3, "HRTIM_FLT1"),
+               STM32_FUNCTION(5, "HDMI_CEC"),
+               STM32_FUNCTION(6, "SPI1_NSS I2S1_WS"),
+               STM32_FUNCTION(7, "SPI3_NSS I2S3_WS"),
+               STM32_FUNCTION(8, "SPI6_NSS"),
+               STM32_FUNCTION(9, "UART4_RTS"),
+               STM32_FUNCTION(12, "UART7_TX"),
+               STM32_FUNCTION(14, "DSI_TE"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(16, "PB0"),
+               STM32_FUNCTION(0, "GPIOB0"),
+               STM32_FUNCTION(2, "TIM1_CH2N"),
+               STM32_FUNCTION(3, "TIM3_CH3"),
+               STM32_FUNCTION(4, "TIM8_CH2N"),
+               STM32_FUNCTION(7, "DFSDM_CKOUT"),
+               STM32_FUNCTION(9, "UART4_CTS"),
+               STM32_FUNCTION(10, "LCD_R3"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_D1"),
+               STM32_FUNCTION(12, "ETH_MII_RXD2"),
+               STM32_FUNCTION(15, "LCD_G1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(17, "PB1"),
+               STM32_FUNCTION(0, "GPIOB1"),
+               STM32_FUNCTION(2, "TIM1_CH3N"),
+               STM32_FUNCTION(3, "TIM3_CH4"),
+               STM32_FUNCTION(4, "TIM8_CH3N"),
+               STM32_FUNCTION(7, "DFSDM_DATIN1"),
+               STM32_FUNCTION(10, "LCD_R6"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_D2"),
+               STM32_FUNCTION(12, "ETH_MII_RXD3"),
+               STM32_FUNCTION(15, "LCD_G0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(18, "PB2"),
+               STM32_FUNCTION(0, "GPIOB2"),
+               STM32_FUNCTION(3, "SAI1_D1"),
+               STM32_FUNCTION(5, "DFSDM_CKIN1"),
+               STM32_FUNCTION(7, "SAI1_SD_A"),
+               STM32_FUNCTION(8, "SPI3_MOSI I2S3_SDO"),
+               STM32_FUNCTION(9, "SAI4_SD_A"),
+               STM32_FUNCTION(10, "QUADSPI_CLK"),
+               STM32_FUNCTION(11, "SAI4_D1"),
+               STM32_FUNCTION(12, "ETH_TX_ER"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(19, "PB3"),
+               STM32_FUNCTION(0, "GPIOB3"),
+               STM32_FUNCTION(1, "JTDO TRACESWO"),
+               STM32_FUNCTION(2, "TIM2_CH2"),
+               STM32_FUNCTION(3, "HRTIM_FLT4"),
+               STM32_FUNCTION(6, "SPI1_SCK I2S1_CK"),
+               STM32_FUNCTION(7, "SPI3_SCK I2S3_CK"),
+               STM32_FUNCTION(9, "SPI6_SCK"),
+               STM32_FUNCTION(10, "SDMMC2_D2"),
+               STM32_FUNCTION(12, "UART7_RX"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(20, "PB4"),
+               STM32_FUNCTION(0, "GPIOB4"),
+               STM32_FUNCTION(1, "NJTRST"),
+               STM32_FUNCTION(2, "TIM16_BKIN"),
+               STM32_FUNCTION(3, "TIM3_CH1"),
+               STM32_FUNCTION(4, "HRTIM_EEV6"),
+               STM32_FUNCTION(6, "SPI1_MISO I2S1_SDI"),
+               STM32_FUNCTION(7, "SPI3_MISO I2S3_SDI"),
+               STM32_FUNCTION(8, "SPI2_NSS I2S2_WS"),
+               STM32_FUNCTION(9, "SPI6_MISO"),
+               STM32_FUNCTION(10, "SDMMC2_D3"),
+               STM32_FUNCTION(12, "UART7_TX"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(21, "PB5"),
+               STM32_FUNCTION(0, "GPIOB5"),
+               STM32_FUNCTION(2, "TIM17_BKIN"),
+               STM32_FUNCTION(3, "TIM3_CH2"),
+               STM32_FUNCTION(4, "HRTIM_EEV7"),
+               STM32_FUNCTION(5, "I2C1_SMBA"),
+               STM32_FUNCTION(6, "SPI1_MOSI I2S1_SDO"),
+               STM32_FUNCTION(7, "I2C4_SMBA"),
+               STM32_FUNCTION(8, "SPI3_MOSI I2S3_SDO"),
+               STM32_FUNCTION(9, "SPI6_MOSI"),
+               STM32_FUNCTION(10, "CAN2_RX"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_D7"),
+               STM32_FUNCTION(12, "ETH_PPS_OUT"),
+               STM32_FUNCTION(13, "FMC_SDCKE1"),
+               STM32_FUNCTION(14, "DCMI_D10"),
+               STM32_FUNCTION(15, "UART5_RX"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(22, "PB6"),
+               STM32_FUNCTION(0, "GPIOB6"),
+               STM32_FUNCTION(2, "TIM16_CH1N"),
+               STM32_FUNCTION(3, "TIM4_CH1"),
+               STM32_FUNCTION(4, "HRTIM_EEV8"),
+               STM32_FUNCTION(5, "I2C1_SCL"),
+               STM32_FUNCTION(6, "HDMI_CEC"),
+               STM32_FUNCTION(7, "I2C4_SCL"),
+               STM32_FUNCTION(8, "USART1_TX"),
+               STM32_FUNCTION(9, "LPUART1_TX"),
+               STM32_FUNCTION(10, "CAN2_TX"),
+               STM32_FUNCTION(11, "QUADSPI_BK1_NCS"),
+               STM32_FUNCTION(12, "DFSDM_DATIN5"),
+               STM32_FUNCTION(13, "FMC_SDNE1"),
+               STM32_FUNCTION(14, "DCMI_D5"),
+               STM32_FUNCTION(15, "UART5_TX"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(23, "PB7"),
+               STM32_FUNCTION(0, "GPIOB7"),
+               STM32_FUNCTION(2, "TIM17_CH1N"),
+               STM32_FUNCTION(3, "TIM4_CH2"),
+               STM32_FUNCTION(4, "HRTIM_EEV9"),
+               STM32_FUNCTION(5, "I2C1_SDA"),
+               STM32_FUNCTION(7, "I2C4_SDA"),
+               STM32_FUNCTION(8, "USART1_RX"),
+               STM32_FUNCTION(9, "LPUART1_RX"),
+               STM32_FUNCTION(10, "CAN2_TXFD"),
+               STM32_FUNCTION(12, "DFSDM_CKIN5"),
+               STM32_FUNCTION(13, "FMC_NL"),
+               STM32_FUNCTION(14, "DCMI_VSYNC"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(24, "PB8"),
+               STM32_FUNCTION(0, "GPIOB8"),
+               STM32_FUNCTION(2, "TIM16_CH1"),
+               STM32_FUNCTION(3, "TIM4_CH3"),
+               STM32_FUNCTION(4, "DFSDM_CKIN7"),
+               STM32_FUNCTION(5, "I2C1_SCL"),
+               STM32_FUNCTION(7, "I2C4_SCL"),
+               STM32_FUNCTION(8, "SDMMC1_CKIN"),
+               STM32_FUNCTION(9, "UART4_RX"),
+               STM32_FUNCTION(10, "CAN1_RX"),
+               STM32_FUNCTION(11, "SDMMC2_D4"),
+               STM32_FUNCTION(12, "ETH_MII_TXD3"),
+               STM32_FUNCTION(13, "SDMMC1_D4"),
+               STM32_FUNCTION(14, "DCMI_D6"),
+               STM32_FUNCTION(15, "LCD_B6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(25, "PB9"),
+               STM32_FUNCTION(0, "GPIOB9"),
+               STM32_FUNCTION(2, "TIM17_CH1"),
+               STM32_FUNCTION(3, "TIM4_CH4"),
+               STM32_FUNCTION(4, "DFSDM_DATIN7"),
+               STM32_FUNCTION(5, "I2C1_SDA"),
+               STM32_FUNCTION(6, "SPI2_NSS I2S2_WS"),
+               STM32_FUNCTION(7, "I2C4_SDA"),
+               STM32_FUNCTION(8, "SDMMC1_CDIR"),
+               STM32_FUNCTION(9, "UART4_TX"),
+               STM32_FUNCTION(10, "CAN1_TX"),
+               STM32_FUNCTION(11, "SDMMC2_D5"),
+               STM32_FUNCTION(12, "I2C4_SMBA"),
+               STM32_FUNCTION(13, "SDMMC1_D5"),
+               STM32_FUNCTION(14, "DCMI_D7"),
+               STM32_FUNCTION(15, "LCD_B7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(26, "PB10"),
+               STM32_FUNCTION(0, "GPIOB10"),
+               STM32_FUNCTION(2, "TIM2_CH3"),
+               STM32_FUNCTION(3, "HRTIM_SCOUT"),
+               STM32_FUNCTION(4, "LPTIM2_IN1"),
+               STM32_FUNCTION(5, "I2C2_SCL"),
+               STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"),
+               STM32_FUNCTION(7, "DFSDM_DATIN7"),
+               STM32_FUNCTION(8, "USART3_TX"),
+               STM32_FUNCTION(10, "QUADSPI_BK1_NCS"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_D3"),
+               STM32_FUNCTION(12, "ETH_MII_RX_ER"),
+               STM32_FUNCTION(15, "LCD_G4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(27, "PB11"),
+               STM32_FUNCTION(0, "GPIOB11"),
+               STM32_FUNCTION(2, "TIM2_CH4"),
+               STM32_FUNCTION(3, "HRTIM_SCIN"),
+               STM32_FUNCTION(4, "LPTIM2_ETR"),
+               STM32_FUNCTION(5, "I2C2_SDA"),
+               STM32_FUNCTION(7, "DFSDM_CKIN7"),
+               STM32_FUNCTION(8, "USART3_RX"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_D4"),
+               STM32_FUNCTION(12, "ETH_MII_TX_EN ETH_RMII_TX_EN"),
+               STM32_FUNCTION(14, "DSI_TE"),
+               STM32_FUNCTION(15, "LCD_G5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(28, "PB12"),
+               STM32_FUNCTION(0, "GPIOB12"),
+               STM32_FUNCTION(2, "TIM1_BKIN"),
+               STM32_FUNCTION(5, "I2C2_SMBA"),
+               STM32_FUNCTION(6, "SPI2_NSS I2S2_WS"),
+               STM32_FUNCTION(7, "DFSDM_DATIN1"),
+               STM32_FUNCTION(8, "USART3_CK"),
+               STM32_FUNCTION(10, "CAN2_RX"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_D5"),
+               STM32_FUNCTION(12, "ETH_MII_TXD0 ETH_RMII_TXD0"),
+               STM32_FUNCTION(13, "OTG_HS_ID"),
+               STM32_FUNCTION(14, "TIM1_BKIN_COMP12"),
+               STM32_FUNCTION(15, "UART5_RX"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(29, "PB13"),
+               STM32_FUNCTION(0, "GPIOB13"),
+               STM32_FUNCTION(2, "TIM1_CH1N"),
+               STM32_FUNCTION(4, "LPTIM2_OUT"),
+               STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"),
+               STM32_FUNCTION(7, "DFSDM_CKIN1"),
+               STM32_FUNCTION(8, "USART3_CTS_NSS"),
+               STM32_FUNCTION(10, "CAN2_TX"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_D6"),
+               STM32_FUNCTION(12, "ETH_MII_TXD1 ETH_RMII_TXD1"),
+               STM32_FUNCTION(15, "UART5_TX"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(30, "PB14"),
+               STM32_FUNCTION(0, "GPIOB14"),
+               STM32_FUNCTION(2, "TIM1_CH2N"),
+               STM32_FUNCTION(4, "TIM8_CH2N"),
+               STM32_FUNCTION(5, "USART1_TX"),
+               STM32_FUNCTION(6, "SPI2_MISO I2S2_SDI"),
+               STM32_FUNCTION(7, "DFSDM_DATIN2"),
+               STM32_FUNCTION(8, "USART3_RTS"),
+               STM32_FUNCTION(9, "UART4_RTS"),
+               STM32_FUNCTION(10, "SDMMC2_D0"),
+               STM32_FUNCTION(13, "OTG_HS_DM"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(31, "PB15"),
+               STM32_FUNCTION(0, "GPIOB15"),
+               STM32_FUNCTION(1, "RTC_REFIN"),
+               STM32_FUNCTION(2, "TIM1_CH3N"),
+               STM32_FUNCTION(4, "TIM8_CH3N"),
+               STM32_FUNCTION(5, "USART1_RX"),
+               STM32_FUNCTION(6, "SPI2_MOSI I2S2_SDO"),
+               STM32_FUNCTION(7, "DFSDM_CKIN2"),
+               STM32_FUNCTION(9, "UART4_CTS"),
+               STM32_FUNCTION(10, "SDMMC2_D1"),
+               STM32_FUNCTION(13, "OTG_HS_DP"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(32, "PC0"),
+               STM32_FUNCTION(0, "GPIOC0"),
+               STM32_FUNCTION(4, "DFSDM_CKIN0"),
+               STM32_FUNCTION(7, "DFSDM_DATIN4"),
+               STM32_FUNCTION(9, "SAI2_FS_B"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_STP"),
+               STM32_FUNCTION(13, "FMC_SDNWE"),
+               STM32_FUNCTION(15, "LCD_R5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(33, "PC1"),
+               STM32_FUNCTION(0, "GPIOC1"),
+               STM32_FUNCTION(1, "TRACED0"),
+               STM32_FUNCTION(3, "SAI1_D1"),
+               STM32_FUNCTION(4, "DFSDM_DATIN0"),
+               STM32_FUNCTION(5, "DFSDM_CKIN4"),
+               STM32_FUNCTION(6, "SPI2_MOSI I2S2_SDO"),
+               STM32_FUNCTION(7, "SAI1_SD_A"),
+               STM32_FUNCTION(9, "SAI4_SD_A"),
+               STM32_FUNCTION(10, "SDMMC2_CK"),
+               STM32_FUNCTION(11, "SAI4_D1"),
+               STM32_FUNCTION(12, "ETH_MDC"),
+               STM32_FUNCTION(13, "MDIOS_MDC"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(34, "PC2"),
+               STM32_FUNCTION(0, "GPIOC2"),
+               STM32_FUNCTION(4, "DFSDM_CKIN1"),
+               STM32_FUNCTION(6, "SPI2_MISO I2S2_SDI"),
+               STM32_FUNCTION(7, "DFSDM_CKOUT"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_DIR"),
+               STM32_FUNCTION(12, "ETH_MII_TXD2"),
+               STM32_FUNCTION(13, "FMC_SDNE0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(35, "PC3"),
+               STM32_FUNCTION(0, "GPIOC3"),
+               STM32_FUNCTION(4, "DFSDM_DATIN1"),
+               STM32_FUNCTION(6, "SPI2_MOSI I2S2_SDO"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_NXT"),
+               STM32_FUNCTION(12, "ETH_MII_TX_CLK"),
+               STM32_FUNCTION(13, "FMC_SDCKE0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(36, "PC4"),
+               STM32_FUNCTION(0, "GPIOC4"),
+               STM32_FUNCTION(4, "DFSDM_CKIN2"),
+               STM32_FUNCTION(6, "I2S1_MCK"),
+               STM32_FUNCTION(10, "SPDIFRX_IN2"),
+               STM32_FUNCTION(12, "ETH_MII_RXD0 ETH_RMII_RXD0"),
+               STM32_FUNCTION(13, "FMC_SDNE0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(37, "PC5"),
+               STM32_FUNCTION(0, "GPIOC5"),
+               STM32_FUNCTION(3, "SAI1_D3"),
+               STM32_FUNCTION(4, "DFSDM_DATIN2"),
+               STM32_FUNCTION(10, "SPDIFRX_IN3"),
+               STM32_FUNCTION(11, "SAI4_D3"),
+               STM32_FUNCTION(12, "ETH_MII_RXD1 ETH_RMII_RXD1"),
+               STM32_FUNCTION(13, "FMC_SDCKE0"),
+               STM32_FUNCTION(14, "COMP_1_OUT"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(38, "PC6"),
+               STM32_FUNCTION(0, "GPIOC6"),
+               STM32_FUNCTION(2, "HRTIM_CHA1"),
+               STM32_FUNCTION(3, "TIM3_CH1"),
+               STM32_FUNCTION(4, "TIM8_CH1"),
+               STM32_FUNCTION(5, "DFSDM_CKIN3"),
+               STM32_FUNCTION(6, "I2S2_MCK"),
+               STM32_FUNCTION(8, "USART6_TX"),
+               STM32_FUNCTION(9, "SDMMC1_D0DIR"),
+               STM32_FUNCTION(10, "FMC_NWAIT"),
+               STM32_FUNCTION(11, "SDMMC2_D6"),
+               STM32_FUNCTION(13, "SDMMC1_D6"),
+               STM32_FUNCTION(14, "DCMI_D0"),
+               STM32_FUNCTION(15, "LCD_HSYNC"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(39, "PC7"),
+               STM32_FUNCTION(0, "GPIOC7"),
+               STM32_FUNCTION(1, "TRGIO"),
+               STM32_FUNCTION(2, "HRTIM_CHA2"),
+               STM32_FUNCTION(3, "TIM3_CH2"),
+               STM32_FUNCTION(4, "TIM8_CH2"),
+               STM32_FUNCTION(5, "DFSDM_DATIN3"),
+               STM32_FUNCTION(7, "I2S3_MCK"),
+               STM32_FUNCTION(8, "USART6_RX"),
+               STM32_FUNCTION(9, "SDMMC1_D123DIR"),
+               STM32_FUNCTION(10, "FMC_NE1"),
+               STM32_FUNCTION(11, "SDMMC2_D7"),
+               STM32_FUNCTION(12, "SWPMI_TX"),
+               STM32_FUNCTION(13, "SDMMC1_D7"),
+               STM32_FUNCTION(14, "DCMI_D1"),
+               STM32_FUNCTION(15, "LCD_G6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(40, "PC8"),
+               STM32_FUNCTION(0, "GPIOC8"),
+               STM32_FUNCTION(1, "TRACED1"),
+               STM32_FUNCTION(2, "HRTIM_CHB1"),
+               STM32_FUNCTION(3, "TIM3_CH3"),
+               STM32_FUNCTION(4, "TIM8_CH3"),
+               STM32_FUNCTION(8, "USART6_CK"),
+               STM32_FUNCTION(9, "UART5_RTS"),
+               STM32_FUNCTION(10, "FMC_NE2 FMC_NCE"),
+               STM32_FUNCTION(12, "SWPMI_RX"),
+               STM32_FUNCTION(13, "SDMMC1_D0"),
+               STM32_FUNCTION(14, "DCMI_D2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(41, "PC9"),
+               STM32_FUNCTION(0, "GPIOC9"),
+               STM32_FUNCTION(1, "MCO2"),
+               STM32_FUNCTION(3, "TIM3_CH4"),
+               STM32_FUNCTION(4, "TIM8_CH4"),
+               STM32_FUNCTION(5, "I2C3_SDA"),
+               STM32_FUNCTION(6, "I2S_CKIN"),
+               STM32_FUNCTION(9, "UART5_CTS"),
+               STM32_FUNCTION(10, "QUADSPI_BK1_IO0"),
+               STM32_FUNCTION(11, "LCD_G3"),
+               STM32_FUNCTION(12, "SWPMI_SUSPEND"),
+               STM32_FUNCTION(13, "SDMMC1_D1"),
+               STM32_FUNCTION(14, "DCMI_D3"),
+               STM32_FUNCTION(15, "LCD_B2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(42, "PC10"),
+               STM32_FUNCTION(0, "GPIOC10"),
+               STM32_FUNCTION(3, "HRTIM_EEV1"),
+               STM32_FUNCTION(4, "DFSDM_CKIN5"),
+               STM32_FUNCTION(7, "SPI3_SCK I2S3_CK"),
+               STM32_FUNCTION(8, "USART3_TX"),
+               STM32_FUNCTION(9, "UART4_TX"),
+               STM32_FUNCTION(10, "QUADSPI_BK1_IO1"),
+               STM32_FUNCTION(13, "SDMMC1_D2"),
+               STM32_FUNCTION(14, "DCMI_D8"),
+               STM32_FUNCTION(15, "LCD_R2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(43, "PC11"),
+               STM32_FUNCTION(0, "GPIOC11"),
+               STM32_FUNCTION(3, "HRTIM_FLT2"),
+               STM32_FUNCTION(4, "DFSDM_DATIN5"),
+               STM32_FUNCTION(7, "SPI3_MISO I2S3_SDI"),
+               STM32_FUNCTION(8, "USART3_RX"),
+               STM32_FUNCTION(9, "UART4_RX"),
+               STM32_FUNCTION(10, "QUADSPI_BK2_NCS"),
+               STM32_FUNCTION(13, "SDMMC1_D3"),
+               STM32_FUNCTION(14, "DCMI_D4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(44, "PC12"),
+               STM32_FUNCTION(0, "GPIOC12"),
+               STM32_FUNCTION(1, "TRACED3"),
+               STM32_FUNCTION(3, "HRTIM_EEV2"),
+               STM32_FUNCTION(7, "SPI3_MOSI I2S3_SDO"),
+               STM32_FUNCTION(8, "USART3_CK"),
+               STM32_FUNCTION(9, "UART5_TX"),
+               STM32_FUNCTION(13, "SDMMC1_CK"),
+               STM32_FUNCTION(14, "DCMI_D9"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(45, "PC13"),
+               STM32_FUNCTION(0, "GPIOC13"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(46, "PC14"),
+               STM32_FUNCTION(0, "GPIOC14"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(47, "PC15"),
+               STM32_FUNCTION(0, "GPIOC15"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(48, "PD0"),
+               STM32_FUNCTION(0, "GPIOD0"),
+               STM32_FUNCTION(4, "DFSDM_CKIN6"),
+               STM32_FUNCTION(7, "SAI3_SCK_A"),
+               STM32_FUNCTION(9, "UART4_RX"),
+               STM32_FUNCTION(10, "CAN1_RX"),
+               STM32_FUNCTION(13, "FMC_D2 FMC_DA2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(49, "PD1"),
+               STM32_FUNCTION(0, "GPIOD1"),
+               STM32_FUNCTION(4, "DFSDM_DATIN6"),
+               STM32_FUNCTION(7, "SAI3_SD_A"),
+               STM32_FUNCTION(9, "UART4_TX"),
+               STM32_FUNCTION(10, "CAN1_TX"),
+               STM32_FUNCTION(13, "FMC_D3 FMC_DA3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(50, "PD2"),
+               STM32_FUNCTION(0, "GPIOD2"),
+               STM32_FUNCTION(1, "TRACED2"),
+               STM32_FUNCTION(3, "TIM3_ETR"),
+               STM32_FUNCTION(9, "UART5_RX"),
+               STM32_FUNCTION(13, "SDMMC1_CMD"),
+               STM32_FUNCTION(14, "DCMI_D11"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(51, "PD3"),
+               STM32_FUNCTION(0, "GPIOD3"),
+               STM32_FUNCTION(4, "DFSDM_CKOUT"),
+               STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"),
+               STM32_FUNCTION(8, "USART2_CTS_NSS"),
+               STM32_FUNCTION(13, "FMC_CLK"),
+               STM32_FUNCTION(14, "DCMI_D5"),
+               STM32_FUNCTION(15, "LCD_G7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(52, "PD4"),
+               STM32_FUNCTION(0, "GPIOD4"),
+               STM32_FUNCTION(3, "HRTIM_FLT3"),
+               STM32_FUNCTION(7, "SAI3_FS_A"),
+               STM32_FUNCTION(8, "USART2_RTS"),
+               STM32_FUNCTION(10, "CAN1_RXFD"),
+               STM32_FUNCTION(13, "FMC_NOE"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(53, "PD5"),
+               STM32_FUNCTION(0, "GPIOD5"),
+               STM32_FUNCTION(3, "HRTIM_EEV3"),
+               STM32_FUNCTION(8, "USART2_TX"),
+               STM32_FUNCTION(10, "CAN1_TXFD"),
+               STM32_FUNCTION(13, "FMC_NWE"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(54, "PD6"),
+               STM32_FUNCTION(0, "GPIOD6"),
+               STM32_FUNCTION(3, "SAI1_D1"),
+               STM32_FUNCTION(4, "DFSDM_CKIN4"),
+               STM32_FUNCTION(5, "DFSDM_DATIN1"),
+               STM32_FUNCTION(6, "SPI3_MOSI I2S3_SDO"),
+               STM32_FUNCTION(7, "SAI1_SD_A"),
+               STM32_FUNCTION(8, "USART2_RX"),
+               STM32_FUNCTION(9, "SAI4_SD_A"),
+               STM32_FUNCTION(10, "CAN2_RXFD"),
+               STM32_FUNCTION(11, "SAI4_D1"),
+               STM32_FUNCTION(12, "SDMMC2_CK"),
+               STM32_FUNCTION(13, "FMC_NWAIT"),
+               STM32_FUNCTION(14, "DCMI_D10"),
+               STM32_FUNCTION(15, "LCD_B2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(55, "PD7"),
+               STM32_FUNCTION(0, "GPIOD7"),
+               STM32_FUNCTION(4, "DFSDM_DATIN4"),
+               STM32_FUNCTION(6, "SPI1_MOSI I2S1_SDO"),
+               STM32_FUNCTION(7, "DFSDM_CKIN1"),
+               STM32_FUNCTION(8, "USART2_CK"),
+               STM32_FUNCTION(10, "SPDIFRX_IN0"),
+               STM32_FUNCTION(12, "SDMMC2_CMD"),
+               STM32_FUNCTION(13, "FMC_NE1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(56, "PD8"),
+               STM32_FUNCTION(0, "GPIOD8"),
+               STM32_FUNCTION(4, "DFSDM_CKIN3"),
+               STM32_FUNCTION(7, "SAI3_SCK_B"),
+               STM32_FUNCTION(8, "USART3_TX"),
+               STM32_FUNCTION(10, "SPDIFRX_IN1"),
+               STM32_FUNCTION(13, "FMC_D13 FMC_DA13"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(57, "PD9"),
+               STM32_FUNCTION(0, "GPIOD9"),
+               STM32_FUNCTION(4, "DFSDM_DATIN3"),
+               STM32_FUNCTION(7, "SAI3_SD_B"),
+               STM32_FUNCTION(8, "USART3_RX"),
+               STM32_FUNCTION(10, "CAN2_RXFD"),
+               STM32_FUNCTION(13, "FMC_D14 FMC_DA14"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(58, "PD10"),
+               STM32_FUNCTION(0, "GPIOD10"),
+               STM32_FUNCTION(4, "DFSDM_CKOUT"),
+               STM32_FUNCTION(7, "SAI3_FS_B"),
+               STM32_FUNCTION(8, "USART3_CK"),
+               STM32_FUNCTION(10, "CAN2_TXFD"),
+               STM32_FUNCTION(13, "FMC_D15 FMC_DA15"),
+               STM32_FUNCTION(15, "LCD_B3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(59, "PD11"),
+               STM32_FUNCTION(0, "GPIOD11"),
+               STM32_FUNCTION(4, "LPTIM2_IN2"),
+               STM32_FUNCTION(5, "I2C4_SMBA"),
+               STM32_FUNCTION(8, "USART3_CTS_NSS"),
+               STM32_FUNCTION(10, "QUADSPI_BK1_IO0"),
+               STM32_FUNCTION(11, "SAI2_SD_A"),
+               STM32_FUNCTION(13, "FMC_A16"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(60, "PD12"),
+               STM32_FUNCTION(0, "GPIOD12"),
+               STM32_FUNCTION(2, "LPTIM1_IN1"),
+               STM32_FUNCTION(3, "TIM4_CH1"),
+               STM32_FUNCTION(4, "LPTIM2_IN1"),
+               STM32_FUNCTION(5, "I2C4_SCL"),
+               STM32_FUNCTION(8, "USART3_RTS"),
+               STM32_FUNCTION(10, "QUADSPI_BK1_IO1"),
+               STM32_FUNCTION(11, "SAI2_FS_A"),
+               STM32_FUNCTION(13, "FMC_A17"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(61, "PD13"),
+               STM32_FUNCTION(0, "GPIOD13"),
+               STM32_FUNCTION(2, "LPTIM1_OUT"),
+               STM32_FUNCTION(3, "TIM4_CH2"),
+               STM32_FUNCTION(5, "I2C4_SDA"),
+               STM32_FUNCTION(10, "QUADSPI_BK1_IO3"),
+               STM32_FUNCTION(11, "SAI2_SCK_A"),
+               STM32_FUNCTION(13, "FMC_A18"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(62, "PD14"),
+               STM32_FUNCTION(0, "GPIOD14"),
+               STM32_FUNCTION(3, "TIM4_CH3"),
+               STM32_FUNCTION(7, "SAI3_MCLK_B"),
+               STM32_FUNCTION(9, "UART8_CTS"),
+               STM32_FUNCTION(13, "FMC_D0 FMC_DA0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(63, "PD15"),
+               STM32_FUNCTION(0, "GPIOD15"),
+               STM32_FUNCTION(3, "TIM4_CH4"),
+               STM32_FUNCTION(7, "SAI3_MCLK_A"),
+               STM32_FUNCTION(9, "UART8_RTS"),
+               STM32_FUNCTION(13, "FMC_D1 FMC_DA1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(64, "PE0"),
+               STM32_FUNCTION(0, "GPIOE0"),
+               STM32_FUNCTION(2, "LPTIM1_ETR"),
+               STM32_FUNCTION(3, "TIM4_ETR"),
+               STM32_FUNCTION(4, "HRTIM_SCIN"),
+               STM32_FUNCTION(5, "LPTIM2_ETR"),
+               STM32_FUNCTION(9, "UART8_RX"),
+               STM32_FUNCTION(10, "CAN1_RXFD"),
+               STM32_FUNCTION(11, "SAI2_MCK_A"),
+               STM32_FUNCTION(13, "FMC_NBL0"),
+               STM32_FUNCTION(14, "DCMI_D2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(65, "PE1"),
+               STM32_FUNCTION(0, "GPIOE1"),
+               STM32_FUNCTION(2, "LPTIM1_IN2"),
+               STM32_FUNCTION(4, "HRTIM_SCOUT"),
+               STM32_FUNCTION(9, "UART8_TX"),
+               STM32_FUNCTION(10, "CAN1_TXFD"),
+               STM32_FUNCTION(13, "FMC_NBL1"),
+               STM32_FUNCTION(14, "DCMI_D3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(66, "PE2"),
+               STM32_FUNCTION(0, "GPIOE2"),
+               STM32_FUNCTION(1, "TRACECLK"),
+               STM32_FUNCTION(3, "SAI1_CK1"),
+               STM32_FUNCTION(6, "SPI4_SCK"),
+               STM32_FUNCTION(7, "SAI1_MCLK_A"),
+               STM32_FUNCTION(9, "SAI4_MCLK_A"),
+               STM32_FUNCTION(10, "QUADSPI_BK1_IO2"),
+               STM32_FUNCTION(11, "SAI4_CK1"),
+               STM32_FUNCTION(12, "ETH_MII_TXD3"),
+               STM32_FUNCTION(13, "FMC_A23"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(67, "PE3"),
+               STM32_FUNCTION(0, "GPIOE3"),
+               STM32_FUNCTION(1, "TRACED0"),
+               STM32_FUNCTION(5, "TIM15_BKIN"),
+               STM32_FUNCTION(7, "SAI1_SD_B"),
+               STM32_FUNCTION(9, "SAI4_SD_B"),
+               STM32_FUNCTION(13, "FMC_A19"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(68, "PE4"),
+               STM32_FUNCTION(0, "GPIOE4"),
+               STM32_FUNCTION(1, "TRACED1"),
+               STM32_FUNCTION(3, "SAI1_D2"),
+               STM32_FUNCTION(4, "DFSDM_DATIN3"),
+               STM32_FUNCTION(5, "TIM15_CH1N"),
+               STM32_FUNCTION(6, "SPI4_NSS"),
+               STM32_FUNCTION(7, "SAI1_FS_A"),
+               STM32_FUNCTION(9, "SAI4_FS_A"),
+               STM32_FUNCTION(11, "SAI4_D2"),
+               STM32_FUNCTION(13, "FMC_A20"),
+               STM32_FUNCTION(14, "DCMI_D4"),
+               STM32_FUNCTION(15, "LCD_B0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(69, "PE5"),
+               STM32_FUNCTION(0, "GPIOE5"),
+               STM32_FUNCTION(1, "TRACED2"),
+               STM32_FUNCTION(3, "SAI1_CK2"),
+               STM32_FUNCTION(4, "DFSDM_CKIN3"),
+               STM32_FUNCTION(5, "TIM15_CH1"),
+               STM32_FUNCTION(6, "SPI4_MISO"),
+               STM32_FUNCTION(7, "SAI1_SCK_A"),
+               STM32_FUNCTION(9, "SAI4_SCK_A"),
+               STM32_FUNCTION(11, "SAI4_CK2"),
+               STM32_FUNCTION(13, "FMC_A21"),
+               STM32_FUNCTION(14, "DCMI_D6"),
+               STM32_FUNCTION(15, "LCD_G0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(70, "PE6"),
+               STM32_FUNCTION(0, "GPIOE6"),
+               STM32_FUNCTION(1, "TRACED3"),
+               STM32_FUNCTION(2, "TIM1_BKIN2"),
+               STM32_FUNCTION(3, "SAI1_D1"),
+               STM32_FUNCTION(5, "TIM15_CH2"),
+               STM32_FUNCTION(6, "SPI4_MOSI"),
+               STM32_FUNCTION(7, "SAI1_SD_A"),
+               STM32_FUNCTION(9, "SAI4_SD_A"),
+               STM32_FUNCTION(10, "SAI4_D1"),
+               STM32_FUNCTION(11, "SAI2_MCK_B"),
+               STM32_FUNCTION(12, "TIM1_BKIN2_COMP12"),
+               STM32_FUNCTION(13, "FMC_A22"),
+               STM32_FUNCTION(14, "DCMI_D7"),
+               STM32_FUNCTION(15, "LCD_G1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(71, "PE7"),
+               STM32_FUNCTION(0, "GPIOE7"),
+               STM32_FUNCTION(2, "TIM1_ETR"),
+               STM32_FUNCTION(4, "DFSDM_DATIN2"),
+               STM32_FUNCTION(8, "UART7_RX"),
+               STM32_FUNCTION(11, "QUADSPI_BK2_IO0"),
+               STM32_FUNCTION(13, "FMC_D4 FMC_DA4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(72, "PE8"),
+               STM32_FUNCTION(0, "GPIOE8"),
+               STM32_FUNCTION(2, "TIM1_CH1N"),
+               STM32_FUNCTION(4, "DFSDM_CKIN2"),
+               STM32_FUNCTION(8, "UART7_TX"),
+               STM32_FUNCTION(11, "QUADSPI_BK2_IO1"),
+               STM32_FUNCTION(13, "FMC_D5 FMC_DA5"),
+               STM32_FUNCTION(14, "COMP_2_OUT"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(73, "PE9"),
+               STM32_FUNCTION(0, "GPIOE9"),
+               STM32_FUNCTION(2, "TIM1_CH1"),
+               STM32_FUNCTION(4, "DFSDM_CKOUT"),
+               STM32_FUNCTION(8, "UART7_RTS"),
+               STM32_FUNCTION(11, "QUADSPI_BK2_IO2"),
+               STM32_FUNCTION(13, "FMC_D6 FMC_DA6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(74, "PE10"),
+               STM32_FUNCTION(0, "GPIOE10"),
+               STM32_FUNCTION(2, "TIM1_CH2N"),
+               STM32_FUNCTION(4, "DFSDM_DATIN4"),
+               STM32_FUNCTION(8, "UART7_CTS"),
+               STM32_FUNCTION(11, "QUADSPI_BK2_IO3"),
+               STM32_FUNCTION(13, "FMC_D7 FMC_DA7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(75, "PE11"),
+               STM32_FUNCTION(0, "GPIOE11"),
+               STM32_FUNCTION(2, "TIM1_CH2"),
+               STM32_FUNCTION(4, "DFSDM_CKIN4"),
+               STM32_FUNCTION(6, "SPI4_NSS"),
+               STM32_FUNCTION(11, "SAI2_SD_B"),
+               STM32_FUNCTION(13, "FMC_D8 FMC_DA8"),
+               STM32_FUNCTION(15, "LCD_G3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(76, "PE12"),
+               STM32_FUNCTION(0, "GPIOE12"),
+               STM32_FUNCTION(2, "TIM1_CH3N"),
+               STM32_FUNCTION(4, "DFSDM_DATIN5"),
+               STM32_FUNCTION(6, "SPI4_SCK"),
+               STM32_FUNCTION(11, "SAI2_SCK_B"),
+               STM32_FUNCTION(13, "FMC_D9 FMC_DA9"),
+               STM32_FUNCTION(14, "COMP_1_OUT"),
+               STM32_FUNCTION(15, "LCD_B4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(77, "PE13"),
+               STM32_FUNCTION(0, "GPIOE13"),
+               STM32_FUNCTION(2, "TIM1_CH3"),
+               STM32_FUNCTION(4, "DFSDM_CKIN5"),
+               STM32_FUNCTION(6, "SPI4_MISO"),
+               STM32_FUNCTION(11, "SAI2_FS_B"),
+               STM32_FUNCTION(13, "FMC_D10 FMC_DA10"),
+               STM32_FUNCTION(14, "COMP_2_OUT"),
+               STM32_FUNCTION(15, "LCD_DE"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(78, "PE14"),
+               STM32_FUNCTION(0, "GPIOE14"),
+               STM32_FUNCTION(2, "TIM1_CH4"),
+               STM32_FUNCTION(6, "SPI4_MOSI"),
+               STM32_FUNCTION(11, "SAI2_MCK_B"),
+               STM32_FUNCTION(13, "FMC_D11 FMC_DA11"),
+               STM32_FUNCTION(15, "LCD_CLK"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(79, "PE15"),
+               STM32_FUNCTION(0, "GPIOE15"),
+               STM32_FUNCTION(2, "TIM1_BKIN"),
+               STM32_FUNCTION(6, "HDMI__TIM1_BKIN"),
+               STM32_FUNCTION(13, "FMC_D12 FMC_DA12"),
+               STM32_FUNCTION(14, "TIM1_BKIN_COMP12"),
+               STM32_FUNCTION(15, "LCD_R7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(80, "PF0"),
+               STM32_FUNCTION(0, "GPIOF0"),
+               STM32_FUNCTION(5, "I2C2_SDA"),
+               STM32_FUNCTION(13, "FMC_A0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(81, "PF1"),
+               STM32_FUNCTION(0, "GPIOF1"),
+               STM32_FUNCTION(5, "I2C2_SCL"),
+               STM32_FUNCTION(13, "FMC_A1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(82, "PF2"),
+               STM32_FUNCTION(0, "GPIOF2"),
+               STM32_FUNCTION(5, "I2C2_SMBA"),
+               STM32_FUNCTION(13, "FMC_A2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(83, "PF3"),
+               STM32_FUNCTION(0, "GPIOF3"),
+               STM32_FUNCTION(13, "FMC_A3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(84, "PF4"),
+               STM32_FUNCTION(0, "GPIOF4"),
+               STM32_FUNCTION(13, "FMC_A4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(85, "PF5"),
+               STM32_FUNCTION(0, "GPIOF5"),
+               STM32_FUNCTION(13, "FMC_A5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(86, "PF6"),
+               STM32_FUNCTION(0, "GPIOF6"),
+               STM32_FUNCTION(2, "TIM16_CH1"),
+               STM32_FUNCTION(6, "SPI5_NSS"),
+               STM32_FUNCTION(7, "SAI1_SD_B"),
+               STM32_FUNCTION(8, "UART7_RX"),
+               STM32_FUNCTION(9, "SAI4_SD_B"),
+               STM32_FUNCTION(10, "QUADSPI_BK1_IO3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(87, "PF7"),
+               STM32_FUNCTION(0, "GPIOF7"),
+               STM32_FUNCTION(2, "TIM17_CH1"),
+               STM32_FUNCTION(6, "SPI5_SCK"),
+               STM32_FUNCTION(7, "SAI1_MCLK_B"),
+               STM32_FUNCTION(8, "UART7_TX"),
+               STM32_FUNCTION(9, "SAI4_MCLK_B"),
+               STM32_FUNCTION(10, "QUADSPI_BK1_IO2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(88, "PF8"),
+               STM32_FUNCTION(0, "GPIOF8"),
+               STM32_FUNCTION(2, "TIM16_CH1N"),
+               STM32_FUNCTION(6, "SPI5_MISO"),
+               STM32_FUNCTION(7, "SAI1_SCK_B"),
+               STM32_FUNCTION(8, "UART7_RTS"),
+               STM32_FUNCTION(9, "SAI4_SCK_B"),
+               STM32_FUNCTION(10, "TIM13_CH1"),
+               STM32_FUNCTION(11, "QUADSPI_BK1_IO0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(89, "PF9"),
+               STM32_FUNCTION(0, "GPIOF9"),
+               STM32_FUNCTION(2, "TIM17_CH1N"),
+               STM32_FUNCTION(6, "SPI5_MOSI"),
+               STM32_FUNCTION(7, "SAI1_FS_B"),
+               STM32_FUNCTION(8, "UART7_CTS"),
+               STM32_FUNCTION(9, "SAI4_FS_B"),
+               STM32_FUNCTION(10, "TIM14_CH1"),
+               STM32_FUNCTION(11, "QUADSPI_BK1_IO1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(90, "PF10"),
+               STM32_FUNCTION(0, "GPIOF10"),
+               STM32_FUNCTION(2, "TIM16_BKIN"),
+               STM32_FUNCTION(3, "SAI1_D3"),
+               STM32_FUNCTION(10, "QUADSPI_CLK"),
+               STM32_FUNCTION(11, "SAI4_D3"),
+               STM32_FUNCTION(14, "DCMI_D11"),
+               STM32_FUNCTION(15, "LCD_DE"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(91, "PF11"),
+               STM32_FUNCTION(0, "GPIOF11"),
+               STM32_FUNCTION(6, "SPI5_MOSI"),
+               STM32_FUNCTION(11, "SAI2_SD_B"),
+               STM32_FUNCTION(13, "FMC_SDNRAS"),
+               STM32_FUNCTION(14, "DCMI_D12"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(92, "PF12"),
+               STM32_FUNCTION(0, "GPIOF12"),
+               STM32_FUNCTION(13, "FMC_A6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(93, "PF13"),
+               STM32_FUNCTION(0, "GPIOF13"),
+               STM32_FUNCTION(4, "DFSDM_DATIN6"),
+               STM32_FUNCTION(5, "I2C4_SMBA"),
+               STM32_FUNCTION(13, "FMC_A7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(94, "PF14"),
+               STM32_FUNCTION(0, "GPIOF14"),
+               STM32_FUNCTION(4, "DFSDM_CKIN6"),
+               STM32_FUNCTION(5, "I2C4_SCL"),
+               STM32_FUNCTION(13, "FMC_A8"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(95, "PF15"),
+               STM32_FUNCTION(0, "GPIOF15"),
+               STM32_FUNCTION(5, "I2C4_SDA"),
+               STM32_FUNCTION(13, "FMC_A9"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(96, "PG0"),
+               STM32_FUNCTION(0, "GPIOG0"),
+               STM32_FUNCTION(13, "FMC_A10"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(97, "PG1"),
+               STM32_FUNCTION(0, "GPIOG1"),
+               STM32_FUNCTION(13, "FMC_A11"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(98, "PG2"),
+               STM32_FUNCTION(0, "GPIOG2"),
+               STM32_FUNCTION(4, "TIM8_BKIN"),
+               STM32_FUNCTION(12, "TIM8_BKIN_COMP12"),
+               STM32_FUNCTION(13, "FMC_A12"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(99, "PG3"),
+               STM32_FUNCTION(0, "GPIOG3"),
+               STM32_FUNCTION(4, "TIM8_BKIN2"),
+               STM32_FUNCTION(12, "TIM8_BKIN2_COMP12"),
+               STM32_FUNCTION(13, "FMC_A13"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(100, "PG4"),
+               STM32_FUNCTION(0, "GPIOG4"),
+               STM32_FUNCTION(2, "TIM1_BKIN2"),
+               STM32_FUNCTION(12, "TIM1_BKIN2_COMP12"),
+               STM32_FUNCTION(13, "FMC_A14 FMC_BA0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(101, "PG5"),
+               STM32_FUNCTION(0, "GPIOG5"),
+               STM32_FUNCTION(2, "TIM1_ETR"),
+               STM32_FUNCTION(13, "FMC_A15 FMC_BA1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(102, "PG6"),
+               STM32_FUNCTION(0, "GPIOG6"),
+               STM32_FUNCTION(2, "TIM17_BKIN"),
+               STM32_FUNCTION(3, "HRTIM_CHE1"),
+               STM32_FUNCTION(11, "QUADSPI_BK1_NCS"),
+               STM32_FUNCTION(13, "FMC_NE3"),
+               STM32_FUNCTION(14, "DCMI_D12"),
+               STM32_FUNCTION(15, "LCD_R7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(103, "PG7"),
+               STM32_FUNCTION(0, "GPIOG7"),
+               STM32_FUNCTION(3, "HRTIM_CHE2"),
+               STM32_FUNCTION(7, "SAI1_MCLK_A"),
+               STM32_FUNCTION(8, "USART6_CK"),
+               STM32_FUNCTION(13, "FMC_INT"),
+               STM32_FUNCTION(14, "DCMI_D13"),
+               STM32_FUNCTION(15, "LCD_CLK"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(104, "PG8"),
+               STM32_FUNCTION(0, "GPIOG8"),
+               STM32_FUNCTION(4, "TIM8_ETR"),
+               STM32_FUNCTION(6, "SPI6_NSS"),
+               STM32_FUNCTION(8, "USART6_RTS"),
+               STM32_FUNCTION(9, "SPDIFRX_IN2"),
+               STM32_FUNCTION(12, "ETH_PPS_OUT"),
+               STM32_FUNCTION(13, "FMC_SDCLK"),
+               STM32_FUNCTION(15, "LCD_G7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(105, "PG9"),
+               STM32_FUNCTION(0, "GPIOG9"),
+               STM32_FUNCTION(6, "SPI1_MISO I2S1_SDI"),
+               STM32_FUNCTION(8, "USART6_RX"),
+               STM32_FUNCTION(9, "SPDIFRX_IN3"),
+               STM32_FUNCTION(10, "QUADSPI_BK2_IO2"),
+               STM32_FUNCTION(11, "SAI2_FS_B"),
+               STM32_FUNCTION(13, "FMC_NE2 FMC_NCE"),
+               STM32_FUNCTION(14, "DCMI_VSYNC"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(106, "PG10"),
+               STM32_FUNCTION(0, "GPIOG10"),
+               STM32_FUNCTION(3, "HRTIM_FLT5"),
+               STM32_FUNCTION(6, "SPI1_NSS I2S1_WS"),
+               STM32_FUNCTION(10, "LCD_G3"),
+               STM32_FUNCTION(11, "SAI2_SD_B"),
+               STM32_FUNCTION(13, "FMC_NE3"),
+               STM32_FUNCTION(14, "DCMI_D2"),
+               STM32_FUNCTION(15, "LCD_B2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(107, "PG11"),
+               STM32_FUNCTION(0, "GPIOG11"),
+               STM32_FUNCTION(3, "HRTIM_EEV4"),
+               STM32_FUNCTION(6, "SPI1_SCK I2S1_CK"),
+               STM32_FUNCTION(9, "SPDIFRX_IN0"),
+               STM32_FUNCTION(11, "SDMMC2_D2"),
+               STM32_FUNCTION(12, "ETH_MII_TX_EN ETH_RMII_TX_EN"),
+               STM32_FUNCTION(14, "DCMI_D3"),
+               STM32_FUNCTION(15, "LCD_B3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(108, "PG12"),
+               STM32_FUNCTION(0, "GPIOG12"),
+               STM32_FUNCTION(2, "LPTIM1_IN1"),
+               STM32_FUNCTION(3, "HRTIM_EEV5"),
+               STM32_FUNCTION(6, "SPI6_MISO"),
+               STM32_FUNCTION(8, "USART6_RTS"),
+               STM32_FUNCTION(9, "SPDIFRX_IN1"),
+               STM32_FUNCTION(10, "LCD_B4"),
+               STM32_FUNCTION(12, "ETH_MII_TXD1 ETH_RMII_TXD1"),
+               STM32_FUNCTION(13, "FMC_NE4"),
+               STM32_FUNCTION(15, "LCD_B1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(109, "PG13"),
+               STM32_FUNCTION(0, "GPIOG13"),
+               STM32_FUNCTION(1, "TRACED0"),
+               STM32_FUNCTION(2, "LPTIM1_OUT"),
+               STM32_FUNCTION(3, "HRTIM_EEV10"),
+               STM32_FUNCTION(6, "SPI6_SCK"),
+               STM32_FUNCTION(8, "USART6_CTS_NSS"),
+               STM32_FUNCTION(12, "ETH_MII_TXD0 ETH_RMII_TXD0"),
+               STM32_FUNCTION(13, "FMC_A24"),
+               STM32_FUNCTION(15, "LCD_R0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(110, "PG14"),
+               STM32_FUNCTION(0, "GPIOG14"),
+               STM32_FUNCTION(1, "TRACED1"),
+               STM32_FUNCTION(2, "LPTIM1_ETR"),
+               STM32_FUNCTION(6, "SPI6_MOSI"),
+               STM32_FUNCTION(8, "USART6_TX"),
+               STM32_FUNCTION(10, "QUADSPI_BK2_IO3"),
+               STM32_FUNCTION(12, "ETH_MII_TXD1 ETH_RMII_TXD1"),
+               STM32_FUNCTION(13, "FMC_A25"),
+               STM32_FUNCTION(15, "LCD_B0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(111, "PG15"),
+               STM32_FUNCTION(0, "GPIOG15"),
+               STM32_FUNCTION(8, "USART6_CTS_NSS"),
+               STM32_FUNCTION(13, "FMC_SDNCAS"),
+               STM32_FUNCTION(14, "DCMI_D13"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(112, "PH0"),
+               STM32_FUNCTION(0, "GPIOH0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(113, "PH1"),
+               STM32_FUNCTION(0, "GPIOH1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(114, "PH2"),
+               STM32_FUNCTION(0, "GPIOH2"),
+               STM32_FUNCTION(2, "LPTIM1_IN2"),
+               STM32_FUNCTION(10, "QUADSPI_BK2_IO0"),
+               STM32_FUNCTION(11, "SAI2_SCK_B"),
+               STM32_FUNCTION(12, "ETH_MII_CRS"),
+               STM32_FUNCTION(13, "FMC_SDCKE0"),
+               STM32_FUNCTION(15, "LCD_R0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(115, "PH3"),
+               STM32_FUNCTION(0, "GPIOH3"),
+               STM32_FUNCTION(10, "QUADSPI_BK2_IO1"),
+               STM32_FUNCTION(11, "SAI2_MCK_B"),
+               STM32_FUNCTION(12, "ETH_MII_COL"),
+               STM32_FUNCTION(13, "FMC_SDNE0"),
+               STM32_FUNCTION(15, "LCD_R1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(116, "PH4"),
+               STM32_FUNCTION(0, "GPIOH4"),
+               STM32_FUNCTION(5, "I2C2_SCL"),
+               STM32_FUNCTION(10, "LCD_G5"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_NXT"),
+               STM32_FUNCTION(15, "LCD_G4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(117, "PH5"),
+               STM32_FUNCTION(0, "GPIOH5"),
+               STM32_FUNCTION(5, "I2C2_SDA"),
+               STM32_FUNCTION(6, "SPI5_NSS"),
+               STM32_FUNCTION(13, "FMC_SDNWE"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(118, "PH6"),
+               STM32_FUNCTION(0, "GPIOH6"),
+               STM32_FUNCTION(5, "I2C2_SMBA"),
+               STM32_FUNCTION(6, "SPI5_SCK"),
+               STM32_FUNCTION(12, "ETH_MII_RXD2"),
+               STM32_FUNCTION(13, "FMC_SDNE1"),
+               STM32_FUNCTION(14, "DCMI_D8"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(119, "PH7"),
+               STM32_FUNCTION(0, "GPIOH7"),
+               STM32_FUNCTION(5, "I2C3_SCL"),
+               STM32_FUNCTION(6, "SPI5_MISO"),
+               STM32_FUNCTION(12, "ETH_MII_RXD3"),
+               STM32_FUNCTION(13, "FMC_SDCKE1"),
+               STM32_FUNCTION(14, "DCMI_D9"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(120, "PH8"),
+               STM32_FUNCTION(0, "GPIOH8"),
+               STM32_FUNCTION(3, "TIM5_ETR"),
+               STM32_FUNCTION(5, "I2C3_SDA"),
+               STM32_FUNCTION(13, "FMC_D16"),
+               STM32_FUNCTION(14, "DCMI_HSYNC"),
+               STM32_FUNCTION(15, "LCD_R2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(121, "PH9"),
+               STM32_FUNCTION(0, "GPIOH9"),
+               STM32_FUNCTION(5, "I2C3_SMBA"),
+               STM32_FUNCTION(13, "FMC_D17"),
+               STM32_FUNCTION(14, "DCMI_D0"),
+               STM32_FUNCTION(15, "LCD_R3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(122, "PH10"),
+               STM32_FUNCTION(0, "GPIOH10"),
+               STM32_FUNCTION(3, "TIM5_CH1"),
+               STM32_FUNCTION(5, "I2C4_SMBA"),
+               STM32_FUNCTION(13, "FMC_D18"),
+               STM32_FUNCTION(14, "DCMI_D1"),
+               STM32_FUNCTION(15, "LCD_R4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(123, "PH11"),
+               STM32_FUNCTION(0, "GPIOH11"),
+               STM32_FUNCTION(3, "TIM5_CH2"),
+               STM32_FUNCTION(5, "I2C4_SCL"),
+               STM32_FUNCTION(13, "FMC_D19"),
+               STM32_FUNCTION(14, "DCMI_D2"),
+               STM32_FUNCTION(15, "LCD_R5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(124, "PH12"),
+               STM32_FUNCTION(0, "GPIOH12"),
+               STM32_FUNCTION(3, "TIM5_CH3"),
+               STM32_FUNCTION(5, "I2C4_SDA"),
+               STM32_FUNCTION(13, "FMC_D20"),
+               STM32_FUNCTION(14, "DCMI_D3"),
+               STM32_FUNCTION(15, "LCD_R6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(125, "PH13"),
+               STM32_FUNCTION(0, "GPIOH13"),
+               STM32_FUNCTION(4, "TIM8_CH1N"),
+               STM32_FUNCTION(9, "UART4_TX"),
+               STM32_FUNCTION(10, "CAN1_TX"),
+               STM32_FUNCTION(13, "FMC_D21"),
+               STM32_FUNCTION(15, "LCD_G2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(126, "PH14"),
+               STM32_FUNCTION(0, "GPIOH14"),
+               STM32_FUNCTION(4, "TIM8_CH2N"),
+               STM32_FUNCTION(9, "UART4_RX"),
+               STM32_FUNCTION(10, "CAN1_RX"),
+               STM32_FUNCTION(13, "FMC_D22"),
+               STM32_FUNCTION(14, "DCMI_D4"),
+               STM32_FUNCTION(15, "LCD_G3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(127, "PH15"),
+               STM32_FUNCTION(0, "GPIOH15"),
+               STM32_FUNCTION(4, "TIM8_CH3N"),
+               STM32_FUNCTION(10, "CAN1_TXFD"),
+               STM32_FUNCTION(13, "FMC_D23"),
+               STM32_FUNCTION(14, "DCMI_D11"),
+               STM32_FUNCTION(15, "LCD_G4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(128, "PI0"),
+               STM32_FUNCTION(0, "GPIOI0"),
+               STM32_FUNCTION(3, "TIM5_CH4"),
+               STM32_FUNCTION(6, "SPI2_NSS I2S2_WS"),
+               STM32_FUNCTION(10, "CAN1_RXFD"),
+               STM32_FUNCTION(13, "FMC_D24"),
+               STM32_FUNCTION(14, "DCMI_D13"),
+               STM32_FUNCTION(15, "LCD_G5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(129, "PI1"),
+               STM32_FUNCTION(0, "GPIOI1"),
+               STM32_FUNCTION(4, "TIM8_BKIN2"),
+               STM32_FUNCTION(6, "SPI2_SCK I2S2_CK"),
+               STM32_FUNCTION(12, "TIM8_BKIN2_COMP12"),
+               STM32_FUNCTION(13, "FMC_D25"),
+               STM32_FUNCTION(14, "DCMI_D8"),
+               STM32_FUNCTION(15, "LCD_G6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(130, "PI2"),
+               STM32_FUNCTION(0, "GPIOI2"),
+               STM32_FUNCTION(4, "TIM8_CH4"),
+               STM32_FUNCTION(6, "SPI2_MISO I2S2_SDI"),
+               STM32_FUNCTION(13, "FMC_D26"),
+               STM32_FUNCTION(14, "DCMI_D9"),
+               STM32_FUNCTION(15, "LCD_G7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(131, "PI3"),
+               STM32_FUNCTION(0, "GPIOI3"),
+               STM32_FUNCTION(4, "TIM8_ETR"),
+               STM32_FUNCTION(6, "SPI2_MOSI I2S2_SDO"),
+               STM32_FUNCTION(13, "FMC_D27"),
+               STM32_FUNCTION(14, "DCMI_D10"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(132, "PI4"),
+               STM32_FUNCTION(0, "GPIOI4"),
+               STM32_FUNCTION(4, "TIM8_BKIN"),
+               STM32_FUNCTION(11, "SAI2_MCK_A"),
+               STM32_FUNCTION(12, "TIM8_BKIN_COMP12"),
+               STM32_FUNCTION(13, "FMC_NBL2"),
+               STM32_FUNCTION(14, "DCMI_D5"),
+               STM32_FUNCTION(15, "LCD_B4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(133, "PI5"),
+               STM32_FUNCTION(0, "GPIOI5"),
+               STM32_FUNCTION(4, "TIM8_CH1"),
+               STM32_FUNCTION(11, "SAI2_SCK_A"),
+               STM32_FUNCTION(13, "FMC_NBL3"),
+               STM32_FUNCTION(14, "DCMI_VSYNC"),
+               STM32_FUNCTION(15, "LCD_B5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(134, "PI6"),
+               STM32_FUNCTION(0, "GPIOI6"),
+               STM32_FUNCTION(4, "TIM8_CH2"),
+               STM32_FUNCTION(11, "SAI2_SD_A"),
+               STM32_FUNCTION(13, "FMC_D28"),
+               STM32_FUNCTION(14, "DCMI_D6"),
+               STM32_FUNCTION(15, "LCD_B6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(135, "PI7"),
+               STM32_FUNCTION(0, "GPIOI7"),
+               STM32_FUNCTION(4, "TIM8_CH3"),
+               STM32_FUNCTION(11, "SAI2_FS_A"),
+               STM32_FUNCTION(13, "FMC_D29"),
+               STM32_FUNCTION(14, "DCMI_D7"),
+               STM32_FUNCTION(15, "LCD_B7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(136, "PI8"),
+               STM32_FUNCTION(0, "GPIOI8"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(137, "PI9"),
+               STM32_FUNCTION(0, "GPIOI9"),
+               STM32_FUNCTION(9, "UART4_RX"),
+               STM32_FUNCTION(10, "CAN1_RX"),
+               STM32_FUNCTION(13, "FMC_D30"),
+               STM32_FUNCTION(15, "LCD_VSYNC"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(138, "PI10"),
+               STM32_FUNCTION(0, "GPIOI10"),
+               STM32_FUNCTION(10, "CAN1_RXFD"),
+               STM32_FUNCTION(12, "ETH_MII_RX_ER"),
+               STM32_FUNCTION(13, "FMC_D31"),
+               STM32_FUNCTION(15, "LCD_HSYNC"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(139, "PI11"),
+               STM32_FUNCTION(0, "GPIOI11"),
+               STM32_FUNCTION(10, "LCD_G6"),
+               STM32_FUNCTION(11, "OTG_HS_ULPI_DIR"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(140, "PI12"),
+               STM32_FUNCTION(0, "GPIOI12"),
+               STM32_FUNCTION(12, "ETH_TX_ER"),
+               STM32_FUNCTION(15, "LCD_HSYNC"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(141, "PI13"),
+               STM32_FUNCTION(0, "GPIOI13"),
+               STM32_FUNCTION(15, "LCD_VSYNC"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(142, "PI14"),
+               STM32_FUNCTION(0, "GPIOI14"),
+               STM32_FUNCTION(15, "LCD_CLK"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(143, "PI15"),
+               STM32_FUNCTION(0, "GPIOI15"),
+               STM32_FUNCTION(10, "LCD_G2"),
+               STM32_FUNCTION(15, "LCD_R0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(144, "PJ0"),
+               STM32_FUNCTION(0, "GPIOJ0"),
+               STM32_FUNCTION(10, "LCD_R7"),
+               STM32_FUNCTION(15, "LCD_R1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(145, "PJ1"),
+               STM32_FUNCTION(0, "GPIOJ1"),
+               STM32_FUNCTION(15, "LCD_R2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(146, "PJ2"),
+               STM32_FUNCTION(0, "GPIOJ2"),
+               STM32_FUNCTION(14, "DSI_TE"),
+               STM32_FUNCTION(15, "LCD_R3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(147, "PJ3"),
+               STM32_FUNCTION(0, "GPIOJ3"),
+               STM32_FUNCTION(15, "LCD_R4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(148, "PJ4"),
+               STM32_FUNCTION(0, "GPIOJ4"),
+               STM32_FUNCTION(15, "LCD_R5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(149, "PJ5"),
+               STM32_FUNCTION(0, "GPIOJ5"),
+               STM32_FUNCTION(15, "LCD_R6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(150, "PJ6"),
+               STM32_FUNCTION(0, "GPIOJ6"),
+               STM32_FUNCTION(4, "TIM8_CH2"),
+               STM32_FUNCTION(15, "LCD_R7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(151, "PJ7"),
+               STM32_FUNCTION(0, "GPIOJ7"),
+               STM32_FUNCTION(1, "TRGIN"),
+               STM32_FUNCTION(4, "TIM8_CH2N"),
+               STM32_FUNCTION(15, "LCD_G0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(152, "PJ8"),
+               STM32_FUNCTION(0, "GPIOJ8"),
+               STM32_FUNCTION(2, "TIM1_CH3N"),
+               STM32_FUNCTION(4, "TIM8_CH1"),
+               STM32_FUNCTION(9, "UART8_TX"),
+               STM32_FUNCTION(15, "LCD_G1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(153, "PJ9"),
+               STM32_FUNCTION(0, "GPIOJ9"),
+               STM32_FUNCTION(2, "TIM1_CH3"),
+               STM32_FUNCTION(4, "TIM8_CH1N"),
+               STM32_FUNCTION(9, "UART8_RX"),
+               STM32_FUNCTION(15, "LCD_G2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(154, "PJ10"),
+               STM32_FUNCTION(0, "GPIOJ10"),
+               STM32_FUNCTION(2, "TIM1_CH2N"),
+               STM32_FUNCTION(4, "TIM8_CH2"),
+               STM32_FUNCTION(6, "SPI5_MOSI"),
+               STM32_FUNCTION(15, "LCD_G3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(155, "PJ11"),
+               STM32_FUNCTION(0, "GPIOJ11"),
+               STM32_FUNCTION(2, "TIM1_CH2"),
+               STM32_FUNCTION(4, "TIM8_CH2N"),
+               STM32_FUNCTION(6, "SPI5_MISO"),
+               STM32_FUNCTION(15, "LCD_G4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(156, "PJ12"),
+               STM32_FUNCTION(0, "GPIOJ12"),
+               STM32_FUNCTION(1, "TRGOUT"),
+               STM32_FUNCTION(10, "LCD_G3"),
+               STM32_FUNCTION(15, "LCD_B0"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(157, "PJ13"),
+               STM32_FUNCTION(0, "GPIOJ13"),
+               STM32_FUNCTION(10, "LCD_B4"),
+               STM32_FUNCTION(15, "LCD_B1"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(158, "PJ14"),
+               STM32_FUNCTION(0, "GPIOJ14"),
+               STM32_FUNCTION(15, "LCD_B2"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(159, "PJ15"),
+               STM32_FUNCTION(0, "GPIOJ15"),
+               STM32_FUNCTION(15, "LCD_B3"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(160, "PK0"),
+               STM32_FUNCTION(0, "GPIOK0"),
+               STM32_FUNCTION(2, "TIM1_CH1N"),
+               STM32_FUNCTION(4, "TIM8_CH3"),
+               STM32_FUNCTION(6, "SPI5_SCK"),
+               STM32_FUNCTION(15, "LCD_G5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(161, "PK1"),
+               STM32_FUNCTION(0, "GPIOK1"),
+               STM32_FUNCTION(2, "TIM1_CH1"),
+               STM32_FUNCTION(4, "TIM8_CH3N"),
+               STM32_FUNCTION(6, "SPI5_NSS"),
+               STM32_FUNCTION(15, "LCD_G6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(162, "PK2"),
+               STM32_FUNCTION(0, "GPIOK2"),
+               STM32_FUNCTION(2, "TIM1_BKIN"),
+               STM32_FUNCTION(4, "TIM8_BKIN"),
+               STM32_FUNCTION(11, "TIM8_BKIN_COMP12"),
+               STM32_FUNCTION(12, "TIM1_BKIN_COMP12"),
+               STM32_FUNCTION(15, "LCD_G7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(163, "PK3"),
+               STM32_FUNCTION(0, "GPIOK3"),
+               STM32_FUNCTION(15, "LCD_B4"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(164, "PK4"),
+               STM32_FUNCTION(0, "GPIOK4"),
+               STM32_FUNCTION(15, "LCD_B5"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(165, "PK5"),
+               STM32_FUNCTION(0, "GPIOK5"),
+               STM32_FUNCTION(15, "LCD_B6"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(166, "PK6"),
+               STM32_FUNCTION(0, "GPIOK6"),
+               STM32_FUNCTION(15, "LCD_B7"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+       STM32_PIN(
+               PINCTRL_PIN(167, "PK7"),
+               STM32_FUNCTION(0, "GPIOK7"),
+               STM32_FUNCTION(15, "LCD_DE"),
+               STM32_FUNCTION(16, "EVENTOUT"),
+               STM32_FUNCTION(17, "ANALOG")
+       ),
+};
+
+static struct stm32_pinctrl_match_data stm32h743_match_data = {
+       .pins = stm32h743_pins,
+       .npins = ARRAY_SIZE(stm32h743_pins),
+};
+
+static const struct of_device_id stm32h743_pctrl_match[] = {
+       {
+               .compatible = "st,stm32h743-pinctrl",
+               .data = &stm32h743_match_data,
+       },
+       { }
+};
+
+static struct platform_driver stm32h743_pinctrl_driver = {
+       .probe = stm32_pctl_probe,
+       .driver = {
+               .name = "stm32h743-pinctrl",
+               .of_match_table = stm32h743_pctrl_match,
+       },
+};
+
+builtin_platform_driver(stm32h743_pinctrl_driver);
index bff1ffc6f01edc558aa7cb25b7e8bc966881a611..816015cf7053494088d36b12fa373bc995382daa 100644 (file)
@@ -9,26 +9,14 @@ config PINCTRL_SUN4I_A10
        def_bool MACH_SUN4I
        select PINCTRL_SUNXI
 
-config PINCTRL_SUN5I_A10S
+config PINCTRL_SUN5I
        def_bool MACH_SUN5I
        select PINCTRL_SUNXI
 
-config PINCTRL_SUN5I_A13
-       def_bool MACH_SUN5I
-       select PINCTRL_SUNXI
-
-config PINCTRL_GR8
-       def_bool MACH_SUN5I
-       select PINCTRL_SUNXI_COMMON
-
 config PINCTRL_SUN6I_A31
        def_bool MACH_SUN6I
        select PINCTRL_SUNXI
 
-config PINCTRL_SUN6I_A31S
-       def_bool MACH_SUN6I
-       select PINCTRL_SUNXI
-
 config PINCTRL_SUN6I_A31_R
        def_bool MACH_SUN6I
        depends on RESET_CONTROLLER
@@ -63,6 +51,10 @@ config PINCTRL_SUN8I_H3_R
        def_bool MACH_SUN8I
        select PINCTRL_SUNXI_COMMON
 
+config PINCTRL_SUN8I_V3S
+       def_bool MACH_SUN8I
+       select PINCTRL_SUNXI
+
 config PINCTRL_SUN9I_A80
        def_bool MACH_SUN9I
        select PINCTRL_SUNXI
@@ -76,4 +68,8 @@ config PINCTRL_SUN50I_A64
        bool
        select PINCTRL_SUNXI
 
+config PINCTRL_SUN50I_H5
+       bool
+       select PINCTRL_SUNXI
+
 endif
index 95f93d0561fc336628662688023b43510fadd002..04ccb88ebd5fca152e43cb745e4c74dd44e06021 100644 (file)
@@ -3,11 +3,8 @@ obj-y                                  += pinctrl-sunxi.o
 
 # SoC Drivers
 obj-$(CONFIG_PINCTRL_SUN4I_A10)                += pinctrl-sun4i-a10.o
-obj-$(CONFIG_PINCTRL_SUN5I_A10S)       += pinctrl-sun5i-a10s.o
-obj-$(CONFIG_PINCTRL_SUN5I_A13)                += pinctrl-sun5i-a13.o
-obj-$(CONFIG_PINCTRL_GR8)              += pinctrl-gr8.o
+obj-$(CONFIG_PINCTRL_SUN5I)            += pinctrl-sun5i.o
 obj-$(CONFIG_PINCTRL_SUN6I_A31)                += pinctrl-sun6i-a31.o
-obj-$(CONFIG_PINCTRL_SUN6I_A31S)       += pinctrl-sun6i-a31s.o
 obj-$(CONFIG_PINCTRL_SUN6I_A31_R)      += pinctrl-sun6i-a31-r.o
 obj-$(CONFIG_PINCTRL_SUN7I_A20)                += pinctrl-sun7i-a20.o
 obj-$(CONFIG_PINCTRL_SUN8I_A23)                += pinctrl-sun8i-a23.o
@@ -17,5 +14,7 @@ obj-$(CONFIG_PINCTRL_SUN50I_A64)      += pinctrl-sun50i-a64.o
 obj-$(CONFIG_PINCTRL_SUN8I_A83T)       += pinctrl-sun8i-a83t.o
 obj-$(CONFIG_PINCTRL_SUN8I_H3)         += pinctrl-sun8i-h3.o
 obj-$(CONFIG_PINCTRL_SUN8I_H3_R)       += pinctrl-sun8i-h3-r.o
+obj-$(CONFIG_PINCTRL_SUN8I_V3S)                += pinctrl-sun8i-v3s.o
+obj-$(CONFIG_PINCTRL_SUN50I_H5)                += pinctrl-sun50i-h5.o
 obj-$(CONFIG_PINCTRL_SUN9I_A80)                += pinctrl-sun9i-a80.o
 obj-$(CONFIG_PINCTRL_SUN9I_A80_R)      += pinctrl-sun9i-a80-r.o
diff --git a/drivers/pinctrl/sunxi/pinctrl-gr8.c b/drivers/pinctrl/sunxi/pinctrl-gr8.c
deleted file mode 100644 (file)
index 2f232c3..0000000
+++ /dev/null
@@ -1,536 +0,0 @@
-/*
- * NextThing GR8 SoCs pinctrl driver.
- *
- * Copyright (C) 2016 Mylene Josserand
- *
- * Based on pinctrl-sun5i-a13.c
- *
- * Mylene Josserand <mylene.josserand@free-electrons.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2.  This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/pinctrl/pinctrl.h>
-
-#include "pinctrl-sunxi.h"
-
-static const struct sunxi_desc_pin sun5i_gr8_pins[] = {
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 0),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2c0")),         /* SCK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 1),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2c0")),         /* SDA */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 2),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "pwm0"),
-                 SUNXI_FUNCTION(0x3, "spdif"),         /* DO */
-                 SUNXI_FUNCTION_IRQ(0x6, 16)),         /* EINT16 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 3),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "ir0"),           /* TX */
-                 SUNXI_FUNCTION_IRQ(0x6, 17)),         /* EINT17 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 4),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "ir0"),           /* RX */
-                 SUNXI_FUNCTION_IRQ(0x6, 18)),         /* EINT18 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 5),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2s0"),          /* MCLK */
-                 SUNXI_FUNCTION_IRQ(0x6, 19)),         /* EINT19 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 6),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2s0"),          /* BCLK */
-                 SUNXI_FUNCTION_IRQ(0x6, 20)),         /* EINT20 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 7),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2s0"),          /* LRCK */
-                 SUNXI_FUNCTION_IRQ(0x6, 21)),         /* EINT21 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 8),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2s0"),          /* DO */
-                 SUNXI_FUNCTION_IRQ(0x6, 22)),         /* EINT22 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 9),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2s0"),          /* DI */
-                 SUNXI_FUNCTION(0x3, "spdif"),         /* DI */
-                 SUNXI_FUNCTION_IRQ(0x6, 23)),         /* EINT23 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 10),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi2"),          /* CS1 */
-                 SUNXI_FUNCTION(0x3, "spdif"),         /* DO */
-                 SUNXI_FUNCTION_IRQ(0x6, 24)),         /* EINT24 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 11),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi2"),          /* CS0 */
-                 SUNXI_FUNCTION(0x3, "jtag"),          /* MS0 */
-                 SUNXI_FUNCTION_IRQ(0x6, 25)),         /* EINT25 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 12),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi2"),          /* CLK */
-                 SUNXI_FUNCTION(0x3, "jtag"),          /* CK0 */
-                 SUNXI_FUNCTION_IRQ(0x6, 26)),         /* EINT26 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 13),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi2"),          /* MOSI */
-                 SUNXI_FUNCTION(0x3, "jtag"),          /* DO0 */
-                 SUNXI_FUNCTION_IRQ(0x6, 27)),         /* EINT27 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 14),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi2"),          /* MISO */
-                 SUNXI_FUNCTION(0x3, "jtag"),          /* DI0 */
-                 SUNXI_FUNCTION_IRQ(0x6, 28)),         /* EINT28 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 15),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2c1")),         /* SCK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 16),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2c1")),         /* SDA */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 17),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2c2")),         /* SCK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 18),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2c2")),         /* SDA */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NWE */
-                 SUNXI_FUNCTION(0x3, "spi0")),         /* MOSI */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 1),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NALE */
-                 SUNXI_FUNCTION(0x3, "spi0")),         /* MISO */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 2),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NCLE */
-                 SUNXI_FUNCTION(0x3, "spi0")),         /* CLK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 3),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NCE1 */
-                 SUNXI_FUNCTION(0x3, "spi0")),         /* CS0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 4),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0")),        /* NCE0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 5),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0")),        /* NRE */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 6),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NRB0 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* CMD */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 7),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NRB1 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* CLK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 8),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ0 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 9),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ1 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 10),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ2 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 11),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ3 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 12),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ4 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D4 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 13),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ5 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D5 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ6 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D6 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ7 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D7 */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 19),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQS */
-                 SUNXI_FUNCTION(0x3, "uart2"),         /* RX */
-                 SUNXI_FUNCTION(0x4, "uart3")),        /* RTS */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D2 */
-                 SUNXI_FUNCTION(0x3, "uart2")),        /* TX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 3),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D3 */
-                 SUNXI_FUNCTION(0x3, "uart2")),        /* RX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 4),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D4 */
-                 SUNXI_FUNCTION(0x3, "uart2")),        /* CTS */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 5),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D5 */
-                 SUNXI_FUNCTION(0x3, "uart2")),        /* RTS */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 6),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D6 */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ECRS */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 7),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D7 */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ECOL */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 10),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D10 */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ERXD0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 11),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D11 */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ERXD1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 12),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D12 */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ERXD2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 13),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D13 */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ERXD3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 14),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D14 */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ERXCK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 15),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D15 */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ERXERR */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 18),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D18 */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ERXDV */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 19),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D19 */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ETXD0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 20),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D20 */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ETXD1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 21),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D21 */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ETXD2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 22),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D22 */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ETXD3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 23),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D23 */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ETXEN */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 24),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* CLK */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ETXCK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 25),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* DE */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ETXERR*/
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 26),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* HSYNC */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* EMDC */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 27),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* VSYNC */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* EMDIO */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 0),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x2, "ts0"),           /* CLK */
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* PCLK */
-                 SUNXI_FUNCTION(0x4, "spi2"),          /* CS0 */
-                 SUNXI_FUNCTION_IRQ(0x6, 14)),         /* EINT14 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 1),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x2, "ts0"),           /* ERR */
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* MCLK */
-                 SUNXI_FUNCTION(0x4, "spi2"),          /* CLK */
-                 SUNXI_FUNCTION_IRQ(0x6, 15)),         /* EINT15 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 2),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x2, "ts0"),           /* SYNC */
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* HSYNC */
-                 SUNXI_FUNCTION(0x4, "spi2")),         /* MOSI */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 3),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "ts0"),           /* DVLD */
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* VSYNC */
-                 SUNXI_FUNCTION(0x4, "spi2")),         /* MISO */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 4),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "ts0"),           /* D0 */
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* D0 */
-                 SUNXI_FUNCTION(0x4, "mmc2")),         /* D0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 5),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "ts0"),           /* D1 */
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* D1 */
-                 SUNXI_FUNCTION(0x4, "mmc2")),         /* D1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 6),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "ts0"),           /* D2 */
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* D2 */
-                 SUNXI_FUNCTION(0x4, "mmc2")),         /* D2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "ts0"),           /* D3 */
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* D3 */
-                 SUNXI_FUNCTION(0x4, "mmc2")),         /* D3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "ts0"),           /* D4 */
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* D4 */
-                 SUNXI_FUNCTION(0x4, "mmc2")),         /* CMD */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "ts0"),           /* D5 */
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* D5 */
-                 SUNXI_FUNCTION(0x4, "mmc2")),         /* CLK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "ts0"),           /* D6 */
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* D6 */
-                 SUNXI_FUNCTION(0x4, "uart1")),        /* TX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "ts0"),           /* D7 */
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* D7 */
-                 SUNXI_FUNCTION(0x4, "uart1")),        /* RX */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D1 */
-                 SUNXI_FUNCTION(0x4, "jtag")),         /* MS1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D0 */
-                 SUNXI_FUNCTION(0x4, "jtag")),         /* DI1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 2),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc0"),          /* CLK */
-                 SUNXI_FUNCTION(0x4, "uart0")),        /* TX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 3),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc0"),          /* CMD */
-                 SUNXI_FUNCTION(0x4, "jtag")),         /* DO1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 4),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D3 */
-                 SUNXI_FUNCTION(0x4, "uart0")),        /* RX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 5),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D2 */
-                 SUNXI_FUNCTION(0x4, "jtag")),         /* CK1 */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 0),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x2, "gps"),           /* CLK */
-                 SUNXI_FUNCTION_IRQ(0x6, 0)),          /* EINT0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 1),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x2, "gps"),           /* SIGN */
-                 SUNXI_FUNCTION_IRQ(0x6, 1)),          /* EINT1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 2),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x2, "gps"),           /* MAG */
-                 SUNXI_FUNCTION_IRQ(0x6, 2)),          /* EINT2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 3),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc1"),          /* CMD */
-                 SUNXI_FUNCTION(0x3, "ms"),            /* BS */
-                 SUNXI_FUNCTION(0x4, "uart1"),         /* TX */
-                 SUNXI_FUNCTION_IRQ(0x6, 3)),          /* EINT3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 4),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc1"),          /* CLK */
-                 SUNXI_FUNCTION(0x3, "ms"),            /* CLK */
-                 SUNXI_FUNCTION(0x4, "uart1"),         /* RX */
-                 SUNXI_FUNCTION_IRQ(0x6, 4)),          /* EINT4 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 5),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc1"),          /* D0 */
-                 SUNXI_FUNCTION(0x3, "ms"),            /* D0 */
-                 SUNXI_FUNCTION(0x4, "uart1"),         /* CTS */
-                 SUNXI_FUNCTION_IRQ(0x6, 5)),          /* EINT5 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 6),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc1"),          /* D1 */
-                 SUNXI_FUNCTION(0x3, "ms"),            /* D1 */
-                 SUNXI_FUNCTION(0x4, "uart1"),         /* RTS */
-                 SUNXI_FUNCTION(0x5, "uart2"),         /* RTS */
-                 SUNXI_FUNCTION_IRQ(0x6, 6)),          /* EINT6 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 7),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc1"),          /* D2 */
-                 SUNXI_FUNCTION(0x3, "ms"),            /* D2 */
-                 SUNXI_FUNCTION(0x5, "uart2"),         /* TX */
-                 SUNXI_FUNCTION_IRQ(0x6, 7)),          /* EINT7 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 8),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc1"),          /* D3 */
-                 SUNXI_FUNCTION(0x3, "ms"),            /* D3 */
-                 SUNXI_FUNCTION(0x5, "uart2"),         /* RX */
-                 SUNXI_FUNCTION_IRQ(0x6, 8)),          /* EINT8 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi1"),          /* CS0 */
-                 SUNXI_FUNCTION(0x3, "uart3"),         /* TX */
-                 SUNXI_FUNCTION_IRQ(0x6, 9)),          /* EINT9 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi1"),          /* CLK */
-                 SUNXI_FUNCTION(0x3, "uart3"),         /* RX */
-                 SUNXI_FUNCTION_IRQ(0x6, 10)),         /* EINT10 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 11),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi1"),          /* MOSI */
-                 SUNXI_FUNCTION(0x3, "uart3"),         /* CTS */
-                 SUNXI_FUNCTION_IRQ(0x6, 11)),         /* EINT11 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 12),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi1"),          /* MISO */
-                 SUNXI_FUNCTION(0x3, "uart3"),         /* RTS */
-                 SUNXI_FUNCTION_IRQ(0x6, 12)),         /* EINT12 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 13),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi1"),          /* CS1 */
-                 SUNXI_FUNCTION(0x3, "pwm1"),
-                 SUNXI_FUNCTION(0x5, "uart2"),         /* CTS */
-                 SUNXI_FUNCTION_IRQ(0x6, 13)),         /* EINT13 */
-};
-
-static const struct sunxi_pinctrl_desc sun5i_gr8_pinctrl_data = {
-       .pins = sun5i_gr8_pins,
-       .npins = ARRAY_SIZE(sun5i_gr8_pins),
-       .irq_banks = 1,
-};
-
-static int sun5i_gr8_pinctrl_probe(struct platform_device *pdev)
-{
-       return sunxi_pinctrl_init(pdev,
-                                 &sun5i_gr8_pinctrl_data);
-}
-
-static const struct of_device_id sun5i_gr8_pinctrl_match[] = {
-       { .compatible = "nextthing,gr8-pinctrl", },
-       {}
-};
-
-static struct platform_driver sun5i_gr8_pinctrl_driver = {
-       .probe  = sun5i_gr8_pinctrl_probe,
-       .driver = {
-               .name           = "gr8-pinctrl",
-               .of_match_table = sun5i_gr8_pinctrl_match,
-       },
-};
-builtin_platform_driver(sun5i_gr8_pinctrl_driver);
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun50i-h5.c b/drivers/pinctrl/sunxi/pinctrl-sun50i-h5.c
new file mode 100644 (file)
index 0000000..ccf9419
--- /dev/null
@@ -0,0 +1,558 @@
+/*
+ * Allwinner H5 SoC pinctrl driver.
+ *
+ * Copyright (C) 2016 Icenowy Zheng <icenowy@aosc.xyz>
+ *
+ * Based on pinctrl-sun8i-h3.c, which is:
+ * Copyright (C) 2015 Jens Kuske <jenskuske@gmail.com>
+ *
+ * Based on pinctrl-sun8i-a23.c, which is:
+ * Copyright (C) 2014 Chen-Yu Tsai <wens@csie.org>
+ * Copyright (C) 2014 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-sunxi.h"
+
+static const struct sunxi_desc_pin sun50i_h5_pins[] = {
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 0),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart2"),         /* TX */
+                 SUNXI_FUNCTION(0x3, "jtag"),          /* MS */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 0)),  /* PA_EINT0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 1),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart2"),         /* RX */
+                 SUNXI_FUNCTION(0x3, "jtag"),          /* CK */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 1)),  /* PA_EINT1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 2),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart2"),         /* RTS */
+                 SUNXI_FUNCTION(0x3, "jtag"),          /* DO */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 2)),  /* PA_EINT2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 3),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart2"),         /* CTS */
+                 SUNXI_FUNCTION(0x3, "jtag"),          /* DI */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 3)),  /* PA_EINT3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 4),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart0"),         /* TX */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 4)),  /* PA_EINT4 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 5),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart0"),         /* RX */
+                 SUNXI_FUNCTION(0x3, "pwm0"),
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 5)),  /* PA_EINT5 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 6),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "sim"),           /* PWREN */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 6)),  /* PA_EINT6 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 7),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "sim"),           /* CLK */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 7)),  /* PA_EINT7 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 8),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "sim"),           /* DATA */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 8)),  /* PA_EINT8 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 9),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "sim"),           /* RST */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 9)),  /* PA_EINT9 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 10),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "sim"),           /* DET */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 10)), /* PA_EINT10 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 11),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c0"),          /* SCK */
+                 SUNXI_FUNCTION(0x3, "di"),            /* TX */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 11)), /* PA_EINT11 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 12),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c0"),          /* SDA */
+                 SUNXI_FUNCTION(0x3, "di"),            /* RX */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 12)), /* PA_EINT12 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 13),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi1"),          /* CS */
+                 SUNXI_FUNCTION(0x3, "uart3"),         /* TX */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 13)), /* PA_EINT13 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 14),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi1"),          /* CLK */
+                 SUNXI_FUNCTION(0x3, "uart3"),         /* RX */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 14)), /* PA_EINT14 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 15),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi1"),          /* MOSI */
+                 SUNXI_FUNCTION(0x3, "uart3"),         /* RTS */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 15)), /* PA_EINT15 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 16),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi1"),          /* MISO */
+                 SUNXI_FUNCTION(0x3, "uart3"),         /* CTS */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 16)), /* PA_EINT16 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 17),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spdif"),         /* OUT */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 17)), /* PA_EINT17 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 18),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2s0"),          /* SYNC */
+                 SUNXI_FUNCTION(0x3, "i2c1"),          /* SCK */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 18)), /* PA_EINT18 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 19),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2s0"),          /* CLK */
+                 SUNXI_FUNCTION(0x3, "i2c1"),          /* SDA */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 19)), /* PA_EINT19 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 20),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2s0"),          /* DOUT */
+                 SUNXI_FUNCTION(0x3, "sim"),           /* VPPEN */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 20)), /* PA_EINT20 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 21),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2s0"),          /* DIN */
+                 SUNXI_FUNCTION(0x3, "sim"),           /* VPPPP */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 21)), /* PA_EINT21 */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* WE */
+                 SUNXI_FUNCTION(0x3, "spi0")),         /* MOSI */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 1),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* ALE */
+                 SUNXI_FUNCTION(0x3, "spi0"),          /* MISO */
+                 SUNXI_FUNCTION(0x4, "mmc2")),         /* DS */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 2),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* CLE */
+                 SUNXI_FUNCTION(0x3, "spi0")),         /* CLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 3),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* CE1 */
+                 SUNXI_FUNCTION(0x3, "spi0")),         /* CS */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 4),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* CE0 */
+                 SUNXI_FUNCTION(0x4, "spi0")),         /* MISO */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 5),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* RE */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* CLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 6),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* RB0 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* CMD */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 7),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0")),        /* RB1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 8),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ0 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 9),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ1 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 10),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ2 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 11),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ3 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 12),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ4 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D4 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 13),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ5 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D5 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ6 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D6 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ7 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D7 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 16),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQS */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* RST */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 0),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* RXD3 */
+                 SUNXI_FUNCTION(0x3, "di"),            /* TX */
+                 SUNXI_FUNCTION(0x4, "ts2")),          /* CLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 1),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* RXD2 */
+                 SUNXI_FUNCTION(0x3, "di"),            /* RX */
+                 SUNXI_FUNCTION(0x4, "ts2")),          /* ERR */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* RXD1 */
+                 SUNXI_FUNCTION(0x4, "ts2")),          /* SYNC */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 3),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* RXD0 */
+                 SUNXI_FUNCTION(0x4, "ts2")),          /* DVLD */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 4),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* RXCK */
+                 SUNXI_FUNCTION(0x4, "ts2")),          /* D0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 5),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* RXCTL/RXDV */
+                 SUNXI_FUNCTION(0x4, "ts2")),          /* D1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 6),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* RXERR */
+                 SUNXI_FUNCTION(0x4, "ts2")),          /* D2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 7),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* TXD3 */
+                 SUNXI_FUNCTION(0x4, "ts2"),           /* D3 */
+                 SUNXI_FUNCTION(0x5, "ts3")),          /* CLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 8),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* TXD2 */
+                 SUNXI_FUNCTION(0x4, "ts2"),           /* D4 */
+                 SUNXI_FUNCTION(0x5, "ts3")),          /* ERR */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 9),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* TXD1 */
+                 SUNXI_FUNCTION(0x4, "ts2"),           /* D5 */
+                 SUNXI_FUNCTION(0x5, "ts3")),          /* SYNC */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 10),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* TXD0 */
+                 SUNXI_FUNCTION(0x4, "ts2"),           /* D6 */
+                 SUNXI_FUNCTION(0x5, "ts3")),          /* DVLD */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 11),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* CRS */
+                 SUNXI_FUNCTION(0x4, "ts2"),           /* D7 */
+                 SUNXI_FUNCTION(0x5, "ts3")),          /* D0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 12),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* TXCK */
+                 SUNXI_FUNCTION(0x4, "sim")),          /* PWREN */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 13),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* TXCTL/TXEN */
+                 SUNXI_FUNCTION(0x4, "sim")),          /* CLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 14),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* TXERR */
+                 SUNXI_FUNCTION(0x4, "sim")),          /* DATA */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 15),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* CLKIN/COL */
+                 SUNXI_FUNCTION(0x4, "sim")),          /* RST */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 16),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* MDC */
+                 SUNXI_FUNCTION(0x4, "sim")),          /* DET */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 17),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac")),         /* MDIO */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 0),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* PCLK */
+                 SUNXI_FUNCTION(0x3, "ts0")),          /* CLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 1),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* MCLK */
+                 SUNXI_FUNCTION(0x3, "ts0")),          /* ERR */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 2),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* HSYNC */
+                 SUNXI_FUNCTION(0x3, "ts0")),          /* SYNC */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 3),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* VSYNC */
+                 SUNXI_FUNCTION(0x3, "ts0")),          /* DVLD */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 4),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D0 */
+                 SUNXI_FUNCTION(0x3, "ts0")),          /* D0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 5),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D1 */
+                 SUNXI_FUNCTION(0x3, "ts0")),          /* D1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 6),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D2 */
+                 SUNXI_FUNCTION(0x3, "ts0")),          /* D2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D3 */
+                 SUNXI_FUNCTION(0x3, "ts0"),           /* D3 */
+                 SUNXI_FUNCTION(0x4, "ts1")),          /* CLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D4 */
+                 SUNXI_FUNCTION(0x3, "ts0"),           /* D4 */
+                 SUNXI_FUNCTION(0x4, "ts1")),          /* ERR */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D5 */
+                 SUNXI_FUNCTION(0x3, "ts0"),           /* D5 */
+                 SUNXI_FUNCTION(0x4, "ts1")),          /* SYNC */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D6 */
+                 SUNXI_FUNCTION(0x3, "ts0"),           /* D6 */
+                 SUNXI_FUNCTION(0x4, "ts1")),          /* DVLD */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D7 */
+                 SUNXI_FUNCTION(0x3, "ts"),            /* D7 */
+                 SUNXI_FUNCTION(0x4, "ts1")),          /* D0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 12),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* SCK */
+                 SUNXI_FUNCTION(0x3, "i2c2")),         /* SCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 13),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* SDA */
+                 SUNXI_FUNCTION(0x3, "i2c2")),         /* SDA */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 14),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x3, "sim")),          /* VPPEN */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 15),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x3, "sim")),          /* VPPPP */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D1 */
+                 SUNXI_FUNCTION(0x3, "jtag"),          /* MS */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 0)),  /* PF_EINT0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D0 */
+                 SUNXI_FUNCTION(0x3, "jtag"),          /* DI */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 1)),  /* PF_EINT1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 2),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* CLK */
+                 SUNXI_FUNCTION(0x3, "uart0"),         /* TX */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 2)),  /* PF_EINT2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 3),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* CMD */
+                 SUNXI_FUNCTION(0x3, "jtag"),          /* DO */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 3)),  /* PF_EINT3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 4),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D3 */
+                 SUNXI_FUNCTION(0x3, "uart0"),         /* RX */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 4)),  /* PF_EINT4 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 5),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D2 */
+                 SUNXI_FUNCTION(0x3, "jtag"),          /* CK */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 5)),  /* PF_EINT5 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 6),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 6)),  /* PF_EINT6 */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 0),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* CLK */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 0)),  /* PG_EINT0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 1),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* CMD */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 1)),  /* PG_EINT1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 2),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* D0 */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 2)),  /* PG_EINT2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 3),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* D1 */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 3)),  /* PG_EINT3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 4),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* D2 */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 4)),  /* PG_EINT4 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 5),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* D3 */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 5)),  /* PG_EINT5 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 6),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart1"),         /* TX */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 6)),  /* PG_EINT6 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 7),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart1"),         /* RX */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 7)),  /* PG_EINT7 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 8),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart1"),         /* RTS */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 8)),  /* PG_EINT8 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart1"),         /* CTS */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 9)),  /* PG_EINT9 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2s1"),          /* SYNC */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 10)), /* PG_EINT10 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 11),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2s1"),          /* CLK */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 11)), /* PG_EINT11 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 12),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2s1"),          /* DOUT */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 12)), /* PG_EINT12 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 13),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2s1"),          /* DIN */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 13)), /* PG_EINT13 */
+};
+
+static const struct sunxi_pinctrl_desc sun50i_h5_pinctrl_data = {
+       .pins = sun50i_h5_pins,
+       .npins = ARRAY_SIZE(sun50i_h5_pins),
+       .irq_banks = 2,
+       .irq_read_needs_mux = true
+};
+
+static int sun50i_h5_pinctrl_probe(struct platform_device *pdev)
+{
+       return sunxi_pinctrl_init(pdev,
+                                 &sun50i_h5_pinctrl_data);
+}
+
+static const struct of_device_id sun50i_h5_pinctrl_match[] = {
+       { .compatible = "allwinner,sun50i-h5-pinctrl", },
+       {}
+};
+
+static struct platform_driver sun50i_h5_pinctrl_driver = {
+       .probe  = sun50i_h5_pinctrl_probe,
+       .driver = {
+               .name           = "sun50i-h5-pinctrl",
+               .of_match_table = sun50i_h5_pinctrl_match,
+       },
+};
+builtin_platform_driver(sun50i_h5_pinctrl_driver);
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun5i-a10s.c b/drivers/pinctrl/sunxi/pinctrl-sun5i-a10s.c
deleted file mode 100644 (file)
index a5b57fd..0000000
+++ /dev/null
@@ -1,685 +0,0 @@
-/*
- * Allwinner A10s SoCs pinctrl driver.
- *
- * Copyright (C) 2014 Maxime Ripard
- *
- * Maxime Ripard <maxime.ripard@free-electrons.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2.  This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/pinctrl/pinctrl.h>
-
-#include "pinctrl-sunxi.h"
-
-static const struct sunxi_desc_pin sun5i_a10s_pins[] = {
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 0),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "emac"),          /* ERXD3 */
-                 SUNXI_FUNCTION(0x3, "ts0"),           /* CLK */
-                 SUNXI_FUNCTION(0x5, "keypad")),       /* IN0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 1),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "emac"),          /* ERXD2 */
-                 SUNXI_FUNCTION(0x3, "ts0"),           /* ERR */
-                 SUNXI_FUNCTION(0x5, "keypad")),       /* IN1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 2),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "emac"),          /* ERXD1 */
-                 SUNXI_FUNCTION(0x3, "ts0"),           /* SYNC */
-                 SUNXI_FUNCTION(0x5, "keypad")),       /* IN2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 3),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "emac"),          /* ERXD0 */
-                 SUNXI_FUNCTION(0x3, "ts0"),           /* DLVD */
-                 SUNXI_FUNCTION(0x5, "keypad")),       /* IN3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 4),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "emac"),          /* ETXD3 */
-                 SUNXI_FUNCTION(0x3, "ts0"),           /* D0 */
-                 SUNXI_FUNCTION(0x5, "keypad")),       /* IN4 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 5),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "emac"),          /* ETXD2 */
-                 SUNXI_FUNCTION(0x3, "ts0"),           /* D1 */
-                 SUNXI_FUNCTION(0x5, "keypad")),       /* IN5 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 6),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "emac"),          /* ETXD1 */
-                 SUNXI_FUNCTION(0x3, "ts0"),           /* D2 */
-                 SUNXI_FUNCTION(0x5, "keypad")),       /* IN6 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 7),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "emac"),          /* ETXD0 */
-                 SUNXI_FUNCTION(0x3, "ts0"),           /* D3 */
-                 SUNXI_FUNCTION(0x5, "keypad")),       /* IN7 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 8),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "emac"),          /* ERXCK */
-                 SUNXI_FUNCTION(0x3, "ts0"),           /* D4 */
-                 SUNXI_FUNCTION(0x4, "uart1"),         /* DTR */
-                 SUNXI_FUNCTION(0x5, "keypad")),       /* OUT0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 9),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "emac"),          /* ERXERR */
-                 SUNXI_FUNCTION(0x3, "ts0"),           /* D5 */
-                 SUNXI_FUNCTION(0x4, "uart1"),         /* DSR */
-                 SUNXI_FUNCTION(0x5, "keypad")),       /* OUT1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 10),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "emac"),          /* ERXDV */
-                 SUNXI_FUNCTION(0x3, "ts0"),           /* D6 */
-                 SUNXI_FUNCTION(0x4, "uart1"),         /* DCD */
-                 SUNXI_FUNCTION(0x5, "keypad")),       /* OUT2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 11),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "emac"),          /* EMDC */
-                 SUNXI_FUNCTION(0x3, "ts0"),           /* D7 */
-                 SUNXI_FUNCTION(0x4, "uart1"),         /* RING */
-                 SUNXI_FUNCTION(0x5, "keypad")),       /* OUT3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 12),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "emac"),          /* EMDIO */
-                 SUNXI_FUNCTION(0x3, "uart1"),         /* TX */
-                 SUNXI_FUNCTION(0x5, "keypad")),       /* OUT4 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 13),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "emac"),          /* ETXEN */
-                 SUNXI_FUNCTION(0x3, "uart1"),         /* RX */
-                 SUNXI_FUNCTION(0x5, "keypad")),       /* OUT5 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 14),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "emac"),          /* ETXCK */
-                 SUNXI_FUNCTION(0x3, "uart1"),         /* CTS */
-                 SUNXI_FUNCTION(0x4, "uart3"),         /* TX */
-                 SUNXI_FUNCTION(0x5, "keypad")),       /* OUT6 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 15),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "emac"),          /* ECRS */
-                 SUNXI_FUNCTION(0x3, "uart1"),         /* RTS */
-                 SUNXI_FUNCTION(0x4, "uart3"),         /* RX */
-                 SUNXI_FUNCTION(0x5, "keypad")),       /* OUT7 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 16),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "emac"),          /* ECOL */
-                 SUNXI_FUNCTION(0x3, "uart2")),        /* TX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 17),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "emac"),          /* ETXERR */
-                 SUNXI_FUNCTION(0x3, "uart2"),         /* RX */
-                 SUNXI_FUNCTION_IRQ(0x6, 31)),         /* EINT31 */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 0),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2c0")),         /* SCK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 1),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2c0")),         /* SDA */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 2),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "pwm"),           /* PWM0 */
-                 SUNXI_FUNCTION_IRQ(0x6, 16)),         /* EINT16 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 3),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "ir0"),           /* TX */
-                 SUNXI_FUNCTION_IRQ(0x6, 17)),         /* EINT17 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 4),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "ir0"),           /* RX */
-                 SUNXI_FUNCTION_IRQ(0x6, 18)),         /* EINT18 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 5),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2s"),           /* MCLK */
-                 SUNXI_FUNCTION_IRQ(0x6, 19)),         /* EINT19 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 6),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2s"),           /* BCLK */
-                 SUNXI_FUNCTION_IRQ(0x6, 20)),         /* EINT20 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 7),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2s"),           /* LRCK */
-                 SUNXI_FUNCTION_IRQ(0x6, 21)),         /* EINT21 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 8),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2s"),           /* DO */
-                 SUNXI_FUNCTION_IRQ(0x6, 22)),         /* EINT22 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 9),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2s"),           /* DI */
-                 SUNXI_FUNCTION_IRQ(0x6, 23)),         /* EINT23 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 10),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi2"),          /* CS1 */
-                 SUNXI_FUNCTION_IRQ(0x6, 24)),         /* EINT24 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 11),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi2"),          /* CS0 */
-                 SUNXI_FUNCTION(0x3, "jtag"),          /* MS0 */
-                 SUNXI_FUNCTION_IRQ(0x6, 25)),         /* EINT25 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 12),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi2"),          /* CLK */
-                 SUNXI_FUNCTION(0x3, "jtag"),          /* CK0 */
-                 SUNXI_FUNCTION_IRQ(0x6, 26)),         /* EINT26 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 13),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi2"),          /* MOSI */
-                 SUNXI_FUNCTION(0x3, "jtag"),          /* DO0 */
-                 SUNXI_FUNCTION_IRQ(0x6, 27)),         /* EINT27 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 14),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi2"),          /* MISO */
-                 SUNXI_FUNCTION(0x3, "jtag"),          /* DI0 */
-                 SUNXI_FUNCTION_IRQ(0x6, 28)),         /* EINT28 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 15),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2c1")),         /* SCK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 16),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2c1")),         /* SDA */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 17),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2c2")),         /* SCK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 18),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2c2")),         /* SDA */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 19),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "uart0"),         /* TX */
-                 SUNXI_FUNCTION_IRQ(0x6, 29)),         /* EINT29 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 20),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "uart0"),         /* RX */
-                 SUNXI_FUNCTION_IRQ(0x6, 30)),         /* EINT30 */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NWE */
-                 SUNXI_FUNCTION(0x3, "spi0")),         /* MOSI */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 1),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NALE */
-                 SUNXI_FUNCTION(0x3, "spi0")),         /* MISO */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 2),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NCLE */
-                 SUNXI_FUNCTION(0x3, "spi0")),         /* SCK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 3),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NCE1 */
-                 SUNXI_FUNCTION(0x3, "spi0")),         /* CS0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 4),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0")),        /* NCE0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 5),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0")),        /* NRE */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 6),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NRB0 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* CMD */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 7),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NRB1 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* CLK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 8),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ0 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 9),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ1 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 10),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ2 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 11),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ3 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 12),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ4 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D4 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 13),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ5 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D5 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ6 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D6 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ7 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D7 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 16),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NWP */
-                 SUNXI_FUNCTION(0x4, "uart3")),        /* TX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 17),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NCE2 */
-                 SUNXI_FUNCTION(0x4, "uart3")),        /* RX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 18),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NCE3 */
-                 SUNXI_FUNCTION(0x3, "uart2"),         /* TX */
-                 SUNXI_FUNCTION(0x4, "uart3")),        /* CTS */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 19),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NCE4 */
-                 SUNXI_FUNCTION(0x3, "uart2"),         /* RX */
-                 SUNXI_FUNCTION(0x4, "uart3")),        /* RTS */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 0),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 1),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D2 */
-                 SUNXI_FUNCTION(0x3, "uart2")),        /* TX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 3),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D3 */
-                 SUNXI_FUNCTION(0x3, "uart2")),        /* RX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 4),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D4 */
-                 SUNXI_FUNCTION(0x3, "uart2")),        /* CTS */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 5),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D5 */
-                 SUNXI_FUNCTION(0x3, "uart2")),        /* RTS */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 6),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D6 */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ECRS */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 7),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D7 */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ECOL */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 8),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D8 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 9),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D9 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 10),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D10 */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ERXD0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 11),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D11 */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ERXD1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 12),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D12 */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ERXD2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 13),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D13 */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ERXD3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 14),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D14 */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ERXCK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 15),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D15 */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ERXERR */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 16),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D16 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 17),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D17 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 18),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D18 */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ERXDV */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 19),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D19 */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ETXD0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 20),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D20 */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ETXD1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 21),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D21 */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ETXD2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 22),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D22 */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ETXD3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 23),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D23 */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ETXEN */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 24),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* CLK */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ETXCK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 25),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* DE */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* ETXERR */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 26),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* HSYNC */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* EMDC */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 27),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* VSYNC */
-                 SUNXI_FUNCTION(0x3, "emac")),         /* EMDIO */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 0),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x2, "ts0"),           /* CLK */
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* PCK */
-                 SUNXI_FUNCTION(0x4, "spi2"),          /* CS0 */
-                 SUNXI_FUNCTION_IRQ(0x6, 14)),         /* EINT14 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 1),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x2, "ts0"),           /* ERR */
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* CK */
-                 SUNXI_FUNCTION(0x4, "spi2"),          /* CLK */
-                 SUNXI_FUNCTION_IRQ(0x6, 15)),         /* EINT15 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 2),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x2, "ts0"),           /* SYNC */
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* HSYNC */
-                 SUNXI_FUNCTION(0x4, "spi2")),         /* MOSI */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 3),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "ts0"),           /* DVLD */
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* VSYNC */
-                 SUNXI_FUNCTION(0x4, "spi2")),         /* MISO */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 4),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "ts0"),           /* D0 */
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* D0 */
-                 SUNXI_FUNCTION(0x4, "mmc2")),         /* D0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 5),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "ts0"),           /* D1 */
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* D1 */
-                 SUNXI_FUNCTION(0x4, "mmc2")),         /* D1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 6),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "ts0"),           /* D2 */
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* D2 */
-                 SUNXI_FUNCTION(0x4, "mmc2")),         /* D2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "ts0"),           /* D3 */
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* D3 */
-                 SUNXI_FUNCTION(0x4, "mmc2")),         /* D3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "ts0"),           /* D4 */
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* D4 */
-                 SUNXI_FUNCTION(0x4, "mmc2")),         /* CMD */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "ts0"),           /* D5 */
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* D5 */
-                 SUNXI_FUNCTION(0x4, "mmc2")),         /* CLK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "ts0"),           /* D6 */
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* D6 */
-                 SUNXI_FUNCTION(0x4, "uart1")),        /* TX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "ts0"),           /* D7 */
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* D7 */
-                 SUNXI_FUNCTION(0x4, "uart1")),        /* RX */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D1 */
-                 SUNXI_FUNCTION(0x4, "jtag")),         /* MS1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D0 */
-                 SUNXI_FUNCTION(0x4, "jtag")),         /* DI1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 2),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc0"),          /* CLK */
-                 SUNXI_FUNCTION(0x4, "uart0")),        /* TX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 3),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc0"),          /* CMD */
-                 SUNXI_FUNCTION(0x4, "jtag")),         /* DO1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 4),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D3 */
-                 SUNXI_FUNCTION(0x4, "uart0")),        /* RX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 5),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D2 */
-                 SUNXI_FUNCTION(0x4, "jtag")),         /* CK1 */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 0),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x2, "gps"),           /* CLK */
-                 SUNXI_FUNCTION_IRQ(0x6, 0)),          /* EINT0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 1),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x2, "gps"),           /* SIGN */
-                 SUNXI_FUNCTION_IRQ(0x6, 1)),          /* EINT1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 2),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x2, "gps"),           /* MAG */
-                 SUNXI_FUNCTION_IRQ(0x6, 2)),          /* EINT2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 3),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc1"),          /* CMD */
-                 SUNXI_FUNCTION(0x4, "uart1"),         /* TX */
-                 SUNXI_FUNCTION_IRQ(0x6, 3)),          /* EINT3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 4),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc1"),          /* CLK */
-                 SUNXI_FUNCTION(0x4, "uart1"),         /* RX */
-                 SUNXI_FUNCTION_IRQ(0x6, 4)),          /* EINT4 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 5),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc1"),          /* DO */
-                 SUNXI_FUNCTION(0x4, "uart1"),         /* CTS */
-                 SUNXI_FUNCTION_IRQ(0x6, 5)),          /* EINT5 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 6),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc1"),          /* D1 */
-                 SUNXI_FUNCTION(0x4, "uart1"),         /* RTS */
-                 SUNXI_FUNCTION(0x5, "uart2"),         /* RTS */
-                 SUNXI_FUNCTION_IRQ(0x6, 6)),          /* EINT6 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 7),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc1"),          /* D2 */
-                 SUNXI_FUNCTION(0x5, "uart2"),         /* TX */
-                 SUNXI_FUNCTION_IRQ(0x6, 7)),          /* EINT7 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 8),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc1"),          /* D3 */
-                 SUNXI_FUNCTION(0x5, "uart2"),         /* RX */
-                 SUNXI_FUNCTION_IRQ(0x6, 8)),          /* EINT8 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi1"),          /* CS0 */
-                 SUNXI_FUNCTION(0x3, "uart3"),         /* TX */
-                 SUNXI_FUNCTION_IRQ(0x6, 9)),          /* EINT9 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi1"),          /* CLK */
-                 SUNXI_FUNCTION(0x3, "uart3"),         /* RX */
-                 SUNXI_FUNCTION_IRQ(0x6, 10)),         /* EINT10 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 11),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi1"),          /* MOSI */
-                 SUNXI_FUNCTION(0x3, "uart3"),         /* CTS */
-                 SUNXI_FUNCTION_IRQ(0x6, 11)),         /* EINT11 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 12),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi1"),          /* MISO */
-                 SUNXI_FUNCTION(0x3, "uart3"),         /* RTS */
-                 SUNXI_FUNCTION_IRQ(0x6, 12)),         /* EINT12 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 13),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi1"),          /* CS1 */
-                 SUNXI_FUNCTION(0x3, "pwm"),           /* PWM1 */
-                 SUNXI_FUNCTION(0x5, "uart2"),         /* CTS */
-                 SUNXI_FUNCTION_IRQ(0x6, 13)),         /* EINT13 */
-};
-
-static const struct sunxi_pinctrl_desc sun5i_a10s_pinctrl_data = {
-       .pins = sun5i_a10s_pins,
-       .npins = ARRAY_SIZE(sun5i_a10s_pins),
-       .irq_banks = 1,
-};
-
-static int sun5i_a10s_pinctrl_probe(struct platform_device *pdev)
-{
-       return sunxi_pinctrl_init(pdev,
-                                 &sun5i_a10s_pinctrl_data);
-}
-
-static const struct of_device_id sun5i_a10s_pinctrl_match[] = {
-       { .compatible = "allwinner,sun5i-a10s-pinctrl", },
-       {}
-};
-
-static struct platform_driver sun5i_a10s_pinctrl_driver = {
-       .probe  = sun5i_a10s_pinctrl_probe,
-       .driver = {
-               .name           = "sun5i-a10s-pinctrl",
-               .of_match_table = sun5i_a10s_pinctrl_match,
-       },
-};
-builtin_platform_driver(sun5i_a10s_pinctrl_driver);
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun5i-a13.c b/drivers/pinctrl/sunxi/pinctrl-sun5i-a13.c
deleted file mode 100644 (file)
index 8575f3f..0000000
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
- * Allwinner A13 SoCs pinctrl driver.
- *
- * Copyright (C) 2014 Maxime Ripard
- *
- * Maxime Ripard <maxime.ripard@free-electrons.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2.  This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/pinctrl/pinctrl.h>
-
-#include "pinctrl-sunxi.h"
-
-static const struct sunxi_desc_pin sun5i_a13_pins[] = {
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 0),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2c0")),         /* SCK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 1),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2c0")),         /* SDA */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 2),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "pwm"),
-                 SUNXI_FUNCTION_IRQ(0x6, 16)),         /* EINT16 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 3),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "ir0"),           /* TX */
-                 SUNXI_FUNCTION_IRQ(0x6, 17)),         /* EINT17 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 4),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "ir0"),           /* RX */
-                 SUNXI_FUNCTION_IRQ(0x6, 18)),         /* EINT18 */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 10),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi2"),          /* CS1 */
-                 SUNXI_FUNCTION_IRQ(0x6, 24)),         /* EINT24 */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 15),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2c1")),         /* SCK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 16),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2c1")),         /* SDA */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 17),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2c2")),         /* SCK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 18),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2c2")),         /* SDA */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NWE */
-                 SUNXI_FUNCTION(0x3, "spi0")),         /* MOSI */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 1),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NALE */
-                 SUNXI_FUNCTION(0x3, "spi0")),         /* MISO */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 2),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NCLE */
-                 SUNXI_FUNCTION(0x3, "spi0")),         /* CLK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 3),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NCE1 */
-                 SUNXI_FUNCTION(0x3, "spi0")),         /* CS0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 4),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0")),        /* NCE0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 5),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0")),        /* NRE */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 6),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NRB0 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* CMD */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 7),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NRB1 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* CLK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 8),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ0 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 9),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ1 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 10),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ2 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 11),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ3 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 12),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ4 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D4 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 13),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ5 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D5 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ6 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D6 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ7 */
-                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D7 */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 19),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQS */
-                 SUNXI_FUNCTION(0x4, "uart3")),        /* RTS */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 3),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 4),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D4 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 5),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D5 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 6),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D6 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 7),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D7 */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 10),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D10 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 11),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D11 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 12),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D12 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 13),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D13 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 14),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D14 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 15),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D15 */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 18),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D18 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 19),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D19 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 20),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D20 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 21),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D21 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 22),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D22 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 23),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D23 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 24),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* CLK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 25),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* DE */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 26),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* HSYNC */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 27),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* VSYNC */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 0),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* PCLK */
-                 SUNXI_FUNCTION(0x4, "spi2"),          /* CS0 */
-                 SUNXI_FUNCTION_IRQ(0x6, 14)),         /* EINT14 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 1),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* MCLK */
-                 SUNXI_FUNCTION(0x4, "spi2"),          /* CLK */
-                 SUNXI_FUNCTION_IRQ(0x6, 15)),         /* EINT15 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 2),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* HSYNC */
-                 SUNXI_FUNCTION(0x4, "spi2")),         /* MOSI */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 3),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* VSYNC */
-                 SUNXI_FUNCTION(0x4, "spi2")),         /* MISO */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 4),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* D0 */
-                 SUNXI_FUNCTION(0x4, "mmc2")),         /* D0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 5),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* D1 */
-                 SUNXI_FUNCTION(0x4, "mmc2")),         /* D1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 6),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* D2 */
-                 SUNXI_FUNCTION(0x4, "mmc2")),         /* D2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* D3 */
-                 SUNXI_FUNCTION(0x4, "mmc2")),         /* D3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* D4 */
-                 SUNXI_FUNCTION(0x4, "mmc2")),         /* CMD */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* D5 */
-                 SUNXI_FUNCTION(0x4, "mmc2")),         /* CLK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* D6 */
-                 SUNXI_FUNCTION(0x4, "uart1")),        /* TX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x3, "csi0"),          /* D7 */
-                 SUNXI_FUNCTION(0x4, "uart1")),        /* RX */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc0")),         /* D1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc0")),         /* D0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 2),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc0")),         /* CLK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 3),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc0")),         /* CMD */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 4),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc0")),         /* D3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 5),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc0")),         /* D2 */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 0),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION_IRQ(0x6, 0)),          /* EINT0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 1),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION_IRQ(0x6, 1)),          /* EINT1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 2),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION_IRQ(0x6, 2)),          /* EINT2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 3),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc1"),          /* CMD */
-                 SUNXI_FUNCTION(0x4, "uart1"),         /* TX */
-                 SUNXI_FUNCTION_IRQ(0x6, 3)),          /* EINT3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 4),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc1"),          /* CLK */
-                 SUNXI_FUNCTION(0x4, "uart1"),         /* RX */
-                 SUNXI_FUNCTION_IRQ(0x6, 4)),          /* EINT4 */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi1"),          /* CS0 */
-                 SUNXI_FUNCTION(0x3, "uart3"),         /* TX */
-                 SUNXI_FUNCTION_IRQ(0x6, 9)),          /* EINT9 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi1"),          /* CLK */
-                 SUNXI_FUNCTION(0x3, "uart3"),         /* RX */
-                 SUNXI_FUNCTION_IRQ(0x6, 10)),         /* EINT10 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 11),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi1"),          /* MOSI */
-                 SUNXI_FUNCTION(0x3, "uart3"),         /* CTS */
-                 SUNXI_FUNCTION_IRQ(0x6, 11)),         /* EINT11 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 12),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi1"),          /* MISO */
-                 SUNXI_FUNCTION(0x3, "uart3"),         /* RTS */
-                 SUNXI_FUNCTION_IRQ(0x6, 12)),         /* EINT12 */
-};
-
-static const struct sunxi_pinctrl_desc sun5i_a13_pinctrl_data = {
-       .pins = sun5i_a13_pins,
-       .npins = ARRAY_SIZE(sun5i_a13_pins),
-       .irq_banks = 1,
-};
-
-static int sun5i_a13_pinctrl_probe(struct platform_device *pdev)
-{
-       return sunxi_pinctrl_init(pdev,
-                                 &sun5i_a13_pinctrl_data);
-}
-
-static const struct of_device_id sun5i_a13_pinctrl_match[] = {
-       { .compatible = "allwinner,sun5i-a13-pinctrl", },
-       {}
-};
-
-static struct platform_driver sun5i_a13_pinctrl_driver = {
-       .probe  = sun5i_a13_pinctrl_probe,
-       .driver = {
-               .name           = "sun5i-a13-pinctrl",
-               .of_match_table = sun5i_a13_pinctrl_match,
-       },
-};
-builtin_platform_driver(sun5i_a13_pinctrl_driver);
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun5i.c b/drivers/pinctrl/sunxi/pinctrl-sun5i.c
new file mode 100644 (file)
index 0000000..47afd55
--- /dev/null
@@ -0,0 +1,749 @@
+/*
+ * Allwinner sun5i SoCs pinctrl driver.
+ *
+ * Copyright (C) 2014-2016 Maxime Ripard <maxime.ripard@free-electrons.com>
+ * Copyright (C) 2016 Mylene Josserand <mylene.josserand@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-sunxi.h"
+
+static const struct sunxi_desc_pin sun5i_pins[] = {
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 0),
+                 PINCTRL_SUN5I_A10S,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ERXD3 */
+                 SUNXI_FUNCTION(0x3, "ts0"),           /* CLK */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* IN0 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 1),
+                 PINCTRL_SUN5I_A10S,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ERXD2 */
+                 SUNXI_FUNCTION(0x3, "ts0"),           /* ERR */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* IN1 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 2),
+                 PINCTRL_SUN5I_A10S,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ERXD1 */
+                 SUNXI_FUNCTION(0x3, "ts0"),           /* SYNC */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* IN2 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 3),
+                 PINCTRL_SUN5I_A10S,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ERXD0 */
+                 SUNXI_FUNCTION(0x3, "ts0"),           /* DLVD */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* IN3 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 4),
+                 PINCTRL_SUN5I_A10S,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ETXD3 */
+                 SUNXI_FUNCTION(0x3, "ts0"),           /* D0 */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* IN4 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 5),
+                 PINCTRL_SUN5I_A10S,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ETXD2 */
+                 SUNXI_FUNCTION(0x3, "ts0"),           /* D1 */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* IN5 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 6),
+                 PINCTRL_SUN5I_A10S,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ETXD1 */
+                 SUNXI_FUNCTION(0x3, "ts0"),           /* D2 */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* IN6 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 7),
+                 PINCTRL_SUN5I_A10S,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ETXD0 */
+                 SUNXI_FUNCTION(0x3, "ts0"),           /* D3 */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* IN7 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 8),
+                 PINCTRL_SUN5I_A10S,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ERXCK */
+                 SUNXI_FUNCTION(0x3, "ts0"),           /* D4 */
+                 SUNXI_FUNCTION(0x4, "uart1"),         /* DTR */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* OUT0 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 9),
+                 PINCTRL_SUN5I_A10S,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ERXERR */
+                 SUNXI_FUNCTION(0x3, "ts0"),           /* D5 */
+                 SUNXI_FUNCTION(0x4, "uart1"),         /* DSR */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* OUT1 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 10),
+                 PINCTRL_SUN5I_A10S,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ERXDV */
+                 SUNXI_FUNCTION(0x3, "ts0"),           /* D6 */
+                 SUNXI_FUNCTION(0x4, "uart1"),         /* DCD */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* OUT2 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 11),
+                 PINCTRL_SUN5I_A10S,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* EMDC */
+                 SUNXI_FUNCTION(0x3, "ts0"),           /* D7 */
+                 SUNXI_FUNCTION(0x4, "uart1"),         /* RING */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* OUT3 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 12),
+                 PINCTRL_SUN5I_A10S,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* EMDIO */
+                 SUNXI_FUNCTION(0x3, "uart1"),         /* TX */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* OUT4 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 13),
+                 PINCTRL_SUN5I_A10S,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ETXEN */
+                 SUNXI_FUNCTION(0x3, "uart1"),         /* RX */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* OUT5 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 14),
+                 PINCTRL_SUN5I_A10S,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ETXCK */
+                 SUNXI_FUNCTION(0x3, "uart1"),         /* CTS */
+                 SUNXI_FUNCTION(0x4, "uart3"),         /* TX */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* OUT6 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 15),
+                 PINCTRL_SUN5I_A10S,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ECRS */
+                 SUNXI_FUNCTION(0x3, "uart1"),         /* RTS */
+                 SUNXI_FUNCTION(0x4, "uart3"),         /* RX */
+                 SUNXI_FUNCTION(0x5, "keypad")),       /* OUT7 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 16),
+                 PINCTRL_SUN5I_A10S,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ECOL */
+                 SUNXI_FUNCTION(0x3, "uart2")),        /* TX */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(A, 17),
+                 PINCTRL_SUN5I_A10S,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "emac"),          /* ETXERR */
+                 SUNXI_FUNCTION(0x3, "uart2"),         /* RX */
+                 SUNXI_FUNCTION_IRQ(0x6, 31)),         /* EINT31 */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 0),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c0")),         /* SCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 1),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c0")),         /* SDA */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 2),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "pwm"),           /* PWM0 */
+                 SUNXI_FUNCTION_VARIANT(0x3,
+                                        "spdif",       /* DO */
+                                        PINCTRL_SUN5I_GR8),
+                 SUNXI_FUNCTION_IRQ(0x6, 16)),         /* EINT16 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 3),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ir0"),           /* TX */
+                 SUNXI_FUNCTION_IRQ(0x6, 17)),         /* EINT17 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 4),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ir0"),           /* RX */
+                 SUNXI_FUNCTION_IRQ(0x6, 18)),         /* EINT18 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(B, 5),
+                 PINCTRL_SUN5I_A10S | PINCTRL_SUN5I_GR8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2s"),           /* MCLK */
+                 SUNXI_FUNCTION_IRQ(0x6, 19)),         /* EINT19 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(B, 6),
+                 PINCTRL_SUN5I_A10S | PINCTRL_SUN5I_GR8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2s"),           /* BCLK */
+                 SUNXI_FUNCTION_IRQ(0x6, 20)),         /* EINT20 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(B, 7),
+                 PINCTRL_SUN5I_A10S | PINCTRL_SUN5I_GR8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2s"),           /* LRCK */
+                 SUNXI_FUNCTION_IRQ(0x6, 21)),         /* EINT21 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(B, 8),
+                 PINCTRL_SUN5I_A10S | PINCTRL_SUN5I_GR8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2s"),           /* DO */
+                 SUNXI_FUNCTION_IRQ(0x6, 22)),         /* EINT22 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(B, 9),
+                 PINCTRL_SUN5I_A10S | PINCTRL_SUN5I_GR8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2s"),           /* DI */
+                 SUNXI_FUNCTION_VARIANT(0x3,
+                                        "spdif",       /* DI */
+                                        PINCTRL_SUN5I_GR8),
+                 SUNXI_FUNCTION_IRQ(0x6, 23)),         /* EINT23 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 10),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi2"),          /* CS1 */
+                 SUNXI_FUNCTION_VARIANT(0x3,
+                                        "spdif",       /* DO */
+                                        PINCTRL_SUN5I_GR8),
+                 SUNXI_FUNCTION_IRQ(0x6, 24)),         /* EINT24 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(B, 11),
+                 PINCTRL_SUN5I_A10S | PINCTRL_SUN5I_GR8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi2"),          /* CS0 */
+                 SUNXI_FUNCTION(0x3, "jtag"),          /* MS0 */
+                 SUNXI_FUNCTION_IRQ(0x6, 25)),         /* EINT25 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(B, 12),
+                 PINCTRL_SUN5I_A10S | PINCTRL_SUN5I_GR8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi2"),          /* CLK */
+                 SUNXI_FUNCTION(0x3, "jtag"),          /* CK0 */
+                 SUNXI_FUNCTION_IRQ(0x6, 26)),         /* EINT26 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(B, 13),
+                 PINCTRL_SUN5I_A10S | PINCTRL_SUN5I_GR8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi2"),          /* MOSI */
+                 SUNXI_FUNCTION(0x3, "jtag"),          /* DO0 */
+                 SUNXI_FUNCTION_IRQ(0x6, 27)),         /* EINT27 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(B, 14),
+                 PINCTRL_SUN5I_A10S | PINCTRL_SUN5I_GR8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi2"),          /* MISO */
+                 SUNXI_FUNCTION(0x3, "jtag"),          /* DI0 */
+                 SUNXI_FUNCTION_IRQ(0x6, 28)),         /* EINT28 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 15),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c1")),         /* SCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 16),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c1")),         /* SDA */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 17),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c2")),         /* SCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 18),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c2")),         /* SDA */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(B, 19),
+                 PINCTRL_SUN5I_A10S,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart0"),         /* TX */
+                 SUNXI_FUNCTION_IRQ(0x6, 29)),         /* EINT29 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(B, 20),
+                 PINCTRL_SUN5I_A10S,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart0"),         /* RX */
+                 SUNXI_FUNCTION_IRQ(0x6, 30)),         /* EINT30 */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NWE */
+                 SUNXI_FUNCTION(0x3, "spi0")),         /* MOSI */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 1),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NALE */
+                 SUNXI_FUNCTION(0x3, "spi0")),         /* MISO */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 2),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NCLE */
+                 SUNXI_FUNCTION(0x3, "spi0")),         /* CLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 3),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NCE1 */
+                 SUNXI_FUNCTION(0x3, "spi0")),         /* CS0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 4),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0")),        /* NCE0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 5),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0")),        /* NRE */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 6),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NRB0 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* CMD */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 7),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NRB1 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* CLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 8),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ0 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 9),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ1 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 10),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ2 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 11),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ3 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 12),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ4 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D4 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 13),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ5 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D5 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ6 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D6 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NDQ7 */
+                 SUNXI_FUNCTION(0x3, "mmc2")),         /* D7 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(C, 16),
+                 PINCTRL_SUN5I_A10S,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NWP */
+                 SUNXI_FUNCTION(0x4, "uart3")),        /* TX */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(C, 17),
+                 PINCTRL_SUN5I_A10S,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NCE2 */
+                 SUNXI_FUNCTION(0x4, "uart3")),        /* RX */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(C, 18),
+                 PINCTRL_SUN5I_A10S,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NCE3 */
+                 SUNXI_FUNCTION(0x3, "uart2"),         /* TX */
+                 SUNXI_FUNCTION(0x4, "uart3")),        /* CTS */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 19),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* NCE4 */
+                 SUNXI_FUNCTION(0x3, "uart2"),         /* RX */
+                 SUNXI_FUNCTION(0x4, "uart3")),        /* RTS */
+       /* Hole */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(D, 0),
+                 PINCTRL_SUN5I_A10S,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D0 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(D, 1),
+                 PINCTRL_SUN5I_A10S,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D2 */
+                 SUNXI_FUNCTION(0x3, "uart2")),        /* TX */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 3),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D3 */
+                 SUNXI_FUNCTION(0x3, "uart2")),        /* RX */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 4),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D4 */
+                 SUNXI_FUNCTION(0x3, "uart2")),        /* CTS */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 5),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D5 */
+                 SUNXI_FUNCTION(0x3, "uart2")),        /* RTS */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 6),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D6 */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ECRS */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 7),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D7 */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ECOL */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(D, 8),
+                 PINCTRL_SUN5I_A10S,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D8 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(D, 9),
+                 PINCTRL_SUN5I_A10S,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D9 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 10),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D10 */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ERXD0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 11),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D11 */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ERXD1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 12),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D12 */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ERXD2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 13),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D13 */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ERXD3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 14),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D14 */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ERXCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 15),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D15 */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ERXERR */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(D, 16),
+                 PINCTRL_SUN5I_A10S,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D16 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(D, 17),
+                 PINCTRL_SUN5I_A10S,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D17 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 18),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D18 */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ERXDV */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 19),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D19 */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ETXD0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 20),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D20 */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ETXD1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 21),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D21 */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ETXD2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 22),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D22 */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ETXD3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 23),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D23 */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ETXEN */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 24),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* CLK */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ETXCK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 25),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* DE */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* ETXERR */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 26),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* HSYNC */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* EMDC */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 27),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "lcd0"),          /* VSYNC */
+                 SUNXI_FUNCTION(0x3, "emac")),         /* EMDIO */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 0),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* CLK */
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* PCK */
+                 SUNXI_FUNCTION(0x4, "spi2"),          /* CS0 */
+                 SUNXI_FUNCTION_IRQ(0x6, 14)),         /* EINT14 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 1),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* ERR */
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* CK */
+                 SUNXI_FUNCTION(0x4, "spi2"),          /* CLK */
+                 SUNXI_FUNCTION_IRQ(0x6, 15)),         /* EINT15 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 2),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* SYNC */
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* HSYNC */
+                 SUNXI_FUNCTION(0x4, "spi2")),         /* MOSI */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 3),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* DVLD */
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* VSYNC */
+                 SUNXI_FUNCTION(0x4, "spi2")),         /* MISO */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 4),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* D0 */
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* D0 */
+                 SUNXI_FUNCTION(0x4, "mmc2")),         /* D0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 5),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* D1 */
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* D1 */
+                 SUNXI_FUNCTION(0x4, "mmc2")),         /* D1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 6),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* D2 */
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* D2 */
+                 SUNXI_FUNCTION(0x4, "mmc2")),         /* D2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* D3 */
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* D3 */
+                 SUNXI_FUNCTION(0x4, "mmc2")),         /* D3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* D4 */
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* D4 */
+                 SUNXI_FUNCTION(0x4, "mmc2")),         /* CMD */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* D5 */
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* D5 */
+                 SUNXI_FUNCTION(0x4, "mmc2")),         /* CLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* D6 */
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* D6 */
+                 SUNXI_FUNCTION(0x4, "uart1")),        /* TX */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "ts0"),           /* D7 */
+                 SUNXI_FUNCTION(0x3, "csi0"),          /* D7 */
+                 SUNXI_FUNCTION(0x4, "uart1")),        /* RX */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D1 */
+                 SUNXI_FUNCTION(0x4, "jtag")),         /* MS1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D0 */
+                 SUNXI_FUNCTION(0x4, "jtag")),         /* DI1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 2),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* CLK */
+                 SUNXI_FUNCTION(0x4, "uart0")),        /* TX */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 3),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* CMD */
+                 SUNXI_FUNCTION(0x4, "jtag")),         /* DO1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 4),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D3 */
+                 SUNXI_FUNCTION(0x4, "uart0")),        /* RX */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 5),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D2 */
+                 SUNXI_FUNCTION(0x4, "jtag")),         /* CK1 */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 0),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x2, "gps"),           /* CLK */
+                 SUNXI_FUNCTION_IRQ(0x6, 0)),          /* EINT0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 1),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x2, "gps"),           /* SIGN */
+                 SUNXI_FUNCTION_IRQ(0x6, 1)),          /* EINT1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 2),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x2, "gps"),           /* MAG */
+                 SUNXI_FUNCTION_IRQ(0x6, 2)),          /* EINT2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 3),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* CMD */
+                 SUNXI_FUNCTION(0x4, "uart1"),         /* TX */
+                 SUNXI_FUNCTION_IRQ(0x6, 3)),          /* EINT3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 4),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* CLK */
+                 SUNXI_FUNCTION(0x4, "uart1"),         /* RX */
+                 SUNXI_FUNCTION_IRQ(0x6, 4)),          /* EINT4 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(G, 5),
+                 PINCTRL_SUN5I_A10S | PINCTRL_SUN5I_GR8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* DO */
+                 SUNXI_FUNCTION(0x4, "uart1"),         /* CTS */
+                 SUNXI_FUNCTION_IRQ(0x6, 5)),          /* EINT5 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(G, 6),
+                 PINCTRL_SUN5I_A10S | PINCTRL_SUN5I_GR8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* D1 */
+                 SUNXI_FUNCTION(0x4, "uart1"),         /* RTS */
+                 SUNXI_FUNCTION(0x5, "uart2"),         /* RTS */
+                 SUNXI_FUNCTION_IRQ(0x6, 6)),          /* EINT6 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(G, 7),
+                 PINCTRL_SUN5I_A10S | PINCTRL_SUN5I_GR8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* D2 */
+                 SUNXI_FUNCTION(0x5, "uart2"),         /* TX */
+                 SUNXI_FUNCTION_IRQ(0x6, 7)),          /* EINT7 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(G, 8),
+                 PINCTRL_SUN5I_A10S | PINCTRL_SUN5I_GR8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* D3 */
+                 SUNXI_FUNCTION(0x5, "uart2"),         /* RX */
+                 SUNXI_FUNCTION_IRQ(0x6, 8)),          /* EINT8 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi1"),          /* CS0 */
+                 SUNXI_FUNCTION(0x3, "uart3"),         /* TX */
+                 SUNXI_FUNCTION_IRQ(0x6, 9)),          /* EINT9 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi1"),          /* CLK */
+                 SUNXI_FUNCTION(0x3, "uart3"),         /* RX */
+                 SUNXI_FUNCTION_IRQ(0x6, 10)),         /* EINT10 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 11),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi1"),          /* MOSI */
+                 SUNXI_FUNCTION(0x3, "uart3"),         /* CTS */
+                 SUNXI_FUNCTION_IRQ(0x6, 11)),         /* EINT11 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 12),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi1"),          /* MISO */
+                 SUNXI_FUNCTION(0x3, "uart3"),         /* RTS */
+                 SUNXI_FUNCTION_IRQ(0x6, 12)),         /* EINT12 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(G, 13),
+                 PINCTRL_SUN5I_A10S | PINCTRL_SUN5I_GR8,
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "spi1"),          /* CS1 */
+                 SUNXI_FUNCTION(0x3, "pwm"),           /* PWM1 */
+                 SUNXI_FUNCTION(0x5, "uart2"),         /* CTS */
+                 SUNXI_FUNCTION_IRQ(0x6, 13)),         /* EINT13 */
+};
+
+static const struct sunxi_pinctrl_desc sun5i_pinctrl_data = {
+       .pins = sun5i_pins,
+       .npins = ARRAY_SIZE(sun5i_pins),
+       .irq_banks = 1,
+};
+
+static int sun5i_pinctrl_probe(struct platform_device *pdev)
+{
+       unsigned long variant = (unsigned long)of_device_get_match_data(&pdev->dev);
+
+       return sunxi_pinctrl_init_with_variant(pdev, &sun5i_pinctrl_data,
+                                              variant);
+}
+
+static const struct of_device_id sun5i_pinctrl_match[] = {
+       {
+               .compatible = "allwinner,sun5i-a10s-pinctrl",
+               .data = (void *)PINCTRL_SUN5I_A10S
+       },
+       {
+               .compatible = "allwinner,sun5i-a13-pinctrl",
+               .data = (void *)PINCTRL_SUN5I_A13
+       },
+       {
+               .compatible = "nextthing,gr8-pinctrl",
+               .data = (void *)PINCTRL_SUN5I_GR8
+       },
+       { },
+};
+
+static struct platform_driver sun5i_pinctrl_driver = {
+       .probe  = sun5i_pinctrl_probe,
+       .driver = {
+               .name           = "sun5i-pinctrl",
+               .of_match_table = sun5i_pinctrl_match,
+       },
+};
+builtin_platform_driver(sun5i_pinctrl_driver);
index 9e58926bef37f4f28a6b2ee520a6ff7137a8147d..951a25c1881564e1644ba57bd4df700a743a9ed3 100644 (file)
@@ -23,69 +23,79 @@ static const struct sunxi_desc_pin sun6i_a31_pins[] = {
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "gmac"),          /* TXD0 */
-                 SUNXI_FUNCTION(0x3, "lcd1"),          /* D0 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lcd1",
+                                        PINCTRL_SUN6I_A31),    /* D0 */
                  SUNXI_FUNCTION(0x4, "uart1"),         /* DTR */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 0)),  /* PA_EINT0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 1),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "gmac"),          /* TXD1 */
-                 SUNXI_FUNCTION(0x3, "lcd1"),          /* D1 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lcd1",
+                                        PINCTRL_SUN6I_A31),    /* D1 */
                  SUNXI_FUNCTION(0x4, "uart1"),         /* DSR */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 1)),  /* PA_EINT1 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 2),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "gmac"),          /* TXD2 */
-                 SUNXI_FUNCTION(0x3, "lcd1"),          /* D2 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lcd1",
+                                        PINCTRL_SUN6I_A31),    /* D2 */
                  SUNXI_FUNCTION(0x4, "uart1"),         /* DCD */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 2)),  /* PA_EINT2 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 3),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "gmac"),          /* TXD3 */
-                 SUNXI_FUNCTION(0x3, "lcd1"),          /* D3 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lcd1",
+                                        PINCTRL_SUN6I_A31),    /* D3 */
                  SUNXI_FUNCTION(0x4, "uart1"),         /* RING */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 3)),  /* PA_EINT3 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 4),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "gmac"),          /* TXD4 */
-                 SUNXI_FUNCTION(0x3, "lcd1"),          /* D4 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lcd1",
+                                        PINCTRL_SUN6I_A31),    /* D4 */
                  SUNXI_FUNCTION(0x4, "uart1"),         /* TX */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 4)),  /* PA_EINT4 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 5),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "gmac"),          /* TXD5 */
-                 SUNXI_FUNCTION(0x3, "lcd1"),          /* D5 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lcd1",
+                                        PINCTRL_SUN6I_A31),    /* D5 */
                  SUNXI_FUNCTION(0x4, "uart1"),         /* RX */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 5)),  /* PA_EINT5 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 6),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "gmac"),          /* TXD6 */
-                 SUNXI_FUNCTION(0x3, "lcd1"),          /* D6 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lcd1",
+                                        PINCTRL_SUN6I_A31),    /* D6 */
                  SUNXI_FUNCTION(0x4, "uart1"),         /* RTS */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 6)),  /* PA_EINT6 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 7),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "gmac"),          /* TXD7 */
-                 SUNXI_FUNCTION(0x3, "lcd1"),          /* D7 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lcd1",
+                                        PINCTRL_SUN6I_A31),    /* D7 */
                  SUNXI_FUNCTION(0x4, "uart1"),         /* CTS */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 7)),  /* PA_EINT7 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 8),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "gmac"),          /* TXCLK */
-                 SUNXI_FUNCTION(0x3, "lcd1"),          /* D8 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lcd1",
+                                        PINCTRL_SUN6I_A31),    /* D8 */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 8)),  /* PA_EINT8 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 9),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "gmac"),          /* TXEN */
-                 SUNXI_FUNCTION(0x3, "lcd1"),          /* D9 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lcd1",
+                                        PINCTRL_SUN6I_A31),    /* D9 */
                  SUNXI_FUNCTION(0x4, "mmc3"),          /* CMD */
                  SUNXI_FUNCTION(0x5, "mmc2"),          /* CMD */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 9)),  /* PA_EINT9 */
@@ -93,7 +103,8 @@ static const struct sunxi_desc_pin sun6i_a31_pins[] = {
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "gmac"),          /* GTXCLK */
-                 SUNXI_FUNCTION(0x3, "lcd1"),          /* D10 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lcd1",
+                                        PINCTRL_SUN6I_A31),    /* D10 */
                  SUNXI_FUNCTION(0x4, "mmc3"),          /* CLK */
                  SUNXI_FUNCTION(0x5, "mmc2"),          /* CLK */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 10)), /* PA_EINT10 */
@@ -101,7 +112,8 @@ static const struct sunxi_desc_pin sun6i_a31_pins[] = {
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "gmac"),          /* RXD0 */
-                 SUNXI_FUNCTION(0x3, "lcd1"),          /* D11 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lcd1",
+                                        PINCTRL_SUN6I_A31),    /* D11 */
                  SUNXI_FUNCTION(0x4, "mmc3"),          /* D0 */
                  SUNXI_FUNCTION(0x5, "mmc2"),          /* D0 */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 11)), /* PA_EINT11 */
@@ -109,7 +121,8 @@ static const struct sunxi_desc_pin sun6i_a31_pins[] = {
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "gmac"),          /* RXD1 */
-                 SUNXI_FUNCTION(0x3, "lcd1"),          /* D12 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lcd1",
+                                        PINCTRL_SUN6I_A31),    /* D12 */
                  SUNXI_FUNCTION(0x4, "mmc3"),          /* D1 */
                  SUNXI_FUNCTION(0x5, "mmc2"),          /* D1 */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 12)), /* PA_EINT12 */
@@ -117,7 +130,8 @@ static const struct sunxi_desc_pin sun6i_a31_pins[] = {
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "gmac"),          /* RXD2 */
-                 SUNXI_FUNCTION(0x3, "lcd1"),          /* D13 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lcd1",
+                                        PINCTRL_SUN6I_A31),    /* D13 */
                  SUNXI_FUNCTION(0x4, "mmc3"),          /* D2 */
                  SUNXI_FUNCTION(0x5, "mmc2"),          /* D2 */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 13)), /* PA_EINT13 */
@@ -125,7 +139,8 @@ static const struct sunxi_desc_pin sun6i_a31_pins[] = {
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "gmac"),          /* RXD3 */
-                 SUNXI_FUNCTION(0x3, "lcd1"),          /* D14 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lcd1",
+                                        PINCTRL_SUN6I_A31),    /* D14 */
                  SUNXI_FUNCTION(0x4, "mmc3"),          /* D3 */
                  SUNXI_FUNCTION(0x5, "mmc2"),          /* D3 */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 14)), /* PA_EINT14 */
@@ -133,91 +148,104 @@ static const struct sunxi_desc_pin sun6i_a31_pins[] = {
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "gmac"),          /* RXD4 */
-                 SUNXI_FUNCTION(0x3, "lcd1"),          /* D15 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lcd1",
+                                        PINCTRL_SUN6I_A31),    /* D15 */
                  SUNXI_FUNCTION(0x4, "clk_out_a"),
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 15)), /* PA_EINT15 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 16),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "gmac"),          /* RXD5 */
-                 SUNXI_FUNCTION(0x3, "lcd1"),          /* D16 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lcd1",
+                                        PINCTRL_SUN6I_A31),    /* D16 */
                  SUNXI_FUNCTION(0x4, "dmic"),          /* CLK */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 16)), /* PA_EINT16 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 17),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "gmac"),          /* RXD6 */
-                 SUNXI_FUNCTION(0x3, "lcd1"),          /* D17 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lcd1",
+                                        PINCTRL_SUN6I_A31),    /* D17 */
                  SUNXI_FUNCTION(0x4, "dmic"),          /* DIN */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 17)), /* PA_EINT17 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 18),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "gmac"),          /* RXD7 */
-                 SUNXI_FUNCTION(0x3, "lcd1"),          /* D18 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lcd1",
+                                        PINCTRL_SUN6I_A31),    /* D18 */
                  SUNXI_FUNCTION(0x4, "clk_out_b"),
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 18)), /* PA_EINT18 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 19),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "gmac"),          /* RXDV */
-                 SUNXI_FUNCTION(0x3, "lcd1"),          /* D19 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lcd1",
+                                        PINCTRL_SUN6I_A31),    /* D19 */
                  SUNXI_FUNCTION(0x4, "pwm3"),          /* Positive */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 19)), /* PA_EINT19 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 20),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "gmac"),          /* RXCLK */
-                 SUNXI_FUNCTION(0x3, "lcd1"),          /* D20 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lcd1",
+                                        PINCTRL_SUN6I_A31),    /* D20 */
                  SUNXI_FUNCTION(0x4, "pwm3"),          /* Negative */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 20)), /* PA_EINT20 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 21),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "gmac"),          /* TXERR */
-                 SUNXI_FUNCTION(0x3, "lcd1"),          /* D21 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lcd1",
+                                        PINCTRL_SUN6I_A31),    /* D21 */
                  SUNXI_FUNCTION(0x4, "spi3"),          /* CS0 */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 21)), /* PA_EINT21 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 22),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "gmac"),          /* RXERR */
-                 SUNXI_FUNCTION(0x3, "lcd1"),          /* D22 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lcd1",
+                                        PINCTRL_SUN6I_A31),    /* D22 */
                  SUNXI_FUNCTION(0x4, "spi3"),          /* CLK */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 22)), /* PA_EINT22 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 23),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "gmac"),          /* COL */
-                 SUNXI_FUNCTION(0x3, "lcd1"),          /* D23 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lcd1",
+                                        PINCTRL_SUN6I_A31),    /* D23 */
                  SUNXI_FUNCTION(0x4, "spi3"),          /* MOSI */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 23)), /* PA_EINT23 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 24),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "gmac"),          /* CRS */
-                 SUNXI_FUNCTION(0x3, "lcd1"),          /* CLK */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lcd1",
+                                        PINCTRL_SUN6I_A31),    /* CLK */
                  SUNXI_FUNCTION(0x4, "spi3"),          /* MISO */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 24)), /* PA_EINT24 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 25),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "gmac"),          /* CLKIN */
-                 SUNXI_FUNCTION(0x3, "lcd1"),          /* DE */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lcd1",
+                                        PINCTRL_SUN6I_A31),    /* DE */
                  SUNXI_FUNCTION(0x4, "spi3"),          /* CS1 */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 25)), /* PA_EINT25 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 26),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "gmac"),          /* MDC */
-                 SUNXI_FUNCTION(0x3, "lcd1"),          /* HSYNC */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lcd1",
+                                        PINCTRL_SUN6I_A31),    /* HSYNC */
                  SUNXI_FUNCTION(0x4, "clk_out_c"),
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 26)), /* PA_EINT26 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 27),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "gmac"),          /* MDIO */
-                 SUNXI_FUNCTION(0x3, "lcd1"),          /* VSYNC */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lcd1",
+                                        PINCTRL_SUN6I_A31),    /* VSYNC */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 27)), /* PA_EINT27 */
        /* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 0),
@@ -225,7 +253,8 @@ static const struct sunxi_desc_pin sun6i_a31_pins[] = {
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "i2s0"),          /* MCLK */
                  SUNXI_FUNCTION(0x3, "uart3"),         /* CTS */
-                 SUNXI_FUNCTION(0x4, "csi"),           /* MCLK1 */
+                 SUNXI_FUNCTION_VARIANT(0x4, "csi",
+                                        PINCTRL_SUN6I_A31),    /* MCLK1 */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 0)),  /* PB_EINT0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 1),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
@@ -355,42 +384,43 @@ static const struct sunxi_desc_pin sun6i_a31_pins[] = {
                  SUNXI_FUNCTION(0x2, "nand0"),         /* DQ7 */
                  SUNXI_FUNCTION(0x3, "mmc2"),          /* D7 */
                  SUNXI_FUNCTION(0x4, "mmc3")),         /* D7 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 16),
+       /* Hole in pin numbering for A31s */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(C, 16), PINCTRL_SUN6I_A31,
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "nand0"),         /* DQ8 */
                  SUNXI_FUNCTION(0x3, "nand1")),        /* DQ0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 17),
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(C, 17), PINCTRL_SUN6I_A31,
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "nand0"),         /* DQ9 */
                  SUNXI_FUNCTION(0x3, "nand1")),        /* DQ1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 18),
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(C, 18), PINCTRL_SUN6I_A31,
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "nand0"),         /* DQ10 */
                  SUNXI_FUNCTION(0x3, "nand1")),        /* DQ2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 19),
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(C, 19), PINCTRL_SUN6I_A31,
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "nand0"),         /* DQ11 */
                  SUNXI_FUNCTION(0x3, "nand1")),        /* DQ3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 20),
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(C, 20), PINCTRL_SUN6I_A31,
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "nand0"),         /* DQ12 */
                  SUNXI_FUNCTION(0x3, "nand1")),        /* DQ4 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 21),
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(C, 21), PINCTRL_SUN6I_A31,
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "nand0"),         /* DQ13 */
                  SUNXI_FUNCTION(0x3, "nand1")),        /* DQ5 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 22),
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(C, 22), PINCTRL_SUN6I_A31,
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "nand0"),         /* DQ14 */
                  SUNXI_FUNCTION(0x3, "nand1")),        /* DQ6 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 23),
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(C, 23), PINCTRL_SUN6I_A31,
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "nand0"),         /* DQ15 */
@@ -468,52 +498,62 @@ static const struct sunxi_desc_pin sun6i_a31_pins[] = {
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "lcd0"),          /* D10 */
-                 SUNXI_FUNCTION(0x3, "lvds1")),        /* VP0 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lvds1",
+                                        PINCTRL_SUN6I_A31)),   /* VP0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 11),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "lcd0"),          /* D11 */
-                 SUNXI_FUNCTION(0x3, "lvds1")),        /* VN0 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lvds1",
+                                        PINCTRL_SUN6I_A31)),   /* VN0 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 12),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "lcd0"),          /* D12 */
-                 SUNXI_FUNCTION(0x3, "lvds1")),        /* VP1 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lvds1",
+                                        PINCTRL_SUN6I_A31)),   /* VP1 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 13),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "lcd0"),          /* D13 */
-                 SUNXI_FUNCTION(0x3, "lvds1")),        /* VN1 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lvds1",
+                                        PINCTRL_SUN6I_A31)),   /* VN1 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 14),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "lcd0"),          /* D14 */
-                 SUNXI_FUNCTION(0x3, "lvds1")),        /* VP2 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lvds1",
+                                        PINCTRL_SUN6I_A31)),   /* VP2 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 15),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "lcd0"),          /* D15 */
-                 SUNXI_FUNCTION(0x3, "lvds1")),        /* VN2 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lvds1",
+                                        PINCTRL_SUN6I_A31)),   /* VN2 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 16),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "lcd0"),          /* D16 */
-                 SUNXI_FUNCTION(0x3, "lvds1")),        /* VPC */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lvds1",
+                                        PINCTRL_SUN6I_A31)),   /* VPC */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 17),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "lcd0"),          /* D17 */
-                 SUNXI_FUNCTION(0x3, "lvds1")),        /* VNC */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lvds1",
+                                        PINCTRL_SUN6I_A31)),   /* VNC */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 18),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "lcd0"),          /* D18 */
-                 SUNXI_FUNCTION(0x3, "lvds1")),        /* VP3 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lvds1",
+                                        PINCTRL_SUN6I_A31)),   /* VP3 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 19),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "lcd0"),          /* D19 */
-                 SUNXI_FUNCTION(0x3, "lvds1")),        /* VN3 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "lvds1",
+                                        PINCTRL_SUN6I_A31)),   /* VN3 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 20),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
@@ -643,7 +683,7 @@ static const struct sunxi_desc_pin sun6i_a31_pins[] = {
                  SUNXI_FUNCTION(0x2, "csi"),           /* D11 */
                  SUNXI_FUNCTION(0x3, "ts"),            /* D7 */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 15)), /* PE_EINT15 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 16),
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(E, 16), PINCTRL_SUN6I_A31,
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "csi"),           /* MIPI CSI MCLK */
@@ -734,13 +774,15 @@ static const struct sunxi_desc_pin sun6i_a31_pins[] = {
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "i2c3"),          /* SCK */
-                 SUNXI_FUNCTION(0x3, "usb"),           /* DP3 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "usb",
+                                        PINCTRL_SUN6I_A31),    /* DP3 */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 10)), /* PG_EINT10 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 11),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "i2c3"),          /* SDA */
-                 SUNXI_FUNCTION(0x3, "usb"),           /* DM3 */
+                 SUNXI_FUNCTION_VARIANT(0x3, "usb",
+                                        PINCTRL_SUN6I_A31),    /* DM3 */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 11)), /* PG_EINT11 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 12),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
@@ -782,40 +824,40 @@ static const struct sunxi_desc_pin sun6i_a31_pins[] = {
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "uart4"),         /* RX */
                  SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 18)), /* PG_EINT18 */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 0),
+       /* Hole; H starts at pin 9 for A31s */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(H, 0), PINCTRL_SUN6I_A31,
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "nand1")),        /* WE */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 1),
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(H, 1), PINCTRL_SUN6I_A31,
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "nand1")),        /* ALE */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 2),
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(H, 2), PINCTRL_SUN6I_A31,
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "nand1")),        /* CLE */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 3),
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(H, 3), PINCTRL_SUN6I_A31,
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "nand1")),        /* CE1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 4),
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(H, 4), PINCTRL_SUN6I_A31,
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "nand1")),        /* CE0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 5),
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(H, 5), PINCTRL_SUN6I_A31,
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "nand1")),        /* RE */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 6),
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(H, 6), PINCTRL_SUN6I_A31,
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "nand1")),        /* RB0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 7),
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(H, 7), PINCTRL_SUN6I_A31,
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "nand1")),        /* RB1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 8),
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(H, 8), PINCTRL_SUN6I_A31,
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "nand1")),        /* DQS */
@@ -908,11 +950,12 @@ static const struct sunxi_desc_pin sun6i_a31_pins[] = {
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                /* Undocumented mux function - see above */
                  SUNXI_FUNCTION(0x3, "spdif")),        /* SPDIF OUT */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 29),
+       /* 2 extra pins for A31 */
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(H, 29), PINCTRL_SUN6I_A31,
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "nand1")),        /* CE2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 30),
+       SUNXI_PIN_VARIANT(SUNXI_PINCTRL_PIN(H, 30), PINCTRL_SUN6I_A31,
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
                  SUNXI_FUNCTION(0x2, "nand1")),        /* CE3 */
@@ -926,12 +969,23 @@ static const struct sunxi_pinctrl_desc sun6i_a31_pinctrl_data = {
 
 static int sun6i_a31_pinctrl_probe(struct platform_device *pdev)
 {
-       return sunxi_pinctrl_init(pdev,
-                                 &sun6i_a31_pinctrl_data);
+       unsigned long variant =
+               (unsigned long)of_device_get_match_data(&pdev->dev);
+
+       return sunxi_pinctrl_init_with_variant(pdev,
+                                              &sun6i_a31_pinctrl_data,
+                                              variant);
 }
 
 static const struct of_device_id sun6i_a31_pinctrl_match[] = {
-       { .compatible = "allwinner,sun6i-a31-pinctrl", },
+       {
+               .compatible = "allwinner,sun6i-a31-pinctrl",
+               .data = (void *)PINCTRL_SUN6I_A31
+       },
+       {
+               .compatible = "allwinner,sun6i-a31s-pinctrl",
+               .data = (void *)PINCTRL_SUN6I_A31S
+       },
        {}
 };
 
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun6i-a31s.c b/drivers/pinctrl/sunxi/pinctrl-sun6i-a31s.c
deleted file mode 100644 (file)
index 231a746..0000000
+++ /dev/null
@@ -1,809 +0,0 @@
-/*
- * Allwinner A31s SoCs pinctrl driver.
- *
- * Copyright (C) 2014 Hans de Goede <hdegoede@redhat.com>
- *
- * Based on pinctrl-sun6i-a31.c, which is:
- * Copyright (C) 2014 Maxime Ripard <maxime.ripard@free-electrons.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2.  This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/pinctrl/pinctrl.h>
-
-#include "pinctrl-sunxi.h"
-
-static const struct sunxi_desc_pin sun6i_a31s_pins[] = {
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 0),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "gmac"),          /* TXD0 */
-                 SUNXI_FUNCTION(0x4, "uart1"),         /* DTR */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 0)),  /* PA_EINT0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 1),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "gmac"),          /* TXD1 */
-                 SUNXI_FUNCTION(0x4, "uart1"),         /* DSR */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 1)),  /* PA_EINT1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 2),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "gmac"),          /* TXD2 */
-                 SUNXI_FUNCTION(0x4, "uart1"),         /* DCD */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 2)),  /* PA_EINT2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 3),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "gmac"),          /* TXD3 */
-                 SUNXI_FUNCTION(0x4, "uart1"),         /* RING */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 3)),  /* PA_EINT3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 4),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "gmac"),          /* TXD4 */
-                 SUNXI_FUNCTION(0x4, "uart1"),         /* TX */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 4)),  /* PA_EINT4 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 5),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "gmac"),          /* TXD5 */
-                 SUNXI_FUNCTION(0x4, "uart1"),         /* RX */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 5)),  /* PA_EINT5 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 6),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "gmac"),          /* TXD6 */
-                 SUNXI_FUNCTION(0x4, "uart1"),         /* RTS */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 6)),  /* PA_EINT6 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 7),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "gmac"),          /* TXD7 */
-                 SUNXI_FUNCTION(0x4, "uart1"),         /* CTS */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 7)),  /* PA_EINT7 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 8),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "gmac"),          /* TXCLK */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 8)),  /* PA_EINT8 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 9),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "gmac"),          /* TXEN */
-                 SUNXI_FUNCTION(0x4, "mmc3"),          /* CMD */
-                 SUNXI_FUNCTION(0x5, "mmc2"),          /* CMD */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 9)),  /* PA_EINT9 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 10),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "gmac"),          /* GTXCLK */
-                 SUNXI_FUNCTION(0x4, "mmc3"),          /* CLK */
-                 SUNXI_FUNCTION(0x5, "mmc2"),          /* CLK */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 10)), /* PA_EINT10 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 11),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "gmac"),          /* RXD0 */
-                 SUNXI_FUNCTION(0x4, "mmc3"),          /* D0 */
-                 SUNXI_FUNCTION(0x5, "mmc2"),          /* D0 */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 11)), /* PA_EINT11 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 12),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "gmac"),          /* RXD1 */
-                 SUNXI_FUNCTION(0x4, "mmc3"),          /* D1 */
-                 SUNXI_FUNCTION(0x5, "mmc2"),          /* D1 */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 12)), /* PA_EINT12 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 13),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "gmac"),          /* RXD2 */
-                 SUNXI_FUNCTION(0x4, "mmc3"),          /* D2 */
-                 SUNXI_FUNCTION(0x5, "mmc2"),          /* D2 */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 13)), /* PA_EINT13 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 14),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "gmac"),          /* RXD3 */
-                 SUNXI_FUNCTION(0x4, "mmc3"),          /* D3 */
-                 SUNXI_FUNCTION(0x5, "mmc2"),          /* D3 */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 14)), /* PA_EINT14 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 15),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "gmac"),          /* RXD4 */
-                 SUNXI_FUNCTION(0x4, "clk_out_a"),
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 15)), /* PA_EINT15 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 16),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "gmac"),          /* RXD5 */
-                 SUNXI_FUNCTION(0x4, "dmic"),          /* CLK */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 16)), /* PA_EINT16 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 17),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "gmac"),          /* RXD6 */
-                 SUNXI_FUNCTION(0x4, "dmic"),          /* DIN */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 17)), /* PA_EINT17 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 18),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "gmac"),          /* RXD7 */
-                 SUNXI_FUNCTION(0x4, "clk_out_b"),
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 18)), /* PA_EINT18 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 19),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "gmac"),          /* RXDV */
-                 SUNXI_FUNCTION(0x4, "pwm3"),          /* Positive */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 19)), /* PA_EINT19 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 20),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "gmac"),          /* RXCLK */
-                 SUNXI_FUNCTION(0x4, "pwm3"),          /* Negative */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 20)), /* PA_EINT20 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 21),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "gmac"),          /* TXERR */
-                 SUNXI_FUNCTION(0x4, "spi3"),          /* CS0 */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 21)), /* PA_EINT21 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 22),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "gmac"),          /* RXERR */
-                 SUNXI_FUNCTION(0x4, "spi3"),          /* CLK */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 22)), /* PA_EINT22 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 23),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "gmac"),          /* COL */
-                 SUNXI_FUNCTION(0x4, "spi3"),          /* MOSI */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 23)), /* PA_EINT23 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 24),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "gmac"),          /* CRS */
-                 SUNXI_FUNCTION(0x4, "spi3"),          /* MISO */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 24)), /* PA_EINT24 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 25),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "gmac"),          /* CLKIN */
-                 SUNXI_FUNCTION(0x4, "spi3"),          /* CS1 */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 25)), /* PA_EINT25 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 26),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "gmac"),          /* MDC */
-                 SUNXI_FUNCTION(0x4, "clk_out_c"),
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 26)), /* PA_EINT26 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 27),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "gmac"),          /* MDIO */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 27)), /* PA_EINT27 */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 0),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2s0"),          /* MCLK */
-                 SUNXI_FUNCTION(0x3, "uart3"),         /* CTS */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 0)),  /* PB_EINT0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 1),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2s0"),          /* BCLK */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 1)),  /* PB_EINT1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 2),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2s0"),          /* LRCK */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 2)),  /* PB_EINT2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 3),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2s0"),          /* DO0 */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 3)),  /* PB_EINT3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 4),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2s0"),          /* DO1 */
-                 SUNXI_FUNCTION(0x3, "uart3"),         /* RTS */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 4)),  /* PB_EINT4 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 5),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2s0"),          /* DO2 */
-                 SUNXI_FUNCTION(0x3, "uart3"),         /* TX */
-                 SUNXI_FUNCTION(0x4, "i2c3"),          /* SCK */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 5)),  /* PB_EINT5 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 6),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2s0"),          /* DO3 */
-                 SUNXI_FUNCTION(0x3, "uart3"),         /* RX */
-                 SUNXI_FUNCTION(0x4, "i2c3"),          /* SDA */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 6)),  /* PB_EINT6 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 7),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x3, "i2s0"),          /* DI */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 7)),  /* PB_EINT7 */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* WE */
-                 SUNXI_FUNCTION(0x3, "spi0")),         /* MOSI */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 1),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* ALE */
-                 SUNXI_FUNCTION(0x3, "spi0")),         /* MISO */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 2),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* CLE */
-                 SUNXI_FUNCTION(0x3, "spi0")),         /* CLK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 3),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0")),        /* CE1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 4),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0")),        /* CE0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 5),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0")),        /* RE */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 6),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* RB0 */
-                 SUNXI_FUNCTION(0x3, "mmc2"),          /* CMD */
-                 SUNXI_FUNCTION(0x4, "mmc3")),         /* CMD */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 7),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* RB1 */
-                 SUNXI_FUNCTION(0x3, "mmc2"),          /* CLK */
-                 SUNXI_FUNCTION(0x4, "mmc3")),         /* CLK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 8),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ0 */
-                 SUNXI_FUNCTION(0x3, "mmc2"),          /* D0 */
-                 SUNXI_FUNCTION(0x4, "mmc3")),         /* D0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 9),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ1 */
-                 SUNXI_FUNCTION(0x3, "mmc2"),          /* D1 */
-                 SUNXI_FUNCTION(0x4, "mmc3")),         /* D1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 10),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ2 */
-                 SUNXI_FUNCTION(0x3, "mmc2"),          /* D2 */
-                 SUNXI_FUNCTION(0x4, "mmc3")),         /* D2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 11),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ3 */
-                 SUNXI_FUNCTION(0x3, "mmc2"),          /* D3 */
-                 SUNXI_FUNCTION(0x4, "mmc3")),         /* D3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 12),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ4 */
-                 SUNXI_FUNCTION(0x3, "mmc2"),          /* D4 */
-                 SUNXI_FUNCTION(0x4, "mmc3")),         /* D4 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 13),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ5 */
-                 SUNXI_FUNCTION(0x3, "mmc2"),          /* D5 */
-                 SUNXI_FUNCTION(0x4, "mmc3")),         /* D5 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ6 */
-                 SUNXI_FUNCTION(0x3, "mmc2"),          /* D6 */
-                 SUNXI_FUNCTION(0x4, "mmc3")),         /* D6 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ7 */
-                 SUNXI_FUNCTION(0x3, "mmc2"),          /* D7 */
-                 SUNXI_FUNCTION(0x4, "mmc3")),         /* D7 */
-       /* Hole in pin numbering ! */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 24),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQS */
-                 SUNXI_FUNCTION(0x3, "mmc2"),          /* RST */
-                 SUNXI_FUNCTION(0x4, "mmc3")),         /* RST */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 25),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0")),        /* CE2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 26),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand0")),        /* CE3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 27),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x3, "spi0")),         /* CS0 */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 0),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D0 */
-                 SUNXI_FUNCTION(0x3, "lvds0")),        /* VP0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 1),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D1 */
-                 SUNXI_FUNCTION(0x3, "lvds0")),        /* VN0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D2 */
-                 SUNXI_FUNCTION(0x3, "lvds0")),        /* VP1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 3),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D3 */
-                 SUNXI_FUNCTION(0x3, "lvds0")),        /* VN1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 4),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D4 */
-                 SUNXI_FUNCTION(0x3, "lvds0")),        /* VP2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 5),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D5 */
-                 SUNXI_FUNCTION(0x3, "lvds0")),        /* VN2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 6),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D6 */
-                 SUNXI_FUNCTION(0x3, "lvds0")),        /* VPC */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 7),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D7 */
-                 SUNXI_FUNCTION(0x3, "lvds0")),        /* VNC */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 8),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D8 */
-                 SUNXI_FUNCTION(0x3, "lvds0")),        /* VP3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 9),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0"),          /* D9 */
-                 SUNXI_FUNCTION(0x3, "lvds0")),        /* VN3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 10),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D10 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 11),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D11 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 12),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D12 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 13),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D13 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 14),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D14 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 15),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D15 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 16),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D16 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 17),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D17 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 18),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D18 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 19),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D19 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 20),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D20 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 21),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D21 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 22),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D22 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 23),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* D23 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 24),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* CLK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 25),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* DE */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 26),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* HSYNC */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 27),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "lcd0")),         /* VSYNC */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 0),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "csi"),           /* PCLK */
-                 SUNXI_FUNCTION(0x3, "ts"),            /* CLK */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 0)),  /* PE_EINT0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 1),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "csi"),           /* MCLK */
-                 SUNXI_FUNCTION(0x3, "ts"),            /* ERR */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 1)),  /* PE_EINT1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 2),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "csi"),           /* HSYNC */
-                 SUNXI_FUNCTION(0x3, "ts"),            /* SYNC */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 2)),  /* PE_EINT2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 3),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "csi"),           /* VSYNC */
-                 SUNXI_FUNCTION(0x3, "ts"),            /* DVLD */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 3)),  /* PE_EINT3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 4),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "csi"),           /* D0 */
-                 SUNXI_FUNCTION(0x3, "uart5"),         /* TX */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 4)),  /* PE_EINT4 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 5),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "csi"),           /* D1 */
-                 SUNXI_FUNCTION(0x3, "uart5"),         /* RX */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 5)),  /* PE_EINT5 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 6),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "csi"),           /* D2 */
-                 SUNXI_FUNCTION(0x3, "uart5"),         /* RTS */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 6)),  /* PE_EINT6 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "csi"),           /* D3 */
-                 SUNXI_FUNCTION(0x3, "uart5"),         /* CTS */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 7)),  /* PE_EINT7 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "csi"),           /* D4 */
-                 SUNXI_FUNCTION(0x3, "ts"),            /* D0 */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 8)),  /* PE_EINT8 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "csi"),           /* D5 */
-                 SUNXI_FUNCTION(0x3, "ts"),            /* D1 */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 9)),  /* PE_EINT9 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "csi"),           /* D6 */
-                 SUNXI_FUNCTION(0x3, "ts"),            /* D2 */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 10)), /* PE_EINT10 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "csi"),           /* D7 */
-                 SUNXI_FUNCTION(0x3, "ts"),            /* D3 */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 11)), /* PE_EINT11 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 12),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "csi"),           /* D8 */
-                 SUNXI_FUNCTION(0x3, "ts"),            /* D4 */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 12)), /* PE_EINT12 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 13),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "csi"),           /* D9 */
-                 SUNXI_FUNCTION(0x3, "ts"),            /* D5 */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 13)), /* PE_EINT13 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 14),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "csi"),           /* D10 */
-                 SUNXI_FUNCTION(0x3, "ts"),            /* D6 */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 14)), /* PE_EINT14 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 15),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "csi"),           /* D11 */
-                 SUNXI_FUNCTION(0x3, "ts"),            /* D7 */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 15)), /* PE_EINT15 */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D1 */
-                 SUNXI_FUNCTION(0x4, "jtag")),         /* MS1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D0 */
-                 SUNXI_FUNCTION(0x4, "jtag")),         /* DI1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 2),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc0"),          /* CLK */
-                 SUNXI_FUNCTION(0x4, "uart0")),        /* TX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 3),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc0"),          /* CMD */
-                 SUNXI_FUNCTION(0x4, "jtag")),         /* DO1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 4),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D3 */
-                 SUNXI_FUNCTION(0x4, "uart0")),        /* RX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 5),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D2 */
-                 SUNXI_FUNCTION(0x4, "jtag")),         /* CK1 */
-       /* Hole */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 0),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc1"),          /* CLK */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 0)),  /* PG_EINT0 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 1),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc1"),          /* CMD */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 1)),  /* PG_EINT1 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 2),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc1"),          /* D0 */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 2)),  /* PG_EINT2 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 3),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc1"),          /* D1 */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 3)),  /* PG_EINT3 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 4),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc1"),          /* D2 */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 4)),  /* PG_EINT4 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 5),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "mmc1"),          /* D3 */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 5)),  /* PG_EINT5 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 6),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "uart2"),         /* TX */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 6)),  /* PG_EINT6 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 7),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "uart2"),         /* RX */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 7)),  /* PG_EINT7 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 8),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "uart2"),         /* RTS */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 8)),  /* PG_EINT8 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "uart2"),         /* CTS */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 9)),  /* PG_EINT9 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2c3"),          /* SCK */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 10)), /* PG_EINT10 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 11),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2c3"),          /* SDA */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 11)), /* PG_EINT11 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 12),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi1"),          /* CS1 */
-                 SUNXI_FUNCTION(0x3, "i2s1"),          /* MCLK */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 12)), /* PG_EINT12 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 13),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi1"),          /* CS0 */
-                 SUNXI_FUNCTION(0x3, "i2s1"),          /* BCLK */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 13)), /* PG_EINT13 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 14),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi1"),          /* CLK */
-                 SUNXI_FUNCTION(0x3, "i2s1"),          /* LRCK */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 14)), /* PG_EINT14 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 15),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi1"),          /* MOSI */
-                 SUNXI_FUNCTION(0x3, "i2s1"),          /* DIN */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 15)), /* PG_EINT15 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 16),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi1"),          /* MISO */
-                 SUNXI_FUNCTION(0x3, "i2s1"),          /* DOUT */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 16)), /* PG_EINT16 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 17),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "uart4"),         /* TX */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 17)), /* PG_EINT17 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 18),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "uart4"),         /* RX */
-                 SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 18)), /* PG_EINT18 */
-       /* Hole, note H starts at pin 9 */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 9),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi2"),          /* CS0 */
-                 SUNXI_FUNCTION(0x3, "jtag"),          /* MS0 */
-                 SUNXI_FUNCTION(0x4, "pwm1")),         /* Positive */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 10),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi2"),          /* CLK */
-                 SUNXI_FUNCTION(0x3, "jtag"),          /* CK0 */
-                 SUNXI_FUNCTION(0x4, "pwm1")),         /* Negative */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 11),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi2"),          /* MOSI */
-                 SUNXI_FUNCTION(0x3, "jtag"),          /* DO0 */
-                 SUNXI_FUNCTION(0x4, "pwm2")),         /* Positive */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 12),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "spi2"),          /* MISO */
-                 SUNXI_FUNCTION(0x3, "jtag"),          /* DI0 */
-                 SUNXI_FUNCTION(0x4, "pwm2")),         /* Negative */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 13),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "pwm0")),
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 14),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2c0")),         /* SCK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 15),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2c0")),         /* SDA */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 16),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2c1")),         /* SCK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 17),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2c1")),         /* SDA */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 18),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2c2")),         /* SCK */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 19),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "i2c2")),         /* SDA */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 20),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "uart0")),        /* TX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 21),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "uart0")),        /* RX */
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 22),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out")),
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 23),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out")),
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 24),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out")),
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 25),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out")),
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 26),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out")),
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 27),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out")),
-       SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 28),
-                 SUNXI_FUNCTION(0x0, "gpio_in"),
-                 SUNXI_FUNCTION(0x1, "gpio_out")),
-};
-
-static const struct sunxi_pinctrl_desc sun6i_a31s_pinctrl_data = {
-       .pins = sun6i_a31s_pins,
-       .npins = ARRAY_SIZE(sun6i_a31s_pins),
-       .irq_banks = 4,
-};
-
-static int sun6i_a31s_pinctrl_probe(struct platform_device *pdev)
-{
-       return sunxi_pinctrl_init(pdev,
-                                 &sun6i_a31s_pinctrl_data);
-}
-
-static const struct of_device_id sun6i_a31s_pinctrl_match[] = {
-       { .compatible = "allwinner,sun6i-a31s-pinctrl", },
-       {}
-};
-
-static struct platform_driver sun6i_a31s_pinctrl_driver = {
-       .probe  = sun6i_a31s_pinctrl_probe,
-       .driver = {
-               .name           = "sun6i-a31s-pinctrl",
-               .of_match_table = sun6i_a31s_pinctrl_match,
-       },
-};
-builtin_platform_driver(sun6i_a31s_pinctrl_driver);
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun8i-v3s.c b/drivers/pinctrl/sunxi/pinctrl-sun8i-v3s.c
new file mode 100644 (file)
index 0000000..c86d3c4
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ * Allwinner V3s SoCs pinctrl driver.
+ *
+ * Copyright (C) 2016 Icenowy Zheng <icenowy@aosc.xyz>
+ *
+ * Based on pinctrl-sun8i-h3.c, which is:
+ * Copyright (C) 2015 Jens Kuske <jenskuske@gmail.com>
+ *
+ * Based on pinctrl-sun8i-a23.c, which is:
+ * Copyright (C) 2014 Chen-Yu Tsai <wens@csie.org>
+ * Copyright (C) 2014 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-sunxi.h"
+
+static const struct sunxi_desc_pin sun8i_v3s_pins[] = {
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 0),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart2"),         /* TX */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 0)),  /* PB_EINT0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 1),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart2"),         /* RX */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 1)),  /* PB_EINT1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 2),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart2"),         /* RTS */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 2)),  /* PB_EINT2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 3),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "uart2"),         /* D1 */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 3)),  /* PB_EINT3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 4),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "pwm0"),
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 4)),  /* PB_EINT4 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 5),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "pwm1"),
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 5)),  /* PB_EINT5 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 6),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c0"),          /* SCK */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 6)),  /* PB_EINT6 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 7),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c0"),          /* SDA */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 7)),  /* PB_EINT7 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 8),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c1"),          /* SDA */
+                 SUNXI_FUNCTION(0x3, "uart0"),         /* TX */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 8)),  /* PB_EINT8 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 9),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "i2c1"),          /* SCK */
+                 SUNXI_FUNCTION(0x3, "uart0"),         /* RX */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 9)),  /* PB_EINT9 */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc2"),          /* CLK */
+                 SUNXI_FUNCTION(0x3, "spi0")),         /* MISO */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 1),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc2"),          /* CMD */
+                 SUNXI_FUNCTION(0x3, "spi0")),         /* CLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 2),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc2"),          /* RST */
+                 SUNXI_FUNCTION(0x3, "spi0")),         /* CS */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 3),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc2"),          /* D0 */
+                 SUNXI_FUNCTION(0x3, "spi0")),         /* MOSI */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 0),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* PCLK */
+                 SUNXI_FUNCTION(0x3, "lcd")),          /* CLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 1),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* MCLK */
+                 SUNXI_FUNCTION(0x3, "lcd")),          /* DE */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 2),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* HSYNC */
+                 SUNXI_FUNCTION(0x3, "lcd")),          /* HSYNC */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 3),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* VSYNC */
+                 SUNXI_FUNCTION(0x3, "lcd")),          /* VSYNC */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 4),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D0 */
+                 SUNXI_FUNCTION(0x3, "lcd")),          /* D2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 5),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D1 */
+                 SUNXI_FUNCTION(0x3, "lcd")),          /* D3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 6),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D2 */
+                 SUNXI_FUNCTION(0x3, "lcd")),          /* D4 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D3 */
+                 SUNXI_FUNCTION(0x3, "lcd")),          /* D5 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D4 */
+                 SUNXI_FUNCTION(0x3, "lcd")),          /* D6 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D5 */
+                 SUNXI_FUNCTION(0x3, "lcd")),          /* D7 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D6 */
+                 SUNXI_FUNCTION(0x3, "lcd")),          /* D10 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D7 */
+                 SUNXI_FUNCTION(0x3, "lcd")),          /* D11 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 12),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D8 */
+                 SUNXI_FUNCTION(0x3, "lcd")),          /* D12 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 13),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D9 */
+                 SUNXI_FUNCTION(0x3, "lcd")),          /* D13 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 14),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D10 */
+                 SUNXI_FUNCTION(0x3, "lcd")),          /* D14 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 15),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D11 */
+                 SUNXI_FUNCTION(0x3, "lcd")),          /* D15 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 16),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D12 */
+                 SUNXI_FUNCTION(0x3, "lcd")),          /* D18 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 17),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D13 */
+                 SUNXI_FUNCTION(0x3, "lcd")),          /* D19 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 18),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D14 */
+                 SUNXI_FUNCTION(0x3, "lcd")),          /* D20 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 19),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* D15 */
+                 SUNXI_FUNCTION(0x3, "lcd")),          /* D21 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 20),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* FIELD */
+                 SUNXI_FUNCTION(0x3, "csi_mipi")),     /* MCLK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 21),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* SCK */
+                 SUNXI_FUNCTION(0x3, "i2c1"),          /* SCK */
+                 SUNXI_FUNCTION(0x4, "uart1")),        /* TX */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 22),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "csi"),           /* SDA */
+                 SUNXI_FUNCTION(0x3, "i2c1"),          /* SDA */
+                 SUNXI_FUNCTION(0x4, "uart1")),        /* RX */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 23),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x3, "lcd"),           /* D22 */
+                 SUNXI_FUNCTION(0x4, "uart1")),        /* RTS */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 24),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x3, "lcd"),           /* D23 */
+                 SUNXI_FUNCTION(0x4, "uart1")),        /* CTS */
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D1 */
+                 SUNXI_FUNCTION(0x3, "jtag")),         /* MS */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D0 */
+                 SUNXI_FUNCTION(0x3, "jtag")),         /* DI */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 2),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* CLK */
+                 SUNXI_FUNCTION(0x3, "uart0")),        /* TX */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 3),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* CMD */
+                 SUNXI_FUNCTION(0x3, "jtag")),         /* DO */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 4),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D3 */
+                 SUNXI_FUNCTION(0x3, "uart0")),        /* RX */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 5),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc0"),          /* D2 */
+                 SUNXI_FUNCTION(0x3, "jtag")),         /* CK */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 6),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out")),
+       /* Hole */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 0),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* CLK */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 0)),  /* PG_EINT0 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 1),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* CMD */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 1)),  /* PG_EINT1 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 2),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* D0 */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 2)),  /* PG_EINT2 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 3),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* D1 */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 3)),  /* PG_EINT3 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 4),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* D2 */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 4)),  /* PG_EINT4 */
+       SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 5),
+                 SUNXI_FUNCTION(0x0, "gpio_in"),
+                 SUNXI_FUNCTION(0x1, "gpio_out"),
+                 SUNXI_FUNCTION(0x2, "mmc1"),          /* D3 */
+                 SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 5)),  /* PG_EINT5 */
+};
+
+static const struct sunxi_pinctrl_desc sun8i_v3s_pinctrl_data = {
+       .pins = sun8i_v3s_pins,
+       .npins = ARRAY_SIZE(sun8i_v3s_pins),
+       .irq_banks = 2,
+       .irq_read_needs_mux = true
+};
+
+static int sun8i_v3s_pinctrl_probe(struct platform_device *pdev)
+{
+       return sunxi_pinctrl_init(pdev,
+                                 &sun8i_v3s_pinctrl_data);
+}
+
+static const struct of_device_id sun8i_v3s_pinctrl_match[] = {
+       { .compatible = "allwinner,sun8i-v3s-pinctrl", },
+       {}
+};
+
+static struct platform_driver sun8i_v3s_pinctrl_driver = {
+       .probe  = sun8i_v3s_pinctrl_probe,
+       .driver = {
+               .name           = "sun8i-v3s-pinctrl",
+               .of_match_table = sun8i_v3s_pinctrl_match,
+       },
+};
+builtin_platform_driver(sun8i_v3s_pinctrl_driver);
index 207a8de4e1ed851cf542aa4af008e8f74102cad3..60e6e36c4a7e84fb6d70a46c99c1cc13c7fe2d2f 100644 (file)
@@ -540,7 +540,7 @@ static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev,
                enum pin_config_param param;
                unsigned long flags;
                u32 offset, shift, mask, reg;
-               u16 arg, val;
+               u32 arg, val;
                int ret;
 
                param = pinconf_to_config_param(configs[i]);
@@ -1040,21 +1040,35 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev)
        struct sunxi_pinctrl *pctl = platform_get_drvdata(pdev);
        int i;
 
-       pctl->ngroups = pctl->desc->npins;
+       /*
+        * Allocate groups
+        *
+        * We assume that the number of groups is the number of pins
+        * given in the data array.
 
-       /* Allocate groups */
+        * This will not always be true, since some pins might not be
+        * available in the current variant, but fortunately for us,
+        * this means that the number of pins is the maximum group
+        * number we will ever see.
+        */
        pctl->groups = devm_kzalloc(&pdev->dev,
-                                   pctl->ngroups * sizeof(*pctl->groups),
+                                   pctl->desc->npins * sizeof(*pctl->groups),
                                    GFP_KERNEL);
        if (!pctl->groups)
                return -ENOMEM;
 
        for (i = 0; i < pctl->desc->npins; i++) {
                const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
-               struct sunxi_pinctrl_group *group = pctl->groups + i;
+               struct sunxi_pinctrl_group *group = pctl->groups + pctl->ngroups;
+
+               if (pin->variant && !(pctl->variant & pin->variant))
+                       continue;
 
                group->name = pin->pin.name;
                group->pin = pin->pin.number;
+
+               /* And now we count the actual number of pins / groups */
+               pctl->ngroups++;
        }
 
        /*
@@ -1062,17 +1076,23 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev)
         * we'll reallocate that later anyway
         */
        pctl->functions = devm_kzalloc(&pdev->dev,
-                               pctl->desc->npins * sizeof(*pctl->functions),
-                               GFP_KERNEL);
+                                      pctl->ngroups * sizeof(*pctl->functions),
+                                      GFP_KERNEL);
        if (!pctl->functions)
                return -ENOMEM;
 
        /* Count functions and their associated groups */
        for (i = 0; i < pctl->desc->npins; i++) {
                const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
-               struct sunxi_desc_function *func = pin->functions;
+               struct sunxi_desc_function *func;
+
+               if (pin->variant && !(pctl->variant & pin->variant))
+                       continue;
+
+               for (func = pin->functions; func->name; func++) {
+                       if (func->variant && !(pctl->variant & func->variant))
+                               continue;
 
-               while (func->name) {
                        /* Create interrupt mapping while we're at it */
                        if (!strcmp(func->name, "irq")) {
                                int irqnum = func->irqnum + func->irqbank * IRQ_PER_BANK;
@@ -1080,22 +1100,32 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev)
                        }
 
                        sunxi_pinctrl_add_function(pctl, func->name);
-                       func++;
                }
        }
 
+       /* And now allocated and fill the array for real */
        pctl->functions = krealloc(pctl->functions,
-                               pctl->nfunctions * sizeof(*pctl->functions),
-                               GFP_KERNEL);
+                                  pctl->nfunctions * sizeof(*pctl->functions),
+                                  GFP_KERNEL);
+       if (!pctl->functions) {
+               kfree(pctl->functions);
+               return -ENOMEM;
+       }
 
        for (i = 0; i < pctl->desc->npins; i++) {
                const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
-               struct sunxi_desc_function *func = pin->functions;
+               struct sunxi_desc_function *func;
 
-               while (func->name) {
+               if (pin->variant && !(pctl->variant & pin->variant))
+                       continue;
+
+               for (func = pin->functions; func->name; func++) {
                        struct sunxi_pinctrl_function *func_item;
                        const char **func_grp;
 
+                       if (func->variant && !(pctl->variant & func->variant))
+                               continue;
+
                        func_item = sunxi_pinctrl_find_function_by_name(pctl,
                                                                        func->name);
                        if (!func_item)
@@ -1115,7 +1145,6 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev)
                                func_grp++;
 
                        *func_grp = pin->pin.name;
-                       func++;
                }
        }
 
@@ -1207,15 +1236,16 @@ static int sunxi_pinctrl_setup_debounce(struct sunxi_pinctrl *pctl,
        return 0;
 }
 
-int sunxi_pinctrl_init(struct platform_device *pdev,
-                      const struct sunxi_pinctrl_desc *desc)
+int sunxi_pinctrl_init_with_variant(struct platform_device *pdev,
+                                   const struct sunxi_pinctrl_desc *desc,
+                                   unsigned long variant)
 {
        struct device_node *node = pdev->dev.of_node;
        struct pinctrl_desc *pctrl_desc;
        struct pinctrl_pin_desc *pins;
        struct sunxi_pinctrl *pctl;
        struct resource *res;
-       int i, ret, last_pin;
+       int i, ret, last_pin, pin_idx;
        struct clk *clk;
 
        pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
@@ -1232,6 +1262,7 @@ int sunxi_pinctrl_init(struct platform_device *pdev,
 
        pctl->dev = &pdev->dev;
        pctl->desc = desc;
+       pctl->variant = variant;
 
        pctl->irq_array = devm_kcalloc(&pdev->dev,
                                       IRQ_PER_BANK * pctl->desc->irq_banks,
@@ -1252,8 +1283,14 @@ int sunxi_pinctrl_init(struct platform_device *pdev,
        if (!pins)
                return -ENOMEM;
 
-       for (i = 0; i < pctl->desc->npins; i++)
-               pins[i] = pctl->desc->pins[i].pin;
+       for (i = 0, pin_idx = 0; i < pctl->desc->npins; i++) {
+               const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
+
+               if (pin->variant && !(pctl->variant & pin->variant))
+                       continue;
+
+               pins[pin_idx++] = pin->pin;
+       }
 
        pctrl_desc = devm_kzalloc(&pdev->dev,
                                  sizeof(*pctrl_desc),
@@ -1264,7 +1301,7 @@ int sunxi_pinctrl_init(struct platform_device *pdev,
        pctrl_desc->name = dev_name(&pdev->dev);
        pctrl_desc->owner = THIS_MODULE;
        pctrl_desc->pins = pins;
-       pctrl_desc->npins = pctl->desc->npins;
+       pctrl_desc->npins = pctl->ngroups;
        pctrl_desc->confops = &sunxi_pconf_ops;
        pctrl_desc->pctlops = &sunxi_pctrl_ops;
        pctrl_desc->pmxops =  &sunxi_pmx_ops;
index f78a44a03189fa2bf7124c1ce5f9d47c8e37278c..e1aedd260b2eccb196e6771efa1ab6d6ea074207 100644 (file)
 #define SUN4I_FUNC_INPUT       0
 #define SUN4I_FUNC_IRQ         6
 
+#define PINCTRL_SUN5I_A10S     BIT(1)
+#define PINCTRL_SUN5I_A13      BIT(2)
+#define PINCTRL_SUN5I_GR8      BIT(3)
+#define PINCTRL_SUN6I_A31      BIT(4)
+#define PINCTRL_SUN6I_A31S     BIT(5)
+
 struct sunxi_desc_function {
+       unsigned long   variant;
        const char      *name;
        u8              muxval;
        u8              irqbank;
@@ -91,6 +98,7 @@ struct sunxi_desc_function {
 
 struct sunxi_desc_pin {
        struct pinctrl_pin_desc         pin;
+       unsigned long                   variant;
        struct sunxi_desc_function      *functions;
 };
 
@@ -128,6 +136,7 @@ struct sunxi_pinctrl {
        unsigned                        *irq_array;
        spinlock_t                      lock;
        struct pinctrl_dev              *pctl_dev;
+       unsigned long                   variant;
 };
 
 #define SUNXI_PIN(_pin, ...)                                   \
@@ -137,12 +146,27 @@ struct sunxi_pinctrl {
                        __VA_ARGS__, { } },                     \
        }
 
+#define SUNXI_PIN_VARIANT(_pin, _variant, ...)                 \
+       {                                                       \
+               .pin = _pin,                                    \
+               .variant = _variant,                            \
+               .functions = (struct sunxi_desc_function[]){    \
+                       __VA_ARGS__, { } },                     \
+       }
+
 #define SUNXI_FUNCTION(_val, _name)                            \
        {                                                       \
                .name = _name,                                  \
                .muxval = _val,                                 \
        }
 
+#define SUNXI_FUNCTION_VARIANT(_val, _name, _variant)          \
+       {                                                       \
+               .name = _name,                                  \
+               .muxval = _val,                                 \
+               .variant = _variant,                            \
+       }
+
 #define SUNXI_FUNCTION_IRQ(_val, _irq)                         \
        {                                                       \
                .name = "irq",                                  \
@@ -290,7 +314,11 @@ static inline u32 sunxi_irq_status_offset(u16 irq)
        return irq_num * IRQ_STATUS_IRQ_BITS;
 }
 
-int sunxi_pinctrl_init(struct platform_device *pdev,
-                      const struct sunxi_pinctrl_desc *desc);
+int sunxi_pinctrl_init_with_variant(struct platform_device *pdev,
+                                   const struct sunxi_pinctrl_desc *desc,
+                                   unsigned long variant);
+
+#define sunxi_pinctrl_init(_dev, _desc) \
+       sunxi_pinctrl_init_with_variant(_dev, _desc, 0)
 
 #endif /* __PINCTRL_SUNXI_H */
diff --git a/drivers/pinctrl/ti/Kconfig b/drivers/pinctrl/ti/Kconfig
new file mode 100644 (file)
index 0000000..815a886
--- /dev/null
@@ -0,0 +1,10 @@
+config PINCTRL_TI_IODELAY
+       tristate "TI IODelay Module pinconf driver"
+       depends on OF
+       select GENERIC_PINCTRL_GROUPS
+       select GENERIC_PINMUX_FUNCTIONS
+       select GENERIC_PINCONF
+       select REGMAP_MMIO
+       help
+         Say Y here to support Texas Instruments' IO delay pinconf driver.
+         IO delay module is used for the DRA7 SoC family.
diff --git a/drivers/pinctrl/ti/Makefile b/drivers/pinctrl/ti/Makefile
new file mode 100644 (file)
index 0000000..913744e
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_PINCTRL_TI_IODELAY)       += pinctrl-ti-iodelay.o
diff --git a/drivers/pinctrl/ti/pinctrl-ti-iodelay.c b/drivers/pinctrl/ti/pinctrl-ti-iodelay.c
new file mode 100644 (file)
index 0000000..717e340
--- /dev/null
@@ -0,0 +1,937 @@
+/*
+ * Support for configuration of IO Delay module found on Texas Instruments SoCs
+ * such as DRA7
+ *
+ * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include "../core.h"
+#include "../devicetree.h"
+
+#define DRIVER_NAME    "ti-iodelay"
+
+/**
+ * struct ti_iodelay_reg_data - Describes the registers for the iodelay instance
+ * @signature_mask: CONFIG_REG mask for the signature bits (see TRM)
+ * @signature_value: CONFIG_REG signature value to be written (see TRM)
+ * @lock_mask: CONFIG_REG mask for the lock bits (see TRM)
+ * @lock_val: CONFIG_REG lock value for the lock bits (see TRM)
+ * @unlock_val:CONFIG_REG unlock value for the lock bits (see TRM)
+ * @binary_data_coarse_mask: CONFIG_REG coarse mask (see TRM)
+ * @binary_data_fine_mask: CONFIG_REG fine mask (see TRM)
+ * @reg_refclk_offset: Refclk register offset
+ * @refclk_period_mask: Refclk mask
+ * @reg_coarse_offset: Coarse register configuration offset
+ * @coarse_delay_count_mask: Coarse delay count mask
+ * @coarse_ref_count_mask: Coarse ref count mask
+ * @reg_fine_offset: Fine register configuration offset
+ * @fine_delay_count_mask: Fine delay count mask
+ * @fine_ref_count_mask: Fine ref count mask
+ * @reg_global_lock_offset: Global iodelay module lock register offset
+ * @global_lock_mask: Lock mask
+ * @global_unlock_val: Unlock value
+ * @global_lock_val: Lock value
+ * @reg_start_offset: Offset to iodelay registers after the CONFIG_REG_0 to 8
+ * @reg_nr_per_pin: Number of iodelay registers for each pin
+ * @regmap_config: Regmap configuration for the IODelay region
+ */
+struct ti_iodelay_reg_data {
+       u32 signature_mask;
+       u32 signature_value;
+       u32 lock_mask;
+       u32 lock_val;
+       u32 unlock_val;
+       u32 binary_data_coarse_mask;
+       u32 binary_data_fine_mask;
+
+       u32 reg_refclk_offset;
+       u32 refclk_period_mask;
+
+       u32 reg_coarse_offset;
+       u32 coarse_delay_count_mask;
+       u32 coarse_ref_count_mask;
+
+       u32 reg_fine_offset;
+       u32 fine_delay_count_mask;
+       u32 fine_ref_count_mask;
+
+       u32 reg_global_lock_offset;
+       u32 global_lock_mask;
+       u32 global_unlock_val;
+       u32 global_lock_val;
+
+       u32 reg_start_offset;
+       u32 reg_nr_per_pin;
+
+       struct regmap_config *regmap_config;
+};
+
+/**
+ * struct ti_iodelay_reg_values - Computed io_reg configuration values (see TRM)
+ * @coarse_ref_count: Coarse reference count
+ * @coarse_delay_count: Coarse delay count
+ * @fine_ref_count: Fine reference count
+ * @fine_delay_count: Fine Delay count
+ * @ref_clk_period: Reference Clock period
+ * @cdpe: Coarse delay parameter
+ * @fdpe: Fine delay parameter
+ */
+struct ti_iodelay_reg_values {
+       u16 coarse_ref_count;
+       u16 coarse_delay_count;
+
+       u16 fine_ref_count;
+       u16 fine_delay_count;
+
+       u16 ref_clk_period;
+
+       u32 cdpe;
+       u32 fdpe;
+};
+
+/**
+ * struct ti_iodelay_cfg - Description of each configuration parameters
+ * @offset: Configuration register offset
+ * @a_delay: Agnostic Delay (in ps)
+ * @g_delay: Gnostic Delay (in ps)
+ */
+struct ti_iodelay_cfg {
+       u16 offset;
+       u16 a_delay;
+       u16 g_delay;
+};
+
+/**
+ * struct ti_iodelay_pingroup - Structure that describes one group
+ * @cfg: configuration array for the pin (from dt)
+ * @ncfg: number of configuration values allocated
+ * @config: pinconf "Config" - currently a dummy value
+ */
+struct ti_iodelay_pingroup {
+       struct ti_iodelay_cfg *cfg;
+       int ncfg;
+       unsigned long config;
+};
+
+/**
+ * struct ti_iodelay_device - Represents information for a iodelay instance
+ * @dev: Device pointer
+ * @phys_base: Physical address base of the iodelay device
+ * @reg_base: Virtual address base of the iodelay device
+ * @regmap: Regmap for this iodelay instance
+ * @pctl: Pinctrl device
+ * @desc: pinctrl descriptor for pctl
+ * @pa: pinctrl pin wise description
+ * @reg_data: Register definition data for the IODelay instance
+ * @reg_init_conf_values: Initial configuration values.
+ */
+struct ti_iodelay_device {
+       struct device *dev;
+       unsigned long phys_base;
+       void __iomem *reg_base;
+       struct regmap *regmap;
+
+       struct pinctrl_dev *pctl;
+       struct pinctrl_desc desc;
+       struct pinctrl_pin_desc *pa;
+
+       const struct ti_iodelay_reg_data *reg_data;
+       struct ti_iodelay_reg_values reg_init_conf_values;
+};
+
+/**
+ * ti_iodelay_extract() - extract bits for a field
+ * @val: Register value
+ * @mask: Mask
+ *
+ * Return: extracted value which is appropriately shifted
+ */
+static inline u32 ti_iodelay_extract(u32 val, u32 mask)
+{
+       return (val & mask) >> __ffs(mask);
+}
+
+/**
+ * ti_iodelay_compute_dpe() - Compute equation for delay parameter
+ * @period: Period to use
+ * @ref: Reference Count
+ * @delay: Delay count
+ * @delay_m: Delay multiplier
+ *
+ * Return: Computed delay parameter
+ */
+static inline u32 ti_iodelay_compute_dpe(u16 period, u16 ref, u16 delay,
+                                        u16 delay_m)
+{
+       u64 m, d;
+
+       /* Handle overflow conditions */
+       m = 10 * (u64)period * (u64)ref;
+       d = 2 * (u64)delay * (u64)delay_m;
+
+       /* Truncate result back to 32 bits */
+       return div64_u64(m, d);
+}
+
+/**
+ * ti_iodelay_pinconf_set() - Configure the pin configuration
+ * @iod: iodelay device
+ * @cfg: Configuration
+ *
+ * Update the configuration register as per TRM and lockup once done.
+ * *IMPORTANT NOTE* SoC TRM does recommend doing iodelay programmation only
+ * while in Isolation. But, then, isolation also implies that every pin
+ * on the SoC (including DDR) will be isolated out. The only benefit being
+ * a glitchless configuration, However, the intent of this driver is purely
+ * to support a "glitchy" configuration where applicable.
+ *
+ * Return: 0 in case of success, else appropriate error value
+ */
+static int ti_iodelay_pinconf_set(struct ti_iodelay_device *iod,
+                                 struct ti_iodelay_cfg *cfg)
+{
+       const struct ti_iodelay_reg_data *reg = iod->reg_data;
+       struct ti_iodelay_reg_values *ival = &iod->reg_init_conf_values;
+       struct device *dev = iod->dev;
+       u32 g_delay_coarse, g_delay_fine;
+       u32 a_delay_coarse, a_delay_fine;
+       u32 c_elements, f_elements;
+       u32 total_delay;
+       u32 reg_mask, reg_val, tmp_val;
+       int r;
+
+       /* NOTE: Truncation is expected in all division below */
+       g_delay_coarse = cfg->g_delay / 920;
+       g_delay_fine = ((cfg->g_delay % 920) * 10) / 60;
+
+       a_delay_coarse = cfg->a_delay / ival->cdpe;
+       a_delay_fine = ((cfg->a_delay % ival->cdpe) * 10) / ival->fdpe;
+
+       c_elements = g_delay_coarse + a_delay_coarse;
+       f_elements = (g_delay_fine + a_delay_fine) / 10;
+
+       if (f_elements > 22) {
+               total_delay = c_elements * ival->cdpe + f_elements * ival->fdpe;
+               c_elements = total_delay / ival->cdpe;
+               f_elements = (total_delay % ival->cdpe) / ival->fdpe;
+       }
+
+       reg_mask = reg->signature_mask;
+       reg_val = reg->signature_value << __ffs(reg->signature_mask);
+
+       reg_mask |= reg->binary_data_coarse_mask;
+       tmp_val = c_elements << __ffs(reg->binary_data_coarse_mask);
+       if (tmp_val & ~reg->binary_data_coarse_mask) {
+               dev_err(dev, "Masking overflow of coarse elements %08x\n",
+                       tmp_val);
+               tmp_val &= reg->binary_data_coarse_mask;
+       }
+       reg_val |= tmp_val;
+
+       reg_mask |= reg->binary_data_fine_mask;
+       tmp_val = f_elements << __ffs(reg->binary_data_fine_mask);
+       if (tmp_val & ~reg->binary_data_fine_mask) {
+               dev_err(dev, "Masking overflow of fine elements %08x\n",
+                       tmp_val);
+               tmp_val &= reg->binary_data_fine_mask;
+       }
+       reg_val |= tmp_val;
+
+       /*
+        * NOTE: we leave the iodelay values unlocked - this is to work around
+        * situations such as those found with mmc mode change.
+        * However, this leaves open any unwarranted changes to padconf register
+        * impacting iodelay configuration. Use with care!
+        */
+       reg_mask |= reg->lock_mask;
+       reg_val |= reg->unlock_val << __ffs(reg->lock_mask);
+       r = regmap_update_bits(iod->regmap, cfg->offset, reg_mask, reg_val);
+
+       dev_info(dev, "Set reg 0x%x Delay(a: %d g: %d), Elements(C=%d F=%d)0x%x\n",
+                cfg->offset, cfg->a_delay, cfg->g_delay, c_elements,
+                f_elements, reg_val);
+
+       return r;
+}
+
+/**
+ * ti_iodelay_pinconf_init_dev() - Initialize IODelay device
+ * @iod: iodelay device
+ *
+ * Unlocks the iodelay region, computes the common parameters
+ *
+ * Return: 0 in case of success, else appropriate error value
+ */
+static int ti_iodelay_pinconf_init_dev(struct ti_iodelay_device *iod)
+{
+       const struct ti_iodelay_reg_data *reg = iod->reg_data;
+       struct device *dev = iod->dev;
+       struct ti_iodelay_reg_values *ival = &iod->reg_init_conf_values;
+       u32 val;
+       int r;
+
+       /* unlock the iodelay region */
+       r = regmap_update_bits(iod->regmap, reg->reg_global_lock_offset,
+                              reg->global_lock_mask, reg->global_unlock_val);
+       if (r)
+               return r;
+
+       /* Read up Recalibration sequence done by bootloader */
+       r = regmap_read(iod->regmap, reg->reg_refclk_offset, &val);
+       if (r)
+               return r;
+       ival->ref_clk_period = ti_iodelay_extract(val, reg->refclk_period_mask);
+       dev_dbg(dev, "refclk_period=0x%04x\n", ival->ref_clk_period);
+
+       r = regmap_read(iod->regmap, reg->reg_coarse_offset, &val);
+       if (r)
+               return r;
+       ival->coarse_ref_count =
+           ti_iodelay_extract(val, reg->coarse_ref_count_mask);
+       ival->coarse_delay_count =
+           ti_iodelay_extract(val, reg->coarse_delay_count_mask);
+       if (!ival->coarse_delay_count) {
+               dev_err(dev, "Invalid Coarse delay count (0) (reg=0x%08x)\n",
+                       val);
+               return -EINVAL;
+       }
+       ival->cdpe = ti_iodelay_compute_dpe(ival->ref_clk_period,
+                                           ival->coarse_ref_count,
+                                           ival->coarse_delay_count, 88);
+       if (!ival->cdpe) {
+               dev_err(dev, "Invalid cdpe computed params = %d %d %d\n",
+                       ival->ref_clk_period, ival->coarse_ref_count,
+                       ival->coarse_delay_count);
+               return -EINVAL;
+       }
+       dev_dbg(iod->dev, "coarse: ref=0x%04x delay=0x%04x cdpe=0x%08x\n",
+               ival->coarse_ref_count, ival->coarse_delay_count, ival->cdpe);
+
+       r = regmap_read(iod->regmap, reg->reg_fine_offset, &val);
+       if (r)
+               return r;
+       ival->fine_ref_count =
+           ti_iodelay_extract(val, reg->fine_ref_count_mask);
+       ival->fine_delay_count =
+           ti_iodelay_extract(val, reg->fine_delay_count_mask);
+       if (!ival->fine_delay_count) {
+               dev_err(dev, "Invalid Fine delay count (0) (reg=0x%08x)\n",
+                       val);
+               return -EINVAL;
+       }
+       ival->fdpe = ti_iodelay_compute_dpe(ival->ref_clk_period,
+                                           ival->fine_ref_count,
+                                           ival->fine_delay_count, 264);
+       if (!ival->fdpe) {
+               dev_err(dev, "Invalid fdpe(0) computed params = %d %d %d\n",
+                       ival->ref_clk_period, ival->fine_ref_count,
+                       ival->fine_delay_count);
+               return -EINVAL;
+       }
+       dev_dbg(iod->dev, "fine: ref=0x%04x delay=0x%04x fdpe=0x%08x\n",
+               ival->fine_ref_count, ival->fine_delay_count, ival->fdpe);
+
+       return 0;
+}
+
+/**
+ * ti_iodelay_pinconf_deinit_dev() - deinit the iodelay device
+ * @iod:       IODelay device
+ *
+ * Deinitialize the IODelay device (basically just lock the region back up.
+ */
+static void ti_iodelay_pinconf_deinit_dev(struct ti_iodelay_device *iod)
+{
+       const struct ti_iodelay_reg_data *reg = iod->reg_data;
+
+       /* lock the iodelay region back again */
+       regmap_update_bits(iod->regmap, reg->reg_global_lock_offset,
+                          reg->global_lock_mask, reg->global_lock_val);
+}
+
+/**
+ * ti_iodelay_get_pingroup() - Find the group mapped by a group selector
+ * @iod: iodelay device
+ * @selector: Group Selector
+ *
+ * Return: Corresponding group representing group selector
+ */
+static struct ti_iodelay_pingroup *
+ti_iodelay_get_pingroup(struct ti_iodelay_device *iod, unsigned int selector)
+{
+       struct group_desc *g;
+
+       g = pinctrl_generic_get_group(iod->pctl, selector);
+       if (!g) {
+               dev_err(iod->dev, "%s could not find pingroup %i\n", __func__,
+                       selector);
+
+               return NULL;
+       }
+
+       return g->data;
+}
+
+/**
+ * ti_iodelay_offset_to_pin() - get a pin index based on the register offset
+ * @iod: iodelay driver instance
+ * @offset: register offset from the base
+ */
+static int ti_iodelay_offset_to_pin(struct ti_iodelay_device *iod,
+                                   unsigned int offset)
+{
+       const struct ti_iodelay_reg_data *r = iod->reg_data;
+       unsigned int index;
+
+       if (offset > r->regmap_config->max_register) {
+               dev_err(iod->dev, "mux offset out of range: 0x%x (0x%x)\n",
+                       offset, r->regmap_config->max_register);
+               return -EINVAL;
+       }
+
+       index = (offset - r->reg_start_offset) / r->regmap_config->reg_stride;
+       index /= r->reg_nr_per_pin;
+
+       return index;
+}
+
+/**
+ * ti_iodelay_node_iterator() - Iterate iodelay node
+ * @pctldev: Pin controller driver
+ * @np: Device node
+ * @pinctrl_spec: Parsed arguments from device tree
+ * @pins: Array of pins in the pin group
+ * @pin_index: Pin index in the pin array
+ * @data: Pin controller driver specific data
+ *
+ */
+static int ti_iodelay_node_iterator(struct pinctrl_dev *pctldev,
+                                   struct device_node *np,
+                                   const struct of_phandle_args *pinctrl_spec,
+                                   int *pins, int pin_index, void *data)
+{
+       struct ti_iodelay_device *iod;
+       struct ti_iodelay_cfg *cfg = data;
+       const struct ti_iodelay_reg_data *r;
+       struct pinctrl_pin_desc *pd;
+       int pin;
+
+       iod = pinctrl_dev_get_drvdata(pctldev);
+       if (!iod)
+               return -EINVAL;
+
+       r = iod->reg_data;
+
+       if (pinctrl_spec->args_count < r->reg_nr_per_pin) {
+               dev_err(iod->dev, "invalid args_count for spec: %i\n",
+                       pinctrl_spec->args_count);
+
+               return -EINVAL;
+       }
+
+       /* Index plus two value cells */
+       cfg[pin_index].offset = pinctrl_spec->args[0];
+       cfg[pin_index].a_delay = pinctrl_spec->args[1] & 0xffff;
+       cfg[pin_index].g_delay = pinctrl_spec->args[2] & 0xffff;
+
+       pin = ti_iodelay_offset_to_pin(iod, cfg[pin_index].offset);
+       if (pin < 0) {
+               dev_err(iod->dev, "could not add functions for %s %ux\n",
+                       np->name, cfg[pin_index].offset);
+               return -ENODEV;
+       }
+       pins[pin_index] = pin;
+
+       pd = &iod->pa[pin];
+       pd->drv_data = &cfg[pin_index];
+
+       dev_dbg(iod->dev, "%s offset=%x a_delay = %d g_delay = %d\n",
+               np->name, cfg[pin_index].offset, cfg[pin_index].a_delay,
+               cfg[pin_index].g_delay);
+
+       return 0;
+}
+
+/**
+ * ti_iodelay_dt_node_to_map() - Map a device tree node to appropriate group
+ * @pctldev: pinctrl device representing IODelay device
+ * @np: Node Pointer (device tree)
+ * @map: Pinctrl Map returned back to pinctrl framework
+ * @num_maps: Number of maps (1)
+ *
+ * Maps the device tree description into a group of configuration parameters
+ * for iodelay block entry.
+ *
+ * Return: 0 in case of success, else appropriate error value
+ */
+static int ti_iodelay_dt_node_to_map(struct pinctrl_dev *pctldev,
+                                    struct device_node *np,
+                                    struct pinctrl_map **map,
+                                    unsigned int *num_maps)
+{
+       struct ti_iodelay_device *iod;
+       struct ti_iodelay_cfg *cfg;
+       struct ti_iodelay_pingroup *g;
+       const char *name = "pinctrl-pin-array";
+       int rows, *pins, error = -EINVAL, i;
+
+       iod = pinctrl_dev_get_drvdata(pctldev);
+       if (!iod)
+               return -EINVAL;
+
+       rows = pinctrl_count_index_with_args(np, name);
+       if (rows == -EINVAL)
+               return rows;
+
+       *map = devm_kzalloc(iod->dev, sizeof(**map), GFP_KERNEL);
+       if (!*map)
+               return -ENOMEM;
+       *num_maps = 0;
+
+       g = devm_kzalloc(iod->dev, sizeof(*g), GFP_KERNEL);
+       if (!g) {
+               error = -ENOMEM;
+               goto free_map;
+       }
+
+       pins = devm_kzalloc(iod->dev, sizeof(*pins) * rows, GFP_KERNEL);
+       if (!pins)
+               goto free_group;
+
+       cfg = devm_kzalloc(iod->dev, sizeof(*cfg) * rows, GFP_KERNEL);
+       if (!cfg) {
+               error = -ENOMEM;
+               goto free_pins;
+       }
+
+       for (i = 0; i < rows; i++) {
+               struct of_phandle_args pinctrl_spec;
+
+               error = pinctrl_parse_index_with_args(np, name, i,
+                                                     &pinctrl_spec);
+               if (error)
+                       goto free_data;
+
+               error = ti_iodelay_node_iterator(pctldev, np, &pinctrl_spec,
+                                                pins, i, cfg);
+               if (error)
+                       goto free_data;
+       }
+
+       g->cfg = cfg;
+       g->ncfg = i;
+       g->config = PIN_CONFIG_END;
+
+       error = pinctrl_generic_add_group(iod->pctl, np->name, pins, i, g);
+       if (error < 0)
+               goto free_data;
+
+       (*map)->type = PIN_MAP_TYPE_CONFIGS_GROUP;
+       (*map)->data.configs.group_or_pin = np->name;
+       (*map)->data.configs.configs = &g->config;
+       (*map)->data.configs.num_configs = 1;
+       *num_maps = 1;
+
+       return 0;
+
+free_data:
+       devm_kfree(iod->dev, cfg);
+free_pins:
+       devm_kfree(iod->dev, pins);
+free_group:
+       devm_kfree(iod->dev, g);
+free_map:
+       devm_kfree(iod->dev, *map);
+
+       return error;
+}
+
+/**
+ * ti_iodelay_pinconf_group_get() - Get the group configuration
+ * @pctldev: pinctrl device representing IODelay device
+ * @selector: Group selector
+ * @config: Configuration returned
+ *
+ * Return: The configuration if the group is valid, else returns -EINVAL
+ */
+static int ti_iodelay_pinconf_group_get(struct pinctrl_dev *pctldev,
+                                       unsigned int selector,
+                                       unsigned long *config)
+{
+       struct ti_iodelay_device *iod;
+       struct device *dev;
+       struct ti_iodelay_pingroup *group;
+
+       iod = pinctrl_dev_get_drvdata(pctldev);
+       dev = iod->dev;
+       group = ti_iodelay_get_pingroup(iod, selector);
+
+       if (!group)
+               return -EINVAL;
+
+       *config = group->config;
+       return 0;
+}
+
+/**
+ * ti_iodelay_pinconf_group_set() - Configure the groups of pins
+ * @pctldev: pinctrl device representing IODelay device
+ * @selector: Group selector
+ * @configs: Configurations
+ * @num_configs: Number of configurations
+ *
+ * Return: 0 if all went fine, else appropriate error value.
+ */
+static int ti_iodelay_pinconf_group_set(struct pinctrl_dev *pctldev,
+                                       unsigned int selector,
+                                       unsigned long *configs,
+                                       unsigned int num_configs)
+{
+       struct ti_iodelay_device *iod;
+       struct device *dev;
+       struct ti_iodelay_pingroup *group;
+       int i;
+
+       iod = pinctrl_dev_get_drvdata(pctldev);
+       dev = iod->dev;
+       group = ti_iodelay_get_pingroup(iod, selector);
+
+       if (num_configs != 1) {
+               dev_err(dev, "Unsupported number of configurations %d\n",
+                       num_configs);
+               return -EINVAL;
+       }
+
+       if (*configs != PIN_CONFIG_END) {
+               dev_err(dev, "Unsupported configuration\n");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < group->ncfg; i++) {
+               if (ti_iodelay_pinconf_set(iod, &group->cfg[i]))
+                       return -ENOTSUPP;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_DEBUG_FS
+/**
+ * ti_iodelay_pin_to_offset() - get pin register offset based on the pin index
+ * @iod: iodelay driver instance
+ * @selector: Pin index
+ */
+static unsigned int ti_iodelay_pin_to_offset(struct ti_iodelay_device *iod,
+                                            unsigned int selector)
+{
+       const struct ti_iodelay_reg_data *r = iod->reg_data;
+       unsigned int offset;
+
+       offset = selector * r->regmap_config->reg_stride;
+       offset *= r->reg_nr_per_pin;
+       offset += r->reg_start_offset;
+
+       return offset;
+}
+
+static void ti_iodelay_pin_dbg_show(struct pinctrl_dev *pctldev,
+                                   struct seq_file *s,
+                                   unsigned int pin)
+{
+       struct ti_iodelay_device *iod;
+       struct pinctrl_pin_desc *pd;
+       struct ti_iodelay_cfg *cfg;
+       const struct ti_iodelay_reg_data *r;
+       unsigned long offset;
+       u32 in, oen, out;
+
+       iod = pinctrl_dev_get_drvdata(pctldev);
+       r = iod->reg_data;
+
+       offset = ti_iodelay_pin_to_offset(iod, pin);
+       pd = &iod->pa[pin];
+       cfg = pd->drv_data;
+
+       regmap_read(iod->regmap, offset, &in);
+       regmap_read(iod->regmap, offset + r->regmap_config->reg_stride, &oen);
+       regmap_read(iod->regmap, offset + r->regmap_config->reg_stride * 2,
+                   &out);
+
+       seq_printf(s, "%lx a: %i g: %i (%08x %08x %08x) %s ",
+                  iod->phys_base + offset,
+                  cfg ? cfg->a_delay : -1,
+                  cfg ? cfg->g_delay : -1,
+                  in, oen, out, DRIVER_NAME);
+}
+
+/**
+ * ti_iodelay_pinconf_group_dbg_show() - show the group information
+ * @pctldev: Show the group information
+ * @s: Sequence file
+ * @selector: Group selector
+ *
+ * Provide the configuration information of the selected group
+ */
+static void ti_iodelay_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
+                                             struct seq_file *s,
+                                             unsigned int selector)
+{
+       struct ti_iodelay_device *iod;
+       struct device *dev;
+       struct ti_iodelay_pingroup *group;
+       int i;
+
+       iod = pinctrl_dev_get_drvdata(pctldev);
+       dev = iod->dev;
+       group = ti_iodelay_get_pingroup(iod, selector);
+       if (!group)
+               return;
+
+       for (i = 0; i < group->ncfg; i++) {
+               struct ti_iodelay_cfg *cfg;
+               u32 reg = 0;
+
+               cfg = &group->cfg[i];
+               regmap_read(iod->regmap, cfg->offset, &reg),
+                       seq_printf(s, "\n\t0x%08x = 0x%08x (%3d, %3d)",
+                                  cfg->offset, reg, cfg->a_delay,
+                                  cfg->g_delay);
+       }
+}
+#endif
+
+static struct pinctrl_ops ti_iodelay_pinctrl_ops = {
+       .get_groups_count = pinctrl_generic_get_group_count,
+       .get_group_name = pinctrl_generic_get_group_name,
+       .get_group_pins = pinctrl_generic_get_group_pins,
+#ifdef CONFIG_DEBUG_FS
+       .pin_dbg_show = ti_iodelay_pin_dbg_show,
+#endif
+       .dt_node_to_map = ti_iodelay_dt_node_to_map,
+};
+
+static struct pinconf_ops ti_iodelay_pinctrl_pinconf_ops = {
+       .pin_config_group_get = ti_iodelay_pinconf_group_get,
+       .pin_config_group_set = ti_iodelay_pinconf_group_set,
+#ifdef CONFIG_DEBUG_FS
+       .pin_config_group_dbg_show = ti_iodelay_pinconf_group_dbg_show,
+#endif
+};
+
+/**
+ * ti_iodelay_alloc_pins() - Allocate structures needed for pins for iodelay
+ * @dev: Device pointer
+ * @iod: iodelay device
+ * @base_phy: Base Physical Address
+ *
+ * Return: 0 if all went fine, else appropriate error value.
+ */
+static int ti_iodelay_alloc_pins(struct device *dev,
+                                struct ti_iodelay_device *iod, u32 base_phy)
+{
+       const struct ti_iodelay_reg_data *r = iod->reg_data;
+       struct pinctrl_pin_desc *pin;
+       u32 phy_reg;
+       int nr_pins, i;
+
+       nr_pins = ti_iodelay_offset_to_pin(iod, r->regmap_config->max_register);
+       dev_dbg(dev, "Allocating %i pins\n", nr_pins);
+
+       iod->pa = devm_kzalloc(dev, sizeof(*iod->pa) * nr_pins, GFP_KERNEL);
+       if (!iod->pa)
+               return -ENOMEM;
+
+       iod->desc.pins = iod->pa;
+       iod->desc.npins = nr_pins;
+
+       phy_reg = r->reg_start_offset + base_phy;
+
+       for (i = 0; i < nr_pins; i++, phy_reg += 4) {
+               pin = &iod->pa[i];
+               pin->number = i;
+       }
+
+       return 0;
+}
+
+static struct regmap_config dra7_iodelay_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+       .max_register = 0xd1c,
+};
+
+static struct ti_iodelay_reg_data dra7_iodelay_data = {
+       .signature_mask = 0x0003f000,
+       .signature_value = 0x29,
+       .lock_mask = 0x00000400,
+       .lock_val = 1,
+       .unlock_val = 0,
+       .binary_data_coarse_mask = 0x000003e0,
+       .binary_data_fine_mask = 0x0000001f,
+
+       .reg_refclk_offset = 0x14,
+       .refclk_period_mask = 0xffff,
+
+       .reg_coarse_offset = 0x18,
+       .coarse_delay_count_mask = 0xffff0000,
+       .coarse_ref_count_mask = 0x0000ffff,
+
+       .reg_fine_offset = 0x1C,
+       .fine_delay_count_mask = 0xffff0000,
+       .fine_ref_count_mask = 0x0000ffff,
+
+       .reg_global_lock_offset = 0x2c,
+       .global_lock_mask = 0x0000ffff,
+       .global_unlock_val = 0x0000aaaa,
+       .global_lock_val = 0x0000aaab,
+
+       .reg_start_offset = 0x30,
+       .reg_nr_per_pin = 3,
+       .regmap_config = &dra7_iodelay_regmap_config,
+};
+
+static const struct of_device_id ti_iodelay_of_match[] = {
+       {.compatible = "ti,dra7-iodelay", .data = &dra7_iodelay_data},
+       { /* Hopefully no more.. */ },
+};
+MODULE_DEVICE_TABLE(of, ti_iodelay_of_match);
+
+/**
+ * ti_iodelay_probe() - Standard probe
+ * @pdev: platform device
+ *
+ * Return: 0 if all went fine, else appropriate error value.
+ */
+static int ti_iodelay_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *np = of_node_get(dev->of_node);
+       const struct of_device_id *match;
+       struct resource *res;
+       struct ti_iodelay_device *iod;
+       int ret = 0;
+
+       if (!np) {
+               ret = -EINVAL;
+               dev_err(dev, "No OF node\n");
+               goto exit_out;
+       }
+
+       match = of_match_device(ti_iodelay_of_match, dev);
+       if (!match) {
+               ret = -EINVAL;
+               dev_err(dev, "No DATA match\n");
+               goto exit_out;
+       }
+
+       iod = devm_kzalloc(dev, sizeof(*iod), GFP_KERNEL);
+       if (!iod) {
+               ret = -ENOMEM;
+               goto exit_out;
+       }
+       iod->dev = dev;
+       iod->reg_data = match->data;
+
+       /* So far We can assume there is only 1 bank of registers */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(dev, "Missing MEM resource\n");
+               ret = -ENODEV;
+               goto exit_out;
+       }
+
+       iod->phys_base = res->start;
+       iod->reg_base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(iod->reg_base)) {
+               ret = PTR_ERR(iod->reg_base);
+               goto exit_out;
+       }
+
+       iod->regmap = devm_regmap_init_mmio(dev, iod->reg_base,
+                                           iod->reg_data->regmap_config);
+       if (IS_ERR(iod->regmap)) {
+               dev_err(dev, "Regmap MMIO init failed.\n");
+               ret = PTR_ERR(iod->regmap);
+               goto exit_out;
+       }
+
+       if (ti_iodelay_pinconf_init_dev(iod))
+               goto exit_out;
+
+       ret = ti_iodelay_alloc_pins(dev, iod, res->start);
+       if (ret)
+               goto exit_out;
+
+       iod->desc.pctlops = &ti_iodelay_pinctrl_ops;
+       /* no pinmux ops - we are pinconf */
+       iod->desc.confops = &ti_iodelay_pinctrl_pinconf_ops;
+       iod->desc.name = dev_name(dev);
+       iod->desc.owner = THIS_MODULE;
+
+       ret = pinctrl_register_and_init(&iod->desc, dev, iod, &iod->pctl);
+       if (ret) {
+               dev_err(dev, "Failed to register pinctrl\n");
+               goto exit_out;
+       }
+
+       platform_set_drvdata(pdev, iod);
+
+exit_out:
+       of_node_put(np);
+       return ret;
+}
+
+/**
+ * ti_iodelay_remove() - standard remove
+ * @pdev: platform device
+ *
+ * Return: 0 if all went fine, else appropriate error value.
+ */
+static int ti_iodelay_remove(struct platform_device *pdev)
+{
+       struct ti_iodelay_device *iod = platform_get_drvdata(pdev);
+
+       if (!iod)
+               return 0;
+
+       if (iod->pctl)
+               pinctrl_unregister(iod->pctl);
+
+       ti_iodelay_pinconf_deinit_dev(iod);
+
+       /* Expect other allocations to be freed by devm */
+
+       return 0;
+}
+
+static struct platform_driver ti_iodelay_driver = {
+       .probe = ti_iodelay_probe,
+       .remove = ti_iodelay_remove,
+       .driver = {
+                  .owner = THIS_MODULE,
+                  .name = DRIVER_NAME,
+                  .of_match_table = ti_iodelay_of_match,
+       },
+};
+module_platform_driver(ti_iodelay_driver);
+
+MODULE_AUTHOR("Texas Instruments, Inc.");
+MODULE_DESCRIPTION("Pinconf driver for TI's IO Delay module");
+MODULE_LICENSE("GPL v2");
index 9b2ee717bcccb99fb1ca773806b09afa75f62077..546f23c9040c2f27721f9db2d7a1c646cfe95785 100644 (file)
@@ -297,7 +297,7 @@ static int uniphier_conf_pin_config_get(struct pinctrl_dev *pctldev,
 
 static int uniphier_conf_pin_bias_set(struct pinctrl_dev *pctldev,
                                      const struct pin_desc *desc,
-                                     enum pin_config_param param, u16 arg)
+                                     enum pin_config_param param, u32 arg)
 {
        struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
        enum uniphier_pin_pull_dir pull_dir =
@@ -468,7 +468,7 @@ static int uniphier_conf_pin_config_set(struct pinctrl_dev *pctldev,
        for (i = 0; i < num_configs; i++) {
                enum pin_config_param param =
                                        pinconf_to_config_param(configs[i]);
-               u16 arg = pinconf_to_config_argument(configs[i]);
+               u32 arg = pinconf_to_config_argument(configs[i]);
 
                switch (param) {
                case PIN_CONFIG_BIAS_DISABLE:
index 270ca2a47a8c9a8237921800d64c46192f3e3437..c207e60b734f85ab921b0fa98479f7c4b7405a03 100644 (file)
@@ -428,7 +428,7 @@ static int wmt_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin,
 {
        struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev);
        enum pin_config_param param;
-       u16 arg;
+       u32 arg;
        u32 bank = WMT_BANK_FROM_PIN(pin);
        u32 bit = WMT_BIT_FROM_PIN(pin);
        u32 reg_pull_en = data->banks[bank].reg_pull_en;
index a62a89674fb5f6f82b8223067a6e1ff2b62ade21..89bbd6e8bad131961a811831b724cfecce22e754 100644 (file)
@@ -180,7 +180,7 @@ static int pm800_get_current_limit(struct regulator_dev *rdev)
        return info->max_ua;
 }
 
-static struct regulator_ops pm800_volt_range_ops = {
+static const struct regulator_ops pm800_volt_range_ops = {
        .list_voltage           = regulator_list_voltage_linear_range,
        .map_voltage            = regulator_map_voltage_linear_range,
        .set_voltage_sel        = regulator_set_voltage_sel_regmap,
@@ -191,7 +191,7 @@ static struct regulator_ops pm800_volt_range_ops = {
        .get_current_limit      = pm800_get_current_limit,
 };
 
-static struct regulator_ops pm800_volt_table_ops = {
+static const struct regulator_ops pm800_volt_table_ops = {
        .list_voltage           = regulator_list_voltage_table,
        .map_voltage            = regulator_map_voltage_iterate,
        .set_voltage_sel        = regulator_set_voltage_sel_regmap,
index b100a63ff3b3f6398b649129559f8228f66265c2..fd86446e499b23057a4def120b3baa02e1950c2d 100644 (file)
@@ -220,7 +220,7 @@ static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index)
        return ret;
 }
 
-static struct regulator_ops pm8607_regulator_ops = {
+static const struct regulator_ops pm8607_regulator_ops = {
        .list_voltage   = pm8607_list_voltage,
        .set_voltage_sel = regulator_set_voltage_sel_regmap,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
@@ -229,7 +229,7 @@ static struct regulator_ops pm8607_regulator_ops = {
        .is_enabled = regulator_is_enabled_regmap,
 };
 
-static struct regulator_ops pm8606_preg_ops = {
+static const struct regulator_ops pm8606_preg_ops = {
        .enable         = regulator_enable_regmap,
        .disable        = regulator_disable_regmap,
        .is_enabled     = regulator_is_enabled_regmap,
index 936f7ccc9736f8c550f712f6cb9fd8c8622ce29c..be06eb29c6817bd30f5747384e2da7432f87644c 100644 (file)
@@ -163,6 +163,13 @@ config REGULATOR_BCM590XX
          BCM590xx PMUs. This will enable support for the software
          controllable LDO/Switching regulators.
 
+config REGULATOR_CPCAP
+       tristate "Motorola CPCAP regulator"
+       depends on MFD_CPCAP
+       help
+         Say y here for CPCAP regulator found on some Motorola phones
+         and tablets such as Droid 4.
+
 config REGULATOR_DA903X
        tristate "Dialog Semiconductor DA9030/DA9034 regulators"
        depends on PMIC_DA903X
index 14294692beb9d06bdded2eb5ce4c89a0d4a93fd3..ef7725e2592adde95d4fc250f7b626091d9ade7f 100644 (file)
@@ -11,6 +11,7 @@ obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o
 
 obj-$(CONFIG_REGULATOR_88PM800) += 88pm800.o
 obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o
+obj-$(CONFIG_REGULATOR_CPCAP) += cpcap-regulator.o
 obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o
 obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o
 obj-$(CONFIG_REGULATOR_AB8500) += ab8500-ext.o ab8500.o
index 9dfabda8f47826f72cddbf3486461c2b32815312..afc5b5900181c659ac102f2c852d1fe5493f966f 100644 (file)
@@ -97,7 +97,7 @@ static int aat2870_ldo_is_enabled(struct regulator_dev *rdev)
        return val & ri->enable_mask ? 1 : 0;
 }
 
-static struct regulator_ops aat2870_ldo_ops = {
+static const struct regulator_ops aat2870_ldo_ops = {
        .list_voltage = regulator_list_voltage_table,
        .map_voltage = regulator_map_voltage_ascend,
        .set_voltage_sel = aat2870_ldo_set_voltage_sel,
index 441864b9fece038fc3c95d62b2b436f1b7a04537..43fda8b4455acd87d4c910d5ecfdb885759bba06 100644 (file)
@@ -69,7 +69,7 @@ static const struct regulator_linear_range act8945a_voltage_ranges[] = {
        REGULATOR_LINEAR_RANGE(2400000, 48, 63, 100000),
 };
 
-static struct regulator_ops act8945a_ops = {
+static const struct regulator_ops act8945a_ops = {
        .list_voltage           = regulator_list_voltage_linear_range,
        .map_voltage            = regulator_map_voltage_linear_range,
        .get_voltage_sel        = regulator_get_voltage_sel_regmap,
index 8b0f788a9bbb61afb97390097b83458681e6c94c..11c1f880b7bbffbf7f0446c76ac6d3a27616bfa5 100644 (file)
@@ -181,7 +181,7 @@ static int ad5398_disable(struct regulator_dev *rdev)
        return ret;
 }
 
-static struct regulator_ops ad5398_ops = {
+static const struct regulator_ops ad5398_ops = {
        .get_current_limit = ad5398_get_current_limit,
        .set_current_limit = ad5398_set_current_limit,
        .enable = ad5398_enable,
index 3a6d0290c54c0fbd0f1c82ffcd5329c2facc56ae..b041f277a38b7ba6634656785012ed5737ab03e6 100644 (file)
@@ -301,7 +301,19 @@ static int anatop_regulator_probe(struct platform_device *pdev)
                        return -EINVAL;
                }
        } else {
+               u32 enable_bit;
+
                rdesc->ops = &anatop_rops;
+
+               if (!of_property_read_u32(np, "anatop-enable-bit",
+                                         &enable_bit)) {
+                       anatop_rops.enable  = regulator_enable_regmap;
+                       anatop_rops.disable = regulator_disable_regmap;
+                       anatop_rops.is_enabled = regulator_is_enabled_regmap;
+
+                       rdesc->enable_reg = sreg->control_reg;
+                       rdesc->enable_mask = BIT(enable_bit);
+               }
        }
 
        /* register regulator */
index 302b57cb89c673a8d8036234641d2c9df5622a9d..e76d094591e72bd1813d4d43f776644c0e314b3f 100644 (file)
@@ -109,7 +109,7 @@ static int arizona_ldo1_hc_get_voltage_sel(struct regulator_dev *rdev)
        return (val & ARIZONA_LDO1_VSEL_MASK) >> ARIZONA_LDO1_VSEL_SHIFT;
 }
 
-static struct regulator_ops arizona_ldo1_hc_ops = {
+static const struct regulator_ops arizona_ldo1_hc_ops = {
        .list_voltage = arizona_ldo1_hc_list_voltage,
        .map_voltage = arizona_ldo1_hc_map_voltage,
        .get_voltage_sel = arizona_ldo1_hc_get_voltage_sel,
@@ -135,7 +135,7 @@ static const struct regulator_desc arizona_ldo1_hc = {
        .owner = THIS_MODULE,
 };
 
-static struct regulator_ops arizona_ldo1_ops = {
+static const struct regulator_ops arizona_ldo1_ops = {
        .list_voltage = regulator_list_voltage_linear,
        .map_voltage = regulator_map_voltage_linear,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
index fcb98dbda8379c76f79372a0266056275ef8815a..22bd714076229be6129d73436ac12611f4956f4a 100644 (file)
@@ -45,6 +45,7 @@ static void arizona_micsupp_check_cp(struct work_struct *work)
        struct arizona_micsupp *micsupp =
                container_of(work, struct arizona_micsupp, check_cp_work);
        struct snd_soc_dapm_context *dapm = micsupp->arizona->dapm;
+       struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
        struct arizona *arizona = micsupp->arizona;
        struct regmap *regmap = arizona->regmap;
        unsigned int reg;
@@ -59,9 +60,10 @@ static void arizona_micsupp_check_cp(struct work_struct *work)
        if (dapm) {
                if ((reg & (ARIZONA_CPMIC_ENA | ARIZONA_CPMIC_BYPASS)) ==
                    ARIZONA_CPMIC_ENA)
-                       snd_soc_dapm_force_enable_pin(dapm, "MICSUPP");
+                       snd_soc_component_force_enable_pin(component,
+                                                          "MICSUPP");
                else
-                       snd_soc_dapm_disable_pin(dapm, "MICSUPP");
+                       snd_soc_component_disable_pin(component, "MICSUPP");
 
                snd_soc_dapm_sync(dapm);
        }
@@ -104,7 +106,7 @@ static int arizona_micsupp_set_bypass(struct regulator_dev *rdev, bool ena)
        return ret;
 }
 
-static struct regulator_ops arizona_micsupp_ops = {
+static const struct regulator_ops arizona_micsupp_ops = {
        .enable = arizona_micsupp_enable,
        .disable = arizona_micsupp_disable,
        .is_enabled = regulator_is_enabled_regmap,
index c0e93b1332f7b87f577b46c4a4fe1c93af12b152..874d415d6b4f9a5878fab8394bd043de0fdfeab1 100644 (file)
@@ -82,7 +82,7 @@ static unsigned int as3711_get_mode_sd(struct regulator_dev *rdev)
        return -EINVAL;
 }
 
-static struct regulator_ops as3711_sd_ops = {
+static const struct regulator_ops as3711_sd_ops = {
        .is_enabled             = regulator_is_enabled_regmap,
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
@@ -94,7 +94,7 @@ static struct regulator_ops as3711_sd_ops = {
        .set_mode               = as3711_set_mode_sd,
 };
 
-static struct regulator_ops as3711_aldo_ops = {
+static const struct regulator_ops as3711_aldo_ops = {
        .is_enabled             = regulator_is_enabled_regmap,
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
@@ -104,7 +104,7 @@ static struct regulator_ops as3711_aldo_ops = {
        .map_voltage            = regulator_map_voltage_linear_range,
 };
 
-static struct regulator_ops as3711_dldo_ops = {
+static const struct regulator_ops as3711_dldo_ops = {
        .is_enabled             = regulator_is_enabled_regmap,
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
index a3ade9e4ef478ed90311365a4e86db0cbbc394d5..0b9d4e3e52c7070f1532afa59d731da66c5893ef 100644 (file)
                .ops            = &axp20x_ops_range,                            \
        }
 
-static struct regulator_ops axp20x_ops_fixed = {
+static const struct regulator_ops axp20x_ops_fixed = {
        .list_voltage           = regulator_list_voltage_linear,
 };
 
-static struct regulator_ops axp20x_ops_range = {
+static const struct regulator_ops axp20x_ops_range = {
        .set_voltage_sel        = regulator_set_voltage_sel_regmap,
        .get_voltage_sel        = regulator_get_voltage_sel_regmap,
        .list_voltage           = regulator_list_voltage_linear_range,
@@ -141,7 +141,7 @@ static struct regulator_ops axp20x_ops_range = {
        .is_enabled             = regulator_is_enabled_regmap,
 };
 
-static struct regulator_ops axp20x_ops = {
+static const struct regulator_ops axp20x_ops = {
        .set_voltage_sel        = regulator_set_voltage_sel_regmap,
        .get_voltage_sel        = regulator_get_voltage_sel_regmap,
        .list_voltage           = regulator_list_voltage_linear,
@@ -150,7 +150,7 @@ static struct regulator_ops axp20x_ops = {
        .is_enabled             = regulator_is_enabled_regmap,
 };
 
-static struct regulator_ops axp20x_ops_sw = {
+static const struct regulator_ops axp20x_ops_sw = {
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
        .is_enabled             = regulator_is_enabled_regmap,
index 76b01835dcb44f51e59b8f4986b6fb9874a9a6c3..9dd715407b39471e29309a924393ef8b2ba6ee50 100644 (file)
@@ -250,7 +250,7 @@ static int bcm590xx_get_enable_register(int id)
        return reg;
 }
 
-static struct regulator_ops bcm590xx_ops_ldo = {
+static const struct regulator_ops bcm590xx_ops_ldo = {
        .is_enabled             = regulator_is_enabled_regmap,
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
@@ -260,7 +260,7 @@ static struct regulator_ops bcm590xx_ops_ldo = {
        .map_voltage            = regulator_map_voltage_iterate,
 };
 
-static struct regulator_ops bcm590xx_ops_dcdc = {
+static const struct regulator_ops bcm590xx_ops_dcdc = {
        .is_enabled             = regulator_is_enabled_regmap,
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
@@ -270,7 +270,7 @@ static struct regulator_ops bcm590xx_ops_dcdc = {
        .map_voltage            = regulator_map_voltage_linear_range,
 };
 
-static struct regulator_ops bcm590xx_ops_vbus = {
+static const struct regulator_ops bcm590xx_ops_vbus = {
        .is_enabled             = regulator_is_enabled_regmap,
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
index 04baac9a165bbb56da292a51d0a56055947861e0..53d4fc70dbd0981cdb73eabdc815346c25963b6b 100644 (file)
@@ -1455,12 +1455,14 @@ static struct regulator_dev *regulator_lookup_by_name(const char *name)
  * lookup could succeed in the future.
  *
  * If successful, returns a struct regulator_dev that corresponds to the name
- * @supply and with the embedded struct device refcount incremented by one,
- * or NULL on failure. The refcount must be dropped by calling put_device().
+ * @supply and with the embedded struct device refcount incremented by one.
+ * The refcount must be dropped by calling put_device().
+ * On failure one of the following ERR-PTR-encoded values is returned:
+ * -ENODEV if lookup fails permanently, -EPROBE_DEFER if lookup could succeed
+ * in the future.
  */
 static struct regulator_dev *regulator_dev_lookup(struct device *dev,
-                                                 const char *supply,
-                                                 int *ret)
+                                                 const char *supply)
 {
        struct regulator_dev *r;
        struct device_node *node;
@@ -1476,16 +1478,12 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev,
                        r = of_find_regulator_by_node(node);
                        if (r)
                                return r;
-                       *ret = -EPROBE_DEFER;
-                       return NULL;
-               } else {
+
                        /*
-                        * If we couldn't even get the node then it's
-                        * not just that the device didn't register
-                        * yet, there's no node and we'll never
-                        * succeed.
+                        * We have a node, but there is no device.
+                        * assume it has not registered yet.
                         */
-                       *ret = -ENODEV;
+                       return ERR_PTR(-EPROBE_DEFER);
                }
        }
 
@@ -1506,13 +1504,16 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev,
 
                if (strcmp(map->supply, supply) == 0 &&
                    get_device(&map->regulator->dev)) {
-                       mutex_unlock(&regulator_list_mutex);
-                       return map->regulator;
+                       r = map->regulator;
+                       break;
                }
        }
        mutex_unlock(&regulator_list_mutex);
 
-       return NULL;
+       if (r)
+               return r;
+
+       return ERR_PTR(-ENODEV);
 }
 
 static int regulator_resolve_supply(struct regulator_dev *rdev)
@@ -1529,8 +1530,10 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
        if (rdev->supply)
                return 0;
 
-       r = regulator_dev_lookup(dev, rdev->supply_name, &ret);
-       if (!r) {
+       r = regulator_dev_lookup(dev, rdev->supply_name);
+       if (IS_ERR(r)) {
+               ret = PTR_ERR(r);
+
                if (ret == -ENODEV) {
                        /*
                         * No supply was specified for this regulator and
@@ -1553,6 +1556,19 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
                }
        }
 
+       /*
+        * If the supply's parent device is not the same as the
+        * regulator's parent device, then ensure the parent device
+        * is bound before we resolve the supply, in case the parent
+        * device get probe deferred and unregisters the supply.
+        */
+       if (r->dev.parent && r->dev.parent != rdev->dev.parent) {
+               if (!device_is_bound(r->dev.parent)) {
+                       put_device(&r->dev);
+                       return -EPROBE_DEFER;
+               }
+       }
+
        /* Recursively resolve the supply of the supply */
        ret = regulator_resolve_supply(r);
        if (ret < 0) {
@@ -1580,69 +1596,72 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
 }
 
 /* Internal regulator request function */
-static struct regulator *_regulator_get(struct device *dev, const char *id,
-                                       bool exclusive, bool allow_dummy)
+struct regulator *_regulator_get(struct device *dev, const char *id,
+                                enum regulator_get_type get_type)
 {
        struct regulator_dev *rdev;
-       struct regulator *regulator = ERR_PTR(-EPROBE_DEFER);
-       const char *devname = NULL;
+       struct regulator *regulator;
+       const char *devname = dev ? dev_name(dev) : "deviceless";
        int ret;
 
+       if (get_type >= MAX_GET_TYPE) {
+               dev_err(dev, "invalid type %d in %s\n", get_type, __func__);
+               return ERR_PTR(-EINVAL);
+       }
+
        if (id == NULL) {
                pr_err("get() with no identifier\n");
                return ERR_PTR(-EINVAL);
        }
 
-       if (dev)
-               devname = dev_name(dev);
+       rdev = regulator_dev_lookup(dev, id);
+       if (IS_ERR(rdev)) {
+               ret = PTR_ERR(rdev);
 
-       if (have_full_constraints())
-               ret = -ENODEV;
-       else
-               ret = -EPROBE_DEFER;
-
-       rdev = regulator_dev_lookup(dev, id, &ret);
-       if (rdev)
-               goto found;
-
-       regulator = ERR_PTR(ret);
+               /*
+                * If regulator_dev_lookup() fails with error other
+                * than -ENODEV our job here is done, we simply return it.
+                */
+               if (ret != -ENODEV)
+                       return ERR_PTR(ret);
 
-       /*
-        * If we have return value from dev_lookup fail, we do not expect to
-        * succeed, so, quit with appropriate error value
-        */
-       if (ret && ret != -ENODEV)
-               return regulator;
+               if (!have_full_constraints()) {
+                       dev_warn(dev,
+                                "incomplete constraints, dummy supplies not allowed\n");
+                       return ERR_PTR(-ENODEV);
+               }
 
-       if (!devname)
-               devname = "deviceless";
+               switch (get_type) {
+               case NORMAL_GET:
+                       /*
+                        * Assume that a regulator is physically present and
+                        * enabled, even if it isn't hooked up, and just
+                        * provide a dummy.
+                        */
+                       dev_warn(dev,
+                                "%s supply %s not found, using dummy regulator\n",
+                                devname, id);
+                       rdev = dummy_regulator_rdev;
+                       get_device(&rdev->dev);
+                       break;
 
-       /*
-        * Assume that a regulator is physically present and enabled
-        * even if it isn't hooked up and just provide a dummy.
-        */
-       if (have_full_constraints() && allow_dummy) {
-               pr_warn("%s supply %s not found, using dummy regulator\n",
-                       devname, id);
+               case EXCLUSIVE_GET:
+                       dev_warn(dev,
+                                "dummy supplies not allowed for exclusive requests\n");
+                       /* fall through */
 
-               rdev = dummy_regulator_rdev;
-               get_device(&rdev->dev);
-               goto found;
-       /* Don't log an error when called from regulator_get_optional() */
-       } else if (!have_full_constraints() || exclusive) {
-               dev_warn(dev, "dummy supplies not allowed\n");
+               default:
+                       return ERR_PTR(-ENODEV);
+               }
        }
 
-       return regulator;
-
-found:
        if (rdev->exclusive) {
                regulator = ERR_PTR(-EPERM);
                put_device(&rdev->dev);
                return regulator;
        }
 
-       if (exclusive && rdev->open_count) {
+       if (get_type == EXCLUSIVE_GET && rdev->open_count) {
                regulator = ERR_PTR(-EBUSY);
                put_device(&rdev->dev);
                return regulator;
@@ -1656,6 +1675,7 @@ found:
        }
 
        if (!try_module_get(rdev->owner)) {
+               regulator = ERR_PTR(-EPROBE_DEFER);
                put_device(&rdev->dev);
                return regulator;
        }
@@ -1669,7 +1689,7 @@ found:
        }
 
        rdev->open_count++;
-       if (exclusive) {
+       if (get_type == EXCLUSIVE_GET) {
                rdev->exclusive = 1;
 
                ret = _regulator_is_enabled(rdev);
@@ -1697,7 +1717,7 @@ found:
  */
 struct regulator *regulator_get(struct device *dev, const char *id)
 {
-       return _regulator_get(dev, id, false, true);
+       return _regulator_get(dev, id, NORMAL_GET);
 }
 EXPORT_SYMBOL_GPL(regulator_get);
 
@@ -1724,7 +1744,7 @@ EXPORT_SYMBOL_GPL(regulator_get);
  */
 struct regulator *regulator_get_exclusive(struct device *dev, const char *id)
 {
-       return _regulator_get(dev, id, true, false);
+       return _regulator_get(dev, id, EXCLUSIVE_GET);
 }
 EXPORT_SYMBOL_GPL(regulator_get_exclusive);
 
@@ -1750,7 +1770,7 @@ EXPORT_SYMBOL_GPL(regulator_get_exclusive);
  */
 struct regulator *regulator_get_optional(struct device *dev, const char *id)
 {
-       return _regulator_get(dev, id, false, false);
+       return _regulator_get(dev, id, OPTIONAL_GET);
 }
 EXPORT_SYMBOL_GPL(regulator_get_optional);
 
@@ -3660,7 +3680,7 @@ err:
        for (++i; i < num_consumers; ++i) {
                r = regulator_enable(consumers[i].consumer);
                if (r != 0)
-                       pr_err("Failed to reename %s: %d\n",
+                       pr_err("Failed to re-enable %s: %d\n",
                               consumers[i].supply, r);
        }
 
@@ -3686,21 +3706,17 @@ int regulator_bulk_force_disable(int num_consumers,
                           struct regulator_bulk_data *consumers)
 {
        int i;
-       int ret;
+       int ret = 0;
 
-       for (i = 0; i < num_consumers; i++)
+       for (i = 0; i < num_consumers; i++) {
                consumers[i].ret =
                            regulator_force_disable(consumers[i].consumer);
 
-       for (i = 0; i < num_consumers; i++) {
-               if (consumers[i].ret != 0) {
+               /* Store first error for reporting */
+               if (consumers[i].ret && !ret)
                        ret = consumers[i].ret;
-                       goto out;
-               }
        }
 
-       return 0;
-out:
        return ret;
 }
 EXPORT_SYMBOL_GPL(regulator_bulk_force_disable);
@@ -4391,12 +4407,13 @@ static void regulator_summary_show_subtree(struct seq_file *s,
        seq_puts(s, "\n");
 
        list_for_each_entry(consumer, &rdev->consumer_list, list) {
-               if (consumer->dev->class == &regulator_class)
+               if (consumer->dev && consumer->dev->class == &regulator_class)
                        continue;
 
                seq_printf(s, "%*s%-*s ",
                           (level + 1) * 3 + 1, "",
-                          30 - (level + 1) * 3, dev_name(consumer->dev));
+                          30 - (level + 1) * 3,
+                          consumer->dev ? dev_name(consumer->dev) : "deviceless");
 
                switch (rdev->desc->type) {
                case REGULATOR_VOLTAGE:
@@ -4540,6 +4557,16 @@ static int __init regulator_init_complete(void)
        if (of_have_populated_dt())
                has_full_constraints = true;
 
+       /*
+        * Regulators may had failed to resolve their input supplies
+        * when were registered, either because the input supply was
+        * not registered yet or because its parent device was not
+        * bound yet. So attempt to resolve the input supplies for
+        * pending regulators before trying to disable unused ones.
+        */
+       class_for_each_device(&regulator_class, NULL, NULL,
+                             regulator_register_resolve_supply);
+
        /* If we have a full configuration then disable any regulators
         * we have permission to change the status for and which are
         * not in use or always_on.  This is effectively the default
diff --git a/drivers/regulator/cpcap-regulator.c b/drivers/regulator/cpcap-regulator.c
new file mode 100644 (file)
index 0000000..cc98ace
--- /dev/null
@@ -0,0 +1,464 @@
+/*
+ * Motorola CPCAP PMIC regulator driver
+ *
+ * Based on cpcap-regulator.c from Motorola Linux kernel tree
+ * Copyright (C) 2009-2011 Motorola, Inc.
+ *
+ * Rewritten for mainline kernel to use device tree and regmap
+ * Copyright (C) 2017 Tony Lindgren <tony@atomide.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 "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/mfd/motorola-cpcap.h>
+
+/*
+ * Resource assignment register bits. These seem to control the state
+ * idle modes adn are used at least for omap4.
+ */
+
+/* CPCAP_REG_ASSIGN2 bits - Resource Assignment 2 */
+#define CPCAP_BIT_VSDIO_SEL            BIT(15)
+#define CPCAP_BIT_VDIG_SEL             BIT(14)
+#define CPCAP_BIT_VCAM_SEL             BIT(13)
+#define CPCAP_BIT_SW6_SEL              BIT(12)
+#define CPCAP_BIT_SW5_SEL              BIT(11)
+#define CPCAP_BIT_SW4_SEL              BIT(10)
+#define CPCAP_BIT_SW3_SEL              BIT(9)
+#define CPCAP_BIT_SW2_SEL              BIT(8)
+#define CPCAP_BIT_SW1_SEL              BIT(7)
+
+/* CPCAP_REG_ASSIGN3 bits - Resource Assignment 3 */
+#define CPCAP_BIT_VUSBINT2_SEL         BIT(15)
+#define CPCAP_BIT_VUSBINT1_SEL         BIT(14)
+#define CPCAP_BIT_VVIB_SEL             BIT(13)
+#define CPCAP_BIT_VWLAN1_SEL           BIT(12)
+#define CPCAP_BIT_VRF1_SEL             BIT(11)
+#define CPCAP_BIT_VHVIO_SEL            BIT(10)
+#define CPCAP_BIT_VDAC_SEL             BIT(9)
+#define CPCAP_BIT_VUSB_SEL             BIT(8)
+#define CPCAP_BIT_VSIM_SEL             BIT(7)
+#define CPCAP_BIT_VRFREF_SEL           BIT(6)
+#define CPCAP_BIT_VPLL_SEL             BIT(5)
+#define CPCAP_BIT_VFUSE_SEL            BIT(4)
+#define CPCAP_BIT_VCSI_SEL             BIT(3)
+#define CPCAP_BIT_SPARE_14_2           BIT(2)
+#define CPCAP_BIT_VWLAN2_SEL           BIT(1)
+#define CPCAP_BIT_VRF2_SEL             BIT(0)
+
+/* CPCAP_REG_ASSIGN4 bits - Resource Assignment 4 */
+#define CPCAP_BIT_VAUDIO_SEL           BIT(0)
+
+/*
+ * Enable register bits. At least CPCAP_BIT_AUDIO_LOW_PWR is generic,
+ * and not limited to audio regulator. Let's use the Motorola kernel
+ * naming for now until we have a better understanding of the other
+ * enable register bits. No idea why BIT(3) is not defined.
+ */
+#define CPCAP_BIT_AUDIO_LOW_PWR                BIT(6)
+#define CPCAP_BIT_AUD_LOWPWR_SPEED     BIT(5)
+#define CPCAP_BIT_VAUDIOPRISTBY                BIT(4)
+#define CPCAP_BIT_VAUDIO_MODE1         BIT(2)
+#define CPCAP_BIT_VAUDIO_MODE0         BIT(1)
+#define CPCAP_BIT_V_AUDIO_EN           BIT(0)
+
+/*
+ * Off mode configuration bit. Used currently only by SW5 on omap4. There's
+ * the following comment in Motorola Linux kernel tree for it:
+ *
+ * When set in the regulator mode, the regulator assignment will be changed
+ * to secondary when the regulator is disabled. The mode will be set back to
+ * primary when the regulator is turned on.
+ */
+#define CPCAP_REG_OFF_MODE_SEC         BIT(15)
+
+/**
+ * SoC specific configuraion for CPCAP regulator. There are at least three
+ * different SoCs each with their own parameters: omap3, omap4 and tegra2.
+ *
+ * The assign_reg and assign_mask seem to allow toggling between primary
+ * and secondary mode that at least omap4 uses for off mode.
+ */
+struct cpcap_regulator {
+       struct regulator_desc rdesc;
+       const u16 assign_reg;
+       const u16 assign_mask;
+       const u16 vsel_shift;
+};
+
+#define CPCAP_REG(_ID, reg, assignment_reg, assignment_mask, val_tbl,  \
+               mode_mask, volt_mask, volt_shft,                        \
+               mode_val, off_val, volt_trans_time) {                   \
+       .rdesc = {                                                      \
+               .name = #_ID,                                           \
+               .of_match = of_match_ptr(#_ID),                         \
+               .ops = &cpcap_regulator_ops,                            \
+               .regulators_node = of_match_ptr("regulators"),          \
+               .type = REGULATOR_VOLTAGE,                              \
+               .id = CPCAP_##_ID,                                      \
+               .owner = THIS_MODULE,                                   \
+               .n_voltages = ARRAY_SIZE(val_tbl),                      \
+               .volt_table = (val_tbl),                                \
+               .vsel_reg = (reg),                                      \
+               .vsel_mask = (volt_mask),                               \
+               .enable_reg = (reg),                                    \
+               .enable_mask = (mode_mask),                             \
+               .enable_val = (mode_val),                               \
+               .disable_val = (off_val),                               \
+               .ramp_delay = (volt_trans_time),                        \
+       },                                                              \
+       .assign_reg = (assignment_reg),                                 \
+       .assign_mask = (assignment_mask),                               \
+       .vsel_shift = (volt_shft),                                      \
+}
+
+struct cpcap_ddata {
+       struct regmap *reg;
+       struct device *dev;
+       const struct cpcap_regulator *soc;
+};
+
+enum cpcap_regulator_id {
+       CPCAP_SW1,
+       CPCAP_SW2,
+       CPCAP_SW3,
+       CPCAP_SW4,
+       CPCAP_SW5,
+       CPCAP_SW6,
+       CPCAP_VCAM,
+       CPCAP_VCSI,
+       CPCAP_VDAC,
+       CPCAP_VDIG,
+       CPCAP_VFUSE,
+       CPCAP_VHVIO,
+       CPCAP_VSDIO,
+       CPCAP_VPLL,
+       CPCAP_VRF1,
+       CPCAP_VRF2,
+       CPCAP_VRFREF,
+       CPCAP_VWLAN1,
+       CPCAP_VWLAN2,
+       CPCAP_VSIM,
+       CPCAP_VSIMCARD,
+       CPCAP_VVIB,
+       CPCAP_VUSB,
+       CPCAP_VAUDIO,
+       CPCAP_NR_REGULATORS,
+};
+
+/*
+ * We need to also configure regulator idle mode for SoC off mode if
+ * CPCAP_REG_OFF_MODE_SEC is set.
+ */
+static int cpcap_regulator_enable(struct regulator_dev *rdev)
+{
+       struct cpcap_regulator *regulator = rdev_get_drvdata(rdev);
+       int error, ignore;
+
+       error = regulator_enable_regmap(rdev);
+       if (error)
+               return error;
+
+       if (rdev->desc->enable_val & CPCAP_REG_OFF_MODE_SEC) {
+               error = regmap_update_bits(rdev->regmap, regulator->assign_reg,
+                                          regulator->assign_mask,
+                                          regulator->assign_mask);
+               if (error)
+                       ignore = regulator_disable_regmap(rdev);
+       }
+
+       return error;
+}
+
+/*
+ * We need to also configure regulator idle mode for SoC off mode if
+ * CPCAP_REG_OFF_MODE_SEC is set.
+ */
+static int cpcap_regulator_disable(struct regulator_dev *rdev)
+{
+       struct cpcap_regulator *regulator = rdev_get_drvdata(rdev);
+       int error, ignore;
+
+       if (rdev->desc->enable_val & CPCAP_REG_OFF_MODE_SEC) {
+               error = regmap_update_bits(rdev->regmap, regulator->assign_reg,
+                                          regulator->assign_mask, 0);
+               if (error)
+                       return error;
+       }
+
+       error = regulator_disable_regmap(rdev);
+       if (error && (rdev->desc->enable_val & CPCAP_REG_OFF_MODE_SEC)) {
+               ignore = regmap_update_bits(rdev->regmap, regulator->assign_reg,
+                                           regulator->assign_mask,
+                                           regulator->assign_mask);
+       }
+
+       return error;
+}
+
+static unsigned int cpcap_regulator_get_mode(struct regulator_dev *rdev)
+{
+       int value;
+
+       regmap_read(rdev->regmap, rdev->desc->enable_reg, &value);
+
+       if (!(value & CPCAP_BIT_AUDIO_LOW_PWR))
+               return REGULATOR_MODE_STANDBY;
+
+       return REGULATOR_MODE_NORMAL;
+}
+
+static int cpcap_regulator_set_mode(struct regulator_dev *rdev,
+                                   unsigned int mode)
+{
+       int value;
+
+       switch (mode) {
+       case REGULATOR_MODE_NORMAL:
+               value = CPCAP_BIT_AUDIO_LOW_PWR;
+               break;
+       case REGULATOR_MODE_STANDBY:
+               value = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+                                 CPCAP_BIT_AUDIO_LOW_PWR, value);
+}
+
+static struct regulator_ops cpcap_regulator_ops = {
+       .enable = cpcap_regulator_enable,
+       .disable = cpcap_regulator_disable,
+       .is_enabled = regulator_is_enabled_regmap,
+       .list_voltage = regulator_list_voltage_table,
+       .map_voltage = regulator_map_voltage_iterate,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_mode = cpcap_regulator_get_mode,
+       .set_mode = cpcap_regulator_set_mode,
+};
+
+static const unsigned int unknown_val_tbl[] = { 0, };
+static const unsigned int sw5_val_tbl[] = { 0, 5050000, };
+static const unsigned int vcam_val_tbl[] = { 2600000, 2700000, 2800000,
+                                            2900000, };
+static const unsigned int vcsi_val_tbl[] = { 1200000, 1800000, };
+static const unsigned int vdac_val_tbl[] = { 1200000, 1500000, 1800000,
+                                            2500000,};
+static const unsigned int vdig_val_tbl[] = { 1200000, 1350000, 1500000,
+                                            1875000, };
+static const unsigned int vfuse_val_tbl[] = { 1500000, 1600000, 1700000,
+                                             1800000, 1900000, 2000000,
+                                             2100000, 2200000, 2300000,
+                                             2400000, 2500000, 2600000,
+                                             2700000, 3150000, };
+static const unsigned int vhvio_val_tbl[] = { 2775000, };
+static const unsigned int vsdio_val_tbl[] = { 1500000, 1600000, 1800000,
+                                             2600000, 2700000, 2800000,
+                                             2900000, 3000000, };
+static const unsigned int vpll_val_tbl[] = { 1200000, 1300000, 1400000,
+                                            1800000, };
+/* Quirk: 2775000 is before 2500000 for vrf1 regulator */
+static const unsigned int vrf1_val_tbl[] = { 2775000, 2500000, };
+static const unsigned int vrf2_val_tbl[] = { 0, 2775000, };
+static const unsigned int vrfref_val_tbl[] = { 2500000, 2775000, };
+static const unsigned int vwlan1_val_tbl[] = { 1800000, 1900000, };
+static const unsigned int vwlan2_val_tbl[] = { 2775000, 3000000, 3300000,
+                                              3300000, };
+static const unsigned int vsim_val_tbl[] = { 1800000, 2900000, };
+static const unsigned int vsimcard_val_tbl[] = { 1800000, 2900000, };
+static const unsigned int vvib_val_tbl[] = { 1300000, 1800000, 2000000,
+                                            3000000, };
+static const unsigned int vusb_val_tbl[] = { 0, 3300000, };
+static const unsigned int vaudio_val_tbl[] = { 0, 2775000, };
+
+/**
+ * SoC specific configuration for omap4. The data below is comes from Motorola
+ * Linux kernel tree. It's basically the values of cpcap_regltr_data,
+ * cpcap_regulator_mode_values and cpcap_regulator_off_mode_values, see
+ * CPCAP_REG macro above.
+ *
+ * SW1 to SW4 and SW6 seems to be unused for mapphone. Note that VSIM and
+ * VSIMCARD have a shared resource assignment bit.
+ */
+static struct cpcap_regulator omap4_regulators[] = {
+       CPCAP_REG(SW1, CPCAP_REG_S1C1, CPCAP_REG_ASSIGN2,
+                 CPCAP_BIT_SW1_SEL, unknown_val_tbl,
+                 0, 0, 0, 0, 0, 0),
+       CPCAP_REG(SW2, CPCAP_REG_S2C1, CPCAP_REG_ASSIGN2,
+                 CPCAP_BIT_SW2_SEL, unknown_val_tbl,
+                 0, 0, 0, 0, 0, 0),
+       CPCAP_REG(SW3, CPCAP_REG_S3C, CPCAP_REG_ASSIGN2,
+                 CPCAP_BIT_SW3_SEL, unknown_val_tbl,
+                 0, 0, 0, 0, 0, 0),
+       CPCAP_REG(SW4, CPCAP_REG_S4C1, CPCAP_REG_ASSIGN2,
+                 CPCAP_BIT_SW4_SEL, unknown_val_tbl,
+                 0, 0, 0, 0, 0, 0),
+       CPCAP_REG(SW5, CPCAP_REG_S5C, CPCAP_REG_ASSIGN2,
+                 CPCAP_BIT_SW5_SEL, sw5_val_tbl,
+                 0x28, 0, 0, 0x20 | CPCAP_REG_OFF_MODE_SEC, 0, 0),
+       CPCAP_REG(SW6, CPCAP_REG_S6C, CPCAP_REG_ASSIGN2,
+                 CPCAP_BIT_SW6_SEL, unknown_val_tbl,
+                 0, 0, 0, 0, 0, 0),
+       CPCAP_REG(VCAM, CPCAP_REG_VCAMC, CPCAP_REG_ASSIGN2,
+                 CPCAP_BIT_VCAM_SEL, vcam_val_tbl,
+                 0x87, 0x30, 4, 0x3, 0, 420),
+       CPCAP_REG(VCSI, CPCAP_REG_VCSIC, CPCAP_REG_ASSIGN3,
+                 CPCAP_BIT_VCSI_SEL, vcsi_val_tbl,
+                 0x47, 0x10, 4, 0x43, 0x41, 350),
+       CPCAP_REG(VDAC, CPCAP_REG_VDACC, CPCAP_REG_ASSIGN3,
+                 CPCAP_BIT_VDAC_SEL, vdac_val_tbl,
+                 0x87, 0x30, 4, 0x3, 0, 420),
+       CPCAP_REG(VDIG, CPCAP_REG_VDIGC, CPCAP_REG_ASSIGN2,
+                 CPCAP_BIT_VDIG_SEL, vdig_val_tbl,
+                 0x87, 0x30, 4, 0x82, 0, 420),
+       CPCAP_REG(VFUSE, CPCAP_REG_VFUSEC, CPCAP_REG_ASSIGN3,
+                 CPCAP_BIT_VFUSE_SEL, vfuse_val_tbl,
+                 0x80, 0xf, 0, 0x80, 0, 420),
+       CPCAP_REG(VHVIO, CPCAP_REG_VHVIOC, CPCAP_REG_ASSIGN3,
+                 CPCAP_BIT_VHVIO_SEL, vhvio_val_tbl,
+                 0x17, 0, 0, 0, 0x12, 0),
+       CPCAP_REG(VSDIO, CPCAP_REG_VSDIOC, CPCAP_REG_ASSIGN2,
+                 CPCAP_BIT_VSDIO_SEL, vsdio_val_tbl,
+                 0x87, 0x38, 3, 0x82, 0, 420),
+       CPCAP_REG(VPLL, CPCAP_REG_VPLLC, CPCAP_REG_ASSIGN3,
+                 CPCAP_BIT_VPLL_SEL, vpll_val_tbl,
+                 0x43, 0x18, 3, 0x2, 0, 420),
+       CPCAP_REG(VRF1, CPCAP_REG_VRF1C, CPCAP_REG_ASSIGN3,
+                 CPCAP_BIT_VRF1_SEL, vrf1_val_tbl,
+                 0xac, 0x2, 1, 0x4, 0, 10),
+       CPCAP_REG(VRF2, CPCAP_REG_VRF2C, CPCAP_REG_ASSIGN3,
+                 CPCAP_BIT_VRF2_SEL, vrf2_val_tbl,
+                 0x23, 0x8, 3, 0, 0, 10),
+       CPCAP_REG(VRFREF, CPCAP_REG_VRFREFC, CPCAP_REG_ASSIGN3,
+                 CPCAP_BIT_VRFREF_SEL, vrfref_val_tbl,
+                 0x23, 0x8, 3, 0, 0, 420),
+       CPCAP_REG(VWLAN1, CPCAP_REG_VWLAN1C, CPCAP_REG_ASSIGN3,
+                 CPCAP_BIT_VWLAN1_SEL, vwlan1_val_tbl,
+                 0x47, 0x10, 4, 0, 0, 420),
+       CPCAP_REG(VWLAN2, CPCAP_REG_VWLAN2C, CPCAP_REG_ASSIGN3,
+                 CPCAP_BIT_VWLAN2_SEL, vwlan2_val_tbl,
+                 0x20c, 0xc0, 6, 0x20c, 0, 420),
+       CPCAP_REG(VSIM, CPCAP_REG_VSIMC, CPCAP_REG_ASSIGN3,
+                 0xffff, vsim_val_tbl,
+                 0x23, 0x8, 3, 0x3, 0, 420),
+       CPCAP_REG(VSIMCARD, CPCAP_REG_VSIMC, CPCAP_REG_ASSIGN3,
+                 0xffff, vsimcard_val_tbl,
+                 0x1e80, 0x8, 3, 0x1e00, 0, 420),
+       CPCAP_REG(VVIB, CPCAP_REG_VVIBC, CPCAP_REG_ASSIGN3,
+                 CPCAP_BIT_VVIB_SEL, vvib_val_tbl,
+                 0x1, 0xc, 2, 0x1, 0, 500),
+       CPCAP_REG(VUSB, CPCAP_REG_VUSBC, CPCAP_REG_ASSIGN3,
+                 CPCAP_BIT_VUSB_SEL, vusb_val_tbl,
+                 0x11c, 0x40, 6, 0xc, 0, 0),
+       CPCAP_REG(VAUDIO, CPCAP_REG_VAUDIOC, CPCAP_REG_ASSIGN4,
+                 CPCAP_BIT_VAUDIO_SEL, vaudio_val_tbl,
+                 0x16, 0x1, 0, 0x4, 0, 0),
+       { /* sentinel */ },
+};
+
+static const struct of_device_id cpcap_regulator_id_table[] = {
+       {
+               .compatible = "motorola,cpcap-regulator",
+       },
+       {
+               .compatible = "motorola,mapphone-cpcap-regulator",
+               .data = omap4_regulators,
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, cpcap_regulator_id_table);
+
+static int cpcap_regulator_probe(struct platform_device *pdev)
+{
+       struct cpcap_ddata *ddata;
+       const struct of_device_id *match;
+       struct regulator_config config;
+       struct regulator_init_data init_data;
+       int i;
+
+       match = of_match_device(of_match_ptr(cpcap_regulator_id_table),
+                               &pdev->dev);
+       if (!match)
+               return -EINVAL;
+
+       if (!match->data) {
+               dev_err(&pdev->dev, "no configuration data found\n");
+
+               return -ENODEV;
+       }
+
+       ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
+       if (!ddata)
+               return -ENOMEM;
+
+       ddata->reg = dev_get_regmap(pdev->dev.parent, NULL);
+       if (!ddata->reg)
+               return -ENODEV;
+
+       ddata->dev = &pdev->dev;
+       ddata->soc = match->data;
+       platform_set_drvdata(pdev, ddata);
+
+       memset(&config, 0, sizeof(config));
+       memset(&init_data, 0, sizeof(init_data));
+       config.dev = &pdev->dev;
+       config.regmap = ddata->reg;
+       config.init_data = &init_data;
+
+       for (i = 0; i < CPCAP_NR_REGULATORS; i++) {
+               const struct cpcap_regulator *regulator = &ddata->soc[i];
+               struct regulator_dev *rdev;
+
+               if (!regulator->rdesc.name)
+                       break;
+
+               if (regulator->rdesc.volt_table == unknown_val_tbl)
+                       continue;
+
+               config.driver_data = (void *)regulator;
+               rdev = devm_regulator_register(&pdev->dev,
+                                              &regulator->rdesc,
+                                              &config);
+               if (IS_ERR(rdev)) {
+                       dev_err(&pdev->dev, "failed to register regulator %s\n",
+                               regulator->rdesc.name);
+
+                       return PTR_ERR(rdev);
+               }
+       }
+
+       return 0;
+}
+
+static struct platform_driver cpcap_regulator_driver = {
+       .probe          = cpcap_regulator_probe,
+       .driver         = {
+               .name   = "cpcap-regulator",
+               .of_match_table = of_match_ptr(cpcap_regulator_id_table),
+       },
+};
+
+module_platform_driver(cpcap_regulator_driver);
+
+MODULE_ALIAS("platform:cpcap-regulator");
+MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>");
+MODULE_DESCRIPTION("CPCAP regulator driver");
+MODULE_LICENSE("GPL v2");
index 6ec1d400adae7e444102266385171c5d787110a3..784e3bf32210bb74a34934078dc6218a82e2aa6e 100644 (file)
 
 #include "internal.h"
 
-enum {
-       NORMAL_GET,
-       EXCLUSIVE_GET,
-       OPTIONAL_GET,
-};
-
 static void devm_regulator_release(struct device *dev, void *res)
 {
        regulator_put(*(struct regulator **)res);
@@ -39,20 +33,7 @@ static struct regulator *_devm_regulator_get(struct device *dev, const char *id,
        if (!ptr)
                return ERR_PTR(-ENOMEM);
 
-       switch (get_type) {
-       case NORMAL_GET:
-               regulator = regulator_get(dev, id);
-               break;
-       case EXCLUSIVE_GET:
-               regulator = regulator_get_exclusive(dev, id);
-               break;
-       case OPTIONAL_GET:
-               regulator = regulator_get_optional(dev, id);
-               break;
-       default:
-               regulator = ERR_PTR(-EINVAL);
-       }
-
+       regulator = _regulator_get(dev, id, get_type);
        if (!IS_ERR(regulator)) {
                *ptr = regulator;
                devres_add(dev, ptr);
@@ -139,6 +120,18 @@ void devm_regulator_put(struct regulator *regulator)
 }
 EXPORT_SYMBOL_GPL(devm_regulator_put);
 
+struct regulator_bulk_devres {
+       struct regulator_bulk_data *consumers;
+       int num_consumers;
+};
+
+static void devm_regulator_bulk_release(struct device *dev, void *res)
+{
+       struct regulator_bulk_devres *devres = res;
+
+       regulator_bulk_free(devres->num_consumers, devres->consumers);
+}
+
 /**
  * devm_regulator_bulk_get - managed get multiple regulator consumers
  *
@@ -157,29 +150,22 @@ EXPORT_SYMBOL_GPL(devm_regulator_put);
 int devm_regulator_bulk_get(struct device *dev, int num_consumers,
                            struct regulator_bulk_data *consumers)
 {
-       int i;
+       struct regulator_bulk_devres *devres;
        int ret;
 
-       for (i = 0; i < num_consumers; i++)
-               consumers[i].consumer = NULL;
-
-       for (i = 0; i < num_consumers; i++) {
-               consumers[i].consumer = devm_regulator_get(dev,
-                                                          consumers[i].supply);
-               if (IS_ERR(consumers[i].consumer)) {
-                       ret = PTR_ERR(consumers[i].consumer);
-                       dev_err(dev, "Failed to get supply '%s': %d\n",
-                               consumers[i].supply, ret);
-                       consumers[i].consumer = NULL;
-                       goto err;
-               }
-       }
-
-       return 0;
+       devres = devres_alloc(devm_regulator_bulk_release,
+                             sizeof(*devres), GFP_KERNEL);
+       if (!devres)
+               return -ENOMEM;
 
-err:
-       for (i = 0; i < num_consumers && consumers[i].consumer; i++)
-               devm_regulator_put(consumers[i].consumer);
+       ret = regulator_bulk_get(dev, num_consumers, consumers);
+       if (!ret) {
+               devres->consumers = consumers;
+               devres->num_consumers = num_consumers;
+               devres_add(dev, devres);
+       } else {
+               devres_free(devres);
+       }
 
        return ret;
 }
index d7da81a875cf612bf367d08f174f66f18aed4341..60f4318315826765d6f52bc4ff4e863dc3873ebc 100644 (file)
@@ -202,7 +202,7 @@ static int fan53555_set_ramp(struct regulator_dev *rdev, int ramp)
                                  CTL_SLEW_MASK, regval << CTL_SLEW_SHIFT);
 }
 
-static struct regulator_ops fan53555_regulator_ops = {
+static const struct regulator_ops fan53555_regulator_ops = {
        .set_voltage_sel = regulator_set_voltage_sel_regmap,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
        .set_voltage_time_sel = regulator_set_voltage_time_sel,
index aca18466f5220a68fc989e201e01ce42639a35db..065c100e9a03592f53a4b981fe71899a1b236cba 100644 (file)
@@ -96,7 +96,7 @@ static int hi655x_disable(struct regulator_dev *rdev)
        return ret;
 }
 
-static struct regulator_ops hi655x_regulator_ops = {
+static const struct regulator_ops hi655x_regulator_ops = {
        .enable = regulator_enable_regmap,
        .disable = hi655x_disable,
        .is_enabled = hi655x_is_enabled,
@@ -105,7 +105,7 @@ static struct regulator_ops hi655x_regulator_ops = {
        .set_voltage_sel = regulator_set_voltage_sel_regmap,
 };
 
-static struct regulator_ops hi655x_ldo_linear_ops = {
+static const struct regulator_ops hi655x_ldo_linear_ops = {
        .enable = regulator_enable_regmap,
        .disable = hi655x_disable,
        .is_enabled = hi655x_is_enabled,
index c74ac873402370b5057464b22a694672cccf4d73..1dd575b285649b04b81a0d109b09f77bd7fd01a6 100644 (file)
@@ -51,4 +51,14 @@ regulator_of_get_init_data(struct device *dev,
 }
 #endif
 
+enum regulator_get_type {
+       NORMAL_GET,
+       EXCLUSIVE_GET,
+       OPTIONAL_GET,
+       MAX_GET_TYPE
+};
+
+struct regulator *_regulator_get(struct device *dev, const char *id,
+                                enum regulator_get_type get_type);
+
 #endif
index d6773da925bad00f3bc227294255f8786c2eaf9b..db34e1da75ef8a347b88aba9278911d0e054d288 100644 (file)
@@ -227,7 +227,7 @@ err_i2c:
        return ret;
 }
 
-static struct regulator_ops lp8755_buck_ops = {
+static const struct regulator_ops lp8755_buck_ops = {
        .map_voltage = regulator_map_voltage_linear,
        .list_voltage = regulator_list_voltage_linear,
        .set_voltage_sel = regulator_set_voltage_sel_regmap,
index 47bef328fb58b356c061f2a7d408da9e8a971be7..a7a1a0313bbfc68625080012e681f50916fe947f 100644 (file)
@@ -161,7 +161,7 @@ static int ltc3589_set_suspend_mode(struct regulator_dev *rdev,
 }
 
 /* SW1, SW2, SW3, LDO2 */
-static struct regulator_ops ltc3589_linear_regulator_ops = {
+static const struct regulator_ops ltc3589_linear_regulator_ops = {
        .enable = regulator_enable_regmap,
        .disable = regulator_disable_regmap,
        .is_enabled = regulator_is_enabled_regmap,
@@ -175,18 +175,18 @@ static struct regulator_ops ltc3589_linear_regulator_ops = {
 };
 
 /* BB_OUT, LDO3 */
-static struct regulator_ops ltc3589_fixed_regulator_ops = {
+static const struct regulator_ops ltc3589_fixed_regulator_ops = {
        .enable = regulator_enable_regmap,
        .disable = regulator_disable_regmap,
        .is_enabled = regulator_is_enabled_regmap,
 };
 
 /* LDO1 */
-static struct regulator_ops ltc3589_fixed_standby_regulator_ops = {
+static const struct regulator_ops ltc3589_fixed_standby_regulator_ops = {
 };
 
 /* LDO4 */
-static struct regulator_ops ltc3589_table_regulator_ops = {
+static const struct regulator_ops ltc3589_table_regulator_ops = {
        .enable = regulator_enable_regmap,
        .disable = regulator_disable_regmap,
        .is_enabled = regulator_is_enabled_regmap,
index e2b476ca2b4d67ca828a7e3099ae1142266564b7..503cd90eba393439114a05c0c8d5e788216d7653 100644 (file)
@@ -161,7 +161,7 @@ static int ltc3676_of_parse_cb(struct device_node *np,
 }
 
 /* SW1, SW2, SW3, SW4 linear 0.8V-3.3V with scalar via R1/R2 feeback res */
-static struct regulator_ops ltc3676_linear_regulator_ops = {
+static const struct regulator_ops ltc3676_linear_regulator_ops = {
        .enable = regulator_enable_regmap,
        .disable = regulator_disable_regmap,
        .is_enabled = regulator_is_enabled_regmap,
@@ -173,11 +173,11 @@ static struct regulator_ops ltc3676_linear_regulator_ops = {
 };
 
 /* LDO1 always on fixed 0.8V-3.3V via scalar via R1/R2 feeback res */
-static struct regulator_ops ltc3676_fixed_standby_regulator_ops = {
+static const struct regulator_ops ltc3676_fixed_standby_regulator_ops = {
 };
 
 /* LDO2, LDO3 fixed (LDO2 has external scalar via R1/R2 feedback res) */
-static struct regulator_ops ltc3676_fixed_regulator_ops = {
+static const struct regulator_ops ltc3676_fixed_regulator_ops = {
        .enable = regulator_enable_regmap,
        .disable = regulator_disable_regmap,
        .is_enabled = regulator_is_enabled_regmap,
index c9ff2619971166f0f7b853242fca65e0323c1381..0db288ce319ce4a27562fd5e8afe5cb113c3799a 100644 (file)
@@ -85,14 +85,14 @@ static int max14577_reg_set_current_limit(struct regulator_dev *rdev,
                        reg_data);
 }
 
-static struct regulator_ops max14577_safeout_ops = {
+static const struct regulator_ops max14577_safeout_ops = {
        .is_enabled             = regulator_is_enabled_regmap,
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
        .list_voltage           = regulator_list_voltage_linear,
 };
 
-static struct regulator_ops max14577_charger_ops = {
+static const struct regulator_ops max14577_charger_ops = {
        .is_enabled             = max14577_reg_is_enabled,
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
@@ -130,7 +130,7 @@ static const struct regulator_desc max14577_supported_regulators[] = {
        [MAX14577_CHARGER] = MAX14577_CHARGER_REG,
 };
 
-static struct regulator_ops max77836_ldo_ops = {
+static const struct regulator_ops max77836_ldo_ops = {
        .is_enabled             = regulator_is_enabled_regmap,
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
index d088a7c79e60be4e6799337fd1834c28dea166a3..b94e3a721721b26449be79a49f287411a60d33b0 100644 (file)
@@ -644,7 +644,7 @@ static int max77620_of_parse_cb(struct device_node *np,
        return max77620_init_pmic(pmic, desc->id);
 }
 
-static struct regulator_ops max77620_regulator_ops = {
+static const struct regulator_ops max77620_regulator_ops = {
        .is_enabled = max77620_regulator_is_enabled,
        .enable = max77620_regulator_enable,
        .disable = max77620_regulator_disable,
index ac4fa581e0a5eaa60f1afd4179778883d3919561..c301f37334758599fc98ba615a9159a62c9ba708 100644 (file)
@@ -289,7 +289,7 @@ static int max77686_of_parse_cb(struct device_node *np,
        return 0;
 }
 
-static struct regulator_ops max77686_ops = {
+static const struct regulator_ops max77686_ops = {
        .list_voltage           = regulator_list_voltage_linear,
        .map_voltage            = regulator_map_voltage_linear,
        .is_enabled             = regulator_is_enabled_regmap,
@@ -301,7 +301,7 @@ static struct regulator_ops max77686_ops = {
        .set_suspend_mode       = max77686_set_suspend_mode,
 };
 
-static struct regulator_ops max77686_ldo_ops = {
+static const struct regulator_ops max77686_ldo_ops = {
        .list_voltage           = regulator_list_voltage_linear,
        .map_voltage            = regulator_map_voltage_linear,
        .is_enabled             = regulator_is_enabled_regmap,
@@ -314,7 +314,7 @@ static struct regulator_ops max77686_ldo_ops = {
        .set_suspend_disable    = max77686_set_suspend_disable,
 };
 
-static struct regulator_ops max77686_buck1_ops = {
+static const struct regulator_ops max77686_buck1_ops = {
        .list_voltage           = regulator_list_voltage_linear,
        .map_voltage            = regulator_map_voltage_linear,
        .is_enabled             = regulator_is_enabled_regmap,
@@ -326,7 +326,7 @@ static struct regulator_ops max77686_buck1_ops = {
        .set_suspend_disable    = max77686_set_suspend_disable,
 };
 
-static struct regulator_ops max77686_buck_dvs_ops = {
+static const struct regulator_ops max77686_buck_dvs_ops = {
        .list_voltage           = regulator_list_voltage_linear,
        .map_voltage            = regulator_map_voltage_linear,
        .is_enabled             = regulator_is_enabled_regmap,
index cfbb9512e48623429899cbe0785332b0a1171734..3fce67982682c576748a8f5b5b740dc6cac447d2 100644 (file)
@@ -141,7 +141,7 @@ static const unsigned int max77693_safeout_table[] = {
        3300000,
 };
 
-static struct regulator_ops max77693_safeout_ops = {
+static const struct regulator_ops max77693_safeout_ops = {
        .list_voltage           = regulator_list_voltage_table,
        .is_enabled             = regulator_is_enabled_regmap,
        .enable                 = regulator_enable_regmap,
index 1d3539324d9ae3e0ca7b8d6bff7ba1c0d8d87148..b6261903818c6266a431f3cb2bb8d83b7a5296f1 100644 (file)
@@ -288,7 +288,7 @@ static int max77802_set_ramp_delay_4bit(struct regulator_dev *rdev,
 /*
  * LDOs 2, 4-19, 22-35
  */
-static struct regulator_ops max77802_ldo_ops_logic1 = {
+static const struct regulator_ops max77802_ldo_ops_logic1 = {
        .list_voltage           = regulator_list_voltage_linear,
        .map_voltage            = regulator_map_voltage_linear,
        .is_enabled             = regulator_is_enabled_regmap,
@@ -304,7 +304,7 @@ static struct regulator_ops max77802_ldo_ops_logic1 = {
 /*
  * LDOs 1, 20, 21, 3
  */
-static struct regulator_ops max77802_ldo_ops_logic2 = {
+static const struct regulator_ops max77802_ldo_ops_logic2 = {
        .list_voltage           = regulator_list_voltage_linear,
        .map_voltage            = regulator_map_voltage_linear,
        .is_enabled             = regulator_is_enabled_regmap,
@@ -319,7 +319,7 @@ static struct regulator_ops max77802_ldo_ops_logic2 = {
 };
 
 /* BUCKS 1, 6 */
-static struct regulator_ops max77802_buck_16_dvs_ops = {
+static const struct regulator_ops max77802_buck_16_dvs_ops = {
        .list_voltage           = regulator_list_voltage_linear,
        .map_voltage            = regulator_map_voltage_linear,
        .is_enabled             = regulator_is_enabled_regmap,
@@ -333,7 +333,7 @@ static struct regulator_ops max77802_buck_16_dvs_ops = {
 };
 
 /* BUCKs 2-4 */
-static struct regulator_ops max77802_buck_234_ops = {
+static const struct regulator_ops max77802_buck_234_ops = {
        .list_voltage           = regulator_list_voltage_linear,
        .map_voltage            = regulator_map_voltage_linear,
        .is_enabled             = regulator_is_enabled_regmap,
@@ -348,7 +348,7 @@ static struct regulator_ops max77802_buck_234_ops = {
 };
 
 /* BUCKs 5, 7-10 */
-static struct regulator_ops max77802_buck_dvs_ops = {
+static const struct regulator_ops max77802_buck_dvs_ops = {
        .list_voltage           = regulator_list_voltage_linear,
        .map_voltage            = regulator_map_voltage_linear,
        .is_enabled             = regulator_is_enabled_regmap,
index 5e941db5ccafb2c2bff40ed04bce76c8012787e9..860400d2cd8591522ca3d4ff4366459cbdc2397e 100644 (file)
@@ -109,7 +109,7 @@ struct max8907_regulator {
 #define LDO_650_25(id, supply, base) REG_LDO(id, supply, (base), \
                        650000, 2225000, 25000)
 
-static struct regulator_ops max8907_mbatt_ops = {
+static const struct regulator_ops max8907_mbatt_ops = {
 };
 
 static struct regulator_ops max8907_ldo_ops = {
@@ -121,13 +121,13 @@ static struct regulator_ops max8907_ldo_ops = {
        .is_enabled = regulator_is_enabled_regmap,
 };
 
-static struct regulator_ops max8907_ldo_hwctl_ops = {
+static const struct regulator_ops max8907_ldo_hwctl_ops = {
        .list_voltage = regulator_list_voltage_linear,
        .set_voltage_sel = regulator_set_voltage_sel_regmap,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
 };
 
-static struct regulator_ops max8907_fixed_ops = {
+static const struct regulator_ops max8907_fixed_ops = {
        .list_voltage = regulator_list_voltage_linear,
 };
 
@@ -138,11 +138,11 @@ static struct regulator_ops max8907_out5v_ops = {
        .is_enabled = regulator_is_enabled_regmap,
 };
 
-static struct regulator_ops max8907_out5v_hwctl_ops = {
+static const struct regulator_ops max8907_out5v_hwctl_ops = {
        .list_voltage = regulator_list_voltage_linear,
 };
 
-static struct regulator_ops max8907_bbat_ops = {
+static const struct regulator_ops max8907_bbat_ops = {
        .list_voltage = regulator_list_voltage_linear,
        .set_voltage_sel = regulator_set_voltage_sel_regmap,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
index c802f0239dc790bfb5051c28640773d5085b95cd..39b63ddefeb2df7a397e8075164b88d5ecd1171f 100644 (file)
@@ -132,7 +132,7 @@ static int max8925_set_dvm_disable(struct regulator_dev *rdev)
        return max8925_set_bits(info->i2c, info->vol_reg, 1 << SD1_DVM_EN, 0);
 }
 
-static struct regulator_ops max8925_regulator_sdv_ops = {
+static const struct regulator_ops max8925_regulator_sdv_ops = {
        .map_voltage            = regulator_map_voltage_linear,
        .list_voltage           = regulator_list_voltage_linear,
        .set_voltage_sel        = max8925_set_voltage_sel,
@@ -145,7 +145,7 @@ static struct regulator_ops max8925_regulator_sdv_ops = {
        .set_suspend_disable    = max8925_set_dvm_disable,
 };
 
-static struct regulator_ops max8925_regulator_ldo_ops = {
+static const struct regulator_ops max8925_regulator_ldo_ops = {
        .map_voltage            = regulator_map_voltage_linear,
        .list_voltage           = regulator_list_voltage_linear,
        .set_voltage_sel        = max8925_set_voltage_sel,
index 1af8f4a2ab86dedab889510baeba7cc93921ea06..1096546c05e95d5842853c77859380797ac9308a 100644 (file)
@@ -113,7 +113,7 @@ static int max8952_set_voltage_sel(struct regulator_dev *rdev,
        return 0;
 }
 
-static struct regulator_ops max8952_ops = {
+static const struct regulator_ops max8952_ops = {
        .list_voltage           = max8952_list_voltage,
        .get_voltage_sel        = max8952_get_voltage_sel,
        .set_voltage_sel        = max8952_set_voltage_sel,
index f11d41dad9c13b9d581fe6fa122f1898bc140e55..31ae5ee3a80d87b2c296c54efb75e726b3a83b84 100644 (file)
@@ -528,7 +528,7 @@ static int palmas_smps_set_ramp_delay(struct regulator_dev *rdev,
        return ret;
 }
 
-static struct regulator_ops palmas_ops_smps = {
+static const struct regulator_ops palmas_ops_smps = {
        .is_enabled             = regulator_is_enabled_regmap,
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
@@ -542,7 +542,7 @@ static struct regulator_ops palmas_ops_smps = {
        .set_ramp_delay         = palmas_smps_set_ramp_delay,
 };
 
-static struct regulator_ops palmas_ops_ext_control_smps = {
+static const struct regulator_ops palmas_ops_ext_control_smps = {
        .set_mode               = palmas_set_mode_smps,
        .get_mode               = palmas_get_mode_smps,
        .get_voltage_sel        = regulator_get_voltage_sel_regmap,
@@ -553,7 +553,7 @@ static struct regulator_ops palmas_ops_ext_control_smps = {
        .set_ramp_delay         = palmas_smps_set_ramp_delay,
 };
 
-static struct regulator_ops palmas_ops_smps10 = {
+static const struct regulator_ops palmas_ops_smps10 = {
        .is_enabled             = regulator_is_enabled_regmap,
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
@@ -565,7 +565,7 @@ static struct regulator_ops palmas_ops_smps10 = {
        .get_bypass             = regulator_get_bypass_regmap,
 };
 
-static struct regulator_ops tps65917_ops_smps = {
+static const struct regulator_ops tps65917_ops_smps = {
        .is_enabled             = regulator_is_enabled_regmap,
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
@@ -578,7 +578,7 @@ static struct regulator_ops tps65917_ops_smps = {
        .set_voltage_time_sel   = regulator_set_voltage_time_sel,
 };
 
-static struct regulator_ops tps65917_ops_ext_control_smps = {
+static const struct regulator_ops tps65917_ops_ext_control_smps = {
        .set_mode               = palmas_set_mode_smps,
        .get_mode               = palmas_get_mode_smps,
        .get_voltage_sel        = regulator_get_voltage_sel_regmap,
@@ -602,7 +602,7 @@ static int palmas_is_enabled_ldo(struct regulator_dev *dev)
        return !!(reg);
 }
 
-static struct regulator_ops palmas_ops_ldo = {
+static const struct regulator_ops palmas_ops_ldo = {
        .is_enabled             = palmas_is_enabled_ldo,
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
@@ -612,7 +612,7 @@ static struct regulator_ops palmas_ops_ldo = {
        .map_voltage            = regulator_map_voltage_linear,
 };
 
-static struct regulator_ops palmas_ops_ldo9 = {
+static const struct regulator_ops palmas_ops_ldo9 = {
        .is_enabled             = palmas_is_enabled_ldo,
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
@@ -624,23 +624,23 @@ static struct regulator_ops palmas_ops_ldo9 = {
        .get_bypass             = regulator_get_bypass_regmap,
 };
 
-static struct regulator_ops palmas_ops_ext_control_ldo = {
+static const struct regulator_ops palmas_ops_ext_control_ldo = {
        .get_voltage_sel        = regulator_get_voltage_sel_regmap,
        .set_voltage_sel        = regulator_set_voltage_sel_regmap,
        .list_voltage           = regulator_list_voltage_linear,
        .map_voltage            = regulator_map_voltage_linear,
 };
 
-static struct regulator_ops palmas_ops_extreg = {
+static const struct regulator_ops palmas_ops_extreg = {
        .is_enabled             = regulator_is_enabled_regmap,
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
 };
 
-static struct regulator_ops palmas_ops_ext_control_extreg = {
+static const struct regulator_ops palmas_ops_ext_control_extreg = {
 };
 
-static struct regulator_ops tps65917_ops_ldo = {
+static const struct regulator_ops tps65917_ops_ldo = {
        .is_enabled             = palmas_is_enabled_ldo,
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
@@ -651,7 +651,7 @@ static struct regulator_ops tps65917_ops_ldo = {
        .set_voltage_time_sel   = regulator_set_voltage_time_sel,
 };
 
-static struct regulator_ops tps65917_ops_ldo_1_2 = {
+static const struct regulator_ops tps65917_ops_ldo_1_2 = {
        .is_enabled             = palmas_is_enabled_ldo,
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
index f9d74d63be7c7e6bb88d7cfeb8d4d4046d919002..0cb76ba29e84303b9eaf1e32a2c7b81445a32935 100644 (file)
@@ -54,7 +54,7 @@ static const unsigned int pbias_volt_table[] = {
        3000000
 };
 
-static struct regulator_ops pbias_regulator_voltage_ops = {
+static const struct regulator_ops pbias_regulator_voltage_ops = {
        .list_voltage = regulator_list_voltage_table,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
        .set_voltage_sel = regulator_set_voltage_sel_regmap,
index 9b16e6158f15045e1b725c9e1781f0f98f22bd59..79cb971a69bb1bd616d6c2ddd81f6a1c8dd3dfcc 100644 (file)
@@ -210,7 +210,7 @@ static int pcap_regulator_is_enabled(struct regulator_dev *rdev)
        return (tmp >> vreg->en) & 1;
 }
 
-static struct regulator_ops pcap_regulator_ops = {
+static const struct regulator_ops pcap_regulator_ops = {
        .list_voltage   = regulator_list_voltage_table,
        .set_voltage_sel = pcap_regulator_set_voltage_sel,
        .get_voltage_sel = pcap_regulator_get_voltage_sel,
index 134f90ec9ca1fc80c1728d0ae4d6778edc93e2f6..762e18447cae06601c8658b974e23c62851996e7 100644 (file)
@@ -41,7 +41,7 @@
                .enable_mask = PCF50633_REGULATOR_ON,           \
        }
 
-static struct regulator_ops pcf50633_regulator_ops = {
+static const struct regulator_ops pcf50633_regulator_ops = {
        .set_voltage_sel = regulator_set_voltage_sel_regmap,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
        .list_voltage = regulator_list_voltage_linear,
index cb18b5c4f2db967e05713d7a29dd0433ea4f778a..e193bbbb8ffc1beebabd453a06dc8670d159fe0d 100644 (file)
@@ -126,7 +126,7 @@ static int pfuze100_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
        return ret;
 }
 
-static struct regulator_ops pfuze100_ldo_regulator_ops = {
+static const struct regulator_ops pfuze100_ldo_regulator_ops = {
        .enable = regulator_enable_regmap,
        .disable = regulator_disable_regmap,
        .is_enabled = regulator_is_enabled_regmap,
@@ -135,14 +135,14 @@ static struct regulator_ops pfuze100_ldo_regulator_ops = {
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
 };
 
-static struct regulator_ops pfuze100_fixed_regulator_ops = {
+static const struct regulator_ops pfuze100_fixed_regulator_ops = {
        .enable = regulator_enable_regmap,
        .disable = regulator_disable_regmap,
        .is_enabled = regulator_is_enabled_regmap,
        .list_voltage = regulator_list_voltage_linear,
 };
 
-static struct regulator_ops pfuze100_sw_regulator_ops = {
+static const struct regulator_ops pfuze100_sw_regulator_ops = {
        .list_voltage = regulator_list_voltage_linear,
        .set_voltage_sel = regulator_set_voltage_sel_regmap,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
@@ -150,7 +150,7 @@ static struct regulator_ops pfuze100_sw_regulator_ops = {
        .set_ramp_delay = pfuze100_set_ramp_delay,
 };
 
-static struct regulator_ops pfuze100_swb_regulator_ops = {
+static const struct regulator_ops pfuze100_swb_regulator_ops = {
        .enable = regulator_enable_regmap,
        .disable = regulator_disable_regmap,
        .list_voltage = regulator_list_voltage_table,
index 6c4afc73ecac3d7cb47d1a87da60b95f14ba9370..a9446056435f9b71772d4cecb33017c42abeebcf 100644 (file)
@@ -162,7 +162,7 @@ static int pv88060_get_current_limit(struct regulator_dev *rdev)
        return info->current_limits[data];
 }
 
-static struct regulator_ops pv88060_buck_ops = {
+static const struct regulator_ops pv88060_buck_ops = {
        .get_mode = pv88060_buck_get_mode,
        .set_mode = pv88060_buck_set_mode,
        .enable = regulator_enable_regmap,
@@ -175,7 +175,7 @@ static struct regulator_ops pv88060_buck_ops = {
        .get_current_limit = pv88060_get_current_limit,
 };
 
-static struct regulator_ops pv88060_ldo_ops = {
+static const struct regulator_ops pv88060_ldo_ops = {
        .enable = regulator_enable_regmap,
        .disable = regulator_disable_regmap,
        .is_enabled = regulator_is_enabled_regmap,
index 954a20eeb26f89362be0a4274d364b22a8db3783..9a08cb2de501e95175fe4f56168ec0bfe123b08a 100644 (file)
@@ -306,7 +306,7 @@ static int pv88080_get_current_limit(struct regulator_dev *rdev)
        return info->current_limits[data];
 }
 
-static struct regulator_ops pv88080_buck_ops = {
+static const struct regulator_ops pv88080_buck_ops = {
        .get_mode = pv88080_buck_get_mode,
        .set_mode = pv88080_buck_set_mode,
        .enable = regulator_enable_regmap,
@@ -319,7 +319,7 @@ static struct regulator_ops pv88080_buck_ops = {
        .get_current_limit = pv88080_get_current_limit,
 };
 
-static struct regulator_ops pv88080_hvbuck_ops = {
+static const struct regulator_ops pv88080_hvbuck_ops = {
        .enable = regulator_enable_regmap,
        .disable = regulator_disable_regmap,
        .is_enabled = regulator_is_enabled_regmap,
index 42164117535298bc011378bad23f221e8063c566..ab51e254d13a0dacd78a6f4b910fd34b7164d353 100644 (file)
@@ -184,7 +184,7 @@ static int pv88090_get_current_limit(struct regulator_dev *rdev)
        return info->current_limits[data];
 }
 
-static struct regulator_ops pv88090_buck_ops = {
+static const struct regulator_ops pv88090_buck_ops = {
        .get_mode = pv88090_buck_get_mode,
        .set_mode = pv88090_buck_set_mode,
        .enable = regulator_enable_regmap,
@@ -197,7 +197,7 @@ static struct regulator_ops pv88090_buck_ops = {
        .get_current_limit = pv88090_get_current_limit,
 };
 
-static struct regulator_ops pv88090_ldo_ops = {
+static const struct regulator_ops pv88090_ldo_ops = {
        .enable = regulator_enable_regmap,
        .disable = regulator_disable_regmap,
        .is_enabled = regulator_is_enabled_regmap,
index 8ed46a9a55c8469e38c0b14f7c5c8c95fb4fe569..f35994a2a5be043a88aae22b5a2875cd96de7180 100644 (file)
@@ -305,6 +305,56 @@ static const struct regulator_desc pm8916_buck_hvo_smps = {
        .ops = &rpm_smps_ldo_ops,
 };
 
+static const struct regulator_desc pm8994_hfsmps = {
+       .linear_ranges = (struct regulator_linear_range[]) {
+               REGULATOR_LINEAR_RANGE( 375000,  0,  95, 12500),
+               REGULATOR_LINEAR_RANGE(1550000, 96, 158, 25000),
+       },
+       .n_linear_ranges = 2,
+       .n_voltages = 159,
+       .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pm8994_ftsmps = {
+       .linear_ranges = (struct regulator_linear_range[]) {
+               REGULATOR_LINEAR_RANGE(350000,  0, 199, 5000),
+               REGULATOR_LINEAR_RANGE(700000, 200, 349, 10000),
+       },
+       .n_linear_ranges = 2,
+       .n_voltages = 350,
+       .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pm8994_nldo = {
+       .linear_ranges = (struct regulator_linear_range[]) {
+               REGULATOR_LINEAR_RANGE(750000, 0, 63, 12500),
+       },
+       .n_linear_ranges = 1,
+       .n_voltages = 64,
+       .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pm8994_pldo = {
+       .linear_ranges = (struct regulator_linear_range[]) {
+               REGULATOR_LINEAR_RANGE( 750000,  0,  63, 12500),
+               REGULATOR_LINEAR_RANGE(1550000, 64, 126, 25000),
+               REGULATOR_LINEAR_RANGE(3100000, 127, 163, 50000),
+       },
+       .n_linear_ranges = 3,
+       .n_voltages = 164,
+       .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pm8994_switch = {
+       .ops = &rpm_switch_ops,
+};
+
+static const struct regulator_desc pm8994_lnldo = {
+       .fixed_uV = 1740000,
+       .n_voltages = 1,
+       .ops = &rpm_smps_ldo_ops_fixed,
+};
+
 struct rpm_regulator_data {
        const char *name;
        u32 type;
@@ -443,10 +493,62 @@ static const struct rpm_regulator_data rpm_pma8084_regulators[] = {
        {}
 };
 
+static const struct rpm_regulator_data rpm_pm8994_regulators[] = {
+       { "s1", QCOM_SMD_RPM_SMPA, 1, &pm8994_ftsmps, "vdd_s1" },
+       { "s2", QCOM_SMD_RPM_SMPA, 2, &pm8994_ftsmps, "vdd_s2" },
+       { "s3", QCOM_SMD_RPM_SMPA, 3, &pm8994_hfsmps, "vdd_s3" },
+       { "s4", QCOM_SMD_RPM_SMPA, 4, &pm8994_hfsmps, "vdd_s4" },
+       { "s5", QCOM_SMD_RPM_SMPA, 5, &pm8994_hfsmps, "vdd_s5" },
+       { "s6", QCOM_SMD_RPM_SMPA, 6, &pm8994_ftsmps, "vdd_s6" },
+       { "s7", QCOM_SMD_RPM_SMPA, 7, &pm8994_hfsmps, "vdd_s7" },
+       { "s8", QCOM_SMD_RPM_SMPA, 8, &pm8994_ftsmps, "vdd_s8" },
+       { "s9", QCOM_SMD_RPM_SMPA, 9, &pm8994_ftsmps, "vdd_s9" },
+       { "s10", QCOM_SMD_RPM_SMPA, 10, &pm8994_ftsmps, "vdd_s10" },
+       { "s11", QCOM_SMD_RPM_SMPA, 11, &pm8994_ftsmps, "vdd_s11" },
+       { "s12", QCOM_SMD_RPM_SMPA, 12, &pm8994_ftsmps, "vdd_s12" },
+       { "l1", QCOM_SMD_RPM_LDOA, 1, &pm8994_nldo, "vdd_l1" },
+       { "l2", QCOM_SMD_RPM_LDOA, 2, &pm8994_nldo, "vdd_l2_l26_l28" },
+       { "l3", QCOM_SMD_RPM_LDOA, 3, &pm8994_nldo, "vdd_l3_l11" },
+       { "l4", QCOM_SMD_RPM_LDOA, 4, &pm8994_nldo, "vdd_l4_l27_l31" },
+       { "l5", QCOM_SMD_RPM_LDOA, 5, &pm8994_lnldo, "vdd_l5_l7" },
+       { "l6", QCOM_SMD_RPM_LDOA, 6, &pm8994_pldo, "vdd_l6_l12_l32" },
+       { "l7", QCOM_SMD_RPM_LDOA, 7, &pm8994_lnldo, "vdd_l5_l7" },
+       { "l8", QCOM_SMD_RPM_LDOA, 8, &pm8994_pldo, "vdd_l8_l16_l30" },
+       { "l9", QCOM_SMD_RPM_LDOA, 9, &pm8994_pldo, "vdd_l9_l10_l18_l22" },
+       { "l10", QCOM_SMD_RPM_LDOA, 10, &pm8994_pldo, "vdd_l9_l10_l18_l22" },
+       { "l11", QCOM_SMD_RPM_LDOA, 11, &pm8994_nldo, "vdd_l3_l11" },
+       { "l12", QCOM_SMD_RPM_LDOA, 12, &pm8994_pldo, "vdd_l6_l12_l32" },
+       { "l13", QCOM_SMD_RPM_LDOA, 13, &pm8994_pldo, "vdd_l13_l19_l23_l24" },
+       { "l14", QCOM_SMD_RPM_LDOA, 14, &pm8994_pldo, "vdd_l14_l15" },
+       { "l15", QCOM_SMD_RPM_LDOA, 15, &pm8994_pldo, "vdd_l14_l15" },
+       { "l16", QCOM_SMD_RPM_LDOA, 16, &pm8994_pldo, "vdd_l8_l16_l30" },
+       { "l17", QCOM_SMD_RPM_LDOA, 17, &pm8994_pldo, "vdd_l17_l29" },
+       { "l18", QCOM_SMD_RPM_LDOA, 18, &pm8994_pldo, "vdd_l9_l10_l18_l22" },
+       { "l19", QCOM_SMD_RPM_LDOA, 19, &pm8994_pldo, "vdd_l13_l19_l23_l24" },
+       { "l20", QCOM_SMD_RPM_LDOA, 20, &pm8994_pldo, "vdd_l20_l21" },
+       { "l21", QCOM_SMD_RPM_LDOA, 21, &pm8994_pldo, "vdd_l20_l21" },
+       { "l22", QCOM_SMD_RPM_LDOA, 22, &pm8994_pldo, "vdd_l9_l10_l18_l22" },
+       { "l23", QCOM_SMD_RPM_LDOA, 23, &pm8994_pldo, "vdd_l13_l19_l23_l24" },
+       { "l24", QCOM_SMD_RPM_LDOA, 24, &pm8994_pldo, "vdd_l13_l19_l23_l24" },
+       { "l25", QCOM_SMD_RPM_LDOA, 25, &pm8994_pldo, "vdd_l25" },
+       { "l26", QCOM_SMD_RPM_LDOA, 26, &pm8994_nldo, "vdd_l2_l26_l28" },
+       { "l27", QCOM_SMD_RPM_LDOA, 27, &pm8994_nldo, "vdd_l4_l27_l31" },
+       { "l28", QCOM_SMD_RPM_LDOA, 28, &pm8994_nldo, "vdd_l2_l26_l28" },
+       { "l29", QCOM_SMD_RPM_LDOA, 29, &pm8994_pldo, "vdd_l17_l29" },
+       { "l30", QCOM_SMD_RPM_LDOA, 30, &pm8994_pldo, "vdd_l8_l16_l30" },
+       { "l31", QCOM_SMD_RPM_LDOA, 31, &pm8994_nldo, "vdd_l4_l27_l31" },
+       { "l32", QCOM_SMD_RPM_LDOA, 32, &pm8994_pldo, "vdd_l6_l12_l32" },
+       { "lvs1", QCOM_SMD_RPM_VSA, 1, &pm8994_switch, "vdd_lvs1_2" },
+       { "lvs2", QCOM_SMD_RPM_VSA, 2, &pm8994_switch, "vdd_lvs1_2" },
+
+       {}
+};
+
 static const struct of_device_id rpm_of_match[] = {
        { .compatible = "qcom,rpm-pm8841-regulators", .data = &rpm_pm8841_regulators },
        { .compatible = "qcom,rpm-pm8916-regulators", .data = &rpm_pm8916_regulators },
        { .compatible = "qcom,rpm-pm8941-regulators", .data = &rpm_pm8941_regulators },
+       { .compatible = "qcom,rpm-pm8994-regulators", .data = &rpm_pm8994_regulators },
        { .compatible = "qcom,rpm-pma8084-regulators", .data = &rpm_pma8084_regulators },
        {}
 };
index d2e67c5121955915a2f9d561e40a62361bbe552e..d0f1340168b18080875e08e8b0b1f578cc5c3091 100644 (file)
@@ -61,7 +61,7 @@ static int rc5t583_regulator_enable_time(struct regulator_dev *rdev)
        return DIV_ROUND_UP(curr_uV, reg->reg_info->enable_uv_per_us);
 }
 
-static struct regulator_ops rc5t583_ops = {
+static const struct regulator_ops rc5t583_ops = {
        .is_enabled             = regulator_is_enabled_regmap,
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
index 9c930eb68cda69bf6ad87cec1d302b2c7f83e9ba..8d2819e36654522ff5605317452904a54dffa2d4 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/regulator/driver.h>
 #include <linux/regulator/of_regulator.h>
 
-static struct regulator_ops rn5t618_reg_ops = {
+static const struct regulator_ops rn5t618_reg_ops = {
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
        .is_enabled             = regulator_is_enabled_regmap,
index 92f88753bfed274fa5acbec2d2e37dda22c43380..38ee97a085f915921d8d67b4ae839f202422eaa8 100644 (file)
@@ -26,6 +26,7 @@
 #define S2MPA01_REGULATOR_CNT ARRAY_SIZE(regulators)
 
 struct s2mpa01_info {
+       struct of_regulator_match rdata[S2MPA01_REGULATOR_MAX];
        int ramp_delay24;
        int ramp_delay3;
        int ramp_delay5;
@@ -341,9 +342,9 @@ static int s2mpa01_pmic_probe(struct platform_device *pdev)
 {
        struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
        struct sec_platform_data *pdata = dev_get_platdata(iodev->dev);
-       struct of_regulator_match rdata[S2MPA01_REGULATOR_MAX] = { };
        struct device_node *reg_np = NULL;
        struct regulator_config config = { };
+       struct of_regulator_match *rdata;
        struct s2mpa01_info *s2mpa01;
        int i;
 
@@ -351,6 +352,7 @@ static int s2mpa01_pmic_probe(struct platform_device *pdev)
        if (!s2mpa01)
                return -ENOMEM;
 
+       rdata = s2mpa01->rdata;
        for (i = 0; i < S2MPA01_REGULATOR_CNT; i++)
                rdata[i].name = regulators[i].name;
 
index ecb0371780af6d8927a95c5ec61da1849172be40..45e96e15469005f376478d49dbc09045aae4bc3c 100644 (file)
@@ -157,19 +157,19 @@ static struct tps65086_regulator regulators[] = {
                           VDOA23_VID_MASK, TPS65086_LDOA3CTRL, BIT(0),
                           tps65086_ldoa23_ranges, 0, 0),
        TPS65086_SWITCH("SWA1", "swa1", SWA1, TPS65086_SWVTT_EN, BIT(5)),
-       TPS65086_SWITCH("SWB1", "swa2", SWB1, TPS65086_SWVTT_EN, BIT(6)),
-       TPS65086_SWITCH("SWB2", "swa3", SWB2, TPS65086_SWVTT_EN, BIT(7)),
+       TPS65086_SWITCH("SWB1", "swb1", SWB1, TPS65086_SWVTT_EN, BIT(6)),
+       TPS65086_SWITCH("SWB2", "swb2", SWB2, TPS65086_SWVTT_EN, BIT(7)),
        TPS65086_SWITCH("VTT", "vtt", VTT, TPS65086_SWVTT_EN, BIT(4)),
 };
 
-static int tps65086_of_parse_cb(struct device_node *dev,
+static int tps65086_of_parse_cb(struct device_node *node,
                                const struct regulator_desc *desc,
                                struct regulator_config *config)
 {
        int ret;
 
        /* Check for 25mV step mode */
-       if (of_property_read_bool(config->of_node, "ti,regulator-step-size-25mv")) {
+       if (of_property_read_bool(node, "ti,regulator-step-size-25mv")) {
                switch (desc->id) {
                case BUCK1:
                case BUCK2:
@@ -193,7 +193,7 @@ static int tps65086_of_parse_cb(struct device_node *dev,
        }
 
        /* Check for decay mode */
-       if (desc->id <= BUCK6 && of_property_read_bool(config->of_node, "ti,regulator-decay")) {
+       if (desc->id <= BUCK6 && of_property_read_bool(node, "ti,regulator-decay")) {
                ret = regmap_write_bits(config->regmap,
                                        regulators[desc->id].decay_reg,
                                        regulators[desc->id].decay_mask,
index 2d12b9af35402c6f3af37a0b9e24c1c3227fb66f..5324dc9e6d6e67d763f4f65c9532fe39f2fd0a0c 100644 (file)
@@ -179,7 +179,8 @@ static const struct regulator_desc regulators[] = {
        TPS65217_REGULATOR("DCDC1", TPS65217_DCDC_1, "dcdc1",
                           tps65217_pmic_ops, 64, TPS65217_REG_DEFDCDC1,
                           TPS65217_DEFDCDCX_DCDC_MASK, TPS65217_ENABLE_DC1_EN,
-                          NULL, tps65217_uv1_ranges, 2, TPS65217_REG_SEQ1,
+                          NULL, tps65217_uv1_ranges,
+                          ARRAY_SIZE(tps65217_uv1_ranges), TPS65217_REG_SEQ1,
                           TPS65217_SEQ1_DC1_SEQ_MASK),
        TPS65217_REGULATOR("DCDC2", TPS65217_DCDC_2, "dcdc2",
                           tps65217_pmic_ops, 64, TPS65217_REG_DEFDCDC2,
@@ -190,7 +191,8 @@ static const struct regulator_desc regulators[] = {
        TPS65217_REGULATOR("DCDC3", TPS65217_DCDC_3, "dcdc3",
                           tps65217_pmic_ops, 64, TPS65217_REG_DEFDCDC3,
                           TPS65217_DEFDCDCX_DCDC_MASK, TPS65217_ENABLE_DC3_EN,
-                          NULL, tps65217_uv1_ranges, 1, TPS65217_REG_SEQ2,
+                          NULL, tps65217_uv1_ranges,
+                          ARRAY_SIZE(tps65217_uv1_ranges), TPS65217_REG_SEQ2,
                           TPS65217_SEQ2_DC3_SEQ_MASK),
        TPS65217_REGULATOR("LDO1", TPS65217_LDO_1, "ldo1",
                           tps65217_pmic_ldo1_ops, 16, TPS65217_REG_DEFLDO1,
index 51e52446eacb8f4d1e32821fd9c2d6da019825f3..73594f38c453e3cbfe4d301b4a18404520a7d8ef 100644 (file)
@@ -610,7 +610,7 @@ static int rtc_pinconf_set(struct pinctrl_dev *pctldev,
        struct omap_rtc *rtc = pinctrl_dev_get_drvdata(pctldev);
        u32 val;
        unsigned int param;
-       u16 param_val;
+       u32 param_val;
        int i;
 
        rtc->type->unlock(rtc);
index 9f16ea6964ec6182e996168c0f67408b61c93f6e..152de6817875cb6d47cfe45c76c6f677daf83520 100644 (file)
@@ -300,13 +300,6 @@ static void scm_blk_request(struct request_queue *rq)
        struct request *req;
 
        while ((req = blk_peek_request(rq))) {
-               if (req->cmd_type != REQ_TYPE_FS) {
-                       blk_start_request(req);
-                       blk_dump_rq_flags(req, KMSG_COMPONENT " bad request");
-                       __blk_end_request_all(req, -EIO);
-                       continue;
-               }
-
                if (!scm_permit_request(bdev, req))
                        goto out;
 
index 07ffdbb5107f732082e88c94b0362b845e7e17d6..0678cf714c0ee6060eb10e80c3a7c05f6a21f1d2 100644 (file)
@@ -330,6 +330,7 @@ static struct scsi_host_template zfcp_scsi_host_template = {
        .module                  = THIS_MODULE,
        .name                    = "zfcp",
        .queuecommand            = zfcp_scsi_queuecommand,
+       .eh_timed_out            = fc_eh_timed_out,
        .eh_abort_handler        = zfcp_scsi_eh_abort_handler,
        .eh_device_reset_handler = zfcp_scsi_eh_device_reset_handler,
        .eh_target_reset_handler = zfcp_scsi_eh_target_reset_handler,
index a4f6b0d955159cde292b9c7f09811d5d542c3fa8..d4023bf1e739d2765b5a1aa64c31609b13fb47df 100644 (file)
@@ -18,6 +18,7 @@ config SCSI
        depends on BLOCK
        select SCSI_DMA if HAS_DMA
        select SG_POOL
+       select BLK_SCSI_REQUEST
        ---help---
          If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or
          any other SCSI device under Linux, say Y and make sure that you know
index 4f5ca794bb71507a90879af23f0f4ea998fea9ec..acc33440bca0bfbc3e1c168ffb73ed952efe97d1 100644 (file)
  * of chips.  To use it, you write an architecture specific functions
  * and macros and include this file in your driver.
  *
- * These macros control options :
- * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
- * for commands that return with a CHECK CONDITION status.
- *
- * DIFFERENTIAL - if defined, NCR53c81 chips will use external differential
- * transceivers.
- *
- * PSEUDO_DMA - if defined, PSEUDO DMA is used during the data transfer phases.
- *
- * REAL_DMA - if defined, REAL DMA is used during the data transfer phases.
- *
  * These macros MUST be defined :
  *
  * NCR5380_read(register)  - read from the specified register
@@ -347,7 +336,7 @@ static void NCR5380_print_phase(struct Scsi_Host *instance)
 #endif
 
 /**
- * NCR58380_info - report driver and host information
+ * NCR5380_info - report driver and host information
  * @instance: relevant scsi host instance
  *
  * For use as the host template info() handler.
@@ -360,33 +349,6 @@ static const char *NCR5380_info(struct Scsi_Host *instance)
        return hostdata->info;
 }
 
-static void prepare_info(struct Scsi_Host *instance)
-{
-       struct NCR5380_hostdata *hostdata = shost_priv(instance);
-
-       snprintf(hostdata->info, sizeof(hostdata->info),
-                "%s, irq %d, "
-                "io_port 0x%lx, base 0x%lx, "
-                "can_queue %d, cmd_per_lun %d, "
-                "sg_tablesize %d, this_id %d, "
-                "flags { %s%s%s}, "
-                "options { %s} ",
-                instance->hostt->name, instance->irq,
-                hostdata->io_port, hostdata->base,
-                instance->can_queue, instance->cmd_per_lun,
-                instance->sg_tablesize, instance->this_id,
-                hostdata->flags & FLAG_DMA_FIXUP     ? "DMA_FIXUP "     : "",
-                hostdata->flags & FLAG_NO_PSEUDO_DMA ? "NO_PSEUDO_DMA " : "",
-                hostdata->flags & FLAG_TOSHIBA_DELAY ? "TOSHIBA_DELAY "  : "",
-#ifdef DIFFERENTIAL
-                "DIFFERENTIAL "
-#endif
-#ifdef PARITY
-                "PARITY "
-#endif
-                "");
-}
-
 /**
  * NCR5380_init - initialise an NCR5380
  * @instance: adapter to configure
@@ -436,7 +398,14 @@ static int NCR5380_init(struct Scsi_Host *instance, int flags)
        if (!hostdata->work_q)
                return -ENOMEM;
 
-       prepare_info(instance);
+       snprintf(hostdata->info, sizeof(hostdata->info),
+               "%s, irq %d, io_port 0x%lx, base 0x%lx, can_queue %d, cmd_per_lun %d, sg_tablesize %d, this_id %d, flags { %s%s%s}",
+               instance->hostt->name, instance->irq, hostdata->io_port,
+               hostdata->base, instance->can_queue, instance->cmd_per_lun,
+               instance->sg_tablesize, instance->this_id,
+               hostdata->flags & FLAG_DMA_FIXUP     ? "DMA_FIXUP "     : "",
+               hostdata->flags & FLAG_NO_PSEUDO_DMA ? "NO_PSEUDO_DMA " : "",
+               hostdata->flags & FLAG_TOSHIBA_DELAY ? "TOSHIBA_DELAY " : "");
 
        NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
        NCR5380_write(MODE_REG, MR_BASE);
@@ -622,8 +591,9 @@ static inline void maybe_release_dma_irq(struct Scsi_Host *instance)
            list_empty(&hostdata->unissued) &&
            list_empty(&hostdata->autosense) &&
            !hostdata->connected &&
-           !hostdata->selecting)
+           !hostdata->selecting) {
                NCR5380_release_dma_irq(instance);
+       }
 }
 
 /**
@@ -962,6 +932,7 @@ static irqreturn_t __maybe_unused NCR5380_intr(int irq, void *dev_id)
 
 static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance,
                                         struct scsi_cmnd *cmd)
+       __releases(&hostdata->lock) __acquires(&hostdata->lock)
 {
        struct NCR5380_hostdata *hostdata = shost_priv(instance);
        unsigned char tmp[3], phase;
@@ -1194,8 +1165,16 @@ static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance,
        data = tmp;
        phase = PHASE_MSGOUT;
        NCR5380_transfer_pio(instance, &phase, &len, &data);
+       if (len) {
+               NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+               cmd->result = DID_ERROR << 16;
+               complete_cmd(instance, cmd);
+               dsprintk(NDEBUG_SELECTION, instance, "IDENTIFY message transfer failed\n");
+               cmd = NULL;
+               goto out;
+       }
+
        dsprintk(NDEBUG_SELECTION, instance, "nexus established.\n");
-       /* XXX need to handle errors here */
 
        hostdata->connected = cmd;
        hostdata->busy[cmd->device->id] |= 1 << cmd->device->lun;
@@ -1654,6 +1633,7 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
  */
 
 static void NCR5380_information_transfer(struct Scsi_Host *instance)
+       __releases(&hostdata->lock) __acquires(&hostdata->lock)
 {
        struct NCR5380_hostdata *hostdata = shost_priv(instance);
        unsigned char msgout = NOP;
index 51a3567a6fb2a36a3eb44fbf94edf5536e333fe4..d78f0957d8653535eda0f01f2af55f82a75a1a3c 100644 (file)
 #define ICR_ASSERT_ATN         0x02    /* rw Set to assert ATN */
 #define ICR_ASSERT_DATA                0x01    /* rw SCSI_DATA_REG is asserted */
 
-#ifdef DIFFERENTIAL
-#define ICR_BASE               ICR_DIFF_ENABLE
-#else
 #define ICR_BASE               0
-#endif
 
 #define MODE_REG               2
 /*
 #define MR_DMA_MODE            0x02    /* rw DMA / pseudo DMA mode */
 #define MR_ARBITRATE           0x01    /* rw start arbitration */
 
-#ifdef PARITY
-#define MR_BASE                        MR_ENABLE_PAR_CHECK
-#else
 #define MR_BASE                        0
-#endif
 
 #define TARGET_COMMAND_REG     3
 #define TCR_LAST_BYTE_SENT     0x80    /* ro DMA done */
 #define CSR_SCSI_BUF_RDY       0x02    /* ro  SCSI buffer read */
 #define CSR_GATED_53C80_IRQ    0x01    /* ro  Last block xferred */
 
-#if 0
-#define CSR_BASE CSR_SCSI_BUFF_INTR | CSR_53C80_INTR
-#else
 #define CSR_BASE CSR_53C80_INTR
-#endif
 
 /* Note : PHASE_* macros are based on the values of the STATUS register */
 #define PHASE_MASK     (SR_MSG | SR_CD | SR_IO)
@@ -234,11 +222,9 @@ struct NCR5380_hostdata {
        unsigned char id_higher_mask;           /* All bits above id_mask */
        unsigned char last_message;             /* Last Message Out */
        unsigned long region_size;              /* Size of address/port range */
-       char info[256];
+       char info[168];                         /* Host banner message */
 };
 
-#ifdef __KERNEL__
-
 struct NCR5380_cmd {
        struct list_head list;
 };
@@ -331,5 +317,4 @@ static inline int NCR5380_dma_residual_none(struct NCR5380_hostdata *hostdata)
        return 0;
 }
 
-#endif                         /* __KERNEL__ */
 #endif                         /* NCR5380_H */
index 1ee7c654f7b80a44b395715fb5675aa3cef3940d..907f1e80665b1c3302cb42f38ae69e9992fca314 100644 (file)
@@ -6,7 +6,8 @@
  * Adaptec aacraid device driver for Linux.
  *
  * Copyright (c) 2000-2010 Adaptec, Inc.
- *               2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
+ *               2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
+ *              2016-2017 Microsemi Corp. (aacraid@microsemi.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
  * along with this program; see the file COPYING.  If not, write to
  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  *
+ * Module Name:
+ *  aachba.c
+ *
+ * Abstract: Contains Interfaces to manage IOs.
+ *
  */
 
 #include <linux/kernel.h>
@@ -62,6 +68,7 @@
 #define SENCODE_END_OF_DATA                    0x00
 #define SENCODE_BECOMING_READY                 0x04
 #define SENCODE_INIT_CMD_REQUIRED              0x04
+#define SENCODE_UNRECOVERED_READ_ERROR         0x11
 #define SENCODE_PARAM_LIST_LENGTH_ERROR                0x1A
 #define SENCODE_INVALID_COMMAND                        0x20
 #define SENCODE_LBA_OUT_OF_RANGE               0x21
 #define ASENCODE_LUN_FAILED_SELF_CONFIG                0x00
 #define ASENCODE_OVERLAPPED_COMMAND            0x00
 
+#define AAC_STAT_GOOD (DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD)
+
 #define BYTE0(x) (unsigned char)(x)
 #define BYTE1(x) (unsigned char)((x) >> 8)
 #define BYTE2(x) (unsigned char)((x) >> 16)
@@ -164,46 +173,56 @@ struct inquiry_data {
 };
 
 /* Added for VPD 0x83 */
-typedef struct {
-       u8 CodeSet:4;   /* VPD_CODE_SET */
-       u8 Reserved:4;
-       u8 IdentifierType:4;    /* VPD_IDENTIFIER_TYPE */
-       u8 Reserved2:4;
-       u8 Reserved3;
-       u8 IdentifierLength;
-       u8 VendId[8];
-       u8 ProductId[16];
-       u8 SerialNumber[8];     /* SN in ASCII */
-
-} TVPD_ID_Descriptor_Type_1;
+struct  tvpd_id_descriptor_type_1 {
+       u8 codeset:4;           /* VPD_CODE_SET */
+       u8 reserved:4;
+       u8 identifiertype:4;    /* VPD_IDENTIFIER_TYPE */
+       u8 reserved2:4;
+       u8 reserved3;
+       u8 identifierlength;
+       u8 venid[8];
+       u8 productid[16];
+       u8 serialnumber[8];     /* SN in ASCII */
 
-typedef struct {
-       u8 CodeSet:4;   /* VPD_CODE_SET */
-       u8 Reserved:4;
-       u8 IdentifierType:4;    /* VPD_IDENTIFIER_TYPE */
-       u8 Reserved2:4;
-       u8 Reserved3;
-       u8 IdentifierLength;
-       struct TEU64Id {
+};
+
+struct tvpd_id_descriptor_type_2 {
+       u8 codeset:4;           /* VPD_CODE_SET */
+       u8 reserved:4;
+       u8 identifiertype:4;    /* VPD_IDENTIFIER_TYPE */
+       u8 reserved2:4;
+       u8 reserved3;
+       u8 identifierlength;
+       struct teu64id {
                u32 Serial;
                 /* The serial number supposed to be 40 bits,
                  * bit we only support 32, so make the last byte zero. */
-               u8 Reserved;
-               u8 VendId[3];
-       } EU64Id;
+               u8 reserved;
+               u8 venid[3];
+       } eu64id;
 
-} TVPD_ID_Descriptor_Type_2;
+};
 
-typedef struct {
+struct tvpd_id_descriptor_type_3 {
+       u8 codeset : 4;          /* VPD_CODE_SET */
+       u8 reserved : 4;
+       u8 identifiertype : 4;   /* VPD_IDENTIFIER_TYPE */
+       u8 reserved2 : 4;
+       u8 reserved3;
+       u8 identifierlength;
+       u8 Identifier[16];
+};
+
+struct tvpd_page83 {
        u8 DeviceType:5;
        u8 DeviceTypeQualifier:3;
        u8 PageCode;
-       u8 Reserved;
+       u8 reserved;
        u8 PageLength;
-       TVPD_ID_Descriptor_Type_1 IdDescriptorType1;
-       TVPD_ID_Descriptor_Type_2 IdDescriptorType2;
-
-} TVPD_Page83;
+       struct tvpd_id_descriptor_type_1 type1;
+       struct tvpd_id_descriptor_type_2 type2;
+       struct tvpd_id_descriptor_type_3 type3;
+};
 
 /*
  *              M O D U L E   G L O B A L S
@@ -214,9 +233,13 @@ static long aac_build_sg64(struct scsi_cmnd *scsicmd, struct sgmap64 *psg);
 static long aac_build_sgraw(struct scsi_cmnd *scsicmd, struct sgmapraw *psg);
 static long aac_build_sgraw2(struct scsi_cmnd *scsicmd,
                                struct aac_raw_io2 *rio2, int sg_max);
+static long aac_build_sghba(struct scsi_cmnd *scsicmd,
+                               struct aac_hba_cmd_req *hbacmd,
+                               int sg_max, u64 sg_address);
 static int aac_convert_sgraw2(struct aac_raw_io2 *rio2,
                                int pages, int nseg, int nseg_new);
 static int aac_send_srb_fib(struct scsi_cmnd* scsicmd);
+static int aac_send_hba_fib(struct scsi_cmnd *scsicmd);
 #ifdef AAC_DETAILED_STATUS_INFO
 static char *aac_get_status_string(u32 status);
 #endif
@@ -327,7 +350,7 @@ static inline int aac_valid_context(struct scsi_cmnd *scsicmd,
        }
        scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
        device = scsicmd->device;
-       if (unlikely(!device || !scsi_device_online(device))) {
+       if (unlikely(!device)) {
                dprintk((KERN_WARNING "aac_valid_context: scsi device corrupt\n"));
                aac_fib_complete(fibptr);
                return 0;
@@ -473,16 +496,26 @@ int aac_get_containers(struct aac_dev *dev)
 
        if (maximum_num_containers < MAXIMUM_NUM_CONTAINERS)
                maximum_num_containers = MAXIMUM_NUM_CONTAINERS;
-       fsa_dev_ptr = kzalloc(sizeof(*fsa_dev_ptr) * maximum_num_containers,
-                       GFP_KERNEL);
-       if (!fsa_dev_ptr)
-               return -ENOMEM;
+       if (dev->fsa_dev == NULL ||
+               dev->maximum_num_containers != maximum_num_containers) {
+
+               fsa_dev_ptr = dev->fsa_dev;
+
+               dev->fsa_dev = kcalloc(maximum_num_containers,
+                                       sizeof(*fsa_dev_ptr), GFP_KERNEL);
+
+               kfree(fsa_dev_ptr);
+               fsa_dev_ptr = NULL;
 
-       dev->fsa_dev = fsa_dev_ptr;
-       dev->maximum_num_containers = maximum_num_containers;
 
-       for (index = 0; index < dev->maximum_num_containers; ) {
-               fsa_dev_ptr[index].devname[0] = '\0';
+               if (!dev->fsa_dev)
+                       return -ENOMEM;
+
+               dev->maximum_num_containers = maximum_num_containers;
+       }
+       for (index = 0; index < dev->maximum_num_containers; index++) {
+               dev->fsa_dev[index].devname[0] = '\0';
+               dev->fsa_dev[index].valid = 0;
 
                status = aac_probe_container(dev, index);
 
@@ -490,12 +523,6 @@ int aac_get_containers(struct aac_dev *dev)
                        printk(KERN_WARNING "aac_get_containers: SendFIB failed.\n");
                        break;
                }
-
-               /*
-                *      If there are no more containers, then stop asking.
-                */
-               if (++index >= status)
-                       break;
        }
        return status;
 }
@@ -602,6 +629,7 @@ static void _aac_probe_container2(void * context, struct fib * fibptr)
        struct fsa_dev_info *fsa_dev_ptr;
        int (*callback)(struct scsi_cmnd *);
        struct scsi_cmnd * scsicmd = (struct scsi_cmnd *)context;
+       int i;
 
 
        if (!aac_valid_context(scsicmd, fibptr))
@@ -624,6 +652,10 @@ static void _aac_probe_container2(void * context, struct fib * fibptr)
                                fsa_dev_ptr->block_size =
                                        le32_to_cpu(dresp->mnt[0].fileinfo.bdevinfo.block_size);
                        }
+                       for (i = 0; i < 16; i++)
+                               fsa_dev_ptr->identifier[i] =
+                                       dresp->mnt[0].fileinfo.bdevinfo
+                                                               .identifier[i];
                        fsa_dev_ptr->valid = 1;
                        /* sense_key holds the current state of the spin-up */
                        if (dresp->mnt[0].state & cpu_to_le32(FSCS_NOT_READY))
@@ -918,6 +950,28 @@ static void setinqstr(struct aac_dev *dev, void *data, int tindex)
        inqstrcpy ("V1.0", str->prl);
 }
 
+static void build_vpd83_type3(struct tvpd_page83 *vpdpage83data,
+               struct aac_dev *dev, struct scsi_cmnd *scsicmd)
+{
+       int container;
+
+       vpdpage83data->type3.codeset = 1;
+       vpdpage83data->type3.identifiertype = 3;
+       vpdpage83data->type3.identifierlength = sizeof(vpdpage83data->type3)
+                       - 4;
+
+       for (container = 0; container < dev->maximum_num_containers;
+                       container++) {
+
+               if (scmd_id(scsicmd) == container) {
+                       memcpy(vpdpage83data->type3.Identifier,
+                                       dev->fsa_dev[container].identifier,
+                                       16);
+                       break;
+               }
+       }
+}
+
 static void get_container_serial_callback(void *context, struct fib * fibptr)
 {
        struct aac_get_serial_resp * get_serial_reply;
@@ -935,39 +989,47 @@ static void get_container_serial_callback(void *context, struct fib * fibptr)
                /*Check to see if it's for VPD 0x83 or 0x80 */
                if (scsicmd->cmnd[2] == 0x83) {
                        /* vpd page 0x83 - Device Identification Page */
+                       struct aac_dev *dev;
                        int i;
-                       TVPD_Page83 VPDPage83Data;
+                       struct tvpd_page83 vpdpage83data;
+
+                       dev = (struct aac_dev *)scsicmd->device->host->hostdata;
 
-                       memset(((u8 *)&VPDPage83Data), 0,
-                              sizeof(VPDPage83Data));
+                       memset(((u8 *)&vpdpage83data), 0,
+                              sizeof(vpdpage83data));
 
                        /* DIRECT_ACCESS_DEVIC */
-                       VPDPage83Data.DeviceType = 0;
+                       vpdpage83data.DeviceType = 0;
                        /* DEVICE_CONNECTED */
-                       VPDPage83Data.DeviceTypeQualifier = 0;
+                       vpdpage83data.DeviceTypeQualifier = 0;
                        /* VPD_DEVICE_IDENTIFIERS */
-                       VPDPage83Data.PageCode = 0x83;
-                       VPDPage83Data.Reserved = 0;
-                       VPDPage83Data.PageLength =
-                               sizeof(VPDPage83Data.IdDescriptorType1) +
-                               sizeof(VPDPage83Data.IdDescriptorType2);
+                       vpdpage83data.PageCode = 0x83;
+                       vpdpage83data.reserved = 0;
+                       vpdpage83data.PageLength =
+                               sizeof(vpdpage83data.type1) +
+                               sizeof(vpdpage83data.type2);
+
+                       /* VPD 83 Type 3 is not supported for ARC */
+                       if (dev->sa_firmware)
+                               vpdpage83data.PageLength +=
+                               sizeof(vpdpage83data.type3);
 
                        /* T10 Vendor Identifier Field Format */
-                       /* VpdCodeSetAscii */
-                       VPDPage83Data.IdDescriptorType1.CodeSet = 2;
+                       /* VpdcodesetAscii */
+                       vpdpage83data.type1.codeset = 2;
                        /* VpdIdentifierTypeVendorId */
-                       VPDPage83Data.IdDescriptorType1.IdentifierType = 1;
-                       VPDPage83Data.IdDescriptorType1.IdentifierLength =
-                               sizeof(VPDPage83Data.IdDescriptorType1) - 4;
+                       vpdpage83data.type1.identifiertype = 1;
+                       vpdpage83data.type1.identifierlength =
+                               sizeof(vpdpage83data.type1) - 4;
 
                        /* "ADAPTEC " for adaptec */
-                       memcpy(VPDPage83Data.IdDescriptorType1.VendId,
+                       memcpy(vpdpage83data.type1.venid,
                                "ADAPTEC ",
-                               sizeof(VPDPage83Data.IdDescriptorType1.VendId));
-                       memcpy(VPDPage83Data.IdDescriptorType1.ProductId,
+                               sizeof(vpdpage83data.type1.venid));
+                       memcpy(vpdpage83data.type1.productid,
                                "ARRAY           ",
                                sizeof(
-                               VPDPage83Data.IdDescriptorType1.ProductId));
+                               vpdpage83data.type1.productid));
 
                        /* Convert to ascii based serial number.
                         * The LSB is the the end.
@@ -976,32 +1038,41 @@ static void get_container_serial_callback(void *context, struct fib * fibptr)
                                u8 temp =
                                        (u8)((get_serial_reply->uid >> ((7 - i) * 4)) & 0xF);
                                if (temp  > 0x9) {
-                                       VPDPage83Data.IdDescriptorType1.SerialNumber[i] =
+                                       vpdpage83data.type1.serialnumber[i] =
                                                        'A' + (temp - 0xA);
                                } else {
-                                       VPDPage83Data.IdDescriptorType1.SerialNumber[i] =
+                                       vpdpage83data.type1.serialnumber[i] =
                                                        '0' + temp;
                                }
                        }
 
                        /* VpdCodeSetBinary */
-                       VPDPage83Data.IdDescriptorType2.CodeSet = 1;
-                       /* VpdIdentifierTypeEUI64 */
-                       VPDPage83Data.IdDescriptorType2.IdentifierType = 2;
-                       VPDPage83Data.IdDescriptorType2.IdentifierLength =
-                               sizeof(VPDPage83Data.IdDescriptorType2) - 4;
+                       vpdpage83data.type2.codeset = 1;
+                       /* VpdidentifiertypeEUI64 */
+                       vpdpage83data.type2.identifiertype = 2;
+                       vpdpage83data.type2.identifierlength =
+                               sizeof(vpdpage83data.type2) - 4;
 
-                       VPDPage83Data.IdDescriptorType2.EU64Id.VendId[0] = 0xD0;
-                       VPDPage83Data.IdDescriptorType2.EU64Id.VendId[1] = 0;
-                       VPDPage83Data.IdDescriptorType2.EU64Id.VendId[2] = 0;
+                       vpdpage83data.type2.eu64id.venid[0] = 0xD0;
+                       vpdpage83data.type2.eu64id.venid[1] = 0;
+                       vpdpage83data.type2.eu64id.venid[2] = 0;
 
-                       VPDPage83Data.IdDescriptorType2.EU64Id.Serial =
+                       vpdpage83data.type2.eu64id.Serial =
                                                        get_serial_reply->uid;
-                       VPDPage83Data.IdDescriptorType2.EU64Id.Reserved = 0;
+                       vpdpage83data.type2.eu64id.reserved = 0;
+
+                       /*
+                        * VpdIdentifierTypeFCPHName
+                        * VPD 0x83 Type 3 not supported for ARC
+                        */
+                       if (dev->sa_firmware) {
+                               build_vpd83_type3(&vpdpage83data,
+                                               dev, scsicmd);
+                       }
 
                        /* Move the inquiry data to the response buffer. */
-                       scsi_sg_copy_from_buffer(scsicmd, &VPDPage83Data,
-                                                sizeof(VPDPage83Data));
+                       scsi_sg_copy_from_buffer(scsicmd, &vpdpage83data,
+                                                sizeof(vpdpage83data));
                } else {
                        /* It must be for VPD 0x80 */
                        char sp[13];
@@ -1144,7 +1215,9 @@ static int aac_read_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u3
        long ret;
 
        aac_fib_init(fib);
-       if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2 && !dev->sync_mode) {
+       if ((dev->comm_interface == AAC_COMM_MESSAGE_TYPE2 ||
+               dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) &&
+               !dev->sync_mode) {
                struct aac_raw_io2 *readcmd2;
                readcmd2 = (struct aac_raw_io2 *) fib_data(fib);
                memset(readcmd2, 0, sizeof(struct aac_raw_io2));
@@ -1270,7 +1343,9 @@ static int aac_write_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u
        long ret;
 
        aac_fib_init(fib);
-       if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2 && !dev->sync_mode) {
+       if ((dev->comm_interface == AAC_COMM_MESSAGE_TYPE2 ||
+               dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) &&
+               !dev->sync_mode) {
                struct aac_raw_io2 *writecmd2;
                writecmd2 = (struct aac_raw_io2 *) fib_data(fib);
                memset(writecmd2, 0, sizeof(struct aac_raw_io2));
@@ -1435,6 +1510,52 @@ static struct aac_srb * aac_scsi_common(struct fib * fib, struct scsi_cmnd * cmd
        return srbcmd;
 }
 
+static struct aac_hba_cmd_req *aac_construct_hbacmd(struct fib *fib,
+                                                       struct scsi_cmnd *cmd)
+{
+       struct aac_hba_cmd_req *hbacmd;
+       struct aac_dev *dev;
+       int bus, target;
+       u64 address;
+
+       dev = (struct aac_dev *)cmd->device->host->hostdata;
+
+       hbacmd = (struct aac_hba_cmd_req *)fib->hw_fib_va;
+       memset(hbacmd, 0, 96);  /* sizeof(*hbacmd) is not necessary */
+       /* iu_type is a parameter of aac_hba_send */
+       switch (cmd->sc_data_direction) {
+       case DMA_TO_DEVICE:
+               hbacmd->byte1 = 2;
+               break;
+       case DMA_FROM_DEVICE:
+       case DMA_BIDIRECTIONAL:
+               hbacmd->byte1 = 1;
+               break;
+       case DMA_NONE:
+       default:
+               break;
+       }
+       hbacmd->lun[1] = cpu_to_le32(cmd->device->lun);
+
+       bus = aac_logical_to_phys(scmd_channel(cmd));
+       target = scmd_id(cmd);
+       hbacmd->it_nexus = dev->hba_map[bus][target].rmw_nexus;
+
+       /* we fill in reply_qid later in aac_src_deliver_message */
+       /* we fill in iu_type, request_id later in aac_hba_send */
+       /* we fill in emb_data_desc_count later in aac_build_sghba */
+
+       memcpy(hbacmd->cdb, cmd->cmnd, cmd->cmd_len);
+       hbacmd->data_length = cpu_to_le32(scsi_bufflen(cmd));
+
+       address = (u64)fib->hw_error_pa;
+       hbacmd->error_ptr_hi = cpu_to_le32((u32)(address >> 32));
+       hbacmd->error_ptr_lo = cpu_to_le32((u32)(address & 0xffffffff));
+       hbacmd->error_length = cpu_to_le32(FW_ERROR_BUFFER_SIZE);
+
+       return hbacmd;
+}
+
 static void aac_srb_callback(void *context, struct fib * fibptr);
 
 static int aac_scsi_64(struct fib * fib, struct scsi_cmnd * cmd)
@@ -1505,11 +1626,243 @@ static int aac_scsi_32_64(struct fib * fib, struct scsi_cmnd * cmd)
        return aac_scsi_32(fib, cmd);
 }
 
+static int aac_adapter_hba(struct fib *fib, struct scsi_cmnd *cmd)
+{
+       struct aac_hba_cmd_req *hbacmd = aac_construct_hbacmd(fib, cmd);
+       struct aac_dev *dev;
+       long ret;
+
+       dev = (struct aac_dev *)cmd->device->host->hostdata;
+
+       ret = aac_build_sghba(cmd, hbacmd,
+               dev->scsi_host_ptr->sg_tablesize, (u64)fib->hw_sgl_pa);
+       if (ret < 0)
+               return ret;
+
+       /*
+        *      Now send the HBA command to the adapter
+        */
+       fib->hbacmd_size = 64 + le32_to_cpu(hbacmd->emb_data_desc_count) *
+               sizeof(struct aac_hba_sgl);
+
+       return aac_hba_send(HBA_IU_TYPE_SCSI_CMD_REQ, fib,
+                                 (fib_callback) aac_hba_callback,
+                                 (void *) cmd);
+}
+
+int aac_issue_bmic_identify(struct aac_dev *dev, u32 bus, u32 target)
+{
+       struct fib *fibptr;
+       struct aac_srb *srbcmd;
+       struct sgmap64 *sg64;
+       struct aac_ciss_identify_pd *identify_resp;
+       dma_addr_t addr;
+       u32 vbus, vid;
+       u16 fibsize, datasize;
+       int rcode = -ENOMEM;
+
+
+       fibptr = aac_fib_alloc(dev);
+       if (!fibptr)
+               goto out;
+
+       fibsize = sizeof(struct aac_srb) -
+                       sizeof(struct sgentry) + sizeof(struct sgentry64);
+       datasize = sizeof(struct aac_ciss_identify_pd);
+
+       identify_resp =  pci_alloc_consistent(dev->pdev, datasize, &addr);
+
+       if (!identify_resp)
+               goto fib_free_ptr;
+
+       vbus = (u32)le16_to_cpu(dev->supplement_adapter_info.VirtDeviceBus);
+       vid = (u32)le16_to_cpu(dev->supplement_adapter_info.VirtDeviceTarget);
+
+       aac_fib_init(fibptr);
+
+       srbcmd = (struct aac_srb *) fib_data(fibptr);
+       srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi);
+       srbcmd->channel  = cpu_to_le32(vbus);
+       srbcmd->id       = cpu_to_le32(vid);
+       srbcmd->lun      = 0;
+       srbcmd->flags    = cpu_to_le32(SRB_DataIn);
+       srbcmd->timeout  = cpu_to_le32(10);
+       srbcmd->retry_limit = 0;
+       srbcmd->cdb_size = cpu_to_le32(12);
+       srbcmd->count = cpu_to_le32(datasize);
+
+       memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb));
+       srbcmd->cdb[0] = 0x26;
+       srbcmd->cdb[2] = (u8)((AAC_MAX_LUN + target) & 0x00FF);
+       srbcmd->cdb[6] = CISS_IDENTIFY_PHYSICAL_DEVICE;
+
+       sg64 = (struct sgmap64 *)&srbcmd->sg;
+       sg64->count = cpu_to_le32(1);
+       sg64->sg[0].addr[1] = cpu_to_le32((u32)(((addr) >> 16) >> 16));
+       sg64->sg[0].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff));
+       sg64->sg[0].count = cpu_to_le32(datasize);
+
+       rcode = aac_fib_send(ScsiPortCommand64,
+               fibptr, fibsize, FsaNormal, 1, 1, NULL, NULL);
+
+       if (identify_resp->current_queue_depth_limit <= 0 ||
+               identify_resp->current_queue_depth_limit > 32)
+               dev->hba_map[bus][target].qd_limit = 32;
+       else
+               dev->hba_map[bus][target].qd_limit =
+                       identify_resp->current_queue_depth_limit;
+
+       pci_free_consistent(dev->pdev, datasize, (void *)identify_resp, addr);
+
+       aac_fib_complete(fibptr);
+
+fib_free_ptr:
+       aac_fib_free(fibptr);
+out:
+       return rcode;
+}
+
+/**
+ *     aac_update hba_map()-   update current hba map with data from FW
+ *     @dev:   aac_dev structure
+ *     @phys_luns: FW information from report phys luns
+ *
+ *     Update our hba map with the information gathered from the FW
+ */
+void aac_update_hba_map(struct aac_dev *dev,
+               struct aac_ciss_phys_luns_resp *phys_luns, int rescan)
+{
+       /* ok and extended reporting */
+       u32 lun_count, nexus;
+       u32 i, bus, target;
+       u8 expose_flag, attribs;
+       u8 devtype;
+
+       lun_count = ((phys_luns->list_length[0] << 24)
+                       + (phys_luns->list_length[1] << 16)
+                       + (phys_luns->list_length[2] << 8)
+                       + (phys_luns->list_length[3])) / 24;
+
+       for (i = 0; i < lun_count; ++i) {
+
+               bus = phys_luns->lun[i].level2[1] & 0x3f;
+               target = phys_luns->lun[i].level2[0];
+               expose_flag = phys_luns->lun[i].bus >> 6;
+               attribs = phys_luns->lun[i].node_ident[9];
+               nexus = *((u32 *) &phys_luns->lun[i].node_ident[12]);
+
+               if (bus >= AAC_MAX_BUSES || target >= AAC_MAX_TARGETS)
+                       continue;
+
+               dev->hba_map[bus][target].expose = expose_flag;
+
+               if (expose_flag != 0) {
+                       devtype = AAC_DEVTYPE_RAID_MEMBER;
+                       goto update_devtype;
+               }
+
+               if (nexus != 0 && (attribs & 8)) {
+                       devtype = AAC_DEVTYPE_NATIVE_RAW;
+                       dev->hba_map[bus][target].rmw_nexus =
+                                       nexus;
+               } else
+                       devtype = AAC_DEVTYPE_ARC_RAW;
+
+               if (devtype != AAC_DEVTYPE_NATIVE_RAW)
+                       goto update_devtype;
+
+               if (aac_issue_bmic_identify(dev, bus, target) < 0)
+                       dev->hba_map[bus][target].qd_limit = 32;
+
+update_devtype:
+               if (rescan == AAC_INIT)
+                       dev->hba_map[bus][target].devtype = devtype;
+               else
+                       dev->hba_map[bus][target].new_devtype = devtype;
+       }
+}
+
+/**
+ *     aac_report_phys_luns()  Process topology change
+ *     @dev:           aac_dev structure
+ *     @fibptr:        fib pointer
+ *
+ *     Execute a CISS REPORT PHYS LUNS and process the results into
+ *     the current hba_map.
+ */
+int aac_report_phys_luns(struct aac_dev *dev, struct fib *fibptr, int rescan)
+{
+       int fibsize, datasize;
+       struct aac_ciss_phys_luns_resp *phys_luns;
+       struct aac_srb *srbcmd;
+       struct sgmap64 *sg64;
+       dma_addr_t addr;
+       u32 vbus, vid;
+       int rcode = 0;
+
+       /* Thor SA Firmware -> CISS_REPORT_PHYSICAL_LUNS */
+       fibsize = sizeof(struct aac_srb) - sizeof(struct sgentry)
+                       + sizeof(struct sgentry64);
+       datasize = sizeof(struct aac_ciss_phys_luns_resp)
+                       + (AAC_MAX_TARGETS - 1) * sizeof(struct _ciss_lun);
+
+       phys_luns = (struct aac_ciss_phys_luns_resp *) pci_alloc_consistent(
+                       dev->pdev, datasize, &addr);
+
+       if (phys_luns == NULL) {
+               rcode = -ENOMEM;
+               goto err_out;
+       }
+
+       vbus = (u32) le16_to_cpu(
+                       dev->supplement_adapter_info.VirtDeviceBus);
+       vid = (u32) le16_to_cpu(
+                       dev->supplement_adapter_info.VirtDeviceTarget);
+
+       aac_fib_init(fibptr);
+
+       srbcmd = (struct aac_srb *) fib_data(fibptr);
+       srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi);
+       srbcmd->channel = cpu_to_le32(vbus);
+       srbcmd->id = cpu_to_le32(vid);
+       srbcmd->lun = 0;
+       srbcmd->flags = cpu_to_le32(SRB_DataIn);
+       srbcmd->timeout = cpu_to_le32(10);
+       srbcmd->retry_limit = 0;
+       srbcmd->cdb_size = cpu_to_le32(12);
+       srbcmd->count = cpu_to_le32(datasize);
+
+       memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb));
+       srbcmd->cdb[0] = CISS_REPORT_PHYSICAL_LUNS;
+       srbcmd->cdb[1] = 2; /* extended reporting */
+       srbcmd->cdb[8] = (u8)(datasize >> 8);
+       srbcmd->cdb[9] = (u8)(datasize);
+
+       sg64 = (struct sgmap64 *) &srbcmd->sg;
+       sg64->count = cpu_to_le32(1);
+       sg64->sg[0].addr[1] = cpu_to_le32(upper_32_bits(addr));
+       sg64->sg[0].addr[0] = cpu_to_le32(lower_32_bits(addr));
+       sg64->sg[0].count = cpu_to_le32(datasize);
+
+       rcode = aac_fib_send(ScsiPortCommand64, fibptr, fibsize,
+                       FsaNormal, 1, 1, NULL, NULL);
+
+       /* analyse data */
+       if (rcode >= 0 && phys_luns->resp_flag == 2) {
+               /* ok and extended reporting */
+               aac_update_hba_map(dev, phys_luns, rescan);
+       }
+
+       pci_free_consistent(dev->pdev, datasize, (void *) phys_luns, addr);
+err_out:
+       return rcode;
+}
+
 int aac_get_adapter_info(struct aac_dev* dev)
 {
        struct fib* fibptr;
        int rcode;
-       u32 tmp;
+       u32 tmp, bus, target;
        struct aac_adapter_info *info;
        struct aac_bus_info *command;
        struct aac_bus_info_response *bus_info;
@@ -1540,6 +1893,7 @@ int aac_get_adapter_info(struct aac_dev* dev)
        }
        memcpy(&dev->adapter_info, info, sizeof(*info));
 
+       dev->supplement_adapter_info.VirtDeviceBus = 0xffff;
        if (dev->adapter_info.options & AAC_OPT_SUPPLEMENT_ADAPTER_INFO) {
                struct aac_supplement_adapter_info * sinfo;
 
@@ -1567,6 +1921,13 @@ int aac_get_adapter_info(struct aac_dev* dev)
 
        }
 
+       /* reset all previous mapped devices (i.e. for init. after IOP_RESET) */
+       for (bus = 0; bus < AAC_MAX_BUSES; bus++) {
+               for (target = 0; target < AAC_MAX_TARGETS; target++) {
+                       dev->hba_map[bus][target].devtype = 0;
+                       dev->hba_map[bus][target].qd_limit = 0;
+               }
+       }
 
        /*
         * GetBusInfo
@@ -1599,6 +1960,12 @@ int aac_get_adapter_info(struct aac_dev* dev)
                dev->maximum_num_channels = le32_to_cpu(bus_info->BusCount);
        }
 
+       if (!dev->sync_mode && dev->sa_firmware &&
+                       dev->supplement_adapter_info.VirtDeviceBus != 0xffff) {
+               /* Thor SA Firmware -> CISS_REPORT_PHYSICAL_LUNS */
+               rcode = aac_report_phys_luns(dev, fibptr, AAC_INIT);
+       }
+
        if (!dev->in_reset) {
                char buffer[16];
                tmp = le32_to_cpu(dev->adapter_info.kernelrev);
@@ -1765,6 +2132,11 @@ int aac_get_adapter_info(struct aac_dev* dev)
                          (dev->scsi_host_ptr->sg_tablesize * 8) + 112;
                }
        }
+       if (!dev->sync_mode && dev->sa_firmware &&
+               dev->scsi_host_ptr->sg_tablesize > HBA_MAX_SG_SEPARATE)
+               dev->scsi_host_ptr->sg_tablesize = dev->sg_tablesize =
+                       HBA_MAX_SG_SEPARATE;
+
        /* FIB should be freed only after getting the response from the F/W */
        if (rcode != -ERESTARTSYS) {
                aac_fib_complete(fibptr);
@@ -1845,6 +2217,15 @@ static void io_callback(void *context, struct fib * fibptr)
                       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
                             SCSI_SENSE_BUFFERSIZE));
                break;
+       case ST_MEDERR:
+               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+                       SAM_STAT_CHECK_CONDITION;
+               set_sense(&dev->fsa_dev[cid].sense_data, MEDIUM_ERROR,
+                 SENCODE_UNRECOVERED_READ_ERROR, ASENCODE_NO_SENSE, 0, 0);
+               memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+                      min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
+                            SCSI_SENSE_BUFFERSIZE));
+               break;
        default:
 #ifdef AAC_DETAILED_STATUS_INFO
                printk(KERN_WARNING "io_callback: io failed, status = %d\n",
@@ -2312,7 +2693,7 @@ static int aac_start_stop(struct scsi_cmnd *scsicmd)
 
 int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
 {
-       u32 cid;
+       u32 cid, bus;
        struct Scsi_Host *host = scsicmd->device->host;
        struct aac_dev *dev = (struct aac_dev *)host->hostdata;
        struct fsa_dev_info *fsa_dev_ptr = dev->fsa_dev;
@@ -2330,8 +2711,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                        if((cid >= dev->maximum_num_containers) ||
                                        (scsicmd->device->lun != 0)) {
                                scsicmd->result = DID_NO_CONNECT << 16;
-                               scsicmd->scsi_done(scsicmd);
-                               return 0;
+                               goto scsi_done_ret;
                        }
 
                        /*
@@ -2359,15 +2739,30 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                                }
                        }
                } else {  /* check for physical non-dasd devices */
-                       if (dev->nondasd_support || expose_physicals ||
-                                       dev->jbod) {
+                       bus = aac_logical_to_phys(scmd_channel(scsicmd));
+                       if (bus < AAC_MAX_BUSES && cid < AAC_MAX_TARGETS &&
+                               (dev->hba_map[bus][cid].expose
+                                               == AAC_HIDE_DISK)){
+                               if (scsicmd->cmnd[0] == INQUIRY) {
+                                       scsicmd->result = DID_NO_CONNECT << 16;
+                                       goto scsi_done_ret;
+                               }
+                       }
+
+                       if (bus < AAC_MAX_BUSES && cid < AAC_MAX_TARGETS &&
+                               dev->hba_map[bus][cid].devtype
+                                       == AAC_DEVTYPE_NATIVE_RAW) {
+                               if (dev->in_reset)
+                                       return -1;
+                               return aac_send_hba_fib(scsicmd);
+                       } else if (dev->nondasd_support || expose_physicals ||
+                               dev->jbod) {
                                if (dev->in_reset)
                                        return -1;
                                return aac_send_srb_fib(scsicmd);
                        } else {
                                scsicmd->result = DID_NO_CONNECT << 16;
-                               scsicmd->scsi_done(scsicmd);
-                               return 0;
+                               goto scsi_done_ret;
                        }
                }
        }
@@ -2385,13 +2780,34 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
                       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
                             SCSI_SENSE_BUFFERSIZE));
-               scsicmd->scsi_done(scsicmd);
-               return 0;
+               goto scsi_done_ret;
        }
 
-
-       /* Handle commands here that don't really require going out to the adapter */
        switch (scsicmd->cmnd[0]) {
+       case READ_6:
+       case READ_10:
+       case READ_12:
+       case READ_16:
+               if (dev->in_reset)
+                       return -1;
+               return aac_read(scsicmd);
+
+       case WRITE_6:
+       case WRITE_10:
+       case WRITE_12:
+       case WRITE_16:
+               if (dev->in_reset)
+                       return -1;
+               return aac_write(scsicmd);
+
+       case SYNCHRONIZE_CACHE:
+               if (((aac_cache & 6) == 6) && dev->cache_protected) {
+                       scsicmd->result = AAC_STAT_GOOD;
+                       break;
+               }
+               /* Issue FIB to tell Firmware to flush it's cache */
+               if ((aac_cache & 6) != 2)
+                       return aac_synchronize(scsicmd);
        case INQUIRY:
        {
                struct inquiry_data inq_data;
@@ -2414,8 +2830,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                                arr[1] = scsicmd->cmnd[2];
                                scsi_sg_copy_from_buffer(scsicmd, &inq_data,
                                                         sizeof(inq_data));
-                               scsicmd->result = DID_OK << 16 |
-                                 COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+                               scsicmd->result = AAC_STAT_GOOD;
                        } else if (scsicmd->cmnd[2] == 0x80) {
                                /* unit serial number page */
                                arr[3] = setinqserial(dev, &arr[4],
@@ -2426,8 +2841,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                                if (aac_wwn != 2)
                                        return aac_get_container_serial(
                                                scsicmd);
-                               scsicmd->result = DID_OK << 16 |
-                                 COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+                               scsicmd->result = AAC_STAT_GOOD;
                        } else if (scsicmd->cmnd[2] == 0x83) {
                                /* vpd page 0x83 - Device Identification Page */
                                char *sno = (char *)&inq_data;
@@ -2436,8 +2850,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                                if (aac_wwn != 2)
                                        return aac_get_container_serial(
                                                scsicmd);
-                               scsicmd->result = DID_OK << 16 |
-                                 COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+                               scsicmd->result = AAC_STAT_GOOD;
                        } else {
                                /* vpd page not implemented */
                                scsicmd->result = DID_OK << 16 |
@@ -2452,8 +2865,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                                        sizeof(dev->fsa_dev[cid].sense_data),
                                        SCSI_SENSE_BUFFERSIZE));
                        }
-                       scsicmd->scsi_done(scsicmd);
-                       return 0;
+                       break;
                }
                inq_data.inqd_ver = 2;  /* claim compliance to SCSI-2 */
                inq_data.inqd_rdf = 2;  /* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */
@@ -2469,9 +2881,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                        inq_data.inqd_pdt = INQD_PDT_PROC;      /* Processor device */
                        scsi_sg_copy_from_buffer(scsicmd, &inq_data,
                                                 sizeof(inq_data));
-                       scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
-                       scsicmd->scsi_done(scsicmd);
-                       return 0;
+                       scsicmd->result = AAC_STAT_GOOD;
+                       break;
                }
                if (dev->in_reset)
                        return -1;
@@ -2519,10 +2930,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                /* Do not cache partition table for arrays */
                scsicmd->device->removable = 1;
 
-               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
-               scsicmd->scsi_done(scsicmd);
-
-               return 0;
+               scsicmd->result = AAC_STAT_GOOD;
+               break;
        }
 
        case READ_CAPACITY:
@@ -2547,11 +2956,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                scsi_sg_copy_from_buffer(scsicmd, cp, sizeof(cp));
                /* Do not cache partition table for arrays */
                scsicmd->device->removable = 1;
-               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
-                 SAM_STAT_GOOD;
-               scsicmd->scsi_done(scsicmd);
-
-               return 0;
+               scsicmd->result = AAC_STAT_GOOD;
+               break;
        }
 
        case MODE_SENSE:
@@ -2629,10 +3035,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                scsi_sg_copy_from_buffer(scsicmd,
                                         (char *)&mpd,
                                         mode_buf_length);
-               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
-               scsicmd->scsi_done(scsicmd);
-
-               return 0;
+               scsicmd->result = AAC_STAT_GOOD;
+               break;
        }
        case MODE_SENSE_10:
        {
@@ -2708,18 +3112,17 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                                         (char *)&mpd10,
                                         mode_buf_length);
 
-               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
-               scsicmd->scsi_done(scsicmd);
-
-               return 0;
+               scsicmd->result = AAC_STAT_GOOD;
+               break;
        }
        case REQUEST_SENSE:
                dprintk((KERN_DEBUG "REQUEST SENSE command.\n"));
-               memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, sizeof (struct sense_data));
-               memset(&dev->fsa_dev[cid].sense_data, 0, sizeof (struct sense_data));
-               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
-               scsicmd->scsi_done(scsicmd);
-               return 0;
+               memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+                               sizeof(struct sense_data));
+               memset(&dev->fsa_dev[cid].sense_data, 0,
+                               sizeof(struct sense_data));
+               scsicmd->result = AAC_STAT_GOOD;
+               break;
 
        case ALLOW_MEDIUM_REMOVAL:
                dprintk((KERN_DEBUG "LOCK command.\n"));
@@ -2728,9 +3131,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                else
                        fsa_dev_ptr[cid].locked = 0;
 
-               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
-               scsicmd->scsi_done(scsicmd);
-               return 0;
+               scsicmd->result = AAC_STAT_GOOD;
+               break;
        /*
         *      These commands are all No-Ops
         */
@@ -2746,80 +3148,41 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
                               min_t(size_t,
                                     sizeof(dev->fsa_dev[cid].sense_data),
                                     SCSI_SENSE_BUFFERSIZE));
-                       scsicmd->scsi_done(scsicmd);
-                       return 0;
+               break;
                }
-               /* FALLTHRU */
        case RESERVE:
        case RELEASE:
        case REZERO_UNIT:
        case REASSIGN_BLOCKS:
        case SEEK_10:
-               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
-               scsicmd->scsi_done(scsicmd);
-               return 0;
+               scsicmd->result = AAC_STAT_GOOD;
+               break;
 
        case START_STOP:
                return aac_start_stop(scsicmd);
-       }
-
-       switch (scsicmd->cmnd[0])
-       {
-               case READ_6:
-               case READ_10:
-               case READ_12:
-               case READ_16:
-                       if (dev->in_reset)
-                               return -1;
-                       /*
-                        *      Hack to keep track of ordinal number of the device that
-                        *      corresponds to a container. Needed to convert
-                        *      containers to /dev/sd device names
-                        */
-
-                       if (scsicmd->request->rq_disk)
-                               strlcpy(fsa_dev_ptr[cid].devname,
-                               scsicmd->request->rq_disk->disk_name,
-                               min(sizeof(fsa_dev_ptr[cid].devname),
-                               sizeof(scsicmd->request->rq_disk->disk_name) + 1));
-
-                       return aac_read(scsicmd);
 
-               case WRITE_6:
-               case WRITE_10:
-               case WRITE_12:
-               case WRITE_16:
-                       if (dev->in_reset)
-                               return -1;
-                       return aac_write(scsicmd);
-
-               case SYNCHRONIZE_CACHE:
-                       if (((aac_cache & 6) == 6) && dev->cache_protected) {
-                               scsicmd->result = DID_OK << 16 |
-                                       COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
-                               scsicmd->scsi_done(scsicmd);
-                               return 0;
-                       }
-                       /* Issue FIB to tell Firmware to flush it's cache */
-                       if ((aac_cache & 6) != 2)
-                               return aac_synchronize(scsicmd);
-                       /* FALLTHRU */
-               default:
-                       /*
-                        *      Unhandled commands
-                        */
-                       dprintk((KERN_WARNING "Unhandled SCSI Command: 0x%x.\n", scsicmd->cmnd[0]));
-                       scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
-                       set_sense(&dev->fsa_dev[cid].sense_data,
+       /* FALLTHRU */
+       default:
+       /*
+        *      Unhandled commands
+        */
+               dprintk((KERN_WARNING "Unhandled SCSI Command: 0x%x.\n",
+                               scsicmd->cmnd[0]));
+               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+                               SAM_STAT_CHECK_CONDITION;
+               set_sense(&dev->fsa_dev[cid].sense_data,
                          ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND,
                          ASENCODE_INVALID_COMMAND, 0, 0);
-                       memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+               memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
                                min_t(size_t,
                                      sizeof(dev->fsa_dev[cid].sense_data),
                                      SCSI_SENSE_BUFFERSIZE));
-                       scsicmd->scsi_done(scsicmd);
-                       return 0;
        }
+
+scsi_done_ret:
+
+       scsicmd->scsi_done(scsicmd);
+       return 0;
 }
 
 static int query_disk(struct aac_dev *dev, void __user *arg)
@@ -2954,16 +3317,11 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
                return;
 
        BUG_ON(fibptr == NULL);
-       dev = fibptr->dev;
 
-       scsi_dma_unmap(scsicmd);
-
-       /* expose physical device if expose_physicald flag is on */
-       if (scsicmd->cmnd[0] == INQUIRY && !(scsicmd->cmnd[1] & 0x01)
-         && expose_physicals > 0)
-               aac_expose_phy_device(scsicmd);
+       dev = fibptr->dev;
 
        srbreply = (struct aac_srb_reply *) fib_data(fibptr);
+
        scsicmd->sense_buffer[0] = '\0';  /* Initialize sense valid flag to false */
 
        if (fibptr->flags & FIB_CONTEXT_FLAG_FASTRESP) {
@@ -2976,158 +3334,176 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
                 */
                scsi_set_resid(scsicmd, scsi_bufflen(scsicmd)
                                   - le32_to_cpu(srbreply->data_xfer_length));
-               /*
-                * First check the fib status
-                */
+       }
 
-               if (le32_to_cpu(srbreply->status) != ST_OK) {
-                       int len;
 
-                       printk(KERN_WARNING "aac_srb_callback: srb failed, status = %d\n", le32_to_cpu(srbreply->status));
-                       len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
-                                   SCSI_SENSE_BUFFERSIZE);
-                       scsicmd->result = DID_ERROR << 16
-                                               | COMMAND_COMPLETE << 8
-                                               | SAM_STAT_CHECK_CONDITION;
-                       memcpy(scsicmd->sense_buffer,
-                                       srbreply->sense_data, len);
-               }
+       scsi_dma_unmap(scsicmd);
 
-               /*
-                * Next check the srb status
-                */
-               switch ((le32_to_cpu(srbreply->srb_status))&0x3f) {
-               case SRB_STATUS_ERROR_RECOVERY:
-               case SRB_STATUS_PENDING:
-               case SRB_STATUS_SUCCESS:
-                       scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
-                       break;
-               case SRB_STATUS_DATA_OVERRUN:
-                       switch (scsicmd->cmnd[0]) {
-                       case  READ_6:
-                       case  WRITE_6:
-                       case  READ_10:
-                       case  WRITE_10:
-                       case  READ_12:
-                       case  WRITE_12:
-                       case  READ_16:
-                       case  WRITE_16:
-                               if (le32_to_cpu(srbreply->data_xfer_length)
-                                                       < scsicmd->underflow)
-                                       printk(KERN_WARNING"aacraid: SCSI CMD underflow\n");
-                               else
-                                       printk(KERN_WARNING"aacraid: SCSI CMD Data Overrun\n");
-                               scsicmd->result = DID_ERROR << 16
-                                                       | COMMAND_COMPLETE << 8;
-                               break;
-                       case INQUIRY: {
-                               scsicmd->result = DID_OK << 16
-                                                       | COMMAND_COMPLETE << 8;
-                               break;
-                       }
-                       default:
-                               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
-                               break;
-                       }
-                       break;
-               case SRB_STATUS_ABORTED:
-                       scsicmd->result = DID_ABORT << 16 | ABORT << 8;
-                       break;
-               case SRB_STATUS_ABORT_FAILED:
-                       /*
-                        * Not sure about this one - but assuming the
-                        * hba was trying to abort for some reason
-                        */
-                       scsicmd->result = DID_ERROR << 16 | ABORT << 8;
+       /* expose physical device if expose_physicald flag is on */
+       if (scsicmd->cmnd[0] == INQUIRY && !(scsicmd->cmnd[1] & 0x01)
+         && expose_physicals > 0)
+               aac_expose_phy_device(scsicmd);
+
+       /*
+        * First check the fib status
+        */
+
+       if (le32_to_cpu(srbreply->status) != ST_OK) {
+               int len;
+
+               pr_warn("aac_srb_callback: srb failed, status = %d\n",
+                               le32_to_cpu(srbreply->status));
+               len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
+                           SCSI_SENSE_BUFFERSIZE);
+               scsicmd->result = DID_ERROR << 16
+                               | COMMAND_COMPLETE << 8
+                               | SAM_STAT_CHECK_CONDITION;
+               memcpy(scsicmd->sense_buffer,
+                               srbreply->sense_data, len);
+       }
+
+       /*
+        * Next check the srb status
+        */
+       switch ((le32_to_cpu(srbreply->srb_status))&0x3f) {
+       case SRB_STATUS_ERROR_RECOVERY:
+       case SRB_STATUS_PENDING:
+       case SRB_STATUS_SUCCESS:
+               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+               break;
+       case SRB_STATUS_DATA_OVERRUN:
+               switch (scsicmd->cmnd[0]) {
+               case  READ_6:
+               case  WRITE_6:
+               case  READ_10:
+               case  WRITE_10:
+               case  READ_12:
+               case  WRITE_12:
+               case  READ_16:
+               case  WRITE_16:
+                       if (le32_to_cpu(srbreply->data_xfer_length)
+                                               < scsicmd->underflow)
+                               pr_warn("aacraid: SCSI CMD underflow\n");
+                       else
+                               pr_warn("aacraid: SCSI CMD Data Overrun\n");
+                       scsicmd->result = DID_ERROR << 16
+                                       | COMMAND_COMPLETE << 8;
                        break;
-               case SRB_STATUS_PARITY_ERROR:
-                       scsicmd->result = DID_PARITY << 16
-                                               | MSG_PARITY_ERROR << 8;
+               case INQUIRY:
+                       scsicmd->result = DID_OK << 16
+                                       | COMMAND_COMPLETE << 8;
                        break;
-               case SRB_STATUS_NO_DEVICE:
-               case SRB_STATUS_INVALID_PATH_ID:
-               case SRB_STATUS_INVALID_TARGET_ID:
-               case SRB_STATUS_INVALID_LUN:
-               case SRB_STATUS_SELECTION_TIMEOUT:
-                       scsicmd->result = DID_NO_CONNECT << 16
-                                               | COMMAND_COMPLETE << 8;
+               default:
+                       scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
                        break;
+               }
+               break;
+       case SRB_STATUS_ABORTED:
+               scsicmd->result = DID_ABORT << 16 | ABORT << 8;
+               break;
+       case SRB_STATUS_ABORT_FAILED:
+               /*
+                * Not sure about this one - but assuming the
+                * hba was trying to abort for some reason
+                */
+               scsicmd->result = DID_ERROR << 16 | ABORT << 8;
+               break;
+       case SRB_STATUS_PARITY_ERROR:
+               scsicmd->result = DID_PARITY << 16
+                               | MSG_PARITY_ERROR << 8;
+               break;
+       case SRB_STATUS_NO_DEVICE:
+       case SRB_STATUS_INVALID_PATH_ID:
+       case SRB_STATUS_INVALID_TARGET_ID:
+       case SRB_STATUS_INVALID_LUN:
+       case SRB_STATUS_SELECTION_TIMEOUT:
+               scsicmd->result = DID_NO_CONNECT << 16
+                               | COMMAND_COMPLETE << 8;
+               break;
 
-               case SRB_STATUS_COMMAND_TIMEOUT:
-               case SRB_STATUS_TIMEOUT:
-                       scsicmd->result = DID_TIME_OUT << 16
-                                               | COMMAND_COMPLETE << 8;
-                       break;
+       case SRB_STATUS_COMMAND_TIMEOUT:
+       case SRB_STATUS_TIMEOUT:
+               scsicmd->result = DID_TIME_OUT << 16
+                               | COMMAND_COMPLETE << 8;
+               break;
 
-               case SRB_STATUS_BUSY:
-                       scsicmd->result = DID_BUS_BUSY << 16
-                                               | COMMAND_COMPLETE << 8;
-                       break;
+       case SRB_STATUS_BUSY:
+               scsicmd->result = DID_BUS_BUSY << 16
+                               | COMMAND_COMPLETE << 8;
+               break;
 
-               case SRB_STATUS_BUS_RESET:
-                       scsicmd->result = DID_RESET << 16
-                                               | COMMAND_COMPLETE << 8;
-                       break;
+       case SRB_STATUS_BUS_RESET:
+               scsicmd->result = DID_RESET << 16
+                               | COMMAND_COMPLETE << 8;
+               break;
 
-               case SRB_STATUS_MESSAGE_REJECTED:
-                       scsicmd->result = DID_ERROR << 16
-                                               | MESSAGE_REJECT << 8;
-                       break;
-               case SRB_STATUS_REQUEST_FLUSHED:
-               case SRB_STATUS_ERROR:
-               case SRB_STATUS_INVALID_REQUEST:
-               case SRB_STATUS_REQUEST_SENSE_FAILED:
-               case SRB_STATUS_NO_HBA:
-               case SRB_STATUS_UNEXPECTED_BUS_FREE:
-               case SRB_STATUS_PHASE_SEQUENCE_FAILURE:
-               case SRB_STATUS_BAD_SRB_BLOCK_LENGTH:
-               case SRB_STATUS_DELAYED_RETRY:
-               case SRB_STATUS_BAD_FUNCTION:
-               case SRB_STATUS_NOT_STARTED:
-               case SRB_STATUS_NOT_IN_USE:
-               case SRB_STATUS_FORCE_ABORT:
-               case SRB_STATUS_DOMAIN_VALIDATION_FAIL:
-               default:
+       case SRB_STATUS_MESSAGE_REJECTED:
+               scsicmd->result = DID_ERROR << 16
+                               | MESSAGE_REJECT << 8;
+               break;
+       case SRB_STATUS_REQUEST_FLUSHED:
+       case SRB_STATUS_ERROR:
+       case SRB_STATUS_INVALID_REQUEST:
+       case SRB_STATUS_REQUEST_SENSE_FAILED:
+       case SRB_STATUS_NO_HBA:
+       case SRB_STATUS_UNEXPECTED_BUS_FREE:
+       case SRB_STATUS_PHASE_SEQUENCE_FAILURE:
+       case SRB_STATUS_BAD_SRB_BLOCK_LENGTH:
+       case SRB_STATUS_DELAYED_RETRY:
+       case SRB_STATUS_BAD_FUNCTION:
+       case SRB_STATUS_NOT_STARTED:
+       case SRB_STATUS_NOT_IN_USE:
+       case SRB_STATUS_FORCE_ABORT:
+       case SRB_STATUS_DOMAIN_VALIDATION_FAIL:
+       default:
 #ifdef AAC_DETAILED_STATUS_INFO
-                       printk(KERN_INFO "aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n",
-                               le32_to_cpu(srbreply->srb_status) & 0x3F,
-                               aac_get_status_string(
-                                       le32_to_cpu(srbreply->srb_status) & 0x3F),
-                               scsicmd->cmnd[0],
-                               le32_to_cpu(srbreply->scsi_status));
+               pr_info("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x -scsi status 0x%x\n",
+                       le32_to_cpu(srbreply->srb_status) & 0x3F,
+                       aac_get_status_string(
+                               le32_to_cpu(srbreply->srb_status) & 0x3F),
+                       scsicmd->cmnd[0],
+                       le32_to_cpu(srbreply->scsi_status));
 #endif
-                       if ((scsicmd->cmnd[0] == ATA_12)
-                               || (scsicmd->cmnd[0] == ATA_16)) {
-                                       if (scsicmd->cmnd[2] & (0x01 << 5)) {
-                                               scsicmd->result = DID_OK << 16
-                                                       | COMMAND_COMPLETE << 8;
-                               break;
-                               } else {
-                                       scsicmd->result = DID_ERROR << 16
-                                               | COMMAND_COMPLETE << 8;
-                                       break;
-                               }
+               /*
+                * When the CC bit is SET by the host in ATA pass thru CDB,
+                *  driver is supposed to return DID_OK
+                *
+                * When the CC bit is RESET by the host, driver should
+                *  return DID_ERROR
+                */
+               if ((scsicmd->cmnd[0] == ATA_12)
+                       || (scsicmd->cmnd[0] == ATA_16)) {
+
+                       if (scsicmd->cmnd[2] & (0x01 << 5)) {
+                               scsicmd->result = DID_OK << 16
+                                       | COMMAND_COMPLETE << 8;
+                       break;
                        } else {
                                scsicmd->result = DID_ERROR << 16
                                        | COMMAND_COMPLETE << 8;
-                               break;
+                       break;
                        }
+               } else {
+                       scsicmd->result = DID_ERROR << 16
+                               | COMMAND_COMPLETE << 8;
+                       break;
                }
-               if (le32_to_cpu(srbreply->scsi_status)
-                               == SAM_STAT_CHECK_CONDITION) {
-                       int len;
+       }
+       if (le32_to_cpu(srbreply->scsi_status)
+                       == SAM_STAT_CHECK_CONDITION) {
+               int len;
 
-                       scsicmd->result |= SAM_STAT_CHECK_CONDITION;
-                       len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
-                                   SCSI_SENSE_BUFFERSIZE);
+               scsicmd->result |= SAM_STAT_CHECK_CONDITION;
+               len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
+                           SCSI_SENSE_BUFFERSIZE);
 #ifdef AAC_DETAILED_STATUS_INFO
-                       printk(KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n",
-                                               le32_to_cpu(srbreply->status), len);
+               pr_warn("aac_srb_callback: check condition, status = %d len=%d\n",
+                                       le32_to_cpu(srbreply->status), len);
 #endif
-                       memcpy(scsicmd->sense_buffer,
-                                       srbreply->sense_data, len);
-               }
+               memcpy(scsicmd->sense_buffer,
+                               srbreply->sense_data, len);
        }
+
        /*
         * OR in the scsi status (already shifted up a bit)
         */
@@ -3137,9 +3513,152 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
        scsicmd->scsi_done(scsicmd);
 }
 
+static void hba_resp_task_complete(struct aac_dev *dev,
+                                       struct scsi_cmnd *scsicmd,
+                                       struct aac_hba_resp *err) {
+
+       scsicmd->result = err->status;
+       /* set residual count */
+       scsi_set_resid(scsicmd, le32_to_cpu(err->residual_count));
+
+       switch (err->status) {
+       case SAM_STAT_GOOD:
+               scsicmd->result |= DID_OK << 16 | COMMAND_COMPLETE << 8;
+               break;
+       case SAM_STAT_CHECK_CONDITION:
+       {
+               int len;
+
+               len = min_t(u8, err->sense_response_data_len,
+                       SCSI_SENSE_BUFFERSIZE);
+               if (len)
+                       memcpy(scsicmd->sense_buffer,
+                               err->sense_response_buf, len);
+               scsicmd->result |= DID_OK << 16 | COMMAND_COMPLETE << 8;
+               break;
+       }
+       case SAM_STAT_BUSY:
+               scsicmd->result |= DID_BUS_BUSY << 16 | COMMAND_COMPLETE << 8;
+               break;
+       case SAM_STAT_TASK_ABORTED:
+               scsicmd->result |= DID_ABORT << 16 | ABORT << 8;
+               break;
+       case SAM_STAT_RESERVATION_CONFLICT:
+       case SAM_STAT_TASK_SET_FULL:
+       default:
+               scsicmd->result |= DID_ERROR << 16 | COMMAND_COMPLETE << 8;
+               break;
+       }
+}
+
+static void hba_resp_task_failure(struct aac_dev *dev,
+                                       struct scsi_cmnd *scsicmd,
+                                       struct aac_hba_resp *err)
+{
+       switch (err->status) {
+       case HBA_RESP_STAT_HBAMODE_DISABLED:
+       {
+               u32 bus, cid;
+
+               bus = aac_logical_to_phys(scmd_channel(scsicmd));
+               cid = scmd_id(scsicmd);
+               if (dev->hba_map[bus][cid].devtype == AAC_DEVTYPE_NATIVE_RAW) {
+                       dev->hba_map[bus][cid].devtype = AAC_DEVTYPE_ARC_RAW;
+                       dev->hba_map[bus][cid].rmw_nexus = 0xffffffff;
+               }
+               scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8;
+               break;
+       }
+       case HBA_RESP_STAT_IO_ERROR:
+       case HBA_RESP_STAT_NO_PATH_TO_DEVICE:
+               scsicmd->result = DID_OK << 16 |
+                       COMMAND_COMPLETE << 8 | SAM_STAT_BUSY;
+               break;
+       case HBA_RESP_STAT_IO_ABORTED:
+               scsicmd->result = DID_ABORT << 16 | ABORT << 8;
+               break;
+       case HBA_RESP_STAT_INVALID_DEVICE:
+               scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8;
+               break;
+       case HBA_RESP_STAT_UNDERRUN:
+               /* UNDERRUN is OK */
+               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+               break;
+       case HBA_RESP_STAT_OVERRUN:
+       default:
+               scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8;
+               break;
+       }
+}
+
+/**
+ *
+ * aac_hba_callback
+ * @context: the context set in the fib - here it is scsi cmd
+ * @fibptr: pointer to the fib
+ *
+ * Handles the completion of a native HBA scsi command
+ *
+ */
+void aac_hba_callback(void *context, struct fib *fibptr)
+{
+       struct aac_dev *dev;
+       struct scsi_cmnd *scsicmd;
+
+       struct aac_hba_resp *err =
+                       &((struct aac_native_hba *)fibptr->hw_fib_va)->resp.err;
+
+       scsicmd = (struct scsi_cmnd *) context;
+
+       if (!aac_valid_context(scsicmd, fibptr))
+               return;
+
+       WARN_ON(fibptr == NULL);
+       dev = fibptr->dev;
+
+       if (!(fibptr->flags & FIB_CONTEXT_FLAG_NATIVE_HBA_TMF))
+               scsi_dma_unmap(scsicmd);
+
+       if (fibptr->flags & FIB_CONTEXT_FLAG_FASTRESP) {
+               /* fast response */
+               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+               goto out;
+       }
+
+       switch (err->service_response) {
+       case HBA_RESP_SVCRES_TASK_COMPLETE:
+               hba_resp_task_complete(dev, scsicmd, err);
+               break;
+       case HBA_RESP_SVCRES_FAILURE:
+               hba_resp_task_failure(dev, scsicmd, err);
+               break;
+       case HBA_RESP_SVCRES_TMF_REJECTED:
+               scsicmd->result = DID_ERROR << 16 | MESSAGE_REJECT << 8;
+               break;
+       case HBA_RESP_SVCRES_TMF_LUN_INVALID:
+               scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8;
+               break;
+       case HBA_RESP_SVCRES_TMF_COMPLETE:
+       case HBA_RESP_SVCRES_TMF_SUCCEEDED:
+               scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+               break;
+       default:
+               scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8;
+               break;
+       }
+
+out:
+       aac_fib_complete(fibptr);
+
+       if (fibptr->flags & FIB_CONTEXT_FLAG_NATIVE_HBA_TMF)
+               scsicmd->SCp.sent_command = 1;
+       else
+               scsicmd->scsi_done(scsicmd);
+}
+
 /**
  *
- * aac_send_scb_fib
+ * aac_send_srb_fib
  * @scsicmd: the scsi command block
  *
  * This routine will form a FIB and fill in the aac_srb from the
@@ -3182,6 +3701,54 @@ static int aac_send_srb_fib(struct scsi_cmnd* scsicmd)
        return -1;
 }
 
+/**
+ *
+ * aac_send_hba_fib
+ * @scsicmd: the scsi command block
+ *
+ * This routine will form a FIB and fill in the aac_hba_cmd_req from the
+ * scsicmd passed in.
+ */
+static int aac_send_hba_fib(struct scsi_cmnd *scsicmd)
+{
+       struct fib *cmd_fibcontext;
+       struct aac_dev *dev;
+       int status;
+
+       dev = shost_priv(scsicmd->device->host);
+       if (scmd_id(scsicmd) >= dev->maximum_num_physicals ||
+                       scsicmd->device->lun > AAC_MAX_LUN - 1) {
+               scsicmd->result = DID_NO_CONNECT << 16;
+               scsicmd->scsi_done(scsicmd);
+               return 0;
+       }
+
+       /*
+        *      Allocate and initialize a Fib then setup a BlockWrite command
+        */
+       cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd);
+       if (!cmd_fibcontext)
+               return -1;
+
+       status = aac_adapter_hba(cmd_fibcontext, scsicmd);
+
+       /*
+        *      Check that the command queued to the controller
+        */
+       if (status == -EINPROGRESS) {
+               scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+               return 0;
+       }
+
+       pr_warn("aac_hba_cmd_req: aac_fib_send failed with status: %d\n",
+               status);
+       aac_fib_complete(cmd_fibcontext);
+       aac_fib_free(cmd_fibcontext);
+
+       return -1;
+}
+
+
 static long aac_build_sg(struct scsi_cmnd *scsicmd, struct sgmap *psg)
 {
        struct aac_dev *dev;
@@ -3434,6 +4001,75 @@ static int aac_convert_sgraw2(struct aac_raw_io2 *rio2, int pages, int nseg, int
        return 0;
 }
 
+static long aac_build_sghba(struct scsi_cmnd *scsicmd,
+                       struct aac_hba_cmd_req *hbacmd,
+                       int sg_max,
+                       u64 sg_address)
+{
+       unsigned long byte_count = 0;
+       int nseg;
+       struct scatterlist *sg;
+       int i;
+       u32 cur_size;
+       struct aac_hba_sgl *sge;
+
+       nseg = scsi_dma_map(scsicmd);
+       if (nseg <= 0) {
+               byte_count = nseg;
+               goto out;
+       }
+
+       if (nseg > HBA_MAX_SG_EMBEDDED)
+               sge = &hbacmd->sge[2];
+       else
+               sge = &hbacmd->sge[0];
+
+       scsi_for_each_sg(scsicmd, sg, nseg, i) {
+               int count = sg_dma_len(sg);
+               u64 addr = sg_dma_address(sg);
+
+               WARN_ON(i >= sg_max);
+               sge->addr_hi = cpu_to_le32((u32)(addr>>32));
+               sge->addr_lo = cpu_to_le32((u32)(addr & 0xffffffff));
+               cur_size = cpu_to_le32(count);
+               sge->len = cur_size;
+               sge->flags = 0;
+               byte_count += count;
+               sge++;
+       }
+
+       sge--;
+       /* hba wants the size to be exact */
+       if (byte_count > scsi_bufflen(scsicmd)) {
+               u32 temp;
+
+               temp = le32_to_cpu(sge->len) - byte_count
+                                               - scsi_bufflen(scsicmd);
+               sge->len = cpu_to_le32(temp);
+               byte_count = scsi_bufflen(scsicmd);
+       }
+
+       if (nseg <= HBA_MAX_SG_EMBEDDED) {
+               hbacmd->emb_data_desc_count = cpu_to_le32(nseg);
+               sge->flags = cpu_to_le32(0x40000000);
+       } else {
+               /* not embedded */
+               hbacmd->sge[0].flags = cpu_to_le32(0x80000000);
+               hbacmd->emb_data_desc_count = (u8)cpu_to_le32(1);
+               hbacmd->sge[0].addr_hi = (u32)cpu_to_le32(sg_address >> 32);
+               hbacmd->sge[0].addr_lo =
+                       cpu_to_le32((u32)(sg_address & 0xffffffff));
+       }
+
+       /* Check for command underflow */
+       if (scsicmd->underflow && (byte_count < scsicmd->underflow)) {
+               pr_warn("aacraid: cmd len %08lX cmd underflow %08X\n",
+                               byte_count, scsicmd->underflow);
+       }
+out:
+       return byte_count;
+}
+
 #ifdef AAC_DETAILED_STATUS_INFO
 
 struct aac_srb_status_info {
index f059c14efa0c7cb0c094451ef13e41a0f6d6bee4..f2344971e3cbe3edbe56bf2086d8542ef2bab371 100644 (file)
@@ -1,3 +1,37 @@
+/*
+ *     Adaptec AAC series RAID controller driver
+ *     (c) Copyright 2001 Red Hat Inc. <alan@redhat.com>
+ *
+ * based on the old aacraid driver that is..
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000-2010 Adaptec, Inc.
+ *               2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
+ *              2016-2017 Microsemi Corp. (aacraid@microsemi.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, 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; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *  aacraid.h
+ *
+ * Abstract: Contains all routines for control of the aacraid driver
+ *
+ */
+
+#ifndef _AACRAID_H_
+#define _AACRAID_H_
 #ifndef dprintk
 # define dprintk(x)
 #endif
@@ -63,8 +97,8 @@ enum {
 #define        PMC_GLOBAL_INT_BIT0             0x00000001
 
 #ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 41066
-# define AAC_DRIVER_BRANCH "-ms"
+# define AAC_DRIVER_BUILD 50740
+# define AAC_DRIVER_BRANCH "-custom"
 #endif
 #define MAXIMUM_NUM_CONTAINERS 32
 
@@ -72,13 +106,311 @@ enum {
 #define AAC_NUM_IO_FIB         (1024 - AAC_NUM_MGT_FIB)
 #define AAC_NUM_FIB            (AAC_NUM_IO_FIB + AAC_NUM_MGT_FIB)
 
-#define AAC_MAX_LUN            (8)
+#define AAC_MAX_LUN            256
 
 #define AAC_MAX_HOSTPHYSMEMPAGES (0xfffff)
 #define AAC_MAX_32BIT_SGBCOUNT ((unsigned short)256)
 
 #define AAC_DEBUG_INSTRUMENT_AIF_DELETE
 
+#define AAC_MAX_NATIVE_TARGETS         1024
+/* Thor: 5 phys. buses: #0: empty, 1-4: 256 targets each */
+#define AAC_MAX_BUSES                  5
+#define AAC_MAX_TARGETS                256
+#define AAC_MAX_NATIVE_SIZE            2048
+#define FW_ERROR_BUFFER_SIZE           512
+
+/* Thor AIF events */
+#define SA_AIF_HOTPLUG                 (1<<1)
+#define SA_AIF_HARDWARE                (1<<2)
+#define SA_AIF_PDEV_CHANGE             (1<<4)
+#define SA_AIF_LDEV_CHANGE             (1<<5)
+#define SA_AIF_BPSTAT_CHANGE           (1<<30)
+#define SA_AIF_BPCFG_CHANGE            (1<<31)
+
+#define HBA_MAX_SG_EMBEDDED            28
+#define HBA_MAX_SG_SEPARATE            90
+#define HBA_SENSE_DATA_LEN_MAX         32
+#define HBA_REQUEST_TAG_ERROR_FLAG     0x00000002
+#define HBA_SGL_FLAGS_EXT              0x80000000UL
+
+struct aac_hba_sgl {
+       u32             addr_lo; /* Lower 32-bits of SGL element address */
+       u32             addr_hi; /* Upper 32-bits of SGL element address */
+       u32             len;    /* Length of SGL element in bytes */
+       u32             flags;  /* SGL element flags */
+};
+
+enum {
+       HBA_IU_TYPE_SCSI_CMD_REQ                = 0x40,
+       HBA_IU_TYPE_SCSI_TM_REQ                 = 0x41,
+       HBA_IU_TYPE_SATA_REQ                    = 0x42,
+       HBA_IU_TYPE_RESP                        = 0x60,
+       HBA_IU_TYPE_COALESCED_RESP              = 0x61,
+       HBA_IU_TYPE_INT_COALESCING_CFG_REQ      = 0x70
+};
+
+enum {
+       HBA_CMD_BYTE1_DATA_DIR_IN               = 0x1,
+       HBA_CMD_BYTE1_DATA_DIR_OUT              = 0x2,
+       HBA_CMD_BYTE1_DATA_TYPE_DDR             = 0x4,
+       HBA_CMD_BYTE1_CRYPTO_ENABLE             = 0x8
+};
+
+enum {
+       HBA_CMD_BYTE1_BITOFF_DATA_DIR_IN        = 0x0,
+       HBA_CMD_BYTE1_BITOFF_DATA_DIR_OUT,
+       HBA_CMD_BYTE1_BITOFF_DATA_TYPE_DDR,
+       HBA_CMD_BYTE1_BITOFF_CRYPTO_ENABLE
+};
+
+enum {
+       HBA_RESP_DATAPRES_NO_DATA               = 0x0,
+       HBA_RESP_DATAPRES_RESPONSE_DATA,
+       HBA_RESP_DATAPRES_SENSE_DATA
+};
+
+enum {
+       HBA_RESP_SVCRES_TASK_COMPLETE           = 0x0,
+       HBA_RESP_SVCRES_FAILURE,
+       HBA_RESP_SVCRES_TMF_COMPLETE,
+       HBA_RESP_SVCRES_TMF_SUCCEEDED,
+       HBA_RESP_SVCRES_TMF_REJECTED,
+       HBA_RESP_SVCRES_TMF_LUN_INVALID
+};
+
+enum {
+       HBA_RESP_STAT_IO_ERROR                  = 0x1,
+       HBA_RESP_STAT_IO_ABORTED,
+       HBA_RESP_STAT_NO_PATH_TO_DEVICE,
+       HBA_RESP_STAT_INVALID_DEVICE,
+       HBA_RESP_STAT_HBAMODE_DISABLED          = 0xE,
+       HBA_RESP_STAT_UNDERRUN                  = 0x51,
+       HBA_RESP_STAT_OVERRUN                   = 0x75
+};
+
+struct aac_hba_cmd_req {
+       u8      iu_type;        /* HBA information unit type */
+       /*
+        * byte1:
+        * [1:0] DIR - 0=No data, 0x1 = IN, 0x2 = OUT
+        * [2]   TYPE - 0=PCI, 1=DDR
+        * [3]   CRYPTO_ENABLE - 0=Crypto disabled, 1=Crypto enabled
+        */
+       u8      byte1;
+       u8      reply_qid;      /* Host reply queue to post response to */
+       u8      reserved1;
+       __le32  it_nexus;       /* Device handle for the request */
+       __le32  request_id;     /* Sender context */
+       /* Lower 32-bits of tweak value for crypto enabled IOs */
+       __le32  tweak_value_lo;
+       u8      cdb[16];        /* SCSI CDB of the command */
+       u8      lun[8];         /* SCSI LUN of the command */
+
+       /* Total data length in bytes to be read/written (if any) */
+       __le32  data_length;
+
+       /* [2:0] Task Attribute, [6:3] Command Priority */
+       u8      attr_prio;
+
+       /* Number of SGL elements embedded in the HBA req */
+       u8      emb_data_desc_count;
+
+       __le16  dek_index;      /* DEK index for crypto enabled IOs */
+
+       /* Lower 32-bits of reserved error data target location on the host */
+       __le32  error_ptr_lo;
+
+       /* Upper 32-bits of reserved error data target location on the host */
+       __le32  error_ptr_hi;
+
+       /* Length of reserved error data area on the host in bytes */
+       __le32  error_length;
+
+       /* Upper 32-bits of tweak value for crypto enabled IOs */
+       __le32  tweak_value_hi;
+
+       struct aac_hba_sgl sge[HBA_MAX_SG_SEPARATE+2]; /* SG list space */
+
+       /*
+        * structure must not exceed
+        * AAC_MAX_NATIVE_SIZE-FW_ERROR_BUFFER_SIZE
+        */
+};
+
+/* Task Management Functions (TMF) */
+#define HBA_TMF_ABORT_TASK     0x01
+#define HBA_TMF_LUN_RESET      0x08
+
+struct aac_hba_tm_req {
+       u8      iu_type;        /* HBA information unit type */
+       u8      reply_qid;      /* Host reply queue to post response to */
+       u8      tmf;            /* Task management function */
+       u8      reserved1;
+
+       __le32  it_nexus;       /* Device handle for the command */
+
+       u8      lun[8];         /* SCSI LUN */
+
+       /* Used to hold sender context. */
+       __le32  request_id;     /* Sender context */
+       __le32  reserved2;
+
+       /* Request identifier of managed task */
+       __le32  managed_request_id;     /* Sender context being managed */
+       __le32  reserved3;
+
+       /* Lower 32-bits of reserved error data target location on the host */
+       __le32  error_ptr_lo;
+       /* Upper 32-bits of reserved error data target location on the host */
+       __le32  error_ptr_hi;
+       /* Length of reserved error data area on the host in bytes */
+       __le32  error_length;
+};
+
+struct aac_hba_reset_req {
+       u8      iu_type;        /* HBA information unit type */
+       /* 0 - reset specified device, 1 - reset all devices */
+       u8      reset_type;
+       u8      reply_qid;      /* Host reply queue to post response to */
+       u8      reserved1;
+
+       __le32  it_nexus;       /* Device handle for the command */
+       __le32  request_id;     /* Sender context */
+       /* Lower 32-bits of reserved error data target location on the host */
+       __le32  error_ptr_lo;
+       /* Upper 32-bits of reserved error data target location on the host */
+       __le32  error_ptr_hi;
+       /* Length of reserved error data area on the host in bytes */
+       __le32  error_length;
+};
+
+struct aac_hba_resp {
+       u8      iu_type;                /* HBA information unit type */
+       u8      reserved1[3];
+       __le32  request_identifier;     /* sender context */
+       __le32  reserved2;
+       u8      service_response;       /* SCSI service response */
+       u8      status;                 /* SCSI status */
+       u8      datapres;       /* [1:0] - data present, [7:2] - reserved */
+       u8      sense_response_data_len;        /* Sense/response data length */
+       __le32  residual_count;         /* Residual data length in bytes */
+       /* Sense/response data */
+       u8      sense_response_buf[HBA_SENSE_DATA_LEN_MAX];
+};
+
+struct aac_native_hba {
+       union {
+               struct aac_hba_cmd_req cmd;
+               struct aac_hba_tm_req tmr;
+               u8 cmd_bytes[AAC_MAX_NATIVE_SIZE-FW_ERROR_BUFFER_SIZE];
+       } cmd;
+       union {
+               struct aac_hba_resp err;
+               u8 resp_bytes[FW_ERROR_BUFFER_SIZE];
+       } resp;
+};
+
+#define CISS_REPORT_PHYSICAL_LUNS      0xc3
+#define WRITE_HOST_WELLNESS            0xa5
+#define CISS_IDENTIFY_PHYSICAL_DEVICE  0x15
+#define BMIC_IN                        0x26
+#define BMIC_OUT                       0x27
+
+struct aac_ciss_phys_luns_resp {
+       u8      list_length[4];         /* LUN list length (N-7, big endian) */
+       u8      resp_flag;              /* extended response_flag */
+       u8      reserved[3];
+       struct _ciss_lun {
+               u8      tid[3];         /* Target ID */
+               u8      bus;            /* Bus, flag (bits 6,7) */
+               u8      level3[2];
+               u8      level2[2];
+               u8      node_ident[16]; /* phys. node identifier */
+       } lun[1];                       /* List of phys. devices */
+};
+
+/*
+ * Interrupts
+ */
+#define AAC_MAX_HRRQ           64
+
+struct aac_ciss_identify_pd {
+       u8 scsi_bus;                    /* SCSI Bus number on controller */
+       u8 scsi_id;                     /* SCSI ID on this bus */
+       u16 block_size;                 /* sector size in bytes */
+       u32 total_blocks;               /* number for sectors on drive */
+       u32 reserved_blocks;            /* controller reserved (RIS) */
+       u8 model[40];                   /* Physical Drive Model */
+       u8 serial_number[40];           /* Drive Serial Number */
+       u8 firmware_revision[8];        /* drive firmware revision */
+       u8 scsi_inquiry_bits;           /* inquiry byte 7 bits */
+       u8 compaq_drive_stamp;          /* 0 means drive not stamped */
+       u8 last_failure_reason;
+
+       u8  flags;
+       u8  more_flags;
+       u8  scsi_lun;                   /* SCSI LUN for phys drive */
+       u8  yet_more_flags;
+       u8  even_more_flags;
+       u32 spi_speed_rules;            /* SPI Speed :Ultra disable diagnose */
+       u8  phys_connector[2];          /* connector number on controller */
+       u8  phys_box_on_bus;            /* phys enclosure this drive resides */
+       u8  phys_bay_in_box;            /* phys drv bay this drive resides */
+       u32 rpm;                        /* Drive rotational speed in rpm */
+       u8  device_type;                /* type of drive */
+       u8  sata_version;               /* only valid when drive_type is SATA */
+       u64 big_total_block_count;
+       u64 ris_starting_lba;
+       u32 ris_size;
+       u8  wwid[20];
+       u8  controller_phy_map[32];
+       u16 phy_count;
+       u8  phy_connected_dev_type[256];
+       u8  phy_to_drive_bay_num[256];
+       u16 phy_to_attached_dev_index[256];
+       u8  box_index;
+       u8  spitfire_support;
+       u16 extra_physical_drive_flags;
+       u8  negotiated_link_rate[256];
+       u8  phy_to_phy_map[256];
+       u8  redundant_path_present_map;
+       u8  redundant_path_failure_map;
+       u8  active_path_number;
+       u16 alternate_paths_phys_connector[8];
+       u8  alternate_paths_phys_box_on_port[8];
+       u8  multi_lun_device_lun_count;
+       u8  minimum_good_fw_revision[8];
+       u8  unique_inquiry_bytes[20];
+       u8  current_temperature_degreesC;
+       u8  temperature_threshold_degreesC;
+       u8  max_temperature_degreesC;
+       u8  logical_blocks_per_phys_block_exp;  /* phyblocksize = 512 * 2^exp */
+       u16 current_queue_depth_limit;
+       u8  switch_name[10];
+       u16 switch_port;
+       u8  alternate_paths_switch_name[40];
+       u8  alternate_paths_switch_port[8];
+       u16 power_on_hours;             /* valid only if gas gauge supported */
+       u16 percent_endurance_used;     /* valid only if gas gauge supported. */
+       u8  drive_authentication;
+       u8  smart_carrier_authentication;
+       u8  smart_carrier_app_fw_version;
+       u8  smart_carrier_bootloader_fw_version;
+       u8  SanitizeSecureEraseSupport;
+       u8  DriveKeyFlags;
+       u8  encryption_key_name[64];
+       u32 misc_drive_flags;
+       u16 dek_index;
+       u16 drive_encryption_flags;
+       u8  sanitize_maximum_time[6];
+       u8  connector_info_mode;
+       u8  connector_info_number[4];
+       u8  long_connector_name[64];
+       u8  device_unique_identifier[16];
+       u8  padto_2K[17];
+} __packed;
+
 /*
  * These macros convert from physical channels to virtual channels
  */
@@ -86,6 +418,7 @@ enum {
 #define CONTAINER_TO_CHANNEL(cont)     (CONTAINER_CHANNEL)
 #define CONTAINER_TO_ID(cont)          (cont)
 #define CONTAINER_TO_LUN(cont)         (0)
+#define ENCLOSURE_CHANNEL              (3)
 
 #define PMC_DEVICE_S6  0x28b
 #define PMC_DEVICE_S7  0x28c
@@ -351,10 +684,10 @@ enum aac_queue_types {
 
 /* transport FIB header (PMC) */
 struct aac_fib_xporthdr {
-       u64     HostAddress;    /* FIB host address w/o xport header */
-       u32     Size;           /* FIB size excluding xport header */
-       u32     Handle;         /* driver handle to reference the FIB */
-       u64     Reserved[2];
+       __le64  HostAddress;    /* FIB host address w/o xport header */
+       __le32  Size;           /* FIB size excluding xport header */
+       __le32  Handle;         /* driver handle to reference the FIB */
+       __le64  Reserved[2];
 };
 
 #define                ALIGN32         32
@@ -379,7 +712,7 @@ struct aac_fibhdr {
                __le32 SenderFibAddressHigh;/* upper 32bit of phys. FIB address */
                __le32 TimeStamp;       /* otherwise timestamp for FW internal use */
        } u;
-       u32 Handle;             /* FIB handle used for MSGU commnunication */
+       __le32 Handle;          /* FIB handle used for MSGU commnunication */
        u32 Previous;           /* FW internal use */
        u32 Next;               /* FW internal use */
 };
@@ -489,41 +822,64 @@ enum fib_xfer_state {
 #define ADAPTER_INIT_STRUCT_REVISION_4         4 // rocket science
 #define ADAPTER_INIT_STRUCT_REVISION_6         6 /* PMC src */
 #define ADAPTER_INIT_STRUCT_REVISION_7         7 /* Denali */
+#define ADAPTER_INIT_STRUCT_REVISION_8         8 // Thor
 
-struct aac_init
+union aac_init
 {
-       __le32  InitStructRevision;
-       __le32  Sa_MSIXVectors;
-       __le32  fsrev;
-       __le32  CommHeaderAddress;
-       __le32  FastIoCommAreaAddress;
-       __le32  AdapterFibsPhysicalAddress;
-       __le32  AdapterFibsVirtualAddress;
-       __le32  AdapterFibsSize;
-       __le32  AdapterFibAlign;
-       __le32  printfbuf;
-       __le32  printfbufsiz;
-       __le32  HostPhysMemPages;   /* number of 4k pages of host
-                                      physical memory */
-       __le32  HostElapsedSeconds; /* number of seconds since 1970. */
-       /*
-        * ADAPTER_INIT_STRUCT_REVISION_4 begins here
-        */
-       __le32  InitFlags;      /* flags for supported features */
+       struct _r7 {
+               __le32  init_struct_revision;
+               __le32  no_of_msix_vectors;
+               __le32  fsrev;
+               __le32  comm_header_address;
+               __le32  fast_io_comm_area_address;
+               __le32  adapter_fibs_physical_address;
+               __le32  adapter_fibs_virtual_address;
+               __le32  adapter_fibs_size;
+               __le32  adapter_fib_align;
+               __le32  printfbuf;
+               __le32  printfbufsiz;
+               /* number of 4k pages of host phys. mem. */
+               __le32  host_phys_mem_pages;
+               /* number of seconds since 1970. */
+               __le32  host_elapsed_seconds;
+               /* ADAPTER_INIT_STRUCT_REVISION_4 begins here */
+               __le32  init_flags;     /* flags for supported features */
 #define INITFLAGS_NEW_COMM_SUPPORTED   0x00000001
 #define INITFLAGS_DRIVER_USES_UTC_TIME 0x00000010
 #define INITFLAGS_DRIVER_SUPPORTS_PM   0x00000020
 #define INITFLAGS_NEW_COMM_TYPE1_SUPPORTED     0x00000040
 #define INITFLAGS_FAST_JBOD_SUPPORTED  0x00000080
 #define INITFLAGS_NEW_COMM_TYPE2_SUPPORTED     0x00000100
-       __le32  MaxIoCommands;  /* max outstanding commands */
-       __le32  MaxIoSize;      /* largest I/O command */
-       __le32  MaxFibSize;     /* largest FIB to adapter */
-       /* ADAPTER_INIT_STRUCT_REVISION_5 begins here */
-       __le32  MaxNumAif;      /* max number of aif */
-       /* ADAPTER_INIT_STRUCT_REVISION_6 begins here */
-       __le32  HostRRQ_AddrLow;
-       __le32  HostRRQ_AddrHigh;       /* Host RRQ (response queue) for SRC */
+#define INITFLAGS_DRIVER_SUPPORTS_HBA_MODE  0x00000400
+               __le32  max_io_commands;        /* max outstanding commands */
+               __le32  max_io_size;    /* largest I/O command */
+               __le32  max_fib_size;   /* largest FIB to adapter */
+               /* ADAPTER_INIT_STRUCT_REVISION_5 begins here */
+               __le32  max_num_aif;    /* max number of aif */
+               /* ADAPTER_INIT_STRUCT_REVISION_6 begins here */
+               /* Host RRQ (response queue) for SRC */
+               __le32  host_rrq_addr_low;
+               __le32  host_rrq_addr_high;
+       } r7;
+       struct _r8 {
+               /* ADAPTER_INIT_STRUCT_REVISION_8 */
+               __le32  init_struct_revision;
+               __le32  rr_queue_count;
+               __le32  host_elapsed_seconds; /* number of secs since 1970. */
+               __le32  init_flags;
+               __le32  max_io_size;    /* largest I/O command */
+               __le32  max_num_aif;    /* max number of aif */
+               __le32  reserved1;
+               __le32  reserved2;
+               struct _rrq {
+                       __le32  host_addr_low;
+                       __le32  host_addr_high;
+                       __le16  msix_id;
+                       __le16  element_count;
+                       __le16  comp_thresh;
+                       __le16  unused;
+               } rrq[1];               /* up to 64 RRQ addresses */
+       } r8;
 };
 
 enum aac_log_level {
@@ -554,7 +910,7 @@ struct adapter_ops
        void (*adapter_enable_int)(struct aac_dev *dev);
        int  (*adapter_sync_cmd)(struct aac_dev *dev, u32 command, u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, u32 *status, u32 *r1, u32 *r2, u32 *r3, u32 *r4);
        int  (*adapter_check_health)(struct aac_dev *dev);
-       int  (*adapter_restart)(struct aac_dev *dev, int bled);
+       int  (*adapter_restart)(struct aac_dev *dev, int bled, u8 reset_type);
        void (*adapter_start)(struct aac_dev *dev);
        /* Transport operations */
        int  (*adapter_ioremap)(struct aac_dev * dev, u32 size);
@@ -727,6 +1083,7 @@ struct sa_registers {
 
 
 #define SA_INIT_NUM_MSIXVECTORS                1
+#define SA_MINIPORT_REVISION           SA_INIT_NUM_MSIXVECTORS
 
 #define sa_readw(AEP, CSR)             readl(&((AEP)->regs.sa->CSR))
 #define sa_readl(AEP, CSR)             readl(&((AEP)->regs.sa->CSR))
@@ -820,32 +1177,37 @@ struct rkt_registers {
 #define src_inbound rx_inbound
 
 struct src_mu_registers {
-                               /*      PCI*| Name */
-       __le32  reserved0[6];   /*      00h | Reserved */
-       __le32  IOAR[2];        /*      18h | IOA->host interrupt register */
-       __le32  IDR;            /*      20h | Inbound Doorbell Register */
-       __le32  IISR;           /*      24h | Inbound Int. Status Register */
-       __le32  reserved1[3];   /*      28h | Reserved */
-       __le32  OIMR;           /*      34h | Outbound Int. Mask Register */
-       __le32  reserved2[25];  /*      38h | Reserved */
-       __le32  ODR_R;          /*      9ch | Outbound Doorbell Read */
-       __le32  ODR_C;          /*      a0h | Outbound Doorbell Clear */
-       __le32  reserved3[6];   /*      a4h | Reserved */
-       __le32  OMR;            /*      bch | Outbound Message Register */
+                               /*  PCI*| Name */
+       __le32  reserved0[6];   /*  00h | Reserved */
+       __le32  IOAR[2];        /*  18h | IOA->host interrupt register */
+       __le32  IDR;            /*  20h | Inbound Doorbell Register */
+       __le32  IISR;           /*  24h | Inbound Int. Status Register */
+       __le32  reserved1[3];   /*  28h | Reserved */
+       __le32  OIMR;           /*  34h | Outbound Int. Mask Register */
+       __le32  reserved2[25];  /*  38h | Reserved */
+       __le32  ODR_R;          /*  9ch | Outbound Doorbell Read */
+       __le32  ODR_C;          /*  a0h | Outbound Doorbell Clear */
+       __le32  reserved3[3];   /*  a4h | Reserved */
+       __le32  SCR0;           /*  b0h | Scratchpad 0 */
+       __le32  reserved4[2];   /*  b4h | Reserved */
+       __le32  OMR;            /*  bch | Outbound Message Register */
        __le32  IQ_L;           /*  c0h | Inbound Queue (Low address) */
        __le32  IQ_H;           /*  c4h | Inbound Queue (High address) */
        __le32  ODR_MSI;        /*  c8h | MSI register for sync./AIF */
+       __le32  reserved5;      /*  cch | Reserved */
+       __le32  IQN_L;          /*  d0h | Inbound (native cmd) low  */
+       __le32  IQN_H;          /*  d4h | Inbound (native cmd) high */
 };
 
 struct src_registers {
        struct src_mu_registers MUnit;  /* 00h - cbh */
        union {
                struct {
-                       __le32 reserved1[130789];       /* cch - 7fc5fh */
+                       __le32 reserved1[130786];       /* d8h - 7fc5fh */
                        struct src_inbound IndexRegs;   /* 7fc60h */
                } tupelo;
                struct {
-                       __le32 reserved1[973];          /* cch - fffh */
+                       __le32 reserved1[970];          /* d8h - fffh */
                        struct src_inbound IndexRegs;   /* 1000h */
                } denali;
        } u;
@@ -930,6 +1292,7 @@ struct fsa_dev_info {
        char            devname[8];
        struct sense_data sense_data;
        u32             block_size;
+       u8              identifier[16];
 };
 
 struct fib {
@@ -958,8 +1321,30 @@ struct fib {
        struct list_head        fiblink;
        void                    *data;
        u32                     vector_no;
-       struct hw_fib           *hw_fib_va;             /* Actual shared object */
-       dma_addr_t              hw_fib_pa;              /* physical address of hw_fib*/
+       struct hw_fib           *hw_fib_va;     /* also used for native */
+       dma_addr_t              hw_fib_pa;      /* physical address of hw_fib*/
+       dma_addr_t              hw_sgl_pa;      /* extra sgl for native */
+       dma_addr_t              hw_error_pa;    /* error buffer for native */
+       u32                     hbacmd_size;    /* cmd size for native */
+};
+
+#define AAC_INIT                       0
+#define AAC_RESCAN                     1
+
+#define AAC_DEVTYPE_RAID_MEMBER        1
+#define AAC_DEVTYPE_ARC_RAW            2
+#define AAC_DEVTYPE_NATIVE_RAW         3
+#define AAC_EXPOSE_DISK                0
+#define AAC_HIDE_DISK                  3
+
+struct aac_hba_map_info {
+       __le32  rmw_nexus;              /* nexus for native HBA devices */
+       u8              devtype;        /* device type */
+       u8              new_devtype;
+       u8              reset_state;    /* 0 - no reset, 1..x - */
+                                       /* after xth TM LUN reset */
+       u16             qd_limit;
+       u8              expose;         /*checks if to expose or not*/
 };
 
 /*
@@ -1025,7 +1410,28 @@ struct aac_supplement_adapter_info
        /* StructExpansion == 1 */
        __le32  FeatureBits3;
        __le32  SupportedPerformanceModes;
-       __le32  ReservedForFutureGrowth[80];
+       u8      HostBusType;            /* uses HOST_BUS_TYPE_xxx defines */
+       u8      HostBusWidth;           /* actual width in bits or links */
+       u16     HostBusSpeed;           /* actual bus speed/link rate in MHz */
+       u8      MaxRRCDrives;           /* max. number of ITP-RRC drives/pool */
+       u8      MaxDiskXtasks;          /* max. possible num of DiskX Tasks */
+
+       u8      CpldVerLoaded;
+       u8      CpldVerInFlash;
+
+       __le64  MaxRRCCapacity;
+       __le32  CompiledMaxHistLogLevel;
+       u8      CustomBoardName[12];
+       u16     SupportedCntlrMode;     /* identify supported controller mode */
+       u16     ReservedForFuture16;
+       __le32  SupportedOptions3;      /* reserved for future options */
+
+       __le16  VirtDeviceBus;          /* virt. SCSI device for Thor */
+       __le16  VirtDeviceTarget;
+       __le16  VirtDeviceLUN;
+       __le16  Unused;
+       __le32  ReservedForFutureGrowth[68];
+
 };
 #define AAC_FEATURE_FALCON     cpu_to_le32(0x00000010)
 #define AAC_FEATURE_JBOD       cpu_to_le32(0x08000000)
@@ -1099,11 +1505,21 @@ struct aac_bus_info_response {
 #define AAC_OPT_SUPPLEMENT_ADAPTER_INFO        cpu_to_le32(1<<16)
 #define AAC_OPT_NEW_COMM               cpu_to_le32(1<<17)
 #define AAC_OPT_NEW_COMM_64            cpu_to_le32(1<<18)
+#define AAC_OPT_EXTENDED               cpu_to_le32(1<<23)
+#define AAC_OPT_NATIVE_HBA             cpu_to_le32(1<<25)
 #define AAC_OPT_NEW_COMM_TYPE1         cpu_to_le32(1<<28)
 #define AAC_OPT_NEW_COMM_TYPE2         cpu_to_le32(1<<29)
 #define AAC_OPT_NEW_COMM_TYPE3         cpu_to_le32(1<<30)
 #define AAC_OPT_NEW_COMM_TYPE4         cpu_to_le32(1<<31)
 
+#define AAC_COMM_PRODUCER              0
+#define AAC_COMM_MESSAGE               1
+#define AAC_COMM_MESSAGE_TYPE1         3
+#define AAC_COMM_MESSAGE_TYPE2         4
+#define AAC_COMM_MESSAGE_TYPE3         5
+
+#define AAC_EXTOPT_SA_FIRMWARE         cpu_to_le32(1<<1)
+
 /* MSIX context */
 struct aac_msix_ctx {
        int             vector_no;
@@ -1119,15 +1535,17 @@ struct aac_dev
        /*
         *      negotiated FIB settings
         */
-       unsigned                max_fib_size;
-       unsigned                sg_tablesize;
-       unsigned                max_num_aif;
+       unsigned int            max_fib_size;
+       unsigned int            sg_tablesize;
+       unsigned int            max_num_aif;
+
+       unsigned int            max_cmd_size;   /* max_fib_size or MAX_NATIVE */
 
        /*
         *      Map for 128 fib objects (64k)
         */
-       dma_addr_t              hw_fib_pa;
-       struct hw_fib           *hw_fib_va;
+       dma_addr_t              hw_fib_pa;      /* also used for native cmd */
+       struct hw_fib           *hw_fib_va;     /* also used for native cmd */
        struct hw_fib           *aif_base_va;
        /*
         *      Fib Headers
@@ -1157,21 +1575,23 @@ struct aac_dev
 
        resource_size_t         base_size, dbg_size;    /* Size of
                                                         *  mapped in region */
-
-       struct aac_init         *init;          /* Holds initialization info to communicate with adapter */
+       /*
+        * Holds initialization info
+        * to communicate with adapter
+        */
+       union aac_init          *init;
        dma_addr_t              init_pa;        /* Holds physical address of the init struct */
-
-       u32                     *host_rrq;      /* response queue
-                                                * if AAC_COMM_MESSAGE_TYPE1 */
-
+       /* response queue (if AAC_COMM_MESSAGE_TYPE1) */
+       __le32                  *host_rrq;
        dma_addr_t              host_rrq_pa;    /* phys. address */
        /* index into rrq buffer */
        u32                     host_rrq_idx[AAC_MAX_MSIX];
        atomic_t                rrq_outstanding[AAC_MAX_MSIX];
        u32                     fibs_pushed_no;
        struct pci_dev          *pdev;          /* Our PCI interface */
-       void *                  printfbuf;      /* pointer to buffer used for printf's from the adapter */
-       void *                  comm_addr;      /* Base address of Comm area */
+       /* pointer to buffer used for printf's from the adapter */
+       void                    *printfbuf;
+       void                    *comm_addr;     /* Base address of Comm area */
        dma_addr_t              comm_phys;      /* Physical Address of Comm area */
        size_t                  comm_size;
 
@@ -1227,15 +1647,12 @@ struct aac_dev
        u8                      needs_dac;
        u8                      raid_scsi_mode;
        u8                      comm_interface;
-#      define AAC_COMM_PRODUCER 0
-#      define AAC_COMM_MESSAGE  1
-#      define AAC_COMM_MESSAGE_TYPE1   3
-#      define AAC_COMM_MESSAGE_TYPE2   4
        u8                      raw_io_interface;
        u8                      raw_io_64;
        u8                      printf_enabled;
        u8                      in_reset;
        u8                      msi;
+       u8                      sa_firmware;
        int                     management_fib_count;
        spinlock_t              manage_lock;
        spinlock_t              sync_lock;
@@ -1246,7 +1663,10 @@ struct aac_dev
        u32                     max_msix;       /* max. MSI-X vectors */
        u32                     vector_cap;     /* MSI-X vector capab.*/
        int                     msi_enabled;    /* MSI/MSI-X enabled */
+       atomic_t                msix_counter;
+       struct msix_entry       msixentry[AAC_MAX_MSIX];
        struct aac_msix_ctx     aac_msix[AAC_MAX_MSIX]; /* context */
+       struct aac_hba_map_info hba_map[AAC_MAX_BUSES][AAC_MAX_TARGETS];
        u8                      adapter_shutdown;
        u32                     handle_pci_error;
 };
@@ -1269,8 +1689,8 @@ struct aac_dev
 #define aac_adapter_check_health(dev) \
        (dev)->a_ops.adapter_check_health(dev)
 
-#define aac_adapter_restart(dev,bled) \
-       (dev)->a_ops.adapter_restart(dev,bled)
+#define aac_adapter_restart(dev, bled, reset_type) \
+       ((dev)->a_ops.adapter_restart(dev, bled, reset_type))
 
 #define aac_adapter_start(dev) \
        ((dev)->a_ops.adapter_start(dev))
@@ -1300,6 +1720,8 @@ struct aac_dev
 #define FIB_CONTEXT_FLAG                       (0x00000002)
 #define FIB_CONTEXT_FLAG_WAIT                  (0x00000004)
 #define FIB_CONTEXT_FLAG_FASTRESP              (0x00000008)
+#define FIB_CONTEXT_FLAG_NATIVE_HBA            (0x00000010)
+#define FIB_CONTEXT_FLAG_NATIVE_HBA_TMF        (0x00000020)
 
 /*
  *     Define the command values
@@ -1358,6 +1780,7 @@ struct aac_dev
 #define                ST_IO           5
 #define                ST_NXIO         6
 #define                ST_E2BIG        7
+#define                ST_MEDERR       8
 #define                ST_ACCES        13
 #define                ST_EXIST        17
 #define                ST_XDEV         18
@@ -1715,6 +2138,8 @@ struct aac_fsinfo {
 
 struct  aac_blockdevinfo {
        __le32  block_size;
+       __le32  logical_phys_map;
+       u8      identifier[16];
 };
 
 union aac_contentinfo {
@@ -1940,6 +2365,15 @@ struct revision
 #define FSACTL_FORCE_DELETE_DISK               CTL_CODE(2120, METHOD_NEITHER)
 #define FSACTL_GET_CONTAINERS                  2131
 #define FSACTL_SEND_LARGE_FIB                  CTL_CODE(2138, METHOD_BUFFERED)
+#define FSACTL_RESET_IOP                       CTL_CODE(2140, METHOD_BUFFERED)
+#define FSACTL_GET_HBA_INFO                    CTL_CODE(2150, METHOD_BUFFERED)
+/* flags defined for IOP & HW SOFT RESET */
+#define HW_IOP_RESET                           0x01
+#define HW_SOFT_RESET                          0x02
+#define IOP_HWSOFT_RESET                       (HW_IOP_RESET | HW_SOFT_RESET)
+/* HW Soft Reset register offset */
+#define IBW_SWR_OFFSET                         0x4000
+#define SOFT_RESET_TIME                        60
 
 
 struct aac_common
@@ -1958,6 +2392,8 @@ struct aac_common
 #ifdef DBG
        u32 FibsSent;
        u32 FibRecved;
+       u32 NativeSent;
+       u32 NativeRecved;
        u32 NoResponseSent;
        u32 NoResponseRecved;
        u32 AsyncSent;
@@ -1969,6 +2405,56 @@ struct aac_common
 
 extern struct aac_common aac_config;
 
+/*
+ * This is for management ioctl purpose only.
+ */
+struct aac_hba_info {
+
+       u8      driver_name[50];
+       u8      adapter_number;
+       u8      system_io_bus_number;
+       u8      device_number;
+       u32     function_number;
+       u32     vendor_id;
+       u32     device_id;
+       u32     sub_vendor_id;
+       u32     sub_system_id;
+       u32     mapped_base_address_size;
+       u32     base_physical_address_high_part;
+       u32     base_physical_address_low_part;
+
+       u32     max_command_size;
+       u32     max_fib_size;
+       u32     max_scatter_gather_from_os;
+       u32     max_scatter_gather_to_fw;
+       u32     max_outstanding_fibs;
+
+       u32     queue_start_threshold;
+       u32     queue_dump_threshold;
+       u32     max_io_size_queued;
+       u32     outstanding_io;
+
+       u32     firmware_build_number;
+       u32     bios_build_number;
+       u32     driver_build_number;
+       u32     serial_number_high_part;
+       u32     serial_number_low_part;
+       u32     supported_options;
+       u32     feature_bits;
+       u32     currentnumber_ports;
+
+       u8      new_comm_interface:1;
+       u8      new_commands_supported:1;
+       u8      disable_passthrough:1;
+       u8      expose_non_dasd:1;
+       u8      queue_allowed:1;
+       u8      bled_check_enabled:1;
+       u8      reserved1:1;
+       u8      reserted2:1;
+
+       u32     reserved3[10];
+
+};
 
 /*
  *     The following macro is used when sending and receiving FIBs. It is
@@ -2096,9 +2582,10 @@ extern struct aac_common aac_config;
 
 /* PMC NEW COMM: Request the event data */
 #define                AifReqEvent             200
+#define                AifRawDeviceRemove      203     /* RAW device deleted */
+#define                AifNativeDeviceAdd      204     /* native HBA device added */
+#define                AifNativeDeviceRemove   205     /* native HBA device removed */
 
-/* RAW device deleted */
-#define                AifRawDeviceRemove      203
 
 /*
  *     Adapter Initiated FIB command structures. Start with the adapter
@@ -2131,6 +2618,8 @@ static inline unsigned int cap_to_cyls(sector_t capacity, unsigned divisor)
 
 int aac_acquire_irq(struct aac_dev *dev);
 void aac_free_irq(struct aac_dev *dev);
+int aac_report_phys_luns(struct aac_dev *dev, struct fib *fibptr, int rescan);
+int aac_issue_bmic_identify(struct aac_dev *dev, u32 bus, u32 target);
 const char *aac_driverinfo(struct Scsi_Host *);
 void aac_fib_vector_assign(struct aac_dev *dev);
 struct fib *aac_fib_alloc(struct aac_dev *dev);
@@ -2141,9 +2630,12 @@ void aac_fib_free(struct fib * context);
 void aac_fib_init(struct fib * context);
 void aac_printf(struct aac_dev *dev, u32 val);
 int aac_fib_send(u16 command, struct fib * context, unsigned long size, int priority, int wait, int reply, fib_callback callback, void *ctxt);
+int aac_hba_send(u8 command, struct fib *context,
+               fib_callback callback, void *ctxt);
 int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entry **entry);
 void aac_consumer_free(struct aac_dev * dev, struct aac_queue * q, u32 qnum);
 int aac_fib_complete(struct fib * context);
+void aac_hba_callback(void *context, struct fib *fibptr);
 #define fib_data(fibctx) ((void *)(fibctx)->hw_fib_va->data)
 struct aac_dev *aac_init_adapter(struct aac_dev *dev);
 void aac_src_access_devreg(struct aac_dev *dev, int mode);
@@ -2169,7 +2661,7 @@ unsigned int aac_command_normal(struct aac_queue * q);
 unsigned int aac_intr_normal(struct aac_dev *dev, u32 Index,
                        int isAif, int isFastResponse,
                        struct hw_fib *aif_fib);
-int aac_reset_adapter(struct aac_dev * dev, int forced);
+int aac_reset_adapter(struct aac_dev *dev, int forced, u8 reset_type);
 int aac_check_health(struct aac_dev * dev);
 int aac_command_thread(void *data);
 int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context *fibctx);
@@ -2183,7 +2675,6 @@ int aac_rx_select_comm(struct aac_dev *dev, int comm);
 int aac_rx_deliver_producer(struct fib * fib);
 char * get_container_type(unsigned type);
 extern int numacb;
-extern int acbsize;
 extern char aac_driver_version[];
 extern int startup_timeout;
 extern int aif_timeout;
@@ -2194,3 +2685,4 @@ extern int aac_commit;
 extern int update_interval;
 extern int check_interval;
 extern int aac_check_reset;
+#endif
index e1daff230c7dab05b794cf44a8675d9cad04fcaa..614842a9eb07feddab170096d165d9f6031abe35 100644 (file)
@@ -6,7 +6,8 @@
  * Adaptec aacraid device driver for Linux.
  *
  * Copyright (c) 2000-2010 Adaptec, Inc.
- *               2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
+ *               2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
+ *              2016-2017 Microsemi Corp. (aacraid@microsemi.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
@@ -477,20 +478,24 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
        struct fib* srbfib;
        int status;
        struct aac_srb *srbcmd = NULL;
+       struct aac_hba_cmd_req *hbacmd = NULL;
        struct user_aac_srb *user_srbcmd = NULL;
        struct user_aac_srb __user *user_srb = arg;
        struct aac_srb_reply __user *user_reply;
-       struct aac_srb_reply* reply;
+       u32 chn;
        u32 fibsize = 0;
        u32 flags = 0;
        s32 rcode = 0;
        u32 data_dir;
-       void __user *sg_user[32];
-       void *sg_list[32];
+       void __user *sg_user[HBA_MAX_SG_EMBEDDED];
+       void *sg_list[HBA_MAX_SG_EMBEDDED];
+       u32 sg_count[HBA_MAX_SG_EMBEDDED];
        u32 sg_indx = 0;
        u32 byte_count = 0;
        u32 actual_fibsize64, actual_fibsize = 0;
        int i;
+       int is_native_device;
+       u64 address;
 
 
        if (dev->in_reset) {
@@ -507,11 +512,6 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
        if (!(srbfib = aac_fib_alloc(dev))) {
                return -ENOMEM;
        }
-       aac_fib_init(srbfib);
-       /* raw_srb FIB is not FastResponseCapable */
-       srbfib->hw_fib_va->header.XferState &= ~cpu_to_le32(FastResponseCapable);
-
-       srbcmd = (struct aac_srb*) fib_data(srbfib);
 
        memset(sg_list, 0, sizeof(sg_list)); /* cleanup may take issue */
        if(copy_from_user(&fibsize, &user_srb->count,sizeof(u32))){
@@ -538,21 +538,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                goto cleanup;
        }
 
-       user_reply = arg+fibsize;
-
        flags = user_srbcmd->flags; /* from user in cpu order */
-       // Fix up srb for endian and force some values
-
-       srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi);       // Force this
-       srbcmd->channel  = cpu_to_le32(user_srbcmd->channel);
-       srbcmd->id       = cpu_to_le32(user_srbcmd->id);
-       srbcmd->lun      = cpu_to_le32(user_srbcmd->lun);
-       srbcmd->timeout  = cpu_to_le32(user_srbcmd->timeout);
-       srbcmd->flags    = cpu_to_le32(flags);
-       srbcmd->retry_limit = 0; // Obsolete parameter
-       srbcmd->cdb_size = cpu_to_le32(user_srbcmd->cdb_size);
-       memcpy(srbcmd->cdb, user_srbcmd->cdb, sizeof(srbcmd->cdb));
-
        switch (flags & (SRB_DataIn | SRB_DataOut)) {
        case SRB_DataOut:
                data_dir = DMA_TO_DEVICE;
@@ -568,7 +554,12 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
        }
        if (user_srbcmd->sg.count > ARRAY_SIZE(sg_list)) {
                dprintk((KERN_DEBUG"aacraid: too many sg entries %d\n",
-                 le32_to_cpu(srbcmd->sg.count)));
+                       user_srbcmd->sg.count));
+               rcode = -EINVAL;
+               goto cleanup;
+       }
+       if ((data_dir == DMA_NONE) && user_srbcmd->sg.count) {
+               dprintk((KERN_DEBUG"aacraid:SG with no direction specified\n"));
                rcode = -EINVAL;
                goto cleanup;
        }
@@ -588,13 +579,136 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                rcode = -EINVAL;
                goto cleanup;
        }
-       if ((data_dir == DMA_NONE) && user_srbcmd->sg.count) {
-               dprintk((KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n"));
-               rcode = -EINVAL;
-               goto cleanup;
+
+       chn = aac_logical_to_phys(user_srbcmd->channel);
+       if (chn < AAC_MAX_BUSES && user_srbcmd->id < AAC_MAX_TARGETS &&
+               dev->hba_map[chn][user_srbcmd->id].devtype ==
+               AAC_DEVTYPE_NATIVE_RAW) {
+               is_native_device = 1;
+               hbacmd = (struct aac_hba_cmd_req *)srbfib->hw_fib_va;
+               memset(hbacmd, 0, 96);  /* sizeof(*hbacmd) is not necessary */
+
+               /* iu_type is a parameter of aac_hba_send */
+               switch (data_dir) {
+               case DMA_TO_DEVICE:
+                       hbacmd->byte1 = 2;
+                       break;
+               case DMA_FROM_DEVICE:
+               case DMA_BIDIRECTIONAL:
+                       hbacmd->byte1 = 1;
+                       break;
+               case DMA_NONE:
+               default:
+                       break;
+               }
+               hbacmd->lun[1] = cpu_to_le32(user_srbcmd->lun);
+               hbacmd->it_nexus = dev->hba_map[chn][user_srbcmd->id].rmw_nexus;
+
+               /*
+                * we fill in reply_qid later in aac_src_deliver_message
+                * we fill in iu_type, request_id later in aac_hba_send
+                * we fill in emb_data_desc_count, data_length later
+                * in sg list build
+                */
+
+               memcpy(hbacmd->cdb, user_srbcmd->cdb, sizeof(hbacmd->cdb));
+
+               address = (u64)srbfib->hw_error_pa;
+               hbacmd->error_ptr_hi = cpu_to_le32((u32)(address >> 32));
+               hbacmd->error_ptr_lo = cpu_to_le32((u32)(address & 0xffffffff));
+               hbacmd->error_length = cpu_to_le32(FW_ERROR_BUFFER_SIZE);
+               hbacmd->emb_data_desc_count =
+                                       cpu_to_le32(user_srbcmd->sg.count);
+               srbfib->hbacmd_size = 64 +
+                       user_srbcmd->sg.count * sizeof(struct aac_hba_sgl);
+
+       } else {
+               is_native_device = 0;
+               aac_fib_init(srbfib);
+
+               /* raw_srb FIB is not FastResponseCapable */
+               srbfib->hw_fib_va->header.XferState &=
+                       ~cpu_to_le32(FastResponseCapable);
+
+               srbcmd = (struct aac_srb *) fib_data(srbfib);
+
+               // Fix up srb for endian and force some values
+
+               srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi); // Force this
+               srbcmd->channel  = cpu_to_le32(user_srbcmd->channel);
+               srbcmd->id       = cpu_to_le32(user_srbcmd->id);
+               srbcmd->lun      = cpu_to_le32(user_srbcmd->lun);
+               srbcmd->timeout  = cpu_to_le32(user_srbcmd->timeout);
+               srbcmd->flags    = cpu_to_le32(flags);
+               srbcmd->retry_limit = 0; // Obsolete parameter
+               srbcmd->cdb_size = cpu_to_le32(user_srbcmd->cdb_size);
+               memcpy(srbcmd->cdb, user_srbcmd->cdb, sizeof(srbcmd->cdb));
        }
+
        byte_count = 0;
-       if (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64) {
+       if (is_native_device) {
+               struct user_sgmap *usg32 = &user_srbcmd->sg;
+               struct user_sgmap64 *usg64 =
+                       (struct user_sgmap64 *)&user_srbcmd->sg;
+
+               for (i = 0; i < usg32->count; i++) {
+                       void *p;
+                       u64 addr;
+
+                       sg_count[i] = (actual_fibsize64 == fibsize) ?
+                               usg64->sg[i].count : usg32->sg[i].count;
+                       if (sg_count[i] >
+                               (dev->scsi_host_ptr->max_sectors << 9)) {
+                               pr_err("aacraid: upsg->sg[%d].count=%u>%u\n",
+                                       i, sg_count[i],
+                                       dev->scsi_host_ptr->max_sectors << 9);
+                               rcode = -EINVAL;
+                               goto cleanup;
+                       }
+
+                       p = kmalloc(sg_count[i], GFP_KERNEL|__GFP_DMA);
+                       if (!p) {
+                               rcode = -ENOMEM;
+                               goto cleanup;
+                       }
+
+                       if (actual_fibsize64 == fibsize) {
+                               addr = (u64)usg64->sg[i].addr[0];
+                               addr += ((u64)usg64->sg[i].addr[1]) << 32;
+                       } else {
+                               addr = (u64)usg32->sg[i].addr;
+                       }
+
+                       sg_user[i] = (void __user *)(uintptr_t)addr;
+                       sg_list[i] = p; // save so we can clean up later
+                       sg_indx = i;
+
+                       if (flags & SRB_DataOut) {
+                               if (copy_from_user(p, sg_user[i],
+                                       sg_count[i])) {
+                                       rcode = -EFAULT;
+                                       goto cleanup;
+                               }
+                       }
+                       addr = pci_map_single(dev->pdev, p, sg_count[i],
+                                               data_dir);
+                       hbacmd->sge[i].addr_hi = cpu_to_le32((u32)(addr>>32));
+                       hbacmd->sge[i].addr_lo = cpu_to_le32(
+                                               (u32)(addr & 0xffffffff));
+                       hbacmd->sge[i].len = cpu_to_le32(sg_count[i]);
+                       hbacmd->sge[i].flags = 0;
+                       byte_count += sg_count[i];
+               }
+
+               if (usg32->count > 0)   /* embedded sglist */
+                       hbacmd->sge[usg32->count-1].flags =
+                               cpu_to_le32(0x40000000);
+               hbacmd->data_length = cpu_to_le32(byte_count);
+
+               status = aac_hba_send(HBA_IU_TYPE_SCSI_CMD_REQ, srbfib,
+                                       NULL, NULL);
+
+       } else if (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64) {
                struct user_sgmap64* upsg = (struct user_sgmap64*)&user_srbcmd->sg;
                struct sgmap64* psg = (struct sgmap64*)&srbcmd->sg;
 
@@ -606,7 +720,9 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                        for (i = 0; i < upsg->count; i++) {
                                u64 addr;
                                void* p;
-                               if (upsg->sg[i].count >
+
+                               sg_count[i] = upsg->sg[i].count;
+                               if (sg_count[i] >
                                    ((dev->adapter_info.options &
                                     AAC_OPT_NEW_COMM) ?
                                      (dev->scsi_host_ptr->max_sectors << 9) :
@@ -615,10 +731,10 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                                        goto cleanup;
                                }
                                /* Does this really need to be GFP_DMA? */
-                               p = kmalloc(upsg->sg[i].count,GFP_KERNEL|__GFP_DMA);
+                               p = kmalloc(sg_count[i], GFP_KERNEL|__GFP_DMA);
                                if(!p) {
                                        dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
-                                         upsg->sg[i].count,i,upsg->count));
+                                         sg_count[i], i, upsg->count));
                                        rcode = -ENOMEM;
                                        goto cleanup;
                                }
@@ -629,18 +745,20 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                                sg_indx = i;
 
                                if (flags & SRB_DataOut) {
-                                       if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){
+                                       if (copy_from_user(p, sg_user[i],
+                                               sg_count[i])){
                                                dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
                                                rcode = -EFAULT;
                                                goto cleanup;
                                        }
                                }
-                               addr = pci_map_single(dev->pdev, p, upsg->sg[i].count, data_dir);
+                               addr = pci_map_single(dev->pdev, p,
+                                                       sg_count[i], data_dir);
 
                                psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff);
                                psg->sg[i].addr[1] = cpu_to_le32(addr>>32);
-                               byte_count += upsg->sg[i].count;
-                               psg->sg[i].count = cpu_to_le32(upsg->sg[i].count);
+                               byte_count += sg_count[i];
+                               psg->sg[i].count = cpu_to_le32(sg_count[i]);
                        }
                } else {
                        struct user_sgmap* usg;
@@ -657,7 +775,9 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                        for (i = 0; i < usg->count; i++) {
                                u64 addr;
                                void* p;
-                               if (usg->sg[i].count >
+
+                               sg_count[i] = usg->sg[i].count;
+                               if (sg_count[i] >
                                    ((dev->adapter_info.options &
                                     AAC_OPT_NEW_COMM) ?
                                      (dev->scsi_host_ptr->max_sectors << 9) :
@@ -667,10 +787,10 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                                        goto cleanup;
                                }
                                /* Does this really need to be GFP_DMA? */
-                               p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA);
+                               p = kmalloc(sg_count[i], GFP_KERNEL|__GFP_DMA);
                                if(!p) {
                                        dprintk((KERN_DEBUG "aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
-                                         usg->sg[i].count,i,usg->count));
+                                               sg_count[i], i, usg->count));
                                        kfree(usg);
                                        rcode = -ENOMEM;
                                        goto cleanup;
@@ -680,19 +800,21 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                                sg_indx = i;
 
                                if (flags & SRB_DataOut) {
-                                       if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){
+                                       if (copy_from_user(p, sg_user[i],
+                                               sg_count[i])) {
                                                kfree (usg);
                                                dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
                                                rcode = -EFAULT;
                                                goto cleanup;
                                        }
                                }
-                               addr = pci_map_single(dev->pdev, p, usg->sg[i].count, data_dir);
+                               addr = pci_map_single(dev->pdev, p,
+                                                       sg_count[i], data_dir);
 
                                psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff);
                                psg->sg[i].addr[1] = cpu_to_le32(addr>>32);
-                               byte_count += usg->sg[i].count;
-                               psg->sg[i].count = cpu_to_le32(usg->sg[i].count);
+                               byte_count += sg_count[i];
+                               psg->sg[i].count = cpu_to_le32(sg_count[i]);
                        }
                        kfree (usg);
                }
@@ -711,7 +833,9 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                        for (i = 0; i < upsg->count; i++) {
                                uintptr_t addr;
                                void* p;
-                               if (usg->sg[i].count >
+
+                               sg_count[i] = usg->sg[i].count;
+                               if (sg_count[i] >
                                    ((dev->adapter_info.options &
                                     AAC_OPT_NEW_COMM) ?
                                      (dev->scsi_host_ptr->max_sectors << 9) :
@@ -720,10 +844,10 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                                        goto cleanup;
                                }
                                /* Does this really need to be GFP_DMA? */
-                               p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA);
-                               if(!p) {
+                               p = kmalloc(sg_count[i], GFP_KERNEL|__GFP_DMA);
+                               if (!p) {
                                        dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
-                                         usg->sg[i].count,i,usg->count));
+                                               sg_count[i], i, usg->count));
                                        rcode = -ENOMEM;
                                        goto cleanup;
                                }
@@ -734,7 +858,8 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                                sg_indx = i;
 
                                if (flags & SRB_DataOut) {
-                                       if(copy_from_user(p,sg_user[i],usg->sg[i].count)){
+                                       if (copy_from_user(p, sg_user[i],
+                                               sg_count[i])){
                                                dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
                                                rcode = -EFAULT;
                                                goto cleanup;
@@ -744,13 +869,15 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
 
                                psg->sg[i].addr = cpu_to_le32(addr & 0xffffffff);
                                byte_count += usg->sg[i].count;
-                               psg->sg[i].count = cpu_to_le32(usg->sg[i].count);
+                               psg->sg[i].count = cpu_to_le32(sg_count[i]);
                        }
                } else {
                        for (i = 0; i < upsg->count; i++) {
                                dma_addr_t addr;
                                void* p;
-                               if (upsg->sg[i].count >
+
+                               sg_count[i] = upsg->sg[i].count;
+                               if (sg_count[i] >
                                    ((dev->adapter_info.options &
                                     AAC_OPT_NEW_COMM) ?
                                      (dev->scsi_host_ptr->max_sectors << 9) :
@@ -758,10 +885,10 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                                        rcode = -EINVAL;
                                        goto cleanup;
                                }
-                               p = kmalloc(upsg->sg[i].count, GFP_KERNEL);
+                               p = kmalloc(sg_count[i], GFP_KERNEL);
                                if (!p) {
                                        dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
-                                         upsg->sg[i].count, i, upsg->count));
+                                         sg_count[i], i, upsg->count));
                                        rcode = -ENOMEM;
                                        goto cleanup;
                                }
@@ -770,19 +897,19 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                                sg_indx = i;
 
                                if (flags & SRB_DataOut) {
-                                       if(copy_from_user(p, sg_user[i],
-                                                       upsg->sg[i].count)) {
+                                       if (copy_from_user(p, sg_user[i],
+                                               sg_count[i])) {
                                                dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
                                                rcode = -EFAULT;
                                                goto cleanup;
                                        }
                                }
                                addr = pci_map_single(dev->pdev, p,
-                                       upsg->sg[i].count, data_dir);
+                                       sg_count[i], data_dir);
 
                                psg->sg[i].addr = cpu_to_le32(addr);
-                               byte_count += upsg->sg[i].count;
-                               psg->sg[i].count = cpu_to_le32(upsg->sg[i].count);
+                               byte_count += sg_count[i];
+                               psg->sg[i].count = cpu_to_le32(sg_count[i]);
                        }
                }
                srbcmd->count = cpu_to_le32(byte_count);
@@ -792,12 +919,13 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                        psg->count = 0;
                status = aac_fib_send(ScsiPortCommand, srbfib, actual_fibsize, FsaNormal, 1, 1, NULL, NULL);
        }
+
        if (status == -ERESTARTSYS) {
                rcode = -ERESTARTSYS;
                goto cleanup;
        }
 
-       if (status != 0){
+       if (status != 0) {
                dprintk((KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n"));
                rcode = -ENXIO;
                goto cleanup;
@@ -805,11 +933,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
 
        if (flags & SRB_DataIn) {
                for(i = 0 ; i <= sg_indx; i++){
-                       byte_count = le32_to_cpu(
-                         (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)
-                             ? ((struct sgmap64*)&srbcmd->sg)->sg[i].count
-                             : srbcmd->sg.sg[i].count);
-                       if(copy_to_user(sg_user[i], sg_list[i], byte_count)){
+                       if (copy_to_user(sg_user[i], sg_list[i], sg_count[i])) {
                                dprintk((KERN_DEBUG"aacraid: Could not copy sg data to user\n"));
                                rcode = -EFAULT;
                                goto cleanup;
@@ -818,19 +942,50 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
                }
        }
 
-       reply = (struct aac_srb_reply *) fib_data(srbfib);
-       if(copy_to_user(user_reply,reply,sizeof(struct aac_srb_reply))){
-               dprintk((KERN_DEBUG"aacraid: Could not copy reply to user\n"));
-               rcode = -EFAULT;
-               goto cleanup;
+       user_reply = arg + fibsize;
+       if (is_native_device) {
+               struct aac_hba_resp *err =
+                       &((struct aac_native_hba *)srbfib->hw_fib_va)->resp.err;
+               struct aac_srb_reply reply;
+
+               reply.status = ST_OK;
+               if (srbfib->flags & FIB_CONTEXT_FLAG_FASTRESP) {
+                       /* fast response */
+                       reply.srb_status = SRB_STATUS_SUCCESS;
+                       reply.scsi_status = 0;
+                       reply.data_xfer_length = byte_count;
+               } else {
+                       reply.srb_status = err->service_response;
+                       reply.scsi_status = err->status;
+                       reply.data_xfer_length = byte_count -
+                               le32_to_cpu(err->residual_count);
+                       reply.sense_data_size = err->sense_response_data_len;
+                       memcpy(reply.sense_data, err->sense_response_buf,
+                               AAC_SENSE_BUFFERSIZE);
+               }
+               if (copy_to_user(user_reply, &reply,
+                       sizeof(struct aac_srb_reply))) {
+                       dprintk((KERN_DEBUG"aacraid: Copy to user failed\n"));
+                       rcode = -EFAULT;
+                       goto cleanup;
+               }
+       } else {
+               struct aac_srb_reply *reply;
+
+               reply = (struct aac_srb_reply *) fib_data(srbfib);
+               if (copy_to_user(user_reply, reply,
+                       sizeof(struct aac_srb_reply))) {
+                       dprintk((KERN_DEBUG"aacraid: Copy to user failed\n"));
+                       rcode = -EFAULT;
+                       goto cleanup;
+               }
        }
 
 cleanup:
        kfree(user_srbcmd);
-       for(i=0; i <= sg_indx; i++){
-               kfree(sg_list[i]);
-       }
        if (rcode != -ERESTARTSYS) {
+               for (i = 0; i <= sg_indx; i++)
+                       kfree(sg_list[i]);
                aac_fib_complete(srbfib);
                aac_fib_free(srbfib);
        }
@@ -858,6 +1013,44 @@ static int aac_get_pci_info(struct aac_dev* dev, void __user *arg)
        return 0;
 }
 
+static int aac_get_hba_info(struct aac_dev *dev, void __user *arg)
+{
+       struct aac_hba_info hbainfo;
+
+       hbainfo.adapter_number          = (u8) dev->id;
+       hbainfo.system_io_bus_number    = dev->pdev->bus->number;
+       hbainfo.device_number           = (dev->pdev->devfn >> 3);
+       hbainfo.function_number         = (dev->pdev->devfn & 0x0007);
+
+       hbainfo.vendor_id               = dev->pdev->vendor;
+       hbainfo.device_id               = dev->pdev->device;
+       hbainfo.sub_vendor_id           = dev->pdev->subsystem_vendor;
+       hbainfo.sub_system_id           = dev->pdev->subsystem_device;
+
+       if (copy_to_user(arg, &hbainfo, sizeof(struct aac_hba_info))) {
+               dprintk((KERN_DEBUG "aacraid: Could not copy hba info\n"));
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+struct aac_reset_iop {
+       u8      reset_type;
+};
+
+static int aac_send_reset_adapter(struct aac_dev *dev, void __user *arg)
+{
+       struct aac_reset_iop reset;
+       int retval;
+
+       if (copy_from_user((void *)&reset, arg, sizeof(struct aac_reset_iop)))
+               return -EFAULT;
+
+       retval = aac_reset_adapter(dev, 0, reset.reset_type);
+       return retval;
+
+}
 
 int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg)
 {
@@ -901,6 +1094,13 @@ int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg)
        case FSACTL_GET_PCI_INFO:
                status = aac_get_pci_info(dev,arg);
                break;
+       case FSACTL_GET_HBA_INFO:
+               status = aac_get_hba_info(dev, arg);
+               break;
+       case FSACTL_RESET_IOP:
+               status = aac_send_reset_adapter(dev, arg);
+               break;
+
        default:
                status = -ENOTTY;
                break;
index 5b48bedd7c385f3b73adb97d45f691d540914f42..40bfc57b68493afab33e1a1ce45d4e88446e3ec8 100644 (file)
@@ -6,7 +6,8 @@
  * Adaptec aacraid device driver for Linux.
  *
  * Copyright (c) 2000-2010 Adaptec, Inc.
- *               2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
+ *               2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
+ *               2016-2017 Microsemi Corp. (aacraid@microsemi.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
@@ -72,104 +73,175 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co
        unsigned long size, align;
        const unsigned long fibsize = dev->max_fib_size;
        const unsigned long printfbufsiz = 256;
-       unsigned long host_rrq_size = 0;
-       struct aac_init *init;
+       unsigned long host_rrq_size, aac_init_size;
+       union aac_init *init;
        dma_addr_t phys;
        unsigned long aac_max_hostphysmempages;
 
-       if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1 ||
-           dev->comm_interface == AAC_COMM_MESSAGE_TYPE2)
+       if ((dev->comm_interface == AAC_COMM_MESSAGE_TYPE1) ||
+               (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2) ||
+               (dev->comm_interface == AAC_COMM_MESSAGE_TYPE3 &&
+               !dev->sa_firmware)) {
+               host_rrq_size =
+                       (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB)
+                               * sizeof(u32);
+               aac_init_size = sizeof(union aac_init);
+       } else if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE3 &&
+               dev->sa_firmware) {
                host_rrq_size = (dev->scsi_host_ptr->can_queue
-                       + AAC_NUM_MGT_FIB) * sizeof(u32);
-       size = fibsize + sizeof(struct aac_init) + commsize +
-                       commalign + printfbufsiz + host_rrq_size;
+                       + AAC_NUM_MGT_FIB) * sizeof(u32)  * AAC_MAX_MSIX;
+               aac_init_size = sizeof(union aac_init) +
+                       (AAC_MAX_HRRQ - 1) * sizeof(struct _rrq);
+       } else {
+               host_rrq_size = 0;
+               aac_init_size = sizeof(union aac_init);
+       }
+       size = fibsize + aac_init_size + commsize + commalign +
+                       printfbufsiz + host_rrq_size;
+
        base = pci_alloc_consistent(dev->pdev, size, &phys);
 
-       if(base == NULL)
-       {
+       if (base == NULL) {
                printk(KERN_ERR "aacraid: unable to create mapping.\n");
                return 0;
        }
+
        dev->comm_addr = (void *)base;
        dev->comm_phys = phys;
        dev->comm_size = size;
-       
-       if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1 ||
-           dev->comm_interface == AAC_COMM_MESSAGE_TYPE2) {
+
+       if ((dev->comm_interface == AAC_COMM_MESSAGE_TYPE1) ||
+           (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2) ||
+           (dev->comm_interface == AAC_COMM_MESSAGE_TYPE3)) {
                dev->host_rrq = (u32 *)(base + fibsize);
                dev->host_rrq_pa = phys + fibsize;
                memset(dev->host_rrq, 0, host_rrq_size);
        }
 
-       dev->init = (struct aac_init *)(base + fibsize + host_rrq_size);
+       dev->init = (union aac_init *)(base + fibsize + host_rrq_size);
        dev->init_pa = phys + fibsize + host_rrq_size;
 
        init = dev->init;
 
-       init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION);
-       if (dev->max_fib_size != sizeof(struct hw_fib))
-               init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_4);
-       init->Sa_MSIXVectors = cpu_to_le32(SA_INIT_NUM_MSIXVECTORS);
-       init->fsrev = cpu_to_le32(dev->fsrev);
+       if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) {
+               int i;
+               u64 addr;
+
+               init->r8.init_struct_revision =
+                       cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_8);
+               init->r8.init_flags = cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED |
+                                       INITFLAGS_DRIVER_USES_UTC_TIME |
+                                       INITFLAGS_DRIVER_SUPPORTS_PM);
+               init->r8.init_flags |=
+                               cpu_to_le32(INITFLAGS_DRIVER_SUPPORTS_HBA_MODE);
+               init->r8.rr_queue_count = cpu_to_le32(dev->max_msix);
+               init->r8.max_io_size =
+                       cpu_to_le32(dev->scsi_host_ptr->max_sectors << 9);
+               init->r8.max_num_aif = init->r8.reserved1 =
+                       init->r8.reserved2 = 0;
+
+               for (i = 0; i < dev->max_msix; i++) {
+                       addr = (u64)dev->host_rrq_pa + dev->vector_cap * i *
+                                       sizeof(u32);
+                       init->r8.rrq[i].host_addr_high = cpu_to_le32(
+                                               upper_32_bits(addr));
+                       init->r8.rrq[i].host_addr_low = cpu_to_le32(
+                                               lower_32_bits(addr));
+                       init->r8.rrq[i].msix_id = i;
+                       init->r8.rrq[i].element_count = cpu_to_le16(
+                                       (u16)dev->vector_cap);
+                       init->r8.rrq[i].comp_thresh =
+                                       init->r8.rrq[i].unused = 0;
+               }
 
-       /*
-        *      Adapter Fibs are the first thing allocated so that they
-        *      start page aligned
-        */
-       dev->aif_base_va = (struct hw_fib *)base;
-       
-       init->AdapterFibsVirtualAddress = 0;
-       init->AdapterFibsPhysicalAddress = cpu_to_le32((u32)phys);
-       init->AdapterFibsSize = cpu_to_le32(fibsize);
-       init->AdapterFibAlign = cpu_to_le32(sizeof(struct hw_fib));
-       /*
-        * number of 4k pages of host physical memory. The aacraid fw needs
-        * this number to be less than 4gb worth of pages. New firmware doesn't
-        * have any issues with the mapping system, but older Firmware did, and
-        * had *troubles* dealing with the math overloading past 32 bits, thus
-        * we must limit this field.
-        */
-       aac_max_hostphysmempages = dma_get_required_mask(&dev->pdev->dev) >> 12;
-       if (aac_max_hostphysmempages < AAC_MAX_HOSTPHYSMEMPAGES)
-               init->HostPhysMemPages = cpu_to_le32(aac_max_hostphysmempages);
-       else
-               init->HostPhysMemPages = cpu_to_le32(AAC_MAX_HOSTPHYSMEMPAGES);
-
-       init->InitFlags = cpu_to_le32(INITFLAGS_DRIVER_USES_UTC_TIME |
-               INITFLAGS_DRIVER_SUPPORTS_PM);
-       init->MaxIoCommands = cpu_to_le32(dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB);
-       init->MaxIoSize = cpu_to_le32(dev->scsi_host_ptr->max_sectors << 9);
-       init->MaxFibSize = cpu_to_le32(dev->max_fib_size);
-       init->MaxNumAif = cpu_to_le32(dev->max_num_aif);
-
-       if (dev->comm_interface == AAC_COMM_MESSAGE) {
-               init->InitFlags |= cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED);
-               dprintk((KERN_WARNING"aacraid: New Comm Interface enabled\n"));
-       } else if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1) {
-               init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_6);
-               init->InitFlags |= cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED |
-                       INITFLAGS_NEW_COMM_TYPE1_SUPPORTED | INITFLAGS_FAST_JBOD_SUPPORTED);
-               init->HostRRQ_AddrHigh = cpu_to_le32((u32)((u64)dev->host_rrq_pa >> 32));
-               init->HostRRQ_AddrLow = cpu_to_le32((u32)(dev->host_rrq_pa & 0xffffffff));
-               dprintk((KERN_WARNING"aacraid: New Comm Interface type1 enabled\n"));
-       } else if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2) {
-               init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_7);
-               init->InitFlags |= cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED |
-                       INITFLAGS_NEW_COMM_TYPE2_SUPPORTED | INITFLAGS_FAST_JBOD_SUPPORTED);
-               init->HostRRQ_AddrHigh = cpu_to_le32((u32)((u64)dev->host_rrq_pa >> 32));
-               init->HostRRQ_AddrLow = cpu_to_le32((u32)(dev->host_rrq_pa & 0xffffffff));
-               /* number of MSI-X */
-               init->Sa_MSIXVectors = cpu_to_le32(dev->max_msix);
-               dprintk((KERN_WARNING"aacraid: New Comm Interface type2 enabled\n"));
+               pr_warn("aacraid: Comm Interface type3 enabled\n");
+       } else {
+               init->r7.init_struct_revision =
+                       cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION);
+               if (dev->max_fib_size != sizeof(struct hw_fib))
+                       init->r7.init_struct_revision =
+                               cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_4);
+               init->r7.no_of_msix_vectors = cpu_to_le32(SA_MINIPORT_REVISION);
+               init->r7.fsrev = cpu_to_le32(dev->fsrev);
+
+               /*
+                *      Adapter Fibs are the first thing allocated so that they
+                *      start page aligned
+                */
+               dev->aif_base_va = (struct hw_fib *)base;
+
+               init->r7.adapter_fibs_virtual_address = 0;
+               init->r7.adapter_fibs_physical_address = cpu_to_le32((u32)phys);
+               init->r7.adapter_fibs_size = cpu_to_le32(fibsize);
+               init->r7.adapter_fib_align = cpu_to_le32(sizeof(struct hw_fib));
+
+               /*
+                * number of 4k pages of host physical memory. The aacraid fw
+                * needs this number to be less than 4gb worth of pages. New
+                * firmware doesn't have any issues with the mapping system, but
+                * older Firmware did, and had *troubles* dealing with the math
+                * overloading past 32 bits, thus we must limit this field.
+                */
+               aac_max_hostphysmempages =
+                               dma_get_required_mask(&dev->pdev->dev) >> 12;
+               if (aac_max_hostphysmempages < AAC_MAX_HOSTPHYSMEMPAGES)
+                       init->r7.host_phys_mem_pages =
+                                       cpu_to_le32(aac_max_hostphysmempages);
+               else
+                       init->r7.host_phys_mem_pages =
+                                       cpu_to_le32(AAC_MAX_HOSTPHYSMEMPAGES);
+
+               init->r7.init_flags =
+                       cpu_to_le32(INITFLAGS_DRIVER_USES_UTC_TIME |
+                       INITFLAGS_DRIVER_SUPPORTS_PM);
+               init->r7.max_io_commands =
+                       cpu_to_le32(dev->scsi_host_ptr->can_queue +
+                                       AAC_NUM_MGT_FIB);
+               init->r7.max_io_size =
+                       cpu_to_le32(dev->scsi_host_ptr->max_sectors << 9);
+               init->r7.max_fib_size = cpu_to_le32(dev->max_fib_size);
+               init->r7.max_num_aif = cpu_to_le32(dev->max_num_aif);
+
+               if (dev->comm_interface == AAC_COMM_MESSAGE) {
+                       init->r7.init_flags |=
+                               cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED);
+                       pr_warn("aacraid: Comm Interface enabled\n");
+               } else if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1) {
+                       init->r7.init_struct_revision =
+                               cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_6);
+                       init->r7.init_flags |=
+                               cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED |
+                               INITFLAGS_NEW_COMM_TYPE1_SUPPORTED |
+                               INITFLAGS_FAST_JBOD_SUPPORTED);
+                       init->r7.host_rrq_addr_high =
+                               cpu_to_le32(upper_32_bits(dev->host_rrq_pa));
+                       init->r7.host_rrq_addr_low =
+                               cpu_to_le32(lower_32_bits(dev->host_rrq_pa));
+                       pr_warn("aacraid: Comm Interface type1 enabled\n");
+               } else if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2) {
+                       init->r7.init_struct_revision =
+                               cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_7);
+                       init->r7.init_flags |=
+                               cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED |
+                               INITFLAGS_NEW_COMM_TYPE2_SUPPORTED |
+                               INITFLAGS_FAST_JBOD_SUPPORTED);
+                       init->r7.host_rrq_addr_high =
+                               cpu_to_le32(upper_32_bits(dev->host_rrq_pa));
+                       init->r7.host_rrq_addr_low =
+                               cpu_to_le32(lower_32_bits(dev->host_rrq_pa));
+                       init->r7.no_of_msix_vectors =
+                               cpu_to_le32(dev->max_msix);
+                       /* must be the COMM_PREFERRED_SETTINGS values */
+                       pr_warn("aacraid: Comm Interface type2 enabled\n");
+               }
        }
 
        /*
         * Increment the base address by the amount already used
         */
-       base = base + fibsize + host_rrq_size + sizeof(struct aac_init);
+       base = base + fibsize + host_rrq_size + aac_init_size;
        phys = (dma_addr_t)((ulong)phys + fibsize + host_rrq_size +
-               sizeof(struct aac_init));
+                       aac_init_size);
 
        /*
         *      Align the beginning of Headers to commalign
@@ -181,7 +253,8 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co
         *      Fill in addresses of the Comm Area Headers and Queues
         */
        *commaddr = base;
-       init->CommHeaderAddress = cpu_to_le32((u32)phys);
+       if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE3)
+               init->r7.comm_header_address = cpu_to_le32((u32)phys);
        /*
         *      Increment the base address by the size of the CommArea
         */
@@ -191,12 +264,14 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co
         *       Place the Printf buffer area after the Fast I/O comm area.
         */
        dev->printfbuf = (void *)base;
-       init->printfbuf = cpu_to_le32(phys);
-       init->printfbufsiz = cpu_to_le32(printfbufsiz);
+       if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE3) {
+               init->r7.printfbuf = cpu_to_le32(phys);
+               init->r7.printfbufsiz = cpu_to_le32(printfbufsiz);
+       }
        memset(base, 0, printfbufsiz);
        return 1;
 }
-    
+
 static void aac_queue_init(struct aac_dev * dev, struct aac_queue * q, u32 *mem, int qsize)
 {
        atomic_set(&q->numpending, 0);
@@ -404,9 +479,13 @@ void aac_define_int_mode(struct aac_dev *dev)
                if (dev->max_msix > msi_count)
                        dev->max_msix = msi_count;
        }
-       dev->vector_cap =
-               (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) /
-               msi_count;
+       if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE3 && dev->sa_firmware)
+               dev->vector_cap = dev->scsi_host_ptr->can_queue +
+                               AAC_NUM_MGT_FIB;
+       else
+               dev->vector_cap = (dev->scsi_host_ptr->can_queue +
+                               AAC_NUM_MGT_FIB) / msi_count;
+
 }
 struct aac_dev *aac_init_adapter(struct aac_dev *dev)
 {
@@ -440,30 +519,37 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
 
        if ((!aac_adapter_sync_cmd(dev, GET_ADAPTER_PROPERTIES,
                0, 0, 0, 0, 0, 0,
-               status+0, status+1, status+2, status+3, NULL)) &&
-                       (status[0] == 0x00000001)) {
+               status+0, status+1, status+2, status+3, status+4)) &&
+               (status[0] == 0x00000001)) {
                dev->doorbell_mask = status[3];
-               if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_64))
+               if (status[1] & AAC_OPT_NEW_COMM_64)
                        dev->raw_io_64 = 1;
                dev->sync_mode = aac_sync_mode;
                if (dev->a_ops.adapter_comm &&
-                       (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM))) {
+                       (status[1] & AAC_OPT_NEW_COMM)) {
                                dev->comm_interface = AAC_COMM_MESSAGE;
                                dev->raw_io_interface = 1;
-                       if ((status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE1))) {
+                       if ((status[1] & AAC_OPT_NEW_COMM_TYPE1)) {
                                /* driver supports TYPE1 (Tupelo) */
                                dev->comm_interface = AAC_COMM_MESSAGE_TYPE1;
-                       } else if ((status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE2))) {
-                               /* driver supports TYPE2 (Denali) */
+                       } else if (status[1] & AAC_OPT_NEW_COMM_TYPE2) {
+                               /* driver supports TYPE2 (Denali, Yosemite) */
                                dev->comm_interface = AAC_COMM_MESSAGE_TYPE2;
-                       } else if ((status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE4)) ||
-                                 (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE3))) {
-                               /* driver doesn't TYPE3 and TYPE4 */
-                               /* switch to sync. mode */
+                       } else if (status[1] & AAC_OPT_NEW_COMM_TYPE3) {
+                               /* driver supports TYPE3 (Yosemite, Thor) */
+                               dev->comm_interface = AAC_COMM_MESSAGE_TYPE3;
+                       } else if (status[1] & AAC_OPT_NEW_COMM_TYPE4) {
+                               /* not supported TYPE - switch to sync. mode */
                                dev->comm_interface = AAC_COMM_MESSAGE_TYPE2;
                                dev->sync_mode = 1;
                        }
                }
+               if ((status[1] & le32_to_cpu(AAC_OPT_EXTENDED)) &&
+                       (status[4] & le32_to_cpu(AAC_EXTOPT_SA_FIRMWARE)))
+                       dev->sa_firmware = 1;
+               else
+                       dev->sa_firmware = 0;
+
                if ((dev->comm_interface == AAC_COMM_MESSAGE) &&
                    (status[2] > dev->base_size)) {
                        aac_adapter_ioremap(dev, 0);
@@ -500,61 +586,25 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
                dev->sg_tablesize = status[2] & 0xFFFF;
                if (dev->pdev->device == PMC_DEVICE_S7 ||
                    dev->pdev->device == PMC_DEVICE_S8 ||
-                   dev->pdev->device == PMC_DEVICE_S9)
-                       host->can_queue = ((status[3] >> 16) ? (status[3] >> 16) :
-                               (status[3] & 0xFFFF)) - AAC_NUM_MGT_FIB;
-               else
-                       host->can_queue = (status[3] & 0xFFFF) - AAC_NUM_MGT_FIB;
+                   dev->pdev->device == PMC_DEVICE_S9) {
+                       if (host->can_queue > (status[3] >> 16) -
+                                       AAC_NUM_MGT_FIB)
+                               host->can_queue = (status[3] >> 16) -
+                                       AAC_NUM_MGT_FIB;
+               } else if (host->can_queue > (status[3] & 0xFFFF) -
+                               AAC_NUM_MGT_FIB)
+                       host->can_queue = (status[3] & 0xFFFF) -
+                               AAC_NUM_MGT_FIB;
+
                dev->max_num_aif = status[4] & 0xFFFF;
-               /*
-                *      NOTE:
-                *      All these overrides are based on a fixed internal
-                *      knowledge and understanding of existing adapters,
-                *      acbsize should be set with caution.
-                */
-               if (acbsize == 512) {
-                       host->max_sectors = AAC_MAX_32BIT_SGBCOUNT;
-                       dev->max_fib_size = 512;
-                       dev->sg_tablesize = host->sg_tablesize
-                         = (512 - sizeof(struct aac_fibhdr)
-                           - sizeof(struct aac_write) + sizeof(struct sgentry))
-                            / sizeof(struct sgentry);
-                       host->can_queue = AAC_NUM_IO_FIB;
-               } else if (acbsize == 2048) {
-                       host->max_sectors = 512;
-                       dev->max_fib_size = 2048;
-                       host->sg_tablesize = 65;
-                       dev->sg_tablesize = 81;
-                       host->can_queue = 512 - AAC_NUM_MGT_FIB;
-               } else if (acbsize == 4096) {
-                       host->max_sectors = 1024;
-                       dev->max_fib_size = 4096;
-                       host->sg_tablesize = 129;
-                       dev->sg_tablesize = 166;
-                       host->can_queue = 256 - AAC_NUM_MGT_FIB;
-               } else if (acbsize == 8192) {
-                       host->max_sectors = 2048;
-                       dev->max_fib_size = 8192;
-                       host->sg_tablesize = 257;
-                       dev->sg_tablesize = 337;
-                       host->can_queue = 128 - AAC_NUM_MGT_FIB;
-               } else if (acbsize > 0) {
-                       printk("Illegal acbsize=%d ignored\n", acbsize);
-               }
        }
-       {
-
-               if (numacb > 0) {
-                       if (numacb < host->can_queue)
-                               host->can_queue = numacb;
-                       else
-                               printk("numacb=%d ignored\n", numacb);
-               }
+       if (numacb > 0) {
+               if (numacb < host->can_queue)
+                       host->can_queue = numacb;
+               else
+                       pr_warn("numacb=%d ignored\n", numacb);
        }
 
-       if (host->can_queue > AAC_NUM_IO_FIB)
-               host->can_queue = AAC_NUM_IO_FIB;
-
        if (dev->pdev->device == PMC_DEVICE_S6 ||
            dev->pdev->device == PMC_DEVICE_S7 ||
            dev->pdev->device == PMC_DEVICE_S8 ||
index 9e7551fe4b19cc542219cea5c0c854c3ff456d3e..969727b67cdd14946a2d4a8f91fcb1b9fd8e19ba 100644 (file)
@@ -6,7 +6,8 @@
  * Adaptec aacraid device driver for Linux.
  *
  * Copyright (c) 2000-2010 Adaptec, Inc.
- *               2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
+ *               2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
+ *              2016-2017 Microsemi Corp. (aacraid@microsemi.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
@@ -43,6 +44,7 @@
 #include <linux/kthread.h>
 #include <linux/interrupt.h>
 #include <linux/semaphore.h>
+#include <linux/bcd.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_device.h>
 
 static int fib_map_alloc(struct aac_dev *dev)
 {
+       if (dev->max_fib_size > AAC_MAX_NATIVE_SIZE)
+               dev->max_cmd_size = AAC_MAX_NATIVE_SIZE;
+       else
+               dev->max_cmd_size = dev->max_fib_size;
+       if (dev->max_fib_size < AAC_MAX_NATIVE_SIZE) {
+               dev->max_cmd_size = AAC_MAX_NATIVE_SIZE;
+       } else {
+               dev->max_cmd_size = dev->max_fib_size;
+       }
+
        dprintk((KERN_INFO
          "allocate hardware fibs pci_alloc_consistent(%p, %d * (%d + %d), %p)\n",
-         dev->pdev, dev->max_fib_size, dev->scsi_host_ptr->can_queue,
+         dev->pdev, dev->max_cmd_size, dev->scsi_host_ptr->can_queue,
          AAC_NUM_MGT_FIB, &dev->hw_fib_pa));
        dev->hw_fib_va = pci_alloc_consistent(dev->pdev,
-               (dev->max_fib_size + sizeof(struct aac_fib_xporthdr))
+               (dev->max_cmd_size + sizeof(struct aac_fib_xporthdr))
                * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) + (ALIGN32 - 1),
                &dev->hw_fib_pa);
        if (dev->hw_fib_va == NULL)
@@ -83,9 +95,9 @@ static int fib_map_alloc(struct aac_dev *dev)
 
 void aac_fib_map_free(struct aac_dev *dev)
 {
-       if (dev->hw_fib_va && dev->max_fib_size) {
+       if (dev->hw_fib_va && dev->max_cmd_size) {
                pci_free_consistent(dev->pdev,
-               (dev->max_fib_size *
+               (dev->max_cmd_size *
                (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB)),
                dev->hw_fib_va, dev->hw_fib_pa);
        }
@@ -129,11 +141,14 @@ int aac_fib_setup(struct aac_dev * dev)
        struct hw_fib *hw_fib;
        dma_addr_t hw_fib_pa;
        int i;
+       u32 max_cmds;
 
        while (((i = fib_map_alloc(dev)) == -ENOMEM)
         && (dev->scsi_host_ptr->can_queue > (64 - AAC_NUM_MGT_FIB))) {
-               dev->init->MaxIoCommands = cpu_to_le32((dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) >> 1);
-               dev->scsi_host_ptr->can_queue = le32_to_cpu(dev->init->MaxIoCommands) - AAC_NUM_MGT_FIB;
+               max_cmds = (dev->scsi_host_ptr->can_queue+AAC_NUM_MGT_FIB) >> 1;
+               dev->scsi_host_ptr->can_queue = max_cmds - AAC_NUM_MGT_FIB;
+               if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE3)
+                       dev->init->r7.max_io_commands = cpu_to_le32(max_cmds);
        }
        if (i<0)
                return -ENOMEM;
@@ -144,7 +159,7 @@ int aac_fib_setup(struct aac_dev * dev)
                (hw_fib_pa - dev->hw_fib_pa));
        dev->hw_fib_pa = hw_fib_pa;
        memset(dev->hw_fib_va, 0,
-               (dev->max_fib_size + sizeof(struct aac_fib_xporthdr)) *
+               (dev->max_cmd_size + sizeof(struct aac_fib_xporthdr)) *
                (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB));
 
        /* add Xport header */
@@ -170,12 +185,22 @@ int aac_fib_setup(struct aac_dev * dev)
                sema_init(&fibptr->event_wait, 0);
                spin_lock_init(&fibptr->event_lock);
                hw_fib->header.XferState = cpu_to_le32(0xffffffff);
-               hw_fib->header.SenderSize = cpu_to_le16(dev->max_fib_size);
+               hw_fib->header.SenderSize =
+                       cpu_to_le16(dev->max_fib_size); /* ?? max_cmd_size */
                fibptr->hw_fib_pa = hw_fib_pa;
+               fibptr->hw_sgl_pa = hw_fib_pa +
+                       offsetof(struct aac_hba_cmd_req, sge[2]);
+               /*
+                * one element is for the ptr to the separate sg list,
+                * second element for 32 byte alignment
+                */
+               fibptr->hw_error_pa = hw_fib_pa +
+                       offsetof(struct aac_native_hba, resp.resp_bytes[0]);
+
                hw_fib = (struct hw_fib *)((unsigned char *)hw_fib +
-                       dev->max_fib_size + sizeof(struct aac_fib_xporthdr));
+                       dev->max_cmd_size + sizeof(struct aac_fib_xporthdr));
                hw_fib_pa = hw_fib_pa +
-                       dev->max_fib_size + sizeof(struct aac_fib_xporthdr);
+                       dev->max_cmd_size + sizeof(struct aac_fib_xporthdr);
        }
 
        /*
@@ -273,7 +298,8 @@ void aac_fib_free(struct fib *fibptr)
        spin_lock_irqsave(&fibptr->dev->fib_lock, flags);
        if (unlikely(fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT))
                aac_config.fib_timeouts++;
-       if (fibptr->hw_fib_va->header.XferState != 0) {
+       if (!(fibptr->flags & FIB_CONTEXT_FLAG_NATIVE_HBA) &&
+               fibptr->hw_fib_va->header.XferState != 0) {
                printk(KERN_WARNING "aac_fib_free, XferState != 0, fibptr = 0x%p, XferState = 0x%x\n",
                         (void*)fibptr,
                         le32_to_cpu(fibptr->hw_fib_va->header.XferState));
@@ -501,8 +527,15 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
         *      Map the fib into 32bits by using the fib number
         */
 
-       hw_fib->header.SenderFibAddress = cpu_to_le32(((u32)(fibptr - dev->fibs)) << 2);
-       hw_fib->header.Handle = (u32)(fibptr - dev->fibs) + 1;
+       hw_fib->header.SenderFibAddress =
+               cpu_to_le32(((u32)(fibptr - dev->fibs)) << 2);
+
+       /* use the same shifted value for handle to be compatible
+        * with the new native hba command handle
+        */
+       hw_fib->header.Handle =
+               cpu_to_le32((((u32)(fibptr - dev->fibs)) << 2) + 1);
+
        /*
         *      Set FIB state to indicate where it came from and if we want a
         *      response from the adapter. Also load the command from the
@@ -670,6 +703,82 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
                return 0;
 }
 
+int aac_hba_send(u8 command, struct fib *fibptr, fib_callback callback,
+               void *callback_data)
+{
+       struct aac_dev *dev = fibptr->dev;
+       int wait;
+       unsigned long flags = 0;
+       unsigned long mflags = 0;
+
+       fibptr->flags = (FIB_CONTEXT_FLAG | FIB_CONTEXT_FLAG_NATIVE_HBA);
+       if (callback) {
+               wait = 0;
+               fibptr->callback = callback;
+               fibptr->callback_data = callback_data;
+       } else
+               wait = 1;
+
+
+       if (command == HBA_IU_TYPE_SCSI_CMD_REQ) {
+               struct aac_hba_cmd_req *hbacmd =
+                       (struct aac_hba_cmd_req *)fibptr->hw_fib_va;
+
+               hbacmd->iu_type = command;
+               /* bit1 of request_id must be 0 */
+               hbacmd->request_id =
+                       cpu_to_le32((((u32)(fibptr - dev->fibs)) << 2) + 1);
+       } else
+               return -EINVAL;
+
+
+       if (wait) {
+               spin_lock_irqsave(&dev->manage_lock, mflags);
+               if (dev->management_fib_count >= AAC_NUM_MGT_FIB) {
+                       spin_unlock_irqrestore(&dev->manage_lock, mflags);
+                       return -EBUSY;
+               }
+               dev->management_fib_count++;
+               spin_unlock_irqrestore(&dev->manage_lock, mflags);
+               spin_lock_irqsave(&fibptr->event_lock, flags);
+       }
+
+       if (aac_adapter_deliver(fibptr) != 0) {
+               if (wait) {
+                       spin_unlock_irqrestore(&fibptr->event_lock, flags);
+                       spin_lock_irqsave(&dev->manage_lock, mflags);
+                       dev->management_fib_count--;
+                       spin_unlock_irqrestore(&dev->manage_lock, mflags);
+               }
+               return -EBUSY;
+       }
+       FIB_COUNTER_INCREMENT(aac_config.NativeSent);
+
+       if (wait) {
+               spin_unlock_irqrestore(&fibptr->event_lock, flags);
+               /* Only set for first known interruptable command */
+               if (down_interruptible(&fibptr->event_wait)) {
+                       fibptr->done = 2;
+                       up(&fibptr->event_wait);
+               }
+               spin_lock_irqsave(&fibptr->event_lock, flags);
+               if ((fibptr->done == 0) || (fibptr->done == 2)) {
+                       fibptr->done = 2; /* Tell interrupt we aborted */
+                       spin_unlock_irqrestore(&fibptr->event_lock, flags);
+                       return -ERESTARTSYS;
+               }
+               spin_unlock_irqrestore(&fibptr->event_lock, flags);
+               WARN_ON(fibptr->done == 0);
+
+               if (unlikely(fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT))
+                       return -ETIMEDOUT;
+
+               return 0;
+       }
+
+       return -EINPROGRESS;
+}
+
 /**
  *     aac_consumer_get        -       get the top of the queue
  *     @dev: Adapter
@@ -761,7 +870,8 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size)
        unsigned long qflags;
 
        if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1 ||
-           dev->comm_interface == AAC_COMM_MESSAGE_TYPE2) {
+               dev->comm_interface == AAC_COMM_MESSAGE_TYPE2 ||
+               dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) {
                kfree(hw_fib);
                return 0;
        }
@@ -827,11 +937,17 @@ int aac_fib_complete(struct fib *fibptr)
 {
        struct hw_fib * hw_fib = fibptr->hw_fib_va;
 
+       if (fibptr->flags & FIB_CONTEXT_FLAG_NATIVE_HBA) {
+               fib_dealloc(fibptr);
+               return 0;
+       }
+
        /*
-        *      Check for a fib which has already been completed
+        *      Check for a fib which has already been completed or with a
+        *      status wait timeout
         */
 
-       if (hw_fib->header.XferState == 0)
+       if (hw_fib->header.XferState == 0 || fibptr->done == 2)
                return 0;
        /*
         *      If we plan to do anything check the structure type first.
@@ -984,20 +1100,9 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
                        lun = (container >> 16) & 0xFF;
                        container = (u32)-1;
                        channel = aac_phys_to_logical(channel);
-                       device_config_needed =
-                         (((__le32 *)aifcmd->data)[0] ==
-                           cpu_to_le32(AifRawDeviceRemove)) ? DELETE : ADD;
-
-                       if (device_config_needed == ADD) {
-                               device = scsi_device_lookup(
-                                       dev->scsi_host_ptr,
-                                       channel, id, lun);
-                               if (device) {
-                                       scsi_remove_device(device);
-                                       scsi_device_put(device);
-                               }
-                       }
+                       device_config_needed = DELETE;
                        break;
+
                /*
                 *      Morph or Expand complete
                 */
@@ -1351,7 +1456,7 @@ retry_next:
        }
 }
 
-static int _aac_reset_adapter(struct aac_dev *aac, int forced)
+static int _aac_reset_adapter(struct aac_dev *aac, int forced, u8 reset_type)
 {
        int index, quirks;
        int retval;
@@ -1360,6 +1465,7 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
        struct scsi_cmnd *command;
        struct scsi_cmnd *command_list;
        int jafo = 0;
+       int bled;
 
        /*
         * Assumptions:
@@ -1384,7 +1490,8 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
         *      If a positive health, means in a known DEAD PANIC
         * state and the adapter could be reset to `try again'.
         */
-       retval = aac_adapter_restart(aac, forced ? 0 : aac_adapter_check_health(aac));
+       bled = forced ? 0 : aac_adapter_check_health(aac);
+       retval = aac_adapter_restart(aac, bled, reset_type);
 
        if (retval)
                goto out;
@@ -1494,11 +1601,12 @@ out:
        return retval;
 }
 
-int aac_reset_adapter(struct aac_dev * aac, int forced)
+int aac_reset_adapter(struct aac_dev *aac, int forced, u8 reset_type)
 {
        unsigned long flagv = 0;
        int retval;
        struct Scsi_Host * host;
+       int bled;
 
        if (spin_trylock_irqsave(&aac->fib_lock, flagv) == 0)
                return -EBUSY;
@@ -1547,7 +1655,9 @@ int aac_reset_adapter(struct aac_dev * aac, int forced)
        if (forced < 2)
                aac_send_shutdown(aac);
        spin_lock_irqsave(host->host_lock, flagv);
-       retval = _aac_reset_adapter(aac, forced ? forced : ((aac_check_reset != 0) && (aac_check_reset != 1)));
+       bled = forced ? forced :
+                       (aac_check_reset != 0 && aac_check_reset != 1);
+       retval = _aac_reset_adapter(aac, bled, reset_type);
        spin_unlock_irqrestore(host->host_lock, flagv);
 
        if ((forced < 2) && (retval == -ENODEV)) {
@@ -1593,6 +1703,7 @@ int aac_check_health(struct aac_dev * aac)
        unsigned long time_now, flagv = 0;
        struct list_head * entry;
        struct Scsi_Host * host;
+       int bled;
 
        /* Extending the scope of fib_lock slightly to protect aac->in_reset */
        if (spin_trylock_irqsave(&aac->fib_lock, flagv) == 0)
@@ -1710,7 +1821,8 @@ int aac_check_health(struct aac_dev * aac)
        host = aac->scsi_host_ptr;
        if (aac->thread->pid != current->pid)
                spin_lock_irqsave(host->host_lock, flagv);
-       BlinkLED = _aac_reset_adapter(aac, aac_check_reset != 1);
+       bled = aac_check_reset != 1 ? 1 : 0;
+       _aac_reset_adapter(aac, bled, IOP_HWSOFT_RESET);
        if (aac->thread->pid != current->pid)
                spin_unlock_irqrestore(host->host_lock, flagv);
        return BlinkLED;
@@ -1721,6 +1833,552 @@ out:
 }
 
 
+static void aac_resolve_luns(struct aac_dev *dev)
+{
+       int bus, target, channel;
+       struct scsi_device *sdev;
+       u8 devtype;
+       u8 new_devtype;
+
+       for (bus = 0; bus < AAC_MAX_BUSES; bus++) {
+               for (target = 0; target < AAC_MAX_TARGETS; target++) {
+
+                       if (aac_phys_to_logical(bus) == ENCLOSURE_CHANNEL)
+                               continue;
+
+                       if (bus == CONTAINER_CHANNEL)
+                               channel = CONTAINER_CHANNEL;
+                       else
+                               channel = aac_phys_to_logical(bus);
+
+                       devtype = dev->hba_map[bus][target].devtype;
+                       new_devtype = dev->hba_map[bus][target].new_devtype;
+
+                       sdev = scsi_device_lookup(dev->scsi_host_ptr, channel,
+                                       target, 0);
+
+                       if (!sdev && devtype)
+                               scsi_add_device(dev->scsi_host_ptr, channel,
+                                               target, 0);
+                       else if (sdev && new_devtype != devtype)
+                               scsi_remove_device(sdev);
+                       else if (sdev && new_devtype == devtype)
+                               scsi_rescan_device(&sdev->sdev_gendev);
+
+                       if (sdev)
+                               scsi_device_put(sdev);
+
+                       dev->hba_map[bus][target].devtype = new_devtype;
+               }
+       }
+}
+
+/**
+ *     aac_handle_sa_aif       Handle a message from the firmware
+ *     @dev: Which adapter this fib is from
+ *     @fibptr: Pointer to fibptr from adapter
+ *
+ *     This routine handles a driver notify fib from the adapter and
+ *     dispatches it to the appropriate routine for handling.
+ */
+static void aac_handle_sa_aif(struct aac_dev *dev, struct fib *fibptr)
+{
+       int i, bus, target, container, rcode = 0;
+       u32 events = 0;
+       struct fib *fib;
+       struct scsi_device *sdev;
+
+       if (fibptr->hbacmd_size & SA_AIF_HOTPLUG)
+               events = SA_AIF_HOTPLUG;
+       else if (fibptr->hbacmd_size & SA_AIF_HARDWARE)
+               events = SA_AIF_HARDWARE;
+       else if (fibptr->hbacmd_size & SA_AIF_PDEV_CHANGE)
+               events = SA_AIF_PDEV_CHANGE;
+       else if (fibptr->hbacmd_size & SA_AIF_LDEV_CHANGE)
+               events = SA_AIF_LDEV_CHANGE;
+       else if (fibptr->hbacmd_size & SA_AIF_BPSTAT_CHANGE)
+               events = SA_AIF_BPSTAT_CHANGE;
+       else if (fibptr->hbacmd_size & SA_AIF_BPCFG_CHANGE)
+               events = SA_AIF_BPCFG_CHANGE;
+
+       switch (events) {
+       case SA_AIF_HOTPLUG:
+       case SA_AIF_HARDWARE:
+       case SA_AIF_PDEV_CHANGE:
+       case SA_AIF_LDEV_CHANGE:
+       case SA_AIF_BPCFG_CHANGE:
+
+               fib = aac_fib_alloc(dev);
+               if (!fib) {
+                       pr_err("aac_handle_sa_aif: out of memory\n");
+                       return;
+               }
+               for (bus = 0; bus < AAC_MAX_BUSES; bus++)
+                       for (target = 0; target < AAC_MAX_TARGETS; target++)
+                               dev->hba_map[bus][target].new_devtype = 0;
+
+               rcode = aac_report_phys_luns(dev, fib, AAC_RESCAN);
+
+               if (rcode != -ERESTARTSYS)
+                       aac_fib_free(fib);
+
+               aac_resolve_luns(dev);
+
+               if (events == SA_AIF_LDEV_CHANGE ||
+                   events == SA_AIF_BPCFG_CHANGE) {
+                       aac_get_containers(dev);
+                       for (container = 0; container <
+                       dev->maximum_num_containers; ++container) {
+                               sdev = scsi_device_lookup(dev->scsi_host_ptr,
+                                               CONTAINER_CHANNEL,
+                                               container, 0);
+                               if (dev->fsa_dev[container].valid && !sdev) {
+                                       scsi_add_device(dev->scsi_host_ptr,
+                                               CONTAINER_CHANNEL,
+                                               container, 0);
+                               } else if (!dev->fsa_dev[container].valid &&
+                                       sdev) {
+                                       scsi_remove_device(sdev);
+                                       scsi_device_put(sdev);
+                               } else if (sdev) {
+                                       scsi_rescan_device(&sdev->sdev_gendev);
+                                       scsi_device_put(sdev);
+                               }
+                       }
+               }
+               break;
+
+       case SA_AIF_BPSTAT_CHANGE:
+               /* currently do nothing */
+               break;
+       }
+
+       for (i = 1; i <= 10; ++i) {
+               events = src_readl(dev, MUnit.IDR);
+               if (events & (1<<23)) {
+                       pr_warn(" AIF not cleared by firmware - %d/%d)\n",
+                               i, 10);
+                       ssleep(1);
+               }
+       }
+}
+
+static int get_fib_count(struct aac_dev *dev)
+{
+       unsigned int num = 0;
+       struct list_head *entry;
+       unsigned long flagv;
+
+       /*
+        * Warning: no sleep allowed while
+        * holding spinlock. We take the estimate
+        * and pre-allocate a set of fibs outside the
+        * lock.
+        */
+       num = le32_to_cpu(dev->init->r7.adapter_fibs_size)
+                       / sizeof(struct hw_fib); /* some extra */
+       spin_lock_irqsave(&dev->fib_lock, flagv);
+       entry = dev->fib_list.next;
+       while (entry != &dev->fib_list) {
+               entry = entry->next;
+               ++num;
+       }
+       spin_unlock_irqrestore(&dev->fib_lock, flagv);
+
+       return num;
+}
+
+static int fillup_pools(struct aac_dev *dev, struct hw_fib **hw_fib_pool,
+                                               struct fib **fib_pool,
+                                               unsigned int num)
+{
+       struct hw_fib **hw_fib_p;
+       struct fib **fib_p;
+       int rcode = 1;
+
+       hw_fib_p = hw_fib_pool;
+       fib_p = fib_pool;
+       while (hw_fib_p < &hw_fib_pool[num]) {
+               *(hw_fib_p) = kmalloc(sizeof(struct hw_fib), GFP_KERNEL);
+               if (!(*(hw_fib_p++))) {
+                       --hw_fib_p;
+                       break;
+               }
+
+               *(fib_p) = kmalloc(sizeof(struct fib), GFP_KERNEL);
+               if (!(*(fib_p++))) {
+                       kfree(*(--hw_fib_p));
+                       break;
+               }
+       }
+
+       num = hw_fib_p - hw_fib_pool;
+       if (!num)
+               rcode = 0;
+
+       return rcode;
+}
+
+static void wakeup_fibctx_threads(struct aac_dev *dev,
+                                               struct hw_fib **hw_fib_pool,
+                                               struct fib **fib_pool,
+                                               struct fib *fib,
+                                               struct hw_fib *hw_fib,
+                                               unsigned int num)
+{
+       unsigned long flagv;
+       struct list_head *entry;
+       struct hw_fib **hw_fib_p;
+       struct fib **fib_p;
+       u32 time_now, time_last;
+       struct hw_fib *hw_newfib;
+       struct fib *newfib;
+       struct aac_fib_context *fibctx;
+
+       time_now = jiffies/HZ;
+       spin_lock_irqsave(&dev->fib_lock, flagv);
+       entry = dev->fib_list.next;
+       /*
+        * For each Context that is on the
+        * fibctxList, make a copy of the
+        * fib, and then set the event to wake up the
+        * thread that is waiting for it.
+        */
+
+       hw_fib_p = hw_fib_pool;
+       fib_p = fib_pool;
+       while (entry != &dev->fib_list) {
+               /*
+                * Extract the fibctx
+                */
+               fibctx = list_entry(entry, struct aac_fib_context,
+                               next);
+               /*
+                * Check if the queue is getting
+                * backlogged
+                */
+               if (fibctx->count > 20) {
+                       /*
+                        * It's *not* jiffies folks,
+                        * but jiffies / HZ so do not
+                        * panic ...
+                        */
+                       time_last = fibctx->jiffies;
+                       /*
+                        * Has it been > 2 minutes
+                        * since the last read off
+                        * the queue?
+                        */
+                       if ((time_now - time_last) > aif_timeout) {
+                               entry = entry->next;
+                               aac_close_fib_context(dev, fibctx);
+                               continue;
+                       }
+               }
+               /*
+                * Warning: no sleep allowed while
+                * holding spinlock
+                */
+               if (hw_fib_p >= &hw_fib_pool[num]) {
+                       pr_warn("aifd: didn't allocate NewFib\n");
+                       entry = entry->next;
+                       continue;
+               }
+
+               hw_newfib = *hw_fib_p;
+               *(hw_fib_p++) = NULL;
+               newfib = *fib_p;
+               *(fib_p++) = NULL;
+               /*
+                * Make the copy of the FIB
+                */
+               memcpy(hw_newfib, hw_fib, sizeof(struct hw_fib));
+               memcpy(newfib, fib, sizeof(struct fib));
+               newfib->hw_fib_va = hw_newfib;
+               /*
+                * Put the FIB onto the
+                * fibctx's fibs
+                */
+               list_add_tail(&newfib->fiblink, &fibctx->fib_list);
+               fibctx->count++;
+               /*
+                * Set the event to wake up the
+                * thread that is waiting.
+                */
+               up(&fibctx->wait_sem);
+
+               entry = entry->next;
+       }
+       /*
+        *      Set the status of this FIB
+        */
+       *(__le32 *)hw_fib->data = cpu_to_le32(ST_OK);
+       aac_fib_adapter_complete(fib, sizeof(u32));
+       spin_unlock_irqrestore(&dev->fib_lock, flagv);
+
+}
+
+static void aac_process_events(struct aac_dev *dev)
+{
+       struct hw_fib *hw_fib;
+       struct fib *fib;
+       unsigned long flags;
+       spinlock_t *t_lock;
+       unsigned int rcode;
+
+       t_lock = dev->queues->queue[HostNormCmdQueue].lock;
+       spin_lock_irqsave(t_lock, flags);
+
+       while (!list_empty(&(dev->queues->queue[HostNormCmdQueue].cmdq))) {
+               struct list_head *entry;
+               struct aac_aifcmd *aifcmd;
+               unsigned int  num;
+               struct hw_fib **hw_fib_pool, **hw_fib_p;
+               struct fib **fib_pool, **fib_p;
+
+               set_current_state(TASK_RUNNING);
+
+               entry = dev->queues->queue[HostNormCmdQueue].cmdq.next;
+               list_del(entry);
+
+               t_lock = dev->queues->queue[HostNormCmdQueue].lock;
+               spin_unlock_irqrestore(t_lock, flags);
+
+               fib = list_entry(entry, struct fib, fiblink);
+               hw_fib = fib->hw_fib_va;
+               if (dev->sa_firmware) {
+                       /* Thor AIF */
+                       aac_handle_sa_aif(dev, fib);
+                       aac_fib_adapter_complete(fib, (u16)sizeof(u32));
+                       continue;
+               }
+               /*
+                *      We will process the FIB here or pass it to a
+                *      worker thread that is TBD. We Really can't
+                *      do anything at this point since we don't have
+                *      anything defined for this thread to do.
+                */
+               memset(fib, 0, sizeof(struct fib));
+               fib->type = FSAFS_NTC_FIB_CONTEXT;
+               fib->size = sizeof(struct fib);
+               fib->hw_fib_va = hw_fib;
+               fib->data = hw_fib->data;
+               fib->dev = dev;
+               /*
+                *      We only handle AifRequest fibs from the adapter.
+                */
+
+               aifcmd = (struct aac_aifcmd *) hw_fib->data;
+               if (aifcmd->command == cpu_to_le32(AifCmdDriverNotify)) {
+                       /* Handle Driver Notify Events */
+                       aac_handle_aif(dev, fib);
+                       *(__le32 *)hw_fib->data = cpu_to_le32(ST_OK);
+                       aac_fib_adapter_complete(fib, (u16)sizeof(u32));
+                       goto free_fib;
+               }
+               /*
+                * The u32 here is important and intended. We are using
+                * 32bit wrapping time to fit the adapter field
+                */
+
+               /* Sniff events */
+               if (aifcmd->command == cpu_to_le32(AifCmdEventNotify)
+                || aifcmd->command == cpu_to_le32(AifCmdJobProgress)) {
+                       aac_handle_aif(dev, fib);
+               }
+
+               /*
+                * get number of fibs to process
+                */
+               num = get_fib_count(dev);
+               if (!num)
+                       goto free_fib;
+
+               hw_fib_pool = kmalloc_array(num, sizeof(struct hw_fib *),
+                                               GFP_KERNEL);
+               if (!hw_fib_pool)
+                       goto free_fib;
+
+               fib_pool = kmalloc_array(num, sizeof(struct fib *), GFP_KERNEL);
+               if (!fib_pool)
+                       goto free_hw_fib_pool;
+
+               /*
+                * Fill up fib pointer pools with actual fibs
+                * and hw_fibs
+                */
+               rcode = fillup_pools(dev, hw_fib_pool, fib_pool, num);
+               if (!rcode)
+                       goto free_mem;
+
+               /*
+                * wakeup the thread that is waiting for
+                * the response from fw (ioctl)
+                */
+               wakeup_fibctx_threads(dev, hw_fib_pool, fib_pool,
+                                                           fib, hw_fib, num);
+
+free_mem:
+               /* Free up the remaining resources */
+               hw_fib_p = hw_fib_pool;
+               fib_p = fib_pool;
+               while (hw_fib_p < &hw_fib_pool[num]) {
+                       kfree(*hw_fib_p);
+                       kfree(*fib_p);
+                       ++fib_p;
+                       ++hw_fib_p;
+               }
+               kfree(fib_pool);
+free_hw_fib_pool:
+               kfree(hw_fib_pool);
+free_fib:
+               kfree(fib);
+               t_lock = dev->queues->queue[HostNormCmdQueue].lock;
+               spin_lock_irqsave(t_lock, flags);
+       }
+       /*
+        *      There are no more AIF's
+        */
+       t_lock = dev->queues->queue[HostNormCmdQueue].lock;
+       spin_unlock_irqrestore(t_lock, flags);
+}
+
+static int aac_send_wellness_command(struct aac_dev *dev, char *wellness_str,
+                                                       u32 datasize)
+{
+       struct aac_srb *srbcmd;
+       struct sgmap64 *sg64;
+       dma_addr_t addr;
+       char *dma_buf;
+       struct fib *fibptr;
+       int ret = -ENOMEM;
+       u32 vbus, vid;
+
+       fibptr = aac_fib_alloc(dev);
+       if (!fibptr)
+               goto out;
+
+       dma_buf = pci_alloc_consistent(dev->pdev, datasize, &addr);
+       if (!dma_buf)
+               goto fib_free_out;
+
+       aac_fib_init(fibptr);
+
+       vbus = (u32)le16_to_cpu(dev->supplement_adapter_info.VirtDeviceBus);
+       vid = (u32)le16_to_cpu(dev->supplement_adapter_info.VirtDeviceTarget);
+
+       srbcmd = (struct aac_srb *)fib_data(fibptr);
+
+       srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi);
+       srbcmd->channel = cpu_to_le32(vbus);
+       srbcmd->id = cpu_to_le32(vid);
+       srbcmd->lun = 0;
+       srbcmd->flags = cpu_to_le32(SRB_DataOut);
+       srbcmd->timeout = cpu_to_le32(10);
+       srbcmd->retry_limit = 0;
+       srbcmd->cdb_size = cpu_to_le32(12);
+       srbcmd->count = cpu_to_le32(datasize);
+
+       memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb));
+       srbcmd->cdb[0] = BMIC_OUT;
+       srbcmd->cdb[6] = WRITE_HOST_WELLNESS;
+       memcpy(dma_buf, (char *)wellness_str, datasize);
+
+       sg64 = (struct sgmap64 *)&srbcmd->sg;
+       sg64->count = cpu_to_le32(1);
+       sg64->sg[0].addr[1] = cpu_to_le32((u32)(((addr) >> 16) >> 16));
+       sg64->sg[0].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff));
+       sg64->sg[0].count = cpu_to_le32(datasize);
+
+       ret = aac_fib_send(ScsiPortCommand64, fibptr, sizeof(struct aac_srb),
+                               FsaNormal, 1, 1, NULL, NULL);
+
+       pci_free_consistent(dev->pdev, datasize, (void *)dma_buf, addr);
+
+       /*
+        * Do not set XferState to zero unless
+        * receives a response from F/W
+        */
+       if (ret >= 0)
+               aac_fib_complete(fibptr);
+
+       /*
+        * FIB should be freed only after
+        * getting the response from the F/W
+        */
+       if (ret != -ERESTARTSYS)
+               goto fib_free_out;
+
+out:
+       return ret;
+fib_free_out:
+       aac_fib_free(fibptr);
+       goto out;
+}
+
+int aac_send_safw_hostttime(struct aac_dev *dev, struct timeval *now)
+{
+       struct tm cur_tm;
+       char wellness_str[] = "<HW>TD\010\0\0\0\0\0\0\0\0\0DW\0\0ZZ";
+       u32 datasize = sizeof(wellness_str);
+       unsigned long local_time;
+       int ret = -ENODEV;
+
+       if (!dev->sa_firmware)
+               goto out;
+
+       local_time = (u32)(now->tv_sec - (sys_tz.tz_minuteswest * 60));
+       time_to_tm(local_time, 0, &cur_tm);
+       cur_tm.tm_mon += 1;
+       cur_tm.tm_year += 1900;
+       wellness_str[8] = bin2bcd(cur_tm.tm_hour);
+       wellness_str[9] = bin2bcd(cur_tm.tm_min);
+       wellness_str[10] = bin2bcd(cur_tm.tm_sec);
+       wellness_str[12] = bin2bcd(cur_tm.tm_mon);
+       wellness_str[13] = bin2bcd(cur_tm.tm_mday);
+       wellness_str[14] = bin2bcd(cur_tm.tm_year / 100);
+       wellness_str[15] = bin2bcd(cur_tm.tm_year % 100);
+
+       ret = aac_send_wellness_command(dev, wellness_str, datasize);
+
+out:
+       return ret;
+}
+
+int aac_send_hosttime(struct aac_dev *dev, struct timeval *now)
+{
+       int ret = -ENOMEM;
+       struct fib *fibptr;
+       __le32 *info;
+
+       fibptr = aac_fib_alloc(dev);
+       if (!fibptr)
+               goto out;
+
+       aac_fib_init(fibptr);
+       info = (__le32 *)fib_data(fibptr);
+       *info = cpu_to_le32(now->tv_sec);
+       ret = aac_fib_send(SendHostTime, fibptr, sizeof(*info), FsaNormal,
+                                       1, 1, NULL, NULL);
+
+       /*
+        * Do not set XferState to zero unless
+        * receives a response from F/W
+        */
+       if (ret >= 0)
+               aac_fib_complete(fibptr);
+
+       /*
+        * FIB should be freed only after
+        * getting the response from the F/W
+        */
+       if (ret != -ERESTARTSYS)
+               aac_fib_free(fibptr);
+
+out:
+       return ret;
+}
+
 /**
  *     aac_command_thread      -       command processing thread
  *     @dev: Adapter to monitor
@@ -1734,10 +2392,6 @@ out:
 int aac_command_thread(void *data)
 {
        struct aac_dev *dev = data;
-       struct hw_fib *hw_fib, *hw_newfib;
-       struct fib *fib, *newfib;
-       struct aac_fib_context *fibctx;
-       unsigned long flags;
        DECLARE_WAITQUEUE(wait, current);
        unsigned long next_jiffies = jiffies + HZ;
        unsigned long next_check_jiffies = next_jiffies;
@@ -1757,196 +2411,8 @@ int aac_command_thread(void *data)
        set_current_state(TASK_INTERRUPTIBLE);
        dprintk ((KERN_INFO "aac_command_thread start\n"));
        while (1) {
-               spin_lock_irqsave(dev->queues->queue[HostNormCmdQueue].lock, flags);
-               while(!list_empty(&(dev->queues->queue[HostNormCmdQueue].cmdq))) {
-                       struct list_head *entry;
-                       struct aac_aifcmd * aifcmd;
-
-                       set_current_state(TASK_RUNNING);
 
-                       entry = dev->queues->queue[HostNormCmdQueue].cmdq.next;
-                       list_del(entry);
-
-                       spin_unlock_irqrestore(dev->queues->queue[HostNormCmdQueue].lock, flags);
-                       fib = list_entry(entry, struct fib, fiblink);
-                       /*
-                        *      We will process the FIB here or pass it to a
-                        *      worker thread that is TBD. We Really can't
-                        *      do anything at this point since we don't have
-                        *      anything defined for this thread to do.
-                        */
-                       hw_fib = fib->hw_fib_va;
-                       memset(fib, 0, sizeof(struct fib));
-                       fib->type = FSAFS_NTC_FIB_CONTEXT;
-                       fib->size = sizeof(struct fib);
-                       fib->hw_fib_va = hw_fib;
-                       fib->data = hw_fib->data;
-                       fib->dev = dev;
-                       /*
-                        *      We only handle AifRequest fibs from the adapter.
-                        */
-                       aifcmd = (struct aac_aifcmd *) hw_fib->data;
-                       if (aifcmd->command == cpu_to_le32(AifCmdDriverNotify)) {
-                               /* Handle Driver Notify Events */
-                               aac_handle_aif(dev, fib);
-                               *(__le32 *)hw_fib->data = cpu_to_le32(ST_OK);
-                               aac_fib_adapter_complete(fib, (u16)sizeof(u32));
-                       } else {
-                               /* The u32 here is important and intended. We are using
-                                  32bit wrapping time to fit the adapter field */
-
-                               u32 time_now, time_last;
-                               unsigned long flagv;
-                               unsigned num;
-                               struct hw_fib ** hw_fib_pool, ** hw_fib_p;
-                               struct fib ** fib_pool, ** fib_p;
-
-                               /* Sniff events */
-                               if ((aifcmd->command ==
-                                    cpu_to_le32(AifCmdEventNotify)) ||
-                                   (aifcmd->command ==
-                                    cpu_to_le32(AifCmdJobProgress))) {
-                                       aac_handle_aif(dev, fib);
-                               }
-
-                               time_now = jiffies/HZ;
-
-                               /*
-                                * Warning: no sleep allowed while
-                                * holding spinlock. We take the estimate
-                                * and pre-allocate a set of fibs outside the
-                                * lock.
-                                */
-                               num = le32_to_cpu(dev->init->AdapterFibsSize)
-                                   / sizeof(struct hw_fib); /* some extra */
-                               spin_lock_irqsave(&dev->fib_lock, flagv);
-                               entry = dev->fib_list.next;
-                               while (entry != &dev->fib_list) {
-                                       entry = entry->next;
-                                       ++num;
-                               }
-                               spin_unlock_irqrestore(&dev->fib_lock, flagv);
-                               hw_fib_pool = NULL;
-                               fib_pool = NULL;
-                               if (num
-                                && ((hw_fib_pool = kmalloc(sizeof(struct hw_fib *) * num, GFP_KERNEL)))
-                                && ((fib_pool = kmalloc(sizeof(struct fib *) * num, GFP_KERNEL)))) {
-                                       hw_fib_p = hw_fib_pool;
-                                       fib_p = fib_pool;
-                                       while (hw_fib_p < &hw_fib_pool[num]) {
-                                               if (!(*(hw_fib_p++) = kmalloc(sizeof(struct hw_fib), GFP_KERNEL))) {
-                                                       --hw_fib_p;
-                                                       break;
-                                               }
-                                               if (!(*(fib_p++) = kmalloc(sizeof(struct fib), GFP_KERNEL))) {
-                                                       kfree(*(--hw_fib_p));
-                                                       break;
-                                               }
-                                       }
-                                       if ((num = hw_fib_p - hw_fib_pool) == 0) {
-                                               kfree(fib_pool);
-                                               fib_pool = NULL;
-                                               kfree(hw_fib_pool);
-                                               hw_fib_pool = NULL;
-                                       }
-                               } else {
-                                       kfree(hw_fib_pool);
-                                       hw_fib_pool = NULL;
-                               }
-                               spin_lock_irqsave(&dev->fib_lock, flagv);
-                               entry = dev->fib_list.next;
-                               /*
-                                * For each Context that is on the
-                                * fibctxList, make a copy of the
-                                * fib, and then set the event to wake up the
-                                * thread that is waiting for it.
-                                */
-                               hw_fib_p = hw_fib_pool;
-                               fib_p = fib_pool;
-                               while (entry != &dev->fib_list) {
-                                       /*
-                                        * Extract the fibctx
-                                        */
-                                       fibctx = list_entry(entry, struct aac_fib_context, next);
-                                       /*
-                                        * Check if the queue is getting
-                                        * backlogged
-                                        */
-                                       if (fibctx->count > 20)
-                                       {
-                                               /*
-                                                * It's *not* jiffies folks,
-                                                * but jiffies / HZ so do not
-                                                * panic ...
-                                                */
-                                               time_last = fibctx->jiffies;
-                                               /*
-                                                * Has it been > 2 minutes
-                                                * since the last read off
-                                                * the queue?
-                                                */
-                                               if ((time_now - time_last) > aif_timeout) {
-                                                       entry = entry->next;
-                                                       aac_close_fib_context(dev, fibctx);
-                                                       continue;
-                                               }
-                                       }
-                                       /*
-                                        * Warning: no sleep allowed while
-                                        * holding spinlock
-                                        */
-                                       if (hw_fib_p < &hw_fib_pool[num]) {
-                                               hw_newfib = *hw_fib_p;
-                                               *(hw_fib_p++) = NULL;
-                                               newfib = *fib_p;
-                                               *(fib_p++) = NULL;
-                                               /*
-                                                * Make the copy of the FIB
-                                                */
-                                               memcpy(hw_newfib, hw_fib, sizeof(struct hw_fib));
-                                               memcpy(newfib, fib, sizeof(struct fib));
-                                               newfib->hw_fib_va = hw_newfib;
-                                               /*
-                                                * Put the FIB onto the
-                                                * fibctx's fibs
-                                                */
-                                               list_add_tail(&newfib->fiblink, &fibctx->fib_list);
-                                               fibctx->count++;
-                                               /*
-                                                * Set the event to wake up the
-                                                * thread that is waiting.
-                                                */
-                                               up(&fibctx->wait_sem);
-                                       } else {
-                                               printk(KERN_WARNING "aifd: didn't allocate NewFib.\n");
-                                       }
-                                       entry = entry->next;
-                               }
-                               /*
-                                *      Set the status of this FIB
-                                */
-                               *(__le32 *)hw_fib->data = cpu_to_le32(ST_OK);
-                               aac_fib_adapter_complete(fib, sizeof(u32));
-                               spin_unlock_irqrestore(&dev->fib_lock, flagv);
-                               /* Free up the remaining resources */
-                               hw_fib_p = hw_fib_pool;
-                               fib_p = fib_pool;
-                               while (hw_fib_p < &hw_fib_pool[num]) {
-                                       kfree(*hw_fib_p);
-                                       kfree(*fib_p);
-                                       ++fib_p;
-                                       ++hw_fib_p;
-                               }
-                               kfree(hw_fib_pool);
-                               kfree(fib_pool);
-                       }
-                       kfree(fib);
-                       spin_lock_irqsave(dev->queues->queue[HostNormCmdQueue].lock, flags);
-               }
-               /*
-                *      There are no more AIF's
-                */
-               spin_unlock_irqrestore(dev->queues->queue[HostNormCmdQueue].lock, flags);
+               aac_process_events(dev);
 
                /*
                 *      Background activity
@@ -1968,7 +2434,7 @@ int aac_command_thread(void *data)
 
                        /* Don't even try to talk to adapter if its sick */
                        ret = aac_check_health(dev);
-                       if (!ret && !dev->queues)
+                       if (!dev->queues)
                                break;
                        next_check_jiffies = jiffies
                                           + ((long)(unsigned)check_interval)
@@ -1981,36 +2447,16 @@ int aac_command_thread(void *data)
                                difference = (((1000000 - now.tv_usec) * HZ)
                                  + 500000) / 1000000;
                        else if (ret == 0) {
-                               struct fib *fibptr;
-
-                               if ((fibptr = aac_fib_alloc(dev))) {
-                                       int status;
-                                       __le32 *info;
-
-                                       aac_fib_init(fibptr);
-
-                                       info = (__le32 *) fib_data(fibptr);
-                                       if (now.tv_usec > 500000)
-                                               ++now.tv_sec;
-
-                                       *info = cpu_to_le32(now.tv_sec);
-
-                                       status = aac_fib_send(SendHostTime,
-                                               fibptr,
-                                               sizeof(*info),
-                                               FsaNormal,
-                                               1, 1,
-                                               NULL,
-                                               NULL);
-                                       /* Do not set XferState to zero unless
-                                        * receives a response from F/W */
-                                       if (status >= 0)
-                                               aac_fib_complete(fibptr);
-                                       /* FIB should be freed only after
-                                        * getting the response from the F/W */
-                                       if (status != -ERESTARTSYS)
-                                               aac_fib_free(fibptr);
-                               }
+
+                               if (now.tv_usec > 500000)
+                                       ++now.tv_sec;
+
+                               if (dev->sa_firmware)
+                                       ret =
+                                       aac_send_safw_hostttime(dev, &now);
+                               else
+                                       ret = aac_send_hosttime(dev, &now);
+
                                difference = (long)(unsigned)update_interval*HZ;
                        } else {
                                /* retry shortly */
index 7e836205aef1707b65ccc46ab5c49fbad95ee0b2..417ba349e10e3fb51109cc33d2aa4f326dd22700 100644 (file)
@@ -6,7 +6,8 @@
  * Adaptec aacraid device driver for Linux.
  *
  * Copyright (c) 2000-2010 Adaptec, Inc.
- *               2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
+ *               2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
+ *              2016-2017 Microsemi Corp. (aacraid@microsemi.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
@@ -122,7 +123,6 @@ unsigned int aac_response_normal(struct aac_queue * q)
                         *      NOTE:  we cannot touch the fib after this
                         *          call, because it may have been deallocated.
                         */
-                       fib->flags &= FIB_CONTEXT_FLAG_FASTRESP;
                        fib->callback(fib->callback_data, fib);
                } else {
                        unsigned long flagv;
@@ -251,8 +251,9 @@ static void aac_aif_callback(void *context, struct fib * fibptr)
        BUG_ON(fibptr == NULL);
        dev = fibptr->dev;
 
-       if (fibptr->hw_fib_va->header.XferState &
-           cpu_to_le32(NoMoreAifDataAvailable)) {
+       if ((fibptr->hw_fib_va->header.XferState &
+           cpu_to_le32(NoMoreAifDataAvailable)) ||
+               dev->sa_firmware) {
                aac_fib_complete(fibptr);
                aac_fib_free(fibptr);
                return;
@@ -282,8 +283,8 @@ static void aac_aif_callback(void *context, struct fib * fibptr)
  *     know there is a response on our normal priority queue. We will pull off
  *     all QE there are and wake up all the waiters before exiting.
  */
-unsigned int aac_intr_normal(struct aac_dev *dev, u32 index,
-                       int isAif, int isFastResponse, struct hw_fib *aif_fib)
+unsigned int aac_intr_normal(struct aac_dev *dev, u32 index, int isAif,
+       int isFastResponse, struct hw_fib *aif_fib)
 {
        unsigned long mflags;
        dprintk((KERN_INFO "aac_intr_normal(%p,%x)\n", dev, index));
@@ -305,12 +306,14 @@ unsigned int aac_intr_normal(struct aac_dev *dev, u32 index,
                        kfree (fib);
                        return 1;
                }
-               if (aif_fib != NULL) {
+               if (dev->sa_firmware) {
+                       fib->hbacmd_size = index;       /* store event type */
+               } else if (aif_fib != NULL) {
                        memcpy(hw_fib, aif_fib, sizeof(struct hw_fib));
                } else {
-                       memcpy(hw_fib,
-                               (struct hw_fib *)(((uintptr_t)(dev->regs.sa)) +
-                               index), sizeof(struct hw_fib));
+                       memcpy(hw_fib, (struct hw_fib *)
+                               (((uintptr_t)(dev->regs.sa)) + index),
+                               sizeof(struct hw_fib));
                }
                INIT_LIST_HEAD(&fib->fiblink);
                fib->type = FSAFS_NTC_FIB_CONTEXT;
@@ -344,7 +347,7 @@ unsigned int aac_intr_normal(struct aac_dev *dev, u32 index,
                        (fib_callback)aac_aif_callback, fibctx);
        } else {
                struct fib *fib = &dev->fibs[index];
-               struct hw_fib * hwfib = fib->hw_fib_va;
+               int start_callback = 0;
 
                /*
                 *      Remove this fib from the Outstanding I/O queue.
@@ -362,60 +365,104 @@ unsigned int aac_intr_normal(struct aac_dev *dev, u32 index,
                        return 0;
                }
 
-               if (isFastResponse) {
-                       /*
-                        *      Doctor the fib
-                        */
-                       *(__le32 *)hwfib->data = cpu_to_le32(ST_OK);
-                       hwfib->header.XferState |= cpu_to_le32(AdapterProcessed);
-                       fib->flags |= FIB_CONTEXT_FLAG_FASTRESP;
-               }
-
                FIB_COUNTER_INCREMENT(aac_config.FibRecved);
 
-               if (hwfib->header.Command == cpu_to_le16(NuFileSystem))
-               {
-                       __le32 *pstatus = (__le32 *)hwfib->data;
-                       if (*pstatus & cpu_to_le32(0xffff0000))
-                               *pstatus = cpu_to_le32(ST_OK);
-               }
-               if (hwfib->header.XferState & cpu_to_le32(NoResponseExpected | Async)) 
-               {
-                       if (hwfib->header.XferState & cpu_to_le32(NoResponseExpected))
-                               FIB_COUNTER_INCREMENT(aac_config.NoResponseRecved);
-                       else 
-                               FIB_COUNTER_INCREMENT(aac_config.AsyncRecved);
-                       /*
-                        *      NOTE:  we cannot touch the fib after this
-                        *          call, because it may have been deallocated.
-                        */
-                       if (likely(fib->callback && fib->callback_data)) {
-                               fib->flags &= FIB_CONTEXT_FLAG_FASTRESP;
-                               fib->callback(fib->callback_data, fib);
-                       } else
-                               dev_info(&dev->pdev->dev,
-                               "Invalid callback_fib[%d] (*%p)(%p)\n",
-                               index, fib->callback, fib->callback_data);
+               if (fib->flags & FIB_CONTEXT_FLAG_NATIVE_HBA) {
+
+                       if (isFastResponse)
+                               fib->flags |= FIB_CONTEXT_FLAG_FASTRESP;
+
+                       if (fib->callback) {
+                               start_callback = 1;
+                       } else {
+                               unsigned long flagv;
+                               int complete = 0;
+
+                               dprintk((KERN_INFO "event_wait up\n"));
+                               spin_lock_irqsave(&fib->event_lock, flagv);
+                               if (fib->done == 2) {
+                                       fib->done = 1;
+                                       complete = 1;
+                               } else {
+                                       fib->done = 1;
+                                       up(&fib->event_wait);
+                               }
+                               spin_unlock_irqrestore(&fib->event_lock, flagv);
+
+                               spin_lock_irqsave(&dev->manage_lock, mflags);
+                               dev->management_fib_count--;
+                               spin_unlock_irqrestore(&dev->manage_lock,
+                                       mflags);
+
+                               FIB_COUNTER_INCREMENT(aac_config.NativeRecved);
+                               if (complete)
+                                       aac_fib_complete(fib);
+                       }
                } else {
-                       unsigned long flagv;
-                       dprintk((KERN_INFO "event_wait up\n"));
-                       spin_lock_irqsave(&fib->event_lock, flagv);
-                       if (!fib->done) {
-                               fib->done = 1;
-                               up(&fib->event_wait);
+                       struct hw_fib *hwfib = fib->hw_fib_va;
+
+                       if (isFastResponse) {
+                               /* Doctor the fib */
+                               *(__le32 *)hwfib->data = cpu_to_le32(ST_OK);
+                               hwfib->header.XferState |=
+                                       cpu_to_le32(AdapterProcessed);
+                               fib->flags |= FIB_CONTEXT_FLAG_FASTRESP;
                        }
-                       spin_unlock_irqrestore(&fib->event_lock, flagv);
 
-                       spin_lock_irqsave(&dev->manage_lock, mflags);
-                       dev->management_fib_count--;
-                       spin_unlock_irqrestore(&dev->manage_lock, mflags);
+                       if (hwfib->header.Command ==
+                               cpu_to_le16(NuFileSystem)) {
+                               __le32 *pstatus = (__le32 *)hwfib->data;
 
-                       FIB_COUNTER_INCREMENT(aac_config.NormalRecved);
-                       if (fib->done == 2) {
+                               if (*pstatus & cpu_to_le32(0xffff0000))
+                                       *pstatus = cpu_to_le32(ST_OK);
+                       }
+                       if (hwfib->header.XferState &
+                               cpu_to_le32(NoResponseExpected | Async)) {
+                               if (hwfib->header.XferState & cpu_to_le32(
+                                       NoResponseExpected))
+                                       FIB_COUNTER_INCREMENT(
+                                               aac_config.NoResponseRecved);
+                               else
+                                       FIB_COUNTER_INCREMENT(
+                                               aac_config.AsyncRecved);
+                               start_callback = 1;
+                       } else {
+                               unsigned long flagv;
+                               int complete = 0;
+
+                               dprintk((KERN_INFO "event_wait up\n"));
                                spin_lock_irqsave(&fib->event_lock, flagv);
-                               fib->done = 0;
+                               if (fib->done == 2) {
+                                       fib->done = 1;
+                                       complete = 1;
+                               } else {
+                                       fib->done = 1;
+                                       up(&fib->event_wait);
+                               }
                                spin_unlock_irqrestore(&fib->event_lock, flagv);
+
+                               spin_lock_irqsave(&dev->manage_lock, mflags);
+                               dev->management_fib_count--;
+                               spin_unlock_irqrestore(&dev->manage_lock,
+                                       mflags);
+
+                               FIB_COUNTER_INCREMENT(aac_config.NormalRecved);
+                               if (complete)
+                                       aac_fib_complete(fib);
+                       }
+               }
+
+
+               if (start_callback) {
+                       /*
+                        * NOTE:  we cannot touch the fib after this
+                        *  call, because it may have been deallocated.
+                        */
+                       if (likely(fib->callback && fib->callback_data)) {
+                               fib->callback(fib->callback_data, fib);
+                       } else {
                                aac_fib_complete(fib);
+                               aac_fib_free(fib);
                        }
 
                }
index 3ecbf20ca29f96b970cd4b14c38eb3fdbb3b1511..137d22d3a005ddab73e82beeca66a2d91c24586d 100644 (file)
@@ -6,7 +6,8 @@
  * Adaptec aacraid device driver for Linux.
  *
  * Copyright (c) 2000-2010 Adaptec, Inc.
- *               2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
+ *               2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
+ *              2016-2017 Microsemi Corp. (aacraid@microsemi.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
@@ -57,7 +58,7 @@
 
 #include "aacraid.h"
 
-#define AAC_DRIVER_VERSION             "1.2-1"
+#define AAC_DRIVER_VERSION             "1.2.1"
 #ifndef AAC_DRIVER_BRANCH
 #define AAC_DRIVER_BRANCH              ""
 #endif
@@ -401,61 +402,89 @@ static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev,
 static int aac_slave_configure(struct scsi_device *sdev)
 {
        struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata;
+       int chn, tid;
+       unsigned int depth = 0;
+       unsigned int set_timeout = 0;
+
+       chn = aac_logical_to_phys(sdev_channel(sdev));
+       tid = sdev_id(sdev);
+       if (chn < AAC_MAX_BUSES && tid < AAC_MAX_TARGETS &&
+               aac->hba_map[chn][tid].devtype == AAC_DEVTYPE_NATIVE_RAW) {
+               depth = aac->hba_map[chn][tid].qd_limit;
+               set_timeout = 1;
+               goto common_config;
+       }
+
+
        if (aac->jbod && (sdev->type == TYPE_DISK))
                sdev->removable = 1;
-       if ((sdev->type == TYPE_DISK) &&
-                       (sdev_channel(sdev) != CONTAINER_CHANNEL) &&
-                       (!aac->jbod || sdev->inq_periph_qual) &&
-                       (!aac->raid_scsi_mode || (sdev_channel(sdev) != 2))) {
+
+       if (sdev->type == TYPE_DISK
+        && sdev_channel(sdev) != CONTAINER_CHANNEL
+        && (!aac->jbod || sdev->inq_periph_qual)
+        && (!aac->raid_scsi_mode || (sdev_channel(sdev) != 2))) {
+
                if (expose_physicals == 0)
                        return -ENXIO;
+
                if (expose_physicals < 0)
                        sdev->no_uld_attach = 1;
        }
-       if (sdev->tagged_supported && (sdev->type == TYPE_DISK) &&
-                       (!aac->raid_scsi_mode || (sdev_channel(sdev) != 2)) &&
-                       !sdev->no_uld_attach) {
+
+       if (sdev->tagged_supported
+        &&  sdev->type == TYPE_DISK
+        &&  (!aac->raid_scsi_mode || (sdev_channel(sdev) != 2))
+        && !sdev->no_uld_attach) {
+
                struct scsi_device * dev;
                struct Scsi_Host *host = sdev->host;
                unsigned num_lsu = 0;
                unsigned num_one = 0;
-               unsigned depth;
                unsigned cid;
 
-               /*
-                * Firmware has an individual device recovery time typically
-                * of 35 seconds, give us a margin.
-                */
-               if (sdev->request_queue->rq_timeout < (45 * HZ))
-                       blk_queue_rq_timeout(sdev->request_queue, 45*HZ);
+               set_timeout = 1;
+
                for (cid = 0; cid < aac->maximum_num_containers; ++cid)
                        if (aac->fsa_dev[cid].valid)
                                ++num_lsu;
+
                __shost_for_each_device(dev, host) {
-                       if (dev->tagged_supported && (dev->type == TYPE_DISK) &&
-                                       (!aac->raid_scsi_mode ||
-                                               (sdev_channel(sdev) != 2)) &&
-                                       !dev->no_uld_attach) {
+                       if (dev->tagged_supported
+                        && dev->type == TYPE_DISK
+                        && (!aac->raid_scsi_mode || (sdev_channel(sdev) != 2))
+                        && !dev->no_uld_attach) {
                                if ((sdev_channel(dev) != CONTAINER_CHANNEL)
-                                || !aac->fsa_dev[sdev_id(dev)].valid)
+                                || !aac->fsa_dev[sdev_id(dev)].valid) {
                                        ++num_lsu;
-                       } else
+                               }
+                       } else {
                                ++num_one;
+                       }
                }
+
                if (num_lsu == 0)
                        ++num_lsu;
-               depth = (host->can_queue - num_one) / num_lsu;
-               if (depth > 256)
-                       depth = 256;
-               else if (depth < 2)
-                       depth = 2;
-               scsi_change_queue_depth(sdev, depth);
-       } else {
-               scsi_change_queue_depth(sdev, 1);
 
-               sdev->tagged_supported = 1;
+               depth = (host->can_queue - num_one) / num_lsu;
        }
 
+common_config:
+       /*
+        * Firmware has an individual device recovery time typically
+        * of 35 seconds, give us a margin.
+        */
+       if (set_timeout && sdev->request_queue->rq_timeout < (45 * HZ))
+               blk_queue_rq_timeout(sdev->request_queue, 45*HZ);
+
+       if (depth > 256)
+               depth = 256;
+       else if (depth < 1)
+               depth = 1;
+
+       scsi_change_queue_depth(sdev, depth);
+
+       sdev->tagged_supported = 1;
+
        return 0;
 }
 
@@ -470,6 +499,15 @@ static int aac_slave_configure(struct scsi_device *sdev)
 
 static int aac_change_queue_depth(struct scsi_device *sdev, int depth)
 {
+       struct aac_dev *aac = (struct aac_dev *)(sdev->host->hostdata);
+       int chn, tid, is_native_device = 0;
+
+       chn = aac_logical_to_phys(sdev_channel(sdev));
+       tid = sdev_id(sdev);
+       if (chn < AAC_MAX_BUSES && tid < AAC_MAX_TARGETS &&
+               aac->hba_map[chn][tid].devtype == AAC_DEVTYPE_NATIVE_RAW)
+               is_native_device = 1;
+
        if (sdev->tagged_supported && (sdev->type == TYPE_DISK) &&
            (sdev_channel(sdev) == CONTAINER_CHANNEL)) {
                struct scsi_device * dev;
@@ -491,9 +529,12 @@ static int aac_change_queue_depth(struct scsi_device *sdev, int depth)
                else if (depth < 2)
                        depth = 2;
                return scsi_change_queue_depth(sdev, depth);
+       } else if (is_native_device) {
+               scsi_change_queue_depth(sdev, aac->hba_map[chn][tid].qd_limit);
+       } else {
+               scsi_change_queue_depth(sdev, 1);
        }
-
-       return scsi_change_queue_depth(sdev, 1);
+       return sdev->queue_depth;
 }
 
 static ssize_t aac_show_raid_level(struct device *dev, struct device_attribute *attr, char *buf)
@@ -516,8 +557,39 @@ static struct device_attribute aac_raid_level_attr = {
        .show = aac_show_raid_level
 };
 
+static ssize_t aac_show_unique_id(struct device *dev,
+            struct device_attribute *attr, char *buf)
+{
+       struct scsi_device *sdev = to_scsi_device(dev);
+       struct aac_dev *aac = (struct aac_dev *)(sdev->host->hostdata);
+       unsigned char sn[16];
+
+       memset(sn, 0, sizeof(sn));
+
+       if (sdev_channel(sdev) == CONTAINER_CHANNEL)
+               memcpy(sn, aac->fsa_dev[sdev_id(sdev)].identifier, sizeof(sn));
+
+       return snprintf(buf, 16 * 2 + 2,
+               "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n",
+               sn[0], sn[1], sn[2], sn[3],
+               sn[4], sn[5], sn[6], sn[7],
+               sn[8], sn[9], sn[10], sn[11],
+               sn[12], sn[13], sn[14], sn[15]);
+}
+
+static struct device_attribute aac_unique_id_attr = {
+       .attr = {
+               .name = "unique_id",
+               .mode = 0444,
+       },
+       .show = aac_show_unique_id
+};
+
+
+
 static struct device_attribute *aac_dev_attrs[] = {
        &aac_raid_level_attr,
+       &aac_unique_id_attr,
        NULL,
 };
 
@@ -534,46 +606,136 @@ static int aac_eh_abort(struct scsi_cmnd* cmd)
        struct scsi_device * dev = cmd->device;
        struct Scsi_Host * host = dev->host;
        struct aac_dev * aac = (struct aac_dev *)host->hostdata;
-       int count;
+       int count, found;
+       u32 bus, cid;
        int ret = FAILED;
 
-       printk(KERN_ERR "%s: Host adapter abort request (%d,%d,%d,%llu)\n",
-               AAC_DRIVERNAME,
-               host->host_no, sdev_channel(dev), sdev_id(dev), dev->lun);
-       switch (cmd->cmnd[0]) {
-       case SERVICE_ACTION_IN_16:
-               if (!(aac->raw_io_interface) ||
-                   !(aac->raw_io_64) ||
-                   ((cmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16))
-                       break;
-       case INQUIRY:
-       case READ_CAPACITY:
-               /* Mark associated FIB to not complete, eh handler does this */
+       bus = aac_logical_to_phys(scmd_channel(cmd));
+       cid = scmd_id(cmd);
+       if (aac->hba_map[bus][cid].devtype == AAC_DEVTYPE_NATIVE_RAW) {
+               struct fib *fib;
+               struct aac_hba_tm_req *tmf;
+               int status;
+               u64 address;
+               __le32 managed_request_id;
+
+               pr_err("%s: Host adapter abort request (%d,%d,%d,%d)\n",
+                AAC_DRIVERNAME,
+                host->host_no, sdev_channel(dev), sdev_id(dev), (int)dev->lun);
+
+               found = 0;
                for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) {
-                       struct fib * fib = &aac->fibs[count];
-                       if (fib->hw_fib_va->header.XferState &&
-                         (fib->flags & FIB_CONTEXT_FLAG) &&
-                         (fib->callback_data == cmd)) {
-                               fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT;
-                               cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER;
+                       fib = &aac->fibs[count];
+                       if (*(u8 *)fib->hw_fib_va != 0 &&
+                               (fib->flags & FIB_CONTEXT_FLAG_NATIVE_HBA) &&
+                               (fib->callback_data == cmd)) {
+                               found = 1;
+                               managed_request_id = ((struct aac_hba_cmd_req *)
+                                       fib->hw_fib_va)->request_id;
+                               break;
+                       }
+               }
+               if (!found)
+                       return ret;
+
+               /* start a HBA_TMF_ABORT_TASK TMF request */
+               fib = aac_fib_alloc(aac);
+               if (!fib)
+                       return ret;
+
+               tmf = (struct aac_hba_tm_req *)fib->hw_fib_va;
+               memset(tmf, 0, sizeof(*tmf));
+               tmf->tmf = HBA_TMF_ABORT_TASK;
+               tmf->it_nexus = aac->hba_map[bus][cid].rmw_nexus;
+               tmf->lun[1] = cmd->device->lun;
+
+               address = (u64)fib->hw_error_pa;
+               tmf->error_ptr_hi = cpu_to_le32((u32)(address >> 32));
+               tmf->error_ptr_lo = cpu_to_le32((u32)(address & 0xffffffff));
+               tmf->error_length = cpu_to_le32(FW_ERROR_BUFFER_SIZE);
+
+               fib->hbacmd_size = sizeof(*tmf);
+               cmd->SCp.sent_command = 0;
+
+               status = aac_hba_send(HBA_IU_TYPE_SCSI_TM_REQ, fib,
+                                 (fib_callback) aac_hba_callback,
+                                 (void *) cmd);
+
+               /* Wait up to 2 minutes for completion */
+               for (count = 0; count < 120; ++count) {
+                       if (cmd->SCp.sent_command) {
                                ret = SUCCESS;
+                               break;
                        }
+                       msleep(1000);
                }
-               break;
-       case TEST_UNIT_READY:
-               /* Mark associated FIB to not complete, eh handler does this */
-               for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) {
-                       struct scsi_cmnd * command;
-                       struct fib * fib = &aac->fibs[count];
-                       if ((fib->hw_fib_va->header.XferState & cpu_to_le32(Async | NoResponseExpected)) &&
-                         (fib->flags & FIB_CONTEXT_FLAG) &&
-                         ((command = fib->callback_data)) &&
-                         (command->device == cmd->device)) {
-                               fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT;
-                               command->SCp.phase = AAC_OWNER_ERROR_HANDLER;
-                               if (command == cmd)
+
+               if (ret != SUCCESS)
+                       pr_err("%s: Host adapter abort request timed out\n",
+                       AAC_DRIVERNAME);
+       } else {
+               pr_err(
+                       "%s: Host adapter abort request.\n"
+                       "%s: Outstanding commands on (%d,%d,%d,%d):\n",
+                       AAC_DRIVERNAME, AAC_DRIVERNAME,
+                       host->host_no, sdev_channel(dev), sdev_id(dev),
+                       (int)dev->lun);
+               switch (cmd->cmnd[0]) {
+               case SERVICE_ACTION_IN_16:
+                       if (!(aac->raw_io_interface) ||
+                           !(aac->raw_io_64) ||
+                           ((cmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16))
+                               break;
+               case INQUIRY:
+               case READ_CAPACITY:
+                       /*
+                        * Mark associated FIB to not complete,
+                        * eh handler does this
+                        */
+                       for (count = 0;
+                               count < (host->can_queue + AAC_NUM_MGT_FIB);
+                               ++count) {
+                               struct fib *fib = &aac->fibs[count];
+
+                               if (fib->hw_fib_va->header.XferState &&
+                               (fib->flags & FIB_CONTEXT_FLAG) &&
+                               (fib->callback_data == cmd)) {
+                                       fib->flags |=
+                                               FIB_CONTEXT_FLAG_TIMED_OUT;
+                                       cmd->SCp.phase =
+                                               AAC_OWNER_ERROR_HANDLER;
                                        ret = SUCCESS;
+                               }
+                       }
+                       break;
+               case TEST_UNIT_READY:
+                       /*
+                        * Mark associated FIB to not complete,
+                        * eh handler does this
+                        */
+                       for (count = 0;
+                               count < (host->can_queue + AAC_NUM_MGT_FIB);
+                               ++count) {
+                               struct scsi_cmnd *command;
+                               struct fib *fib = &aac->fibs[count];
+
+                               command = fib->callback_data;
+
+                               if ((fib->hw_fib_va->header.XferState &
+                                       cpu_to_le32
+                                       (Async | NoResponseExpected)) &&
+                                       (fib->flags & FIB_CONTEXT_FLAG) &&
+                                       ((command)) &&
+                                       (command->device == cmd->device)) {
+                                       fib->flags |=
+                                               FIB_CONTEXT_FLAG_TIMED_OUT;
+                                       command->SCp.phase =
+                                               AAC_OWNER_ERROR_HANDLER;
+                                       if (command == cmd)
+                                               ret = SUCCESS;
+                               }
                        }
+                       break;
                }
        }
        return ret;
@@ -588,70 +750,165 @@ static int aac_eh_reset(struct scsi_cmnd* cmd)
 {
        struct scsi_device * dev = cmd->device;
        struct Scsi_Host * host = dev->host;
-       struct scsi_cmnd * command;
-       int count;
        struct aac_dev * aac = (struct aac_dev *)host->hostdata;
-       unsigned long flags;
-
-       /* Mark the associated FIB to not complete, eh handler does this */
-       for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) {
-               struct fib * fib = &aac->fibs[count];
-               if (fib->hw_fib_va->header.XferState &&
-                 (fib->flags & FIB_CONTEXT_FLAG) &&
-                 (fib->callback_data == cmd)) {
-                       fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT;
-                       cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER;
+       int count;
+       u32 bus, cid;
+       int ret = FAILED;
+
+       bus = aac_logical_to_phys(scmd_channel(cmd));
+       cid = scmd_id(cmd);
+       if (bus < AAC_MAX_BUSES && cid < AAC_MAX_TARGETS &&
+               aac->hba_map[bus][cid].devtype == AAC_DEVTYPE_NATIVE_RAW) {
+               struct fib *fib;
+               int status;
+               u64 address;
+               u8 command;
+
+               pr_err("%s: Host adapter reset request. SCSI hang ?\n",
+                       AAC_DRIVERNAME);
+
+               fib = aac_fib_alloc(aac);
+               if (!fib)
+                       return ret;
+
+
+               if (aac->hba_map[bus][cid].reset_state == 0) {
+                       struct aac_hba_tm_req *tmf;
+
+                       /* start a HBA_TMF_LUN_RESET TMF request */
+                       tmf = (struct aac_hba_tm_req *)fib->hw_fib_va;
+                       memset(tmf, 0, sizeof(*tmf));
+                       tmf->tmf = HBA_TMF_LUN_RESET;
+                       tmf->it_nexus = aac->hba_map[bus][cid].rmw_nexus;
+                       tmf->lun[1] = cmd->device->lun;
+
+                       address = (u64)fib->hw_error_pa;
+                       tmf->error_ptr_hi = cpu_to_le32
+                                       ((u32)(address >> 32));
+                       tmf->error_ptr_lo = cpu_to_le32
+                                       ((u32)(address & 0xffffffff));
+                       tmf->error_length = cpu_to_le32(FW_ERROR_BUFFER_SIZE);
+                       fib->hbacmd_size = sizeof(*tmf);
+
+                       command = HBA_IU_TYPE_SCSI_TM_REQ;
+                       aac->hba_map[bus][cid].reset_state++;
+               } else if (aac->hba_map[bus][cid].reset_state >= 1) {
+                       struct aac_hba_reset_req *rst;
+
+                       /* already tried, start a hard reset now */
+                       rst = (struct aac_hba_reset_req *)fib->hw_fib_va;
+                       memset(rst, 0, sizeof(*rst));
+                       /* reset_type is already zero... */
+                       rst->it_nexus = aac->hba_map[bus][cid].rmw_nexus;
+
+                       address = (u64)fib->hw_error_pa;
+                       rst->error_ptr_hi = cpu_to_le32((u32)(address >> 32));
+                       rst->error_ptr_lo = cpu_to_le32
+                               ((u32)(address & 0xffffffff));
+                       rst->error_length = cpu_to_le32(FW_ERROR_BUFFER_SIZE);
+                       fib->hbacmd_size = sizeof(*rst);
+
+                       command = HBA_IU_TYPE_SATA_REQ;
+                       aac->hba_map[bus][cid].reset_state = 0;
                }
-       }
-       printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n",
-                                       AAC_DRIVERNAME);
+               cmd->SCp.sent_command = 0;
 
-       if ((count = aac_check_health(aac)))
-               return count;
-       /*
-        * Wait for all commands to complete to this specific
-        * target (block maximum 60 seconds).
-        */
-       for (count = 60; count; --count) {
-               int active = aac->in_reset;
+               status = aac_hba_send(command, fib,
+                                 (fib_callback) aac_hba_callback,
+                                 (void *) cmd);
 
-               if (active == 0)
-               __shost_for_each_device(dev, host) {
-                       spin_lock_irqsave(&dev->list_lock, flags);
-                       list_for_each_entry(command, &dev->cmd_list, list) {
-                               if ((command != cmd) &&
-                                   (command->SCp.phase == AAC_OWNER_FIRMWARE)) {
-                                       active++;
-                                       break;
-                               }
-                       }
-                       spin_unlock_irqrestore(&dev->list_lock, flags);
-                       if (active)
+               /* Wait up to 2 minutes for completion */
+               for (count = 0; count < 120; ++count) {
+                       if (cmd->SCp.sent_command) {
+                               ret = SUCCESS;
                                break;
+                       }
+                       msleep(1000);
+               }
 
+               if (ret != SUCCESS)
+                       pr_err("%s: Host adapter reset request timed out\n",
+                       AAC_DRIVERNAME);
+       } else {
+               struct scsi_cmnd *command;
+               unsigned long flags;
+
+               /* Mark the assoc. FIB to not complete, eh handler does this */
+               for (count = 0;
+                       count < (host->can_queue + AAC_NUM_MGT_FIB);
+                       ++count) {
+                       struct fib *fib = &aac->fibs[count];
+
+                       if (fib->hw_fib_va->header.XferState &&
+                               (fib->flags & FIB_CONTEXT_FLAG) &&
+                               (fib->callback_data == cmd)) {
+                               fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT;
+                               cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER;
+                       }
                }
+
+               pr_err("%s: Host adapter reset request. SCSI hang ?\n",
+                                       AAC_DRIVERNAME);
+
+               count = aac_check_health(aac);
+               if (count)
+                       return count;
                /*
-                * We can exit If all the commands are complete
+                * Wait for all commands to complete to this specific
+                * target (block maximum 60 seconds).
                 */
-               if (active == 0)
-                       return SUCCESS;
-               ssleep(1);
+               for (count = 60; count; --count) {
+                       int active = aac->in_reset;
+
+                       if (active == 0)
+                       __shost_for_each_device(dev, host) {
+                               spin_lock_irqsave(&dev->list_lock, flags);
+                               list_for_each_entry(command, &dev->cmd_list,
+                                       list) {
+                                       if ((command != cmd) &&
+                                       (command->SCp.phase ==
+                                       AAC_OWNER_FIRMWARE)) {
+                                               active++;
+                                               break;
+                                       }
+                               }
+                               spin_unlock_irqrestore(&dev->list_lock, flags);
+                               if (active)
+                                       break;
+
+                       }
+                       /*
+                        * We can exit If all the commands are complete
+                        */
+                       if (active == 0)
+                               return SUCCESS;
+                       ssleep(1);
+               }
+               pr_err("%s: SCSI bus appears hung\n", AAC_DRIVERNAME);
+
+               /*
+                * This adapter needs a blind reset, only do so for
+                * Adapters that support a register, instead of a commanded,
+                * reset.
+                */
+               if (((aac->supplement_adapter_info.SupportedOptions2 &
+                         AAC_OPTION_MU_RESET) ||
+                         (aac->supplement_adapter_info.SupportedOptions2 &
+                         AAC_OPTION_DOORBELL_RESET)) &&
+                         aac_check_reset &&
+                         ((aac_check_reset != 1) ||
+                          !(aac->supplement_adapter_info.SupportedOptions2 &
+                           AAC_OPTION_IGNORE_RESET))) {
+                       /* Bypass wait for command quiesce */
+                       aac_reset_adapter(aac, 2, IOP_HWSOFT_RESET);
+               }
+               ret = SUCCESS;
        }
-       printk(KERN_ERR "%s: SCSI bus appears hung\n", AAC_DRIVERNAME);
        /*
-        * This adapter needs a blind reset, only do so for Adapters that
-        * support a register, instead of a commanded, reset.
+        * Cause an immediate retry of the command with a ten second delay
+        * after successful tur
         */
-       if (((aac->supplement_adapter_info.SupportedOptions2 &
-         AAC_OPTION_MU_RESET) ||
-         (aac->supplement_adapter_info.SupportedOptions2 &
-         AAC_OPTION_DOORBELL_RESET)) &&
-         aac_check_reset &&
-         ((aac_check_reset != 1) ||
-          !(aac->supplement_adapter_info.SupportedOptions2 &
-           AAC_OPTION_IGNORE_RESET)))
-               aac_reset_adapter(aac, 2); /* Bypass wait for command quiesce */
-       return SUCCESS; /* Cause an immediate retry of the command with a ten second delay after successful tur */
+       return ret;
 }
 
 /**
@@ -911,10 +1168,16 @@ static ssize_t aac_store_reset_adapter(struct device *device,
                                       const char *buf, size_t count)
 {
        int retval = -EACCES;
+       int bled = 0;
+       struct aac_dev *aac;
+
 
        if (!capable(CAP_SYS_ADMIN))
                return retval;
-       retval = aac_reset_adapter((struct aac_dev*)class_to_shost(device)->hostdata, buf[0] == '!');
+
+       aac = (struct aac_dev *)class_to_shost(device)->hostdata;
+       bled = buf[0] == '!' ? 1:0;
+       retval = aac_reset_adapter(aac, bled, IOP_HWSOFT_RESET);
        if (retval >= 0)
                retval = count;
        return retval;
@@ -1070,6 +1333,7 @@ static void __aac_shutdown(struct aac_dev * aac)
 {
        int i;
 
+       aac->adapter_shutdown = 1;
        aac_send_shutdown(aac);
 
        if (aac->aif_thread) {
@@ -1285,7 +1549,7 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        else
                shost->this_id = shost->max_id;
 
-       if (aac_drivers[index].quirks & AAC_QUIRK_SRC)
+       if (!aac->sa_firmware && aac_drivers[index].quirks & AAC_QUIRK_SRC)
                aac_intr_normal(aac, 0, 2, 0, NULL);
 
        /*
@@ -1327,35 +1591,12 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
 static void aac_release_resources(struct aac_dev *aac)
 {
-       int i;
-
        aac_adapter_disable_int(aac);
-       if (aac->pdev->device == PMC_DEVICE_S6 ||
-           aac->pdev->device == PMC_DEVICE_S7 ||
-           aac->pdev->device == PMC_DEVICE_S8 ||
-           aac->pdev->device == PMC_DEVICE_S9) {
-               if (aac->max_msix > 1) {
-                       for (i = 0; i < aac->max_msix; i++)
-                               free_irq(pci_irq_vector(aac->pdev, i),
-                                       &(aac->aac_msix[i]));
-               } else {
-                       free_irq(aac->pdev->irq, &(aac->aac_msix[0]));
-               }
-       } else {
-               free_irq(aac->pdev->irq, aac);
-       }
-       if (aac->msi)
-               pci_disable_msi(aac->pdev);
-       else if (aac->max_msix > 1)
-               pci_disable_msix(aac->pdev);
-
+       aac_free_irq(aac);
 }
 
 static int aac_acquire_resources(struct aac_dev *dev)
 {
-       int i, j;
-       int instance = dev->id;
-       const char *name = dev->name;
        unsigned long status;
        /*
         *      First clear out all interrupts.  Then enable the one's that we
@@ -1377,37 +1618,8 @@ static int aac_acquire_resources(struct aac_dev *dev)
        if (dev->msi_enabled)
                aac_src_access_devreg(dev, AAC_ENABLE_MSIX);
 
-       if (!dev->sync_mode && dev->msi_enabled && dev->max_msix > 1) {
-               for (i = 0; i < dev->max_msix; i++) {
-                       dev->aac_msix[i].vector_no = i;
-                       dev->aac_msix[i].dev = dev;
-
-                       if (request_irq(pci_irq_vector(dev->pdev, i),
-                                       dev->a_ops.adapter_intr,
-                                       0, "aacraid", &(dev->aac_msix[i]))) {
-                               printk(KERN_ERR "%s%d: Failed to register IRQ for vector %d.\n",
-                                               name, instance, i);
-                               for (j = 0 ; j < i ; j++)
-                                       free_irq(pci_irq_vector(dev->pdev, j),
-                                                &(dev->aac_msix[j]));
-                               pci_disable_msix(dev->pdev);
-                               goto error_iounmap;
-                       }
-               }
-       } else {
-               dev->aac_msix[0].vector_no = 0;
-               dev->aac_msix[0].dev = dev;
-
-               if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
-                       IRQF_SHARED, "aacraid",
-                       &(dev->aac_msix[0])) < 0) {
-                       if (dev->msi)
-                               pci_disable_msi(dev->pdev);
-                       printk(KERN_ERR "%s%d: Interrupt unavailable.\n",
-                                       name, instance);
-                       goto error_iounmap;
-               }
-       }
+       if (aac_acquire_irq(dev))
+               goto error_iounmap;
 
        aac_adapter_enable_int(dev);
 
@@ -1420,7 +1632,7 @@ static int aac_acquire_resources(struct aac_dev *dev)
                /* After EEH recovery or suspend resume, max_msix count
                 * may change, therfore updating in init as well.
                 */
-               dev->init->Sa_MSIXVectors = cpu_to_le32(dev->max_msix);
+               dev->init->r7.no_of_msix_vectors = cpu_to_le32(dev->max_msix);
                aac_adapter_start(dev);
        }
        return 0;
index 6c53b1d8b2badc6070a7a2d5cb3f13b42cd47fac..c59074e782d627f768f8f2c92d9d87d167aa8afc 100644 (file)
@@ -5,7 +5,8 @@
  * Adaptec aacraid device driver for Linux.
  *
  * Copyright (c) 2000-2010 Adaptec, Inc.
- *               2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
+ *               2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
+ *              2016-2017 Microsemi Corp. (aacraid@microsemi.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
index 7d8013feeddea4d39d9d821332a1a9a4bfd9e526..a1bc5bbf7a3410b3d8b1a78d934de3da02d16cf1 100644 (file)
@@ -6,7 +6,8 @@
  * Adaptec aacraid device driver for Linux.
  *
  * Copyright (c) 2000-2010 Adaptec, Inc.
- *               2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
+ *               2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
+ *              2016-2017 Microsemi Corp. (aacraid@microsemi.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
@@ -60,7 +61,7 @@ static int aac_rkt_select_comm(struct aac_dev *dev, int comm)
                 * case warrants this half baked, but convenient, check here.
                 */
                if (dev->scsi_host_ptr->can_queue > AAC_NUM_IO_FIB_RKT) {
-                       dev->init->MaxIoCommands =
+                       dev->init->r7.max_io_commands =
                                cpu_to_le32(AAC_NUM_IO_FIB_RKT + AAC_NUM_MGT_FIB);
                        dev->scsi_host_ptr->can_queue = AAC_NUM_IO_FIB_RKT;
                }
index ac1638069335a66e87b4ccfb5da9d323c2ef6b50..0e69a80c327583cd1c6bbce0408a328123d1bb10 100644 (file)
@@ -6,7 +6,8 @@
  * Adaptec aacraid device driver for Linux.
  *
  * Copyright (c) 2000-2010 Adaptec, Inc.
- *               2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
+ *               2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
+ *              2016-2017 Microsemi Corp. (aacraid@microsemi.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
@@ -315,10 +316,10 @@ static void aac_rx_notify_adapter(struct aac_dev *dev, u32 event)
 
 static void aac_rx_start_adapter(struct aac_dev *dev)
 {
-       struct aac_init *init;
+       union aac_init *init;
 
        init = dev->init;
-       init->HostElapsedSeconds = cpu_to_le32(get_seconds());
+       init->r7.host_elapsed_seconds = cpu_to_le32(get_seconds());
        // We can only use a 32 bit address here
        rx_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa,
          0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL);
@@ -470,7 +471,7 @@ static int aac_rx_ioremap(struct aac_dev * dev, u32 size)
        return 0;
 }
 
-static int aac_rx_restart_adapter(struct aac_dev *dev, int bled)
+static int aac_rx_restart_adapter(struct aac_dev *dev, int bled, u8 reset_type)
 {
        u32 var = 0;
 
@@ -559,7 +560,7 @@ int _aac_rx_init(struct aac_dev *dev)
        dev->a_ops.adapter_enable_int = aac_rx_disable_interrupt;
        dev->OIMR = status = rx_readb (dev, MUnit.OIMR);
        if ((((status & 0x0c) != 0x0c) || aac_reset_devices || reset_devices) &&
-         !aac_rx_restart_adapter(dev, 0))
+         !aac_rx_restart_adapter(dev, 0, IOP_HWSOFT_RESET))
                /* Make sure the Hardware FIFO is empty */
                while ((++restart < 512) &&
                  (rx_readl(dev, MUnit.OutboundQueue) != 0xFFFFFFFFL));
@@ -568,7 +569,8 @@ int _aac_rx_init(struct aac_dev *dev)
         */
        status = rx_readl(dev, MUnit.OMRx[0]);
        if (status & KERNEL_PANIC) {
-               if (aac_rx_restart_adapter(dev, aac_rx_check_health(dev)))
+               if (aac_rx_restart_adapter(dev,
+                       aac_rx_check_health(dev), IOP_HWSOFT_RESET))
                        goto error_iounmap;
                ++restart;
        }
@@ -606,7 +608,8 @@ int _aac_rx_init(struct aac_dev *dev)
                  ((startup_timeout > 60)
                    ? (startup_timeout - 60)
                    : (startup_timeout / 2))))) {
-                       if (likely(!aac_rx_restart_adapter(dev, aac_rx_check_health(dev))))
+                       if (likely(!aac_rx_restart_adapter(dev,
+                               aac_rx_check_health(dev), IOP_HWSOFT_RESET)))
                                start = jiffies;
                        ++restart;
                }
index 869aea23c0411be51ff270bc8d140ed6fce254e1..553922fed52426ff47b1eb5fca26eb07f14dc227 100644 (file)
@@ -6,7 +6,8 @@
  * Adaptec aacraid device driver for Linux.
  *
  * Copyright (c) 2000-2010 Adaptec, Inc.
- *               2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
+ *               2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
+ *              2016-2017 Microsemi Corp. (aacraid@microsemi.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
@@ -245,19 +246,19 @@ static void aac_sa_interrupt_adapter (struct aac_dev *dev)
 
 static void aac_sa_start_adapter(struct aac_dev *dev)
 {
-       struct aac_init *init;
+       union aac_init *init;
        /*
         * Fill in the remaining pieces of the init.
         */
        init = dev->init;
-       init->HostElapsedSeconds = cpu_to_le32(get_seconds());
+       init->r7.host_elapsed_seconds = cpu_to_le32(get_seconds());
        /* We can only use a 32 bit address here */
        sa_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, 
                        (u32)(ulong)dev->init_pa, 0, 0, 0, 0, 0,
                        NULL, NULL, NULL, NULL, NULL);
 }
 
-static int aac_sa_restart_adapter(struct aac_dev *dev, int bled)
+static int aac_sa_restart_adapter(struct aac_dev *dev, int bled, u8 reset_type)
 {
        return -EINVAL;
 }
index 0c453880f214bd46dd1580b5a07b45305446c186..8e4e2ddbafd744df5b3be57a4fa4d981470346cc 100644 (file)
@@ -6,7 +6,8 @@
  * Adaptec aacraid device driver for Linux.
  *
  * Copyright (c) 2000-2010 Adaptec, Inc.
- *               2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
+ *               2010-2015 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
+ *              2016-2017 Microsemi Corp. (aacraid@microsemi.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
@@ -135,8 +136,16 @@ static irqreturn_t aac_src_intr_message(int irq, void *dev_id)
 
        if (mode & AAC_INT_MODE_AIF) {
                /* handle AIF */
-               if (dev->aif_thread && dev->fsa_dev)
-                       aac_intr_normal(dev, 0, 2, 0, NULL);
+               if (dev->sa_firmware) {
+                       u32 events = src_readl(dev, MUnit.SCR0);
+
+                       aac_intr_normal(dev, events, 1, 0, NULL);
+                       writel(events, &dev->IndexRegs->Mailbox[0]);
+                       src_writel(dev, MUnit.IDR, 1 << 23);
+               } else {
+                       if (dev->aif_thread && dev->fsa_dev)
+                               aac_intr_normal(dev, 0, 2, 0, NULL);
+               }
                if (dev->msi_enabled)
                        aac_src_access_devreg(dev, AAC_CLEAR_AIF_BIT);
                mode = 0;
@@ -148,17 +157,19 @@ static irqreturn_t aac_src_intr_message(int irq, void *dev_id)
                for (;;) {
                        isFastResponse = 0;
                        /* remove toggle bit (31) */
-                       handle = (dev->host_rrq[index] & 0x7fffffff);
-                       /* check fast response bit (30) */
+                       handle = le32_to_cpu((dev->host_rrq[index])
+                               & 0x7fffffff);
+                       /* check fast response bits (30, 1) */
                        if (handle & 0x40000000)
                                isFastResponse = 1;
                        handle &= 0x0000ffff;
                        if (handle == 0)
                                break;
+                       handle >>= 2;
                        if (dev->msi_enabled && dev->max_msix > 1)
                                atomic_dec(&dev->rrq_outstanding[vector_no]);
+                       aac_intr_normal(dev, handle, 0, isFastResponse, NULL);
                        dev->host_rrq[index++] = 0;
-                       aac_intr_normal(dev, handle-1, 0, isFastResponse, NULL);
                        if (index == (vector_no + 1) * dev->vector_cap)
                                index = vector_no * dev->vector_cap;
                        dev->host_rrq_idx[vector_no] = index;
@@ -384,7 +395,7 @@ static void aac_src_notify_adapter(struct aac_dev *dev, u32 event)
 
 static void aac_src_start_adapter(struct aac_dev *dev)
 {
-       struct aac_init *init;
+       union aac_init *init;
        int i;
 
         /* reset host_rrq_idx first */
@@ -392,14 +403,26 @@ static void aac_src_start_adapter(struct aac_dev *dev)
                dev->host_rrq_idx[i] = i * dev->vector_cap;
                atomic_set(&dev->rrq_outstanding[i], 0);
        }
+       atomic_set(&dev->msix_counter, 0);
        dev->fibs_pushed_no = 0;
 
        init = dev->init;
-       init->HostElapsedSeconds = cpu_to_le32(get_seconds());
+       if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) {
+               init->r8.host_elapsed_seconds = cpu_to_le32(get_seconds());
+               src_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS,
+                       lower_32_bits(dev->init_pa),
+                       upper_32_bits(dev->init_pa),
+                       sizeof(struct _r8) +
+                       (AAC_MAX_HRRQ - 1) * sizeof(struct _rrq),
+                       0, 0, 0, NULL, NULL, NULL, NULL, NULL);
+       } else {
+               init->r7.host_elapsed_seconds = cpu_to_le32(get_seconds());
+               // We can only use a 32 bit address here
+               src_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS,
+                       (u32)(ulong)dev->init_pa, 0, 0, 0, 0, 0,
+                       NULL, NULL, NULL, NULL, NULL);
+       }
 
-       /* We can only use a 32 bit address here */
-       src_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa,
-         0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL);
 }
 
 /**
@@ -435,6 +458,11 @@ static int aac_src_check_health(struct aac_dev *dev)
        return 0;
 }
 
+static inline u32 aac_get_vector(struct aac_dev *dev)
+{
+       return atomic_inc_return(&dev->msix_counter)%dev->max_msix;
+}
+
 /**
  *     aac_src_deliver_message
  *     @fib: fib to issue
@@ -448,66 +476,125 @@ static int aac_src_deliver_message(struct fib *fib)
        u32 fibsize;
        dma_addr_t address;
        struct aac_fib_xporthdr *pFibX;
+       int native_hba;
 #if !defined(writeq)
        unsigned long flags;
 #endif
 
-       u16 hdr_size = le16_to_cpu(fib->hw_fib_va->header.Size);
        u16 vector_no;
 
        atomic_inc(&q->numpending);
 
-       if (dev->msi_enabled && fib->hw_fib_va->header.Command != AifRequest &&
-           dev->max_msix > 1) {
-               vector_no = fib->vector_no;
-               fib->hw_fib_va->header.Handle += (vector_no << 16);
+       native_hba = (fib->flags & FIB_CONTEXT_FLAG_NATIVE_HBA) ? 1 : 0;
+
+
+       if (dev->msi_enabled && dev->max_msix > 1 &&
+               (native_hba || fib->hw_fib_va->header.Command != AifRequest)) {
+
+               if ((dev->comm_interface == AAC_COMM_MESSAGE_TYPE3)
+                       && dev->sa_firmware)
+                       vector_no = aac_get_vector(dev);
+               else
+                       vector_no = fib->vector_no;
+
+               if (native_hba) {
+                       if (fib->flags & FIB_CONTEXT_FLAG_NATIVE_HBA_TMF) {
+                               struct aac_hba_tm_req *tm_req;
+
+                               tm_req = (struct aac_hba_tm_req *)
+                                               fib->hw_fib_va;
+                               if (tm_req->iu_type ==
+                                       HBA_IU_TYPE_SCSI_TM_REQ) {
+                                       ((struct aac_hba_tm_req *)
+                                               fib->hw_fib_va)->reply_qid
+                                                       = vector_no;
+                                       ((struct aac_hba_tm_req *)
+                                               fib->hw_fib_va)->request_id
+                                                       += (vector_no << 16);
+                               } else {
+                                       ((struct aac_hba_reset_req *)
+                                               fib->hw_fib_va)->reply_qid
+                                                       = vector_no;
+                                       ((struct aac_hba_reset_req *)
+                                               fib->hw_fib_va)->request_id
+                                                       += (vector_no << 16);
+                               }
+                       } else {
+                               ((struct aac_hba_cmd_req *)
+                                       fib->hw_fib_va)->reply_qid
+                                               = vector_no;
+                               ((struct aac_hba_cmd_req *)
+                                       fib->hw_fib_va)->request_id
+                                               += (vector_no << 16);
+                       }
+               } else {
+                       fib->hw_fib_va->header.Handle += (vector_no << 16);
+               }
        } else {
                vector_no = 0;
        }
 
        atomic_inc(&dev->rrq_outstanding[vector_no]);
 
-       if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2) {
-               /* Calculate the amount to the fibsize bits */
-               fibsize = (hdr_size + 127) / 128 - 1;
-               if (fibsize > (ALIGN32 - 1))
-                       return -EMSGSIZE;
-               /* New FIB header, 32-bit */
+       if (native_hba) {
                address = fib->hw_fib_pa;
-               fib->hw_fib_va->header.StructType = FIB_MAGIC2;
-               fib->hw_fib_va->header.SenderFibAddress = (u32)address;
-               fib->hw_fib_va->header.u.TimeStamp = 0;
-               BUG_ON(upper_32_bits(address) != 0L);
+               fibsize = (fib->hbacmd_size + 127) / 128 - 1;
+               if (fibsize > 31)
+                       fibsize = 31;
                address |= fibsize;
+#if defined(writeq)
+               src_writeq(dev, MUnit.IQN_L, (u64)address);
+#else
+               spin_lock_irqsave(&fib->dev->iq_lock, flags);
+               src_writel(dev, MUnit.IQN_H,
+                       upper_32_bits(address) & 0xffffffff);
+               src_writel(dev, MUnit.IQN_L, address & 0xffffffff);
+               spin_unlock_irqrestore(&fib->dev->iq_lock, flags);
+#endif
        } else {
-               /* Calculate the amount to the fibsize bits */
-               fibsize = (sizeof(struct aac_fib_xporthdr) + hdr_size + 127) / 128 - 1;
-               if (fibsize > (ALIGN32 - 1))
-                       return -EMSGSIZE;
-
-               /* Fill XPORT header */
-               pFibX = (void *)fib->hw_fib_va - sizeof(struct aac_fib_xporthdr);
-               pFibX->Handle = cpu_to_le32(fib->hw_fib_va->header.Handle);
-               pFibX->HostAddress = cpu_to_le64(fib->hw_fib_pa);
-               pFibX->Size = cpu_to_le32(hdr_size);
-
-               /*
-                * The xport header has been 32-byte aligned for us so that fibsize
-                * can be masked out of this address by hardware. -- BenC
-                */
-               address = fib->hw_fib_pa - sizeof(struct aac_fib_xporthdr);
-               if (address & (ALIGN32 - 1))
-                       return -EINVAL;
+               if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2 ||
+                       dev->comm_interface == AAC_COMM_MESSAGE_TYPE3) {
+                       /* Calculate the amount to the fibsize bits */
+                       fibsize = (le16_to_cpu(fib->hw_fib_va->header.Size)
+                               + 127) / 128 - 1;
+                       /* New FIB header, 32-bit */
+                       address = fib->hw_fib_pa;
+                       fib->hw_fib_va->header.StructType = FIB_MAGIC2;
+                       fib->hw_fib_va->header.SenderFibAddress =
+                               cpu_to_le32((u32)address);
+                       fib->hw_fib_va->header.u.TimeStamp = 0;
+                       WARN_ON(upper_32_bits(address) != 0L);
+               } else {
+                       /* Calculate the amount to the fibsize bits */
+                       fibsize = (sizeof(struct aac_fib_xporthdr) +
+                               le16_to_cpu(fib->hw_fib_va->header.Size)
+                               + 127) / 128 - 1;
+                       /* Fill XPORT header */
+                       pFibX = (struct aac_fib_xporthdr *)
+                               ((unsigned char *)fib->hw_fib_va -
+                               sizeof(struct aac_fib_xporthdr));
+                       pFibX->Handle = fib->hw_fib_va->header.Handle;
+                       pFibX->HostAddress =
+                               cpu_to_le64((u64)fib->hw_fib_pa);
+                       pFibX->Size = cpu_to_le32(
+                               le16_to_cpu(fib->hw_fib_va->header.Size));
+                       address = fib->hw_fib_pa -
+                               (u64)sizeof(struct aac_fib_xporthdr);
+               }
+               if (fibsize > 31)
+                       fibsize = 31;
                address |= fibsize;
-       }
+
 #if defined(writeq)
-       src_writeq(dev, MUnit.IQ_L, (u64)address);
+               src_writeq(dev, MUnit.IQ_L, (u64)address);
 #else
-       spin_lock_irqsave(&fib->dev->iq_lock, flags);
-       src_writel(dev, MUnit.IQ_H, upper_32_bits(address) & 0xffffffff);
-       src_writel(dev, MUnit.IQ_L, address & 0xffffffff);
-       spin_unlock_irqrestore(&fib->dev->iq_lock, flags);
+               spin_lock_irqsave(&fib->dev->iq_lock, flags);
+               src_writel(dev, MUnit.IQ_H,
+                       upper_32_bits(address) & 0xffffffff);
+               src_writel(dev, MUnit.IQ_L, address & 0xffffffff);
+               spin_unlock_irqrestore(&fib->dev->iq_lock, flags);
 #endif
+       }
        return 0;
 }
 
@@ -553,52 +640,117 @@ static int aac_srcv_ioremap(struct aac_dev *dev, u32 size)
                dev->base = dev->regs.src.bar0 = NULL;
                return 0;
        }
+
+       dev->regs.src.bar1 =
+       ioremap(pci_resource_start(dev->pdev, 2), AAC_MIN_SRCV_BAR1_SIZE);
+       dev->base = NULL;
+       if (dev->regs.src.bar1 == NULL)
+               return -1;
        dev->base = dev->regs.src.bar0 = ioremap(dev->base_start, size);
-       if (dev->base == NULL)
+       if (dev->base == NULL) {
+               iounmap(dev->regs.src.bar1);
+               dev->regs.src.bar1 = NULL;
                return -1;
+       }
        dev->IndexRegs = &((struct src_registers __iomem *)
                dev->base)->u.denali.IndexRegs;
        return 0;
 }
 
-static int aac_src_restart_adapter(struct aac_dev *dev, int bled)
+static void aac_set_intx_mode(struct aac_dev *dev)
+{
+       if (dev->msi_enabled) {
+               aac_src_access_devreg(dev, AAC_ENABLE_INTX);
+               dev->msi_enabled = 0;
+               msleep(5000); /* Delay 5 seconds */
+       }
+}
+
+static void aac_send_iop_reset(struct aac_dev *dev, int bled)
 {
        u32 var, reset_mask;
 
-       if (bled >= 0) {
-               if (bled)
-                       printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n",
+       bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS,
+                                   0, 0, 0, 0, 0, 0, &var,
+                                   &reset_mask, NULL, NULL, NULL);
+
+       if ((bled || var != 0x00000001) && !dev->doorbell_mask)
+               bled = -EINVAL;
+       else if (dev->doorbell_mask) {
+               reset_mask = dev->doorbell_mask;
+               bled = 0;
+               var = 0x00000001;
+       }
+
+       aac_set_intx_mode(dev);
+
+       if (!bled && (dev->supplement_adapter_info.SupportedOptions2 &
+           AAC_OPTION_DOORBELL_RESET)) {
+               src_writel(dev, MUnit.IDR, reset_mask);
+       } else {
+               src_writel(dev, MUnit.IDR, 0x100);
+       }
+       msleep(30000);
+}
+
+static void aac_send_hardware_soft_reset(struct aac_dev *dev)
+{
+       u_int32_t val;
+
+       val = readl(((char *)(dev->base) + IBW_SWR_OFFSET));
+       val |= 0x01;
+       writel(val, ((char *)(dev->base) + IBW_SWR_OFFSET));
+       msleep_interruptible(20000);
+}
+
+static int aac_src_restart_adapter(struct aac_dev *dev, int bled, u8 reset_type)
+{
+       unsigned long status, start;
+
+       if (bled < 0)
+               goto invalid_out;
+
+       if (bled)
+               pr_err("%s%d: adapter kernel panic'd %x.\n",
                                dev->name, dev->id, bled);
-               dev->a_ops.adapter_enable_int = aac_src_disable_interrupt;
-               bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS,
-                       0, 0, 0, 0, 0, 0, &var, &reset_mask, NULL, NULL, NULL);
-               if ((bled || (var != 0x00000001)) &&
-                   !dev->doorbell_mask)
-                       return -EINVAL;
-               else if (dev->doorbell_mask) {
-                       reset_mask = dev->doorbell_mask;
-                       bled = 0;
-                       var = 0x00000001;
-               }
 
-               if ((dev->pdev->device == PMC_DEVICE_S7 ||
-                   dev->pdev->device == PMC_DEVICE_S8 ||
-                   dev->pdev->device == PMC_DEVICE_S9) && dev->msi_enabled) {
-                       aac_src_access_devreg(dev, AAC_ENABLE_INTX);
-                       dev->msi_enabled = 0;
-                       msleep(5000); /* Delay 5 seconds */
-               }
+       dev->a_ops.adapter_enable_int = aac_src_disable_interrupt;
 
-               if (!bled && (dev->supplement_adapter_info.SupportedOptions2 &
-                   AAC_OPTION_DOORBELL_RESET)) {
-                       src_writel(dev, MUnit.IDR, reset_mask);
-                       ssleep(45);
-               } else {
-                       src_writel(dev, MUnit.IDR, 0x100);
-                       ssleep(45);
+       switch (reset_type) {
+       case IOP_HWSOFT_RESET:
+               aac_send_iop_reset(dev, bled);
+               /*
+                * Check to see if KERNEL_UP_AND_RUNNING
+                * Wait for the adapter to be up and running.
+                * If !KERNEL_UP_AND_RUNNING issue HW Soft Reset
+                */
+               status = src_readl(dev, MUnit.OMR);
+               if (dev->sa_firmware
+                && !(status & KERNEL_UP_AND_RUNNING)) {
+                       start = jiffies;
+                       do {
+                               status = src_readl(dev, MUnit.OMR);
+                               if (time_after(jiffies,
+                                start+HZ*SOFT_RESET_TIME)) {
+                                       aac_send_hardware_soft_reset(dev);
+                                       start = jiffies;
+                               }
+                       } while (!(status & KERNEL_UP_AND_RUNNING));
                }
+               break;
+       case HW_SOFT_RESET:
+               if (dev->sa_firmware) {
+                       aac_send_hardware_soft_reset(dev);
+                       aac_set_intx_mode(dev);
+               }
+               break;
+       default:
+               aac_send_iop_reset(dev, bled);
+               break;
        }
 
+invalid_out:
+
        if (src_readl(dev, MUnit.OMR) & KERNEL_PANIC)
                return -ENODEV;
 
@@ -653,14 +805,15 @@ int aac_src_init(struct aac_dev *dev)
        dev->a_ops.adapter_sync_cmd = src_sync_cmd;
        dev->a_ops.adapter_enable_int = aac_src_disable_interrupt;
        if ((aac_reset_devices || reset_devices) &&
-               !aac_src_restart_adapter(dev, 0))
+               !aac_src_restart_adapter(dev, 0, IOP_HWSOFT_RESET))
                ++restart;
        /*
         *      Check to see if the board panic'd while booting.
         */
        status = src_readl(dev, MUnit.OMR);
        if (status & KERNEL_PANIC) {
-               if (aac_src_restart_adapter(dev, aac_src_check_health(dev)))
+               if (aac_src_restart_adapter(dev,
+                       aac_src_check_health(dev), IOP_HWSOFT_RESET))
                        goto error_iounmap;
                ++restart;
        }
@@ -701,7 +854,7 @@ int aac_src_init(struct aac_dev *dev)
                    ? (startup_timeout - 60)
                    : (startup_timeout / 2))))) {
                        if (likely(!aac_src_restart_adapter(dev,
-                           aac_src_check_health(dev))))
+                               aac_src_check_health(dev), IOP_HWSOFT_RESET)))
                                start = jiffies;
                        ++restart;
                }
@@ -798,7 +951,7 @@ int aac_srcv_init(struct aac_dev *dev)
        dev->a_ops.adapter_sync_cmd = src_sync_cmd;
        dev->a_ops.adapter_enable_int = aac_src_disable_interrupt;
        if ((aac_reset_devices || reset_devices) &&
-               !aac_src_restart_adapter(dev, 0))
+               !aac_src_restart_adapter(dev, 0, IOP_HWSOFT_RESET))
                ++restart;
        /*
         *      Check to see if flash update is running.
@@ -827,7 +980,8 @@ int aac_srcv_init(struct aac_dev *dev)
         */
        status = src_readl(dev, MUnit.OMR);
        if (status & KERNEL_PANIC) {
-               if (aac_src_restart_adapter(dev, aac_src_check_health(dev)))
+               if (aac_src_restart_adapter(dev,
+                       aac_src_check_health(dev), IOP_HWSOFT_RESET))
                        goto error_iounmap;
                ++restart;
        }
@@ -866,7 +1020,8 @@ int aac_srcv_init(struct aac_dev *dev)
                  ((startup_timeout > 60)
                    ? (startup_timeout - 60)
                    : (startup_timeout / 2))))) {
-                       if (likely(!aac_src_restart_adapter(dev, aac_src_check_health(dev))))
+                       if (likely(!aac_src_restart_adapter(dev,
+                               aac_src_check_health(dev), IOP_HWSOFT_RESET)))
                                start = jiffies;
                        ++restart;
                }
@@ -897,7 +1052,8 @@ int aac_srcv_init(struct aac_dev *dev)
 
        if (aac_init_adapter(dev) == NULL)
                goto error_iounmap;
-       if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE2)
+       if ((dev->comm_interface != AAC_COMM_MESSAGE_TYPE2) &&
+               (dev->comm_interface != AAC_COMM_MESSAGE_TYPE3))
                goto error_iounmap;
        if (dev->msi_enabled)
                aac_src_access_devreg(dev, AAC_ENABLE_MSIX);
@@ -905,9 +1061,9 @@ int aac_srcv_init(struct aac_dev *dev)
        if (aac_acquire_irq(dev))
                goto error_iounmap;
 
-       dev->dbg_base = dev->base_start;
-       dev->dbg_base_mapped = dev->base;
-       dev->dbg_size = dev->base_size;
+       dev->dbg_base = pci_resource_start(dev->pdev, 2);
+       dev->dbg_base_mapped = dev->regs.src.bar1;
+       dev->dbg_size = AAC_MIN_SRCV_BAR1_SIZE;
        dev->a_ops.adapter_enable_int = aac_src_enable_interrupt_message;
 
        aac_adapter_enable_int(dev);
index 105b35393ce91751d859948595ed70508d90e7d7..f792420c533ecee25036b0c16817eb0db3c564f4 100644 (file)
@@ -178,37 +178,6 @@ static int scsi_dma_is_ignored_buserr(unsigned char dma_stat)
 }
 
 
-#if 0
-/* Dead code... wasn't called anyway :-) and causes some trouble, because at
- * end-of-DMA, both SCSI ints are triggered simultaneously, so the NCR int has
- * to clear the DMA int pending bit before it allows other level 6 interrupts.
- */
-static void scsi_dma_buserr(int irq, void *dummy)
-{
-       unsigned char dma_stat = tt_scsi_dma.dma_ctrl;
-
-       /* Don't do anything if a NCR interrupt is pending. Probably it's just
-        * masked... */
-       if (atari_irq_pending(IRQ_TT_MFP_SCSI))
-               return;
-
-       printk("Bad SCSI DMA interrupt! dma_addr=0x%08lx dma_stat=%02x dma_cnt=%08lx\n",
-              SCSI_DMA_READ_P(dma_addr), dma_stat, SCSI_DMA_READ_P(dma_cnt));
-       if (dma_stat & 0x80) {
-               if (!scsi_dma_is_ignored_buserr(dma_stat))
-                       printk("SCSI DMA bus error -- bad DMA programming!\n");
-       } else {
-               /* Under normal circumstances we never should get to this point,
-                * since both interrupts are triggered simultaneously and the 5380
-                * int has higher priority. When this irq is handled, that DMA
-                * interrupt is cleared. So a warning message is printed here.
-                */
-               printk("SCSI DMA intr ?? -- this shouldn't happen!\n");
-       }
-}
-#endif
-
-
 static irqreturn_t scsi_tt_intr(int irq, void *dev)
 {
        struct Scsi_Host *instance = dev;
@@ -713,7 +682,8 @@ static int atari_scsi_bus_reset(struct scsi_cmnd *cmd)
        if (IS_A_TT()) {
                tt_scsi_dma.dma_ctrl = 0;
        } else {
-               st_dma.dma_mode_status = 0x90;
+               if (stdma_is_locked_by(scsi_falcon_intr))
+                       st_dma.dma_mode_status = 0x90;
                atari_dma_active = 0;
                atari_dma_orig_addr = NULL;
        }
@@ -813,7 +783,7 @@ static int __init atari_scsi_probe(struct platform_device *pdev)
                        return -ENOMEM;
                }
                atari_dma_phys_buffer = atari_stram_to_phys(atari_dma_buffer);
-               atari_dma_orig_addr = 0;
+               atari_dma_orig_addr = NULL;
        }
 
        instance = scsi_host_alloc(&atari_scsi_template,
index b1d0fdc5d5e106dee779bb5c676142dfddb80e20..ca9440fb2325154219b5f5faafe0337b93e2f883 100644 (file)
@@ -84,7 +84,6 @@ static inline void queue_tail_inc(struct be_queue_info *q)
 /*ISCSI */
 
 struct be_aic_obj {            /* Adaptive interrupt coalescing (AIC) info */
-       bool enable;
        u32 min_eqd;            /* in usecs */
        u32 max_eqd;            /* in usecs */
        u32 prev_eqd;           /* in usecs */
@@ -94,8 +93,6 @@ struct be_aic_obj {           /* Adaptive interrupt coalescing (AIC) info */
 };
 
 struct be_eq_obj {
-       bool todo_mcc_cq;
-       bool todo_cq;
        u32 cq_count;
        struct be_queue_info q;
        struct beiscsi_hba *phba;
index be65da2988fbca99d3926f30a6ff4f03619d1336..5d59e2630ce614c94fb641d2785132234e863921 100644 (file)
@@ -676,10 +676,10 @@ void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len,
                                bool embedded, u8 sge_cnt)
 {
        if (embedded)
-               wrb->embedded |= MCC_WRB_EMBEDDED_MASK;
+               wrb->emb_sgecnt_special |= MCC_WRB_EMBEDDED_MASK;
        else
-               wrb->embedded |= (sge_cnt & MCC_WRB_SGE_CNT_MASK) <<
-                                               MCC_WRB_SGE_CNT_SHIFT;
+               wrb->emb_sgecnt_special |= (sge_cnt & MCC_WRB_SGE_CNT_MASK) <<
+                                          MCC_WRB_SGE_CNT_SHIFT;
        wrb->payload_length = payload_len;
        be_dws_cpu_to_le(wrb, 8);
 }
@@ -1599,7 +1599,7 @@ int beiscsi_cmd_function_reset(struct beiscsi_hba *phba)
 {
        struct be_ctrl_info *ctrl = &phba->ctrl;
        struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
-       struct be_post_sgl_pages_req *req = embedded_payload(wrb);
+       struct be_post_sgl_pages_req *req;
        int status;
 
        mutex_lock(&ctrl->mbox_lock);
@@ -1700,31 +1700,34 @@ int beiscsi_cmd_iscsi_cleanup(struct beiscsi_hba *phba, unsigned short ulp)
        struct be_ctrl_info *ctrl = &phba->ctrl;
        struct iscsi_cleanup_req_v1 *req_v1;
        struct iscsi_cleanup_req *req;
+       u16 hdr_ring_id, data_ring_id;
        struct be_mcc_wrb *wrb;
        int status;
 
        mutex_lock(&ctrl->mbox_lock);
        wrb = wrb_from_mbox(&ctrl->mbox_mem);
-       req = embedded_payload(wrb);
-       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
-                          OPCODE_COMMON_ISCSI_CLEANUP, sizeof(*req));
 
-       /**
-       * TODO: Check with FW folks the chute value to be set.
-       * For now, use the ULP_MASK as the chute value.
-       */
+       hdr_ring_id = HWI_GET_DEF_HDRQ_ID(phba, ulp);
+       data_ring_id = HWI_GET_DEF_BUFQ_ID(phba, ulp);
        if (is_chip_be2_be3r(phba)) {
+               req = embedded_payload(wrb);
+               be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+               be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
+                                  OPCODE_COMMON_ISCSI_CLEANUP, sizeof(*req));
                req->chute = (1 << ulp);
-               req->hdr_ring_id = HWI_GET_DEF_HDRQ_ID(phba, ulp);
-               req->data_ring_id = HWI_GET_DEF_BUFQ_ID(phba, ulp);
+               /* BE2/BE3 FW creates 8-bit ring id */
+               req->hdr_ring_id = hdr_ring_id;
+               req->data_ring_id = data_ring_id;
        } else {
-               req_v1 = (struct iscsi_cleanup_req_v1 *)req;
+               req_v1 = embedded_payload(wrb);
+               be_wrb_hdr_prepare(wrb, sizeof(*req_v1), true, 0);
+               be_cmd_hdr_prepare(&req_v1->hdr, CMD_SUBSYSTEM_ISCSI,
+                                  OPCODE_COMMON_ISCSI_CLEANUP,
+                                  sizeof(*req_v1));
                req_v1->hdr.version = 1;
-               req_v1->hdr_ring_id = cpu_to_le16(HWI_GET_DEF_HDRQ_ID(phba,
-                                                                     ulp));
-               req_v1->data_ring_id = cpu_to_le16(HWI_GET_DEF_BUFQ_ID(phba,
-                                                                      ulp));
+               req_v1->chute = (1 << ulp);
+               req_v1->hdr_ring_id = cpu_to_le16(hdr_ring_id);
+               req_v1->data_ring_id = cpu_to_le16(data_ring_id);
        }
 
        status = be_mbox_notify(ctrl);
index 328fb5b973cdc433e908075bdb368b36723c6d13..1d40e83b0790aa2eac18f7f858b46d366a6ea292 100644 (file)
@@ -31,10 +31,16 @@ struct be_sge {
        __le32 len;
 };
 
-#define MCC_WRB_SGE_CNT_SHIFT 3        /* bits 3 - 7 of dword 0 */
-#define MCC_WRB_SGE_CNT_MASK 0x1F      /* bits 3 - 7 of dword 0 */
 struct be_mcc_wrb {
-       u32 embedded;           /* dword 0 */
+       u32 emb_sgecnt_special; /* dword 0 */
+       /* bits 0 - embedded    */
+       /* bits 1 - 2 reserved  */
+       /* bits 3 - 7 sge count */
+       /* bits 8 - 23 reserved */
+       /* bits 24 - 31 special */
+#define MCC_WRB_EMBEDDED_MASK 1
+#define MCC_WRB_SGE_CNT_SHIFT 3
+#define MCC_WRB_SGE_CNT_MASK 0x1F
        u32 payload_length;     /* dword 1 */
        u32 tag0;               /* dword 2 */
        u32 tag1;               /* dword 3 */
@@ -1133,11 +1139,6 @@ struct tcp_connect_and_offload_out {
 
 } __packed;
 
-struct be_mcc_wrb_context {
-       struct MCC_WRB *wrb;
-       int *users_final_status;
-} __packed;
-
 #define DB_DEF_PDU_RING_ID_MASK        0x3FFF  /* bits 0 - 13 */
 #define DB_DEF_PDU_CQPROC_MASK         0x3FFF  /* bits 16 - 29 */
 #define DB_DEF_PDU_REARM_SHIFT         14
index ba258217614e6f38d0c20f9ec7673dd65191116c..a4844578e3577e833952af48e02dcb5570446d97 100644 (file)
@@ -165,33 +165,6 @@ beiscsi_conn_create(struct iscsi_cls_session *cls_session, u32 cid)
        return cls_conn;
 }
 
-/**
- * beiscsi_bindconn_cid - Bind the beiscsi_conn with phba connection table
- * @beiscsi_conn: The pointer to  beiscsi_conn structure
- * @phba: The phba instance
- * @cid: The cid to free
- */
-static int beiscsi_bindconn_cid(struct beiscsi_hba *phba,
-                               struct beiscsi_conn *beiscsi_conn,
-                               unsigned int cid)
-{
-       uint16_t cri_index = BE_GET_CRI_FROM_CID(cid);
-
-       if (phba->conn_table[cri_index]) {
-               beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
-                           "BS_%d : Connection table already occupied. Detected clash\n");
-
-               return -EINVAL;
-       } else {
-               beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
-                           "BS_%d : phba->conn_table[%d]=%p(beiscsi_conn)\n",
-                           cri_index, beiscsi_conn);
-
-               phba->conn_table[cri_index] = beiscsi_conn;
-       }
-       return 0;
-}
-
 /**
  * beiscsi_conn_bind - Binds iscsi session/connection with TCP connection
  * @cls_session: pointer to iscsi cls session
@@ -212,6 +185,7 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session,
        struct hwi_wrb_context *pwrb_context;
        struct beiscsi_endpoint *beiscsi_ep;
        struct iscsi_endpoint *ep;
+       uint16_t cri_index;
 
        ep = iscsi_lookup_endpoint(transport_fd);
        if (!ep)
@@ -229,20 +203,34 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session,
 
                return -EEXIST;
        }
-
-       pwrb_context = &phwi_ctrlr->wrb_context[BE_GET_CRI_FROM_CID(
-                                               beiscsi_ep->ep_cid)];
+       cri_index = BE_GET_CRI_FROM_CID(beiscsi_ep->ep_cid);
+       if (phba->conn_table[cri_index]) {
+               if (beiscsi_conn != phba->conn_table[cri_index] ||
+                   beiscsi_ep != phba->conn_table[cri_index]->ep) {
+                       __beiscsi_log(phba, KERN_ERR,
+                                     "BS_%d : conn_table not empty at %u: cid %u conn %p:%p\n",
+                                     cri_index,
+                                     beiscsi_ep->ep_cid,
+                                     beiscsi_conn,
+                                     phba->conn_table[cri_index]);
+                       return -EINVAL;
+               }
+       }
 
        beiscsi_conn->beiscsi_conn_cid = beiscsi_ep->ep_cid;
        beiscsi_conn->ep = beiscsi_ep;
        beiscsi_ep->conn = beiscsi_conn;
+       /**
+        * Each connection is associated with a WRBQ kept in wrb_context.
+        * Store doorbell offset for transmit path.
+        */
+       pwrb_context = &phwi_ctrlr->wrb_context[cri_index];
        beiscsi_conn->doorbell_offset = pwrb_context->doorbell_offset;
-
        beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
-                   "BS_%d : beiscsi_conn=%p conn=%p ep_cid=%d\n",
-                   beiscsi_conn, conn, beiscsi_ep->ep_cid);
-
-       return beiscsi_bindconn_cid(phba, beiscsi_conn, beiscsi_ep->ep_cid);
+                   "BS_%d : cid %d phba->conn_table[%u]=%p\n",
+                   beiscsi_ep->ep_cid, cri_index, beiscsi_conn);
+       phba->conn_table[cri_index] = beiscsi_conn;
+       return 0;
 }
 
 static int beiscsi_iface_create_ipv4(struct beiscsi_hba *phba)
@@ -973,9 +961,9 @@ int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn)
  */
 static int beiscsi_get_cid(struct beiscsi_hba *phba)
 {
-       unsigned short cid = 0xFFFF, cid_from_ulp;
-       struct ulp_cid_info *cid_info = NULL;
        uint16_t cid_avlbl_ulp0, cid_avlbl_ulp1;
+       unsigned short cid, cid_from_ulp;
+       struct ulp_cid_info *cid_info;
 
        /* Find the ULP which has more CID available */
        cid_avlbl_ulp0 = (phba->cid_array_info[BEISCSI_ULP0]) ?
@@ -984,20 +972,27 @@ static int beiscsi_get_cid(struct beiscsi_hba *phba)
                          BEISCSI_ULP1_AVLBL_CID(phba) : 0;
        cid_from_ulp = (cid_avlbl_ulp0 > cid_avlbl_ulp1) ?
                        BEISCSI_ULP0 : BEISCSI_ULP1;
-
-       if (test_bit(cid_from_ulp, (void *)&phba->fw_config.ulp_supported)) {
-               cid_info = phba->cid_array_info[cid_from_ulp];
-               if (!cid_info->avlbl_cids)
-                       return cid;
-
-               cid = cid_info->cid_array[cid_info->cid_alloc++];
-
-               if (cid_info->cid_alloc == BEISCSI_GET_CID_COUNT(
-                                          phba, cid_from_ulp))
-                       cid_info->cid_alloc = 0;
-
-               cid_info->avlbl_cids--;
+       /**
+        * If iSCSI protocol is loaded only on ULP 0, and when cid_avlbl_ulp
+        * is ZERO for both, ULP 1 is returned.
+        * Check if ULP is loaded before getting new CID.
+        */
+       if (!test_bit(cid_from_ulp, (void *)&phba->fw_config.ulp_supported))
+               return BE_INVALID_CID;
+
+       cid_info = phba->cid_array_info[cid_from_ulp];
+       cid = cid_info->cid_array[cid_info->cid_alloc];
+       if (!cid_info->avlbl_cids || cid == BE_INVALID_CID) {
+               __beiscsi_log(phba, KERN_ERR,
+                               "BS_%d : failed to get cid: available %u:%u\n",
+                               cid_info->avlbl_cids, cid_info->cid_free);
+               return BE_INVALID_CID;
        }
+       /* empty the slot */
+       cid_info->cid_array[cid_info->cid_alloc++] = BE_INVALID_CID;
+       if (cid_info->cid_alloc == BEISCSI_GET_CID_COUNT(phba, cid_from_ulp))
+               cid_info->cid_alloc = 0;
+       cid_info->avlbl_cids--;
        return cid;
 }
 
@@ -1008,22 +1003,28 @@ static int beiscsi_get_cid(struct beiscsi_hba *phba)
  */
 static void beiscsi_put_cid(struct beiscsi_hba *phba, unsigned short cid)
 {
-       uint16_t cid_post_ulp;
-       struct hwi_controller *phwi_ctrlr;
-       struct hwi_wrb_context *pwrb_context;
-       struct ulp_cid_info *cid_info = NULL;
        uint16_t cri_index = BE_GET_CRI_FROM_CID(cid);
+       struct hwi_wrb_context *pwrb_context;
+       struct hwi_controller *phwi_ctrlr;
+       struct ulp_cid_info *cid_info;
+       uint16_t cid_post_ulp;
 
        phwi_ctrlr = phba->phwi_ctrlr;
        pwrb_context = &phwi_ctrlr->wrb_context[cri_index];
        cid_post_ulp = pwrb_context->ulp_num;
 
        cid_info = phba->cid_array_info[cid_post_ulp];
-       cid_info->avlbl_cids++;
-
+       /* fill only in empty slot */
+       if (cid_info->cid_array[cid_info->cid_free] != BE_INVALID_CID) {
+               __beiscsi_log(phba, KERN_ERR,
+                             "BS_%d : failed to put cid %u: available %u:%u\n",
+                             cid, cid_info->avlbl_cids, cid_info->cid_free);
+               return;
+       }
        cid_info->cid_array[cid_info->cid_free++] = cid;
        if (cid_info->cid_free == BEISCSI_GET_CID_COUNT(phba, cid_post_ulp))
                cid_info->cid_free = 0;
+       cid_info->avlbl_cids++;
 }
 
 /**
@@ -1037,8 +1038,8 @@ static void beiscsi_free_ep(struct beiscsi_endpoint *beiscsi_ep)
 
        beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
        beiscsi_ep->phba = NULL;
-       phba->ep_array[BE_GET_CRI_FROM_CID
-                      (beiscsi_ep->ep_cid)] = NULL;
+       /* clear this to track freeing in beiscsi_ep_disconnect */
+       phba->ep_array[BE_GET_CRI_FROM_CID(beiscsi_ep->ep_cid)] = NULL;
 
        /**
         * Check if any connection resource allocated by driver
@@ -1049,6 +1050,11 @@ static void beiscsi_free_ep(struct beiscsi_endpoint *beiscsi_ep)
                return;
 
        beiscsi_conn = beiscsi_ep->conn;
+       /**
+        * Break ep->conn link here so that completions after
+        * this are ignored.
+        */
+       beiscsi_ep->conn = NULL;
        if (beiscsi_conn->login_in_progress) {
                beiscsi_free_mgmt_task_handles(beiscsi_conn,
                                               beiscsi_conn->task);
@@ -1079,7 +1085,7 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep,
                    "BS_%d : In beiscsi_open_conn\n");
 
        beiscsi_ep->ep_cid = beiscsi_get_cid(phba);
-       if (beiscsi_ep->ep_cid == 0xFFFF) {
+       if (beiscsi_ep->ep_cid == BE_INVALID_CID) {
                beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
                            "BS_%d : No free cid available\n");
                return ret;
@@ -1114,7 +1120,7 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep,
        nonemb_cmd.size = req_memsize;
        memset(nonemb_cmd.va, 0, nonemb_cmd.size);
        tag = mgmt_open_connection(phba, dst_addr, beiscsi_ep, &nonemb_cmd);
-       if (tag <= 0) {
+       if (!tag) {
                beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
                            "BS_%d : mgmt_open_connection Failed for cid=%d\n",
                            beiscsi_ep->ep_cid);
@@ -1284,26 +1290,6 @@ static int beiscsi_close_conn(struct  beiscsi_endpoint *beiscsi_ep, int flag)
        return ret;
 }
 
-/**
- * beiscsi_unbind_conn_to_cid - Unbind the beiscsi_conn from phba conn table
- * @phba: The phba instance
- * @cid: The cid to free
- */
-static int beiscsi_unbind_conn_to_cid(struct beiscsi_hba *phba,
-                                     unsigned int cid)
-{
-       uint16_t cri_index = BE_GET_CRI_FROM_CID(cid);
-
-       if (phba->conn_table[cri_index])
-               phba->conn_table[cri_index] = NULL;
-       else {
-               beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
-                           "BS_%d : Connection table Not occupied.\n");
-               return -EINVAL;
-       }
-       return 0;
-}
-
 /**
  * beiscsi_ep_disconnect - Tears down the TCP connection
  * @ep:        endpoint to be used
@@ -1318,13 +1304,23 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep)
        unsigned int tag;
        uint8_t mgmt_invalidate_flag, tcp_upload_flag;
        unsigned short savecfg_flag = CMD_ISCSI_SESSION_SAVE_CFG_ON_FLASH;
+       uint16_t cri_index;
 
        beiscsi_ep = ep->dd_data;
        phba = beiscsi_ep->phba;
        beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
-                   "BS_%d : In beiscsi_ep_disconnect for ep_cid = %d\n",
+                   "BS_%d : In beiscsi_ep_disconnect for ep_cid = %u\n",
                    beiscsi_ep->ep_cid);
 
+       cri_index = BE_GET_CRI_FROM_CID(beiscsi_ep->ep_cid);
+       if (!phba->ep_array[cri_index]) {
+               __beiscsi_log(phba, KERN_ERR,
+                             "BS_%d : ep_array at %u cid %u empty\n",
+                             cri_index,
+                             beiscsi_ep->ep_cid);
+               return;
+       }
+
        if (beiscsi_ep->conn) {
                beiscsi_conn = beiscsi_ep->conn;
                iscsi_suspend_queue(beiscsi_conn->conn);
@@ -1356,7 +1352,12 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep)
 free_ep:
        msleep(BEISCSI_LOGOUT_SYNC_DELAY);
        beiscsi_free_ep(beiscsi_ep);
-       beiscsi_unbind_conn_to_cid(phba, beiscsi_ep->ep_cid);
+       if (!phba->conn_table[cri_index])
+               __beiscsi_log(phba, KERN_ERR,
+                               "BS_%d : conn_table empty at %u: cid %u\n",
+                               cri_index,
+                               beiscsi_ep->ep_cid);
+       phba->conn_table[cri_index] = NULL;
        iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep);
 }
 
index b5112d6d7e7343a8f7bce4c0fb4089095ca53460..32b2713cec936ed45c2ce12fe1aa6aa3e02e26b3 100644 (file)
@@ -67,8 +67,6 @@ beiscsi_##_name##_disp(struct device *dev,\
 {      \
        struct Scsi_Host *shost = class_to_shost(dev);\
        struct beiscsi_hba *phba = iscsi_host_priv(shost); \
-       uint32_t param_val = 0; \
-       param_val = phba->attr_##_name;\
        return snprintf(buf, PAGE_SIZE, "%d\n",\
                        phba->attr_##_name);\
 }
@@ -218,160 +216,156 @@ static int beiscsi_slave_configure(struct scsi_device *sdev)
 
 static int beiscsi_eh_abort(struct scsi_cmnd *sc)
 {
+       struct iscsi_task *abrt_task = (struct iscsi_task *)sc->SCp.ptr;
        struct iscsi_cls_session *cls_session;
-       struct iscsi_task *aborted_task = (struct iscsi_task *)sc->SCp.ptr;
-       struct beiscsi_io_task *aborted_io_task;
-       struct iscsi_conn *conn;
+       struct beiscsi_io_task *abrt_io_task;
        struct beiscsi_conn *beiscsi_conn;
-       struct beiscsi_hba *phba;
        struct iscsi_session *session;
-       struct invalidate_command_table *inv_tbl;
-       struct be_dma_mem nonemb_cmd;
-       unsigned int cid, tag, num_invalidate;
+       struct invldt_cmd_tbl inv_tbl;
+       struct beiscsi_hba *phba;
+       struct iscsi_conn *conn;
        int rc;
 
        cls_session = starget_to_session(scsi_target(sc->device));
        session = cls_session->dd_data;
 
-       spin_lock_bh(&session->frwd_lock);
-       if (!aborted_task || !aborted_task->sc) {
-               /* we raced */
-               spin_unlock_bh(&session->frwd_lock);
-               return SUCCESS;
-       }
-
-       aborted_io_task = aborted_task->dd_data;
-       if (!aborted_io_task->scsi_cmnd) {
-               /* raced or invalid command */
-               spin_unlock_bh(&session->frwd_lock);
+       /* check if we raced, task just got cleaned up under us */
+       spin_lock_bh(&session->back_lock);
+       if (!abrt_task || !abrt_task->sc) {
+               spin_unlock_bh(&session->back_lock);
                return SUCCESS;
        }
-       spin_unlock_bh(&session->frwd_lock);
-       /* Invalidate WRB Posted for this Task */
-       AMAP_SET_BITS(struct amap_iscsi_wrb, invld,
-                     aborted_io_task->pwrb_handle->pwrb,
-                     1);
-
-       conn = aborted_task->conn;
+       /* get a task ref till FW processes the req for the ICD used */
+       __iscsi_get_task(abrt_task);
+       abrt_io_task = abrt_task->dd_data;
+       conn = abrt_task->conn;
        beiscsi_conn = conn->dd_data;
        phba = beiscsi_conn->phba;
-
-       /* invalidate iocb */
-       cid = beiscsi_conn->beiscsi_conn_cid;
-       inv_tbl = phba->inv_tbl;
-       memset(inv_tbl, 0x0, sizeof(*inv_tbl));
-       inv_tbl->cid = cid;
-       inv_tbl->icd = aborted_io_task->psgl_handle->sgl_index;
-       num_invalidate = 1;
-       nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev,
-                               sizeof(struct invalidate_commands_params_in),
-                               &nonemb_cmd.dma);
-       if (nonemb_cmd.va == NULL) {
-               beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_EH,
-                           "BM_%d : Failed to allocate memory for"
-                           "mgmt_invalidate_icds\n");
-               return FAILED;
+       /* mark WRB invalid which have been not processed by FW yet */
+       if (is_chip_be2_be3r(phba)) {
+               AMAP_SET_BITS(struct amap_iscsi_wrb, invld,
+                             abrt_io_task->pwrb_handle->pwrb, 1);
+       } else {
+               AMAP_SET_BITS(struct amap_iscsi_wrb_v2, invld,
+                             abrt_io_task->pwrb_handle->pwrb, 1);
        }
-       nonemb_cmd.size = sizeof(struct invalidate_commands_params_in);
+       inv_tbl.cid = beiscsi_conn->beiscsi_conn_cid;
+       inv_tbl.icd = abrt_io_task->psgl_handle->sgl_index;
+       spin_unlock_bh(&session->back_lock);
 
-       tag = mgmt_invalidate_icds(phba, inv_tbl, num_invalidate,
-                                  cid, &nonemb_cmd);
-       if (!tag) {
+       rc = beiscsi_mgmt_invalidate_icds(phba, &inv_tbl, 1);
+       iscsi_put_task(abrt_task);
+       if (rc) {
                beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_EH,
-                           "BM_%d : mgmt_invalidate_icds could not be"
-                           "submitted\n");
-               pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
-                                   nonemb_cmd.va, nonemb_cmd.dma);
-
+                           "BM_%d : sc %p invalidation failed %d\n",
+                           sc, rc);
                return FAILED;
        }
 
-       rc = beiscsi_mccq_compl_wait(phba, tag, NULL, &nonemb_cmd);
-       if (rc != -EBUSY)
-               pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
-                                   nonemb_cmd.va, nonemb_cmd.dma);
-
        return iscsi_eh_abort(sc);
 }
 
 static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
 {
-       struct iscsi_task *abrt_task;
-       struct beiscsi_io_task *abrt_io_task;
-       struct iscsi_conn *conn;
+       struct beiscsi_invldt_cmd_tbl {
+               struct invldt_cmd_tbl tbl[BE_INVLDT_CMD_TBL_SZ];
+               struct iscsi_task *task[BE_INVLDT_CMD_TBL_SZ];
+       } *inv_tbl;
+       struct iscsi_cls_session *cls_session;
        struct beiscsi_conn *beiscsi_conn;
-       struct beiscsi_hba *phba;
+       struct beiscsi_io_task *io_task;
        struct iscsi_session *session;
-       struct iscsi_cls_session *cls_session;
-       struct invalidate_command_table *inv_tbl;
-       struct be_dma_mem nonemb_cmd;
-       unsigned int cid, tag, i, num_invalidate;
-       int rc;
+       struct beiscsi_hba *phba;
+       struct iscsi_conn *conn;
+       struct iscsi_task *task;
+       unsigned int i, nents;
+       int rc, more = 0;
 
-       /* invalidate iocbs */
        cls_session = starget_to_session(scsi_target(sc->device));
        session = cls_session->dd_data;
+
        spin_lock_bh(&session->frwd_lock);
        if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN) {
                spin_unlock_bh(&session->frwd_lock);
                return FAILED;
        }
+
        conn = session->leadconn;
        beiscsi_conn = conn->dd_data;
        phba = beiscsi_conn->phba;
-       cid = beiscsi_conn->beiscsi_conn_cid;
-       inv_tbl = phba->inv_tbl;
-       memset(inv_tbl, 0x0, sizeof(*inv_tbl) * BE2_CMDS_PER_CXN);
-       num_invalidate = 0;
+
+       inv_tbl = kzalloc(sizeof(*inv_tbl), GFP_ATOMIC);
+       if (!inv_tbl) {
+               spin_unlock_bh(&session->frwd_lock);
+               beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_EH,
+                           "BM_%d : invldt_cmd_tbl alloc failed\n");
+               return FAILED;
+       }
+       nents = 0;
+       /* take back_lock to prevent task from getting cleaned up under us */
+       spin_lock(&session->back_lock);
        for (i = 0; i < conn->session->cmds_max; i++) {
-               abrt_task = conn->session->cmds[i];
-               abrt_io_task = abrt_task->dd_data;
-               if (!abrt_task->sc || abrt_task->state == ISCSI_TASK_FREE)
+               task = conn->session->cmds[i];
+               if (!task->sc)
                        continue;
 
-               if (sc->device->lun != abrt_task->sc->device->lun)
+               if (sc->device->lun != task->sc->device->lun)
                        continue;
+               /**
+                * Can't fit in more cmds? Normally this won't happen b'coz
+                * BEISCSI_CMD_PER_LUN is same as BE_INVLDT_CMD_TBL_SZ.
+                */
+               if (nents == BE_INVLDT_CMD_TBL_SZ) {
+                       more = 1;
+                       break;
+               }
 
-               /* Invalidate WRB Posted for this Task */
-               AMAP_SET_BITS(struct amap_iscsi_wrb, invld,
-                             abrt_io_task->pwrb_handle->pwrb,
-                             1);
+               /* get a task ref till FW processes the req for the ICD used */
+               __iscsi_get_task(task);
+               io_task = task->dd_data;
+               /* mark WRB invalid which have been not processed by FW yet */
+               if (is_chip_be2_be3r(phba)) {
+                       AMAP_SET_BITS(struct amap_iscsi_wrb, invld,
+                                     io_task->pwrb_handle->pwrb, 1);
+               } else {
+                       AMAP_SET_BITS(struct amap_iscsi_wrb_v2, invld,
+                                     io_task->pwrb_handle->pwrb, 1);
+               }
 
-               inv_tbl->cid = cid;
-               inv_tbl->icd = abrt_io_task->psgl_handle->sgl_index;
-               num_invalidate++;
-               inv_tbl++;
+               inv_tbl->tbl[nents].cid = beiscsi_conn->beiscsi_conn_cid;
+               inv_tbl->tbl[nents].icd = io_task->psgl_handle->sgl_index;
+               inv_tbl->task[nents] = task;
+               nents++;
        }
+       spin_unlock_bh(&session->back_lock);
        spin_unlock_bh(&session->frwd_lock);
-       inv_tbl = phba->inv_tbl;
 
-       nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev,
-                               sizeof(struct invalidate_commands_params_in),
-                               &nonemb_cmd.dma);
-       if (nonemb_cmd.va == NULL) {
+       rc = SUCCESS;
+       if (!nents)
+               goto end_reset;
+
+       if (more) {
                beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_EH,
-                           "BM_%d : Failed to allocate memory for"
-                           "mgmt_invalidate_icds\n");
-               return FAILED;
+                           "BM_%d : number of cmds exceeds size of invalidation table\n");
+               rc = FAILED;
+               goto end_reset;
        }
-       nonemb_cmd.size = sizeof(struct invalidate_commands_params_in);
-       memset(nonemb_cmd.va, 0, nonemb_cmd.size);
-       tag = mgmt_invalidate_icds(phba, inv_tbl, num_invalidate,
-                                  cid, &nonemb_cmd);
-       if (!tag) {
+
+       if (beiscsi_mgmt_invalidate_icds(phba, &inv_tbl->tbl[0], nents)) {
                beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_EH,
-                           "BM_%d : mgmt_invalidate_icds could not be"
-                           " submitted\n");
-               pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
-                                   nonemb_cmd.va, nonemb_cmd.dma);
-               return FAILED;
+                           "BM_%d : cid %u scmds invalidation failed\n",
+                           beiscsi_conn->beiscsi_conn_cid);
+               rc = FAILED;
        }
 
-       rc = beiscsi_mccq_compl_wait(phba, tag, NULL, &nonemb_cmd);
-       if (rc != -EBUSY)
-               pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
-                                   nonemb_cmd.va, nonemb_cmd.dma);
-       return iscsi_eh_device_reset(sc);
+end_reset:
+       for (i = 0; i < nents; i++)
+               iscsi_put_task(inv_tbl->task[i]);
+       kfree(inv_tbl);
+
+       if (rc == SUCCESS)
+               rc = iscsi_eh_device_reset(sc);
+       return rc;
 }
 
 /*------------------- PCI Driver operations and data ----------------- */
@@ -395,6 +389,7 @@ static struct scsi_host_template beiscsi_sht = {
        .change_queue_depth = scsi_change_queue_depth,
        .slave_configure = beiscsi_slave_configure,
        .target_alloc = iscsi_target_alloc,
+       .eh_timed_out = iscsi_eh_cmd_timed_out,
        .eh_abort_handler = beiscsi_eh_abort,
        .eh_device_reset_handler = beiscsi_eh_device_reset,
        .eh_target_reset_handler = iscsi_eh_session_reset,
@@ -646,7 +641,6 @@ static void beiscsi_get_params(struct beiscsi_hba *phba)
        phba->params.num_sge_per_io = BE2_SGE;
        phba->params.defpdu_hdr_sz = BE2_DEFPDU_HDR_SZ;
        phba->params.defpdu_data_sz = BE2_DEFPDU_DATA_SZ;
-       phba->params.eq_timer = 64;
        phba->params.num_eq_entries = 1024;
        phba->params.num_cq_entries = 1024;
        phba->params.wrbs_per_cxn = 256;
@@ -964,6 +958,10 @@ beiscsi_get_wrb_handle(struct hwi_wrb_context *pwrb_context,
        unsigned long flags;
 
        spin_lock_irqsave(&pwrb_context->wrb_lock, flags);
+       if (!pwrb_context->wrb_handles_available) {
+               spin_unlock_irqrestore(&pwrb_context->wrb_lock, flags);
+               return NULL;
+       }
        pwrb_handle = pwrb_context->pwrb_handle_base[pwrb_context->alloc_index];
        pwrb_context->wrb_handles_available--;
        if (pwrb_context->alloc_index == (wrbs_per_cxn - 1))
@@ -1014,6 +1012,7 @@ beiscsi_put_wrb_handle(struct hwi_wrb_context *pwrb_context,
                pwrb_context->free_index = 0;
        else
                pwrb_context->free_index++;
+       pwrb_handle->pio_handle = NULL;
        spin_unlock_irqrestore(&pwrb_context->wrb_lock, flags);
 }
 
@@ -1224,6 +1223,7 @@ hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn,
        uint16_t wrb_index, cid, cri_index;
        struct hwi_controller *phwi_ctrlr;
        struct wrb_handle *pwrb_handle;
+       struct iscsi_session *session;
        struct iscsi_task *task;
 
        phwi_ctrlr = phba->phwi_ctrlr;
@@ -1242,8 +1242,12 @@ hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn,
        cri_index = BE_GET_CRI_FROM_CID(cid);
        pwrb_context = &phwi_ctrlr->wrb_context[cri_index];
        pwrb_handle = pwrb_context->pwrb_handle_basestd[wrb_index];
+       session = beiscsi_conn->conn->session;
+       spin_lock_bh(&session->back_lock);
        task = pwrb_handle->pio_handle;
-       iscsi_put_task(task);
+       if (task)
+               __iscsi_put_task(task);
+       spin_unlock_bh(&session->back_lock);
 }
 
 static void
@@ -1323,16 +1327,15 @@ static void adapter_get_sol_cqe(struct beiscsi_hba *phba,
 static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
                             struct beiscsi_hba *phba, struct sol_cqe *psol)
 {
-       struct hwi_wrb_context *pwrb_context;
-       struct wrb_handle *pwrb_handle;
-       struct iscsi_wrb *pwrb = NULL;
-       struct hwi_controller *phwi_ctrlr;
-       struct iscsi_task *task;
-       unsigned int type;
        struct iscsi_conn *conn = beiscsi_conn->conn;
        struct iscsi_session *session = conn->session;
        struct common_sol_cqe csol_cqe = {0};
+       struct hwi_wrb_context *pwrb_context;
+       struct hwi_controller *phwi_ctrlr;
+       struct wrb_handle *pwrb_handle;
+       struct iscsi_task *task;
        uint16_t cri_index = 0;
+       uint8_t type;
 
        phwi_ctrlr = phba->phwi_ctrlr;
 
@@ -1345,11 +1348,14 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
        pwrb_handle = pwrb_context->pwrb_handle_basestd[
                      csol_cqe.wrb_index];
 
+       spin_lock_bh(&session->back_lock);
        task = pwrb_handle->pio_handle;
-       pwrb = pwrb_handle->pwrb;
+       if (!task) {
+               spin_unlock_bh(&session->back_lock);
+               return;
+       }
        type = ((struct beiscsi_io_task *)task->dd_data)->wrb_type;
 
-       spin_lock_bh(&session->back_lock);
        switch (type) {
        case HWH_TYPE_IO:
        case HWH_TYPE_IO_RD:
@@ -1711,13 +1717,12 @@ beiscsi_hdq_post_handles(struct beiscsi_hba *phba,
        struct list_head *hfree_list;
        struct phys_addr *pasync_sge;
        u32 ring_id, doorbell = 0;
-       u16 index, num_entries;
        u32 doorbell_offset;
        u16 prod = 0, cons;
+       u16 index;
 
        phwi_ctrlr = phba->phwi_ctrlr;
        pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr, ulp_num);
-       num_entries = pasync_ctx->num_entries;
        if (header) {
                cons = pasync_ctx->async_header.free_entries;
                hfree_list = &pasync_ctx->async_header.free_list;
@@ -2374,13 +2379,10 @@ static int hwi_write_buffer(struct iscsi_wrb *pwrb, struct iscsi_task *task)
 static void beiscsi_find_mem_req(struct beiscsi_hba *phba)
 {
        uint8_t mem_descr_index, ulp_num;
-       unsigned int num_cq_pages, num_async_pdu_buf_pages;
+       unsigned int num_async_pdu_buf_pages;
        unsigned int num_async_pdu_data_pages, wrb_sz_per_cxn;
        unsigned int num_async_pdu_buf_sgl_pages, num_async_pdu_data_sgl_pages;
 
-       num_cq_pages = PAGES_REQUIRED(phba->params.num_cq_entries * \
-                                     sizeof(struct sol_cqe));
-
        phba->params.hwi_ws_sz = sizeof(struct hwi_controller);
 
        phba->mem_req[ISCSI_MEM_GLOBAL_HEADER] = 2 *
@@ -2737,7 +2739,7 @@ static int hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
 
        for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) {
                if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) {
-                        /* get async_ctx for each ULP */
+                       /* get async_ctx for each ULP */
                        mem_descr = (struct be_mem_descriptor *)phba->init_mem;
                        mem_descr += (HWI_MEM_ASYNC_PDU_CONTEXT_ULP0 +
                                     (ulp_num * MEM_DESCR_OFFSET));
@@ -3367,7 +3369,7 @@ beiscsi_create_wrb_rings(struct beiscsi_hba *phba,
                         struct hwi_context_memory *phwi_context,
                         struct hwi_controller *phwi_ctrlr)
 {
-       unsigned int wrb_mem_index, offset, size, num_wrb_rings;
+       unsigned int num_wrb_rings;
        u64 pa_addr_lo;
        unsigned int idx, num, i, ulp_num;
        struct mem_array *pwrb_arr;
@@ -3432,10 +3434,6 @@ beiscsi_create_wrb_rings(struct beiscsi_hba *phba,
                }
 
        for (i = 0; i < phba->params.cxns_per_ctrl; i++) {
-               wrb_mem_index = 0;
-               offset = 0;
-               size = 0;
-
                if (ulp_count > 1) {
                        ulp_base_num = (ulp_base_num + 1) % BEISCSI_ULP_COUNT;
 
@@ -3663,7 +3661,6 @@ static void hwi_cleanup_port(struct beiscsi_hba *phba)
        struct be_ctrl_info *ctrl = &phba->ctrl;
        struct hwi_controller *phwi_ctrlr;
        struct hwi_context_memory *phwi_context;
-       struct hd_async_context *pasync_ctx;
        int i, eq_for_mcc, ulp_num;
 
        for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++)
@@ -3700,8 +3697,6 @@ static void hwi_cleanup_port(struct beiscsi_hba *phba)
                        q = &phwi_context->be_def_dataq[ulp_num];
                        if (q->created)
                                beiscsi_cmd_q_destroy(ctrl, q, QTYPE_DPDUQ);
-
-                       pasync_ctx = phwi_ctrlr->phwi_ctxt->pasync_ctx[ulp_num];
                }
        }
 
@@ -3804,7 +3799,6 @@ static int hwi_init_port(struct beiscsi_hba *phba)
                        /**
                         * Now that the default PDU rings have been created,
                         * let EP know about it.
-                        * Call beiscsi_cmd_iscsi_cleanup before posting?
                         */
                        beiscsi_hdq_post_handles(phba, BEISCSI_DEFQ_HDR,
                                                 ulp_num);
@@ -3850,14 +3844,6 @@ static int hwi_init_port(struct beiscsi_hba *phba)
                                        phwi_ctrlr->wrb_context[cri].cid] =
                                        async_arr_idx++;
                        }
-                       /**
-                        * Now that the default PDU rings have been created,
-                        * let EP know about it.
-                        */
-                       beiscsi_hdq_post_handles(phba, BEISCSI_DEFQ_HDR,
-                                                ulp_num);
-                       beiscsi_hdq_post_handles(phba, BEISCSI_DEFQ_DATA,
-                                                ulp_num);
                }
        }
 
@@ -3934,31 +3920,6 @@ static void beiscsi_free_mem(struct beiscsi_hba *phba)
        kfree(phba->phwi_ctrlr);
 }
 
-static int beiscsi_init_controller(struct beiscsi_hba *phba)
-{
-       int ret = -ENOMEM;
-
-       ret = beiscsi_get_memory(phba);
-       if (ret < 0) {
-               beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
-                           "BM_%d : beiscsi_dev_probe -"
-                           "Failed in beiscsi_alloc_memory\n");
-               return ret;
-       }
-
-       ret = hwi_init_controller(phba);
-       if (ret)
-               goto free_init;
-       beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
-                   "BM_%d : Return success from beiscsi_init_controller");
-
-       return 0;
-
-free_init:
-       beiscsi_free_mem(phba);
-       return ret;
-}
-
 static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba)
 {
        struct be_mem_descriptor *mem_descr_sglh, *mem_descr_sg;
@@ -4089,9 +4050,10 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba)
                        }
 
                        /* Allocate memory for CID array */
-                       ptr_cid_info->cid_array = kzalloc(sizeof(void *) *
-                                                 BEISCSI_GET_CID_COUNT(phba,
-                                                 ulp_num), GFP_KERNEL);
+                       ptr_cid_info->cid_array =
+                               kcalloc(BEISCSI_GET_CID_COUNT(phba, ulp_num),
+                                       sizeof(*ptr_cid_info->cid_array),
+                                       GFP_KERNEL);
                        if (!ptr_cid_info->cid_array) {
                                beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
                                            "BM_%d : Failed to allocate memory"
@@ -4231,33 +4193,30 @@ static int beiscsi_init_port(struct beiscsi_hba *phba)
 {
        int ret;
 
-       ret = beiscsi_init_controller(phba);
+       ret = hwi_init_controller(phba);
        if (ret < 0) {
                beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
-                           "BM_%d : beiscsi_dev_probe - Failed in"
-                           "beiscsi_init_controller\n");
+                           "BM_%d : init controller failed\n");
                return ret;
        }
        ret = beiscsi_init_sgl_handle(phba);
        if (ret < 0) {
                beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
-                           "BM_%d : beiscsi_dev_probe - Failed in"
-                           "beiscsi_init_sgl_handle\n");
-               goto do_cleanup_ctrlr;
+                           "BM_%d : init sgl handles failed\n");
+               goto cleanup_port;
        }
 
        ret = hba_setup_cid_tbls(phba);
        if (ret < 0) {
                beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
-                           "BM_%d : Failed in hba_setup_cid_tbls\n");
+                           "BM_%d : setup CID table failed\n");
                kfree(phba->io_sgl_hndl_base);
                kfree(phba->eh_sgl_hndl_base);
-               goto do_cleanup_ctrlr;
+               goto cleanup_port;
        }
-
        return ret;
 
-do_cleanup_ctrlr:
+cleanup_port:
        hwi_cleanup_port(phba);
        return ret;
 }
@@ -5417,10 +5376,10 @@ static int beiscsi_enable_port(struct beiscsi_hba *phba)
 
        phba->shost->max_id = phba->params.cxns_per_ctrl;
        phba->shost->can_queue = phba->params.ios_per_ctrl;
-       ret = hwi_init_controller(phba);
-       if (ret) {
+       ret = beiscsi_init_port(phba);
+       if (ret < 0) {
                __beiscsi_log(phba, KERN_ERR,
-                             "BM_%d : init controller failed %d\n", ret);
+                             "BM_%d : init port failed\n");
                goto disable_msix;
        }
 
@@ -5526,6 +5485,7 @@ static void beiscsi_disable_port(struct beiscsi_hba *phba, int unload)
                cancel_work_sync(&pbe_eq->mcc_work);
        }
        hwi_cleanup_port(phba);
+       beiscsi_cleanup_port(phba);
 }
 
 static void beiscsi_sess_work(struct work_struct *work)
@@ -5638,11 +5598,12 @@ static void beiscsi_eeh_resume(struct pci_dev *pdev)
 static int beiscsi_dev_probe(struct pci_dev *pcidev,
                             const struct pci_device_id *id)
 {
-       struct beiscsi_hba *phba = NULL;
-       struct hwi_controller *phwi_ctrlr;
        struct hwi_context_memory *phwi_context;
+       struct hwi_controller *phwi_ctrlr;
+       struct beiscsi_hba *phba = NULL;
        struct be_eq_obj *pbe_eq;
        unsigned int s_handle;
+       char wq_name[20];
        int ret, i;
 
        ret = beiscsi_enable_pci(pcidev);
@@ -5680,6 +5641,8 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
        case OC_DEVICE_ID2:
                phba->generation = BE_GEN2;
                phba->iotask_fn = beiscsi_iotask;
+               dev_warn(&pcidev->dev,
+                        "Obsolete/Unsupported BE2 Adapter Family\n");
                break;
        case BE_DEVICE_ID2:
        case OC_DEVICE_ID3:
@@ -5735,11 +5698,18 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
 
        phba->shost->max_id = phba->params.cxns_per_ctrl;
        phba->shost->can_queue = phba->params.ios_per_ctrl;
+       ret = beiscsi_get_memory(phba);
+       if (ret < 0) {
+               beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
+                           "BM_%d : alloc host mem failed\n");
+               goto free_port;
+       }
+
        ret = beiscsi_init_port(phba);
        if (ret < 0) {
                beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
-                           "BM_%d : beiscsi_dev_probe-"
-                           "Failed in beiscsi_init_port\n");
+                           "BM_%d : init port failed\n");
+               beiscsi_free_mem(phba);
                goto free_port;
        }
 
@@ -5754,9 +5724,9 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
 
        phba->ctrl.mcc_alloc_index = phba->ctrl.mcc_free_index = 0;
 
-       snprintf(phba->wq_name, sizeof(phba->wq_name), "beiscsi_%02x_wq",
+       snprintf(wq_name, sizeof(wq_name), "beiscsi_%02x_wq",
                 phba->shost->host_no);
-       phba->wq = alloc_workqueue("%s", WQ_MEM_RECLAIM, 1, phba->wq_name);
+       phba->wq = alloc_workqueue("%s", WQ_MEM_RECLAIM, 1, wq_name);
        if (!phba->wq) {
                beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
                            "BM_%d : beiscsi_dev_probe-"
@@ -5881,7 +5851,6 @@ static void beiscsi_remove(struct pci_dev *pcidev)
 
        /* free all resources */
        destroy_workqueue(phba->wq);
-       beiscsi_cleanup_port(phba);
        beiscsi_free_mem(phba);
 
        /* ctrl uninit */
index 6376657e45f7d3e5d2ad68ca6a34dc4916e835c7..2188579265664e1e8accbe5efd69d09682dddea1 100644 (file)
@@ -36,7 +36,7 @@
 #include <scsi/scsi_transport_iscsi.h>
 
 #define DRV_NAME               "be2iscsi"
-#define BUILD_STR              "11.2.0.0"
+#define BUILD_STR              "11.2.1.0"
 #define BE_NAME                        "Emulex OneConnect" \
                                "Open-iSCSI Driver version" BUILD_STR
 #define DRV_DESC               BE_NAME " " "Driver"
@@ -57,7 +57,6 @@
 
 #define BE2_IO_DEPTH           1024
 #define BE2_MAX_SESSIONS       256
-#define BE2_CMDS_PER_CXN       128
 #define BE2_TMFS               16
 #define BE2_NOPOUT_REQ         16
 #define BE2_SGE                        32
 
 #define BEISCSI_SGLIST_ELEMENTS        30
 
-#define BEISCSI_CMD_PER_LUN    128 /* scsi_host->cmd_per_lun */
-#define BEISCSI_MAX_SECTORS    1024 /* scsi_host->max_sectors */
+/**
+ * BE_INVLDT_CMD_TBL_SZ is 128 which is total number commands that can
+ * be invalidated at a time, consider it before changing the value of
+ * BEISCSI_CMD_PER_LUN.
+ */
+#define BEISCSI_CMD_PER_LUN    128     /* scsi_host->cmd_per_lun */
+#define BEISCSI_MAX_SECTORS    1024    /* scsi_host->max_sectors */
 #define BEISCSI_TEMPLATE_HDR_PER_CXN_SIZE 128 /* Template size per cxn */
 
 #define BEISCSI_MAX_CMD_LEN    16      /* scsi_host->max_cmd_len */
@@ -239,19 +243,7 @@ struct hba_parameters {
        unsigned int num_cq_entries;
        unsigned int num_eq_entries;
        unsigned int wrbs_per_cxn;
-       unsigned int crashmode;
-       unsigned int hba_num;
-
-       unsigned int mgmt_ws_sz;
        unsigned int hwi_ws_sz;
-
-       unsigned int eto;
-       unsigned int ldto;
-
-       unsigned int dbg_flags;
-       unsigned int num_cxn;
-
-       unsigned int eq_timer;
        /**
         * These are calculated from other params. They're here
         * for debug purposes
@@ -272,11 +264,6 @@ struct hba_parameters {
        unsigned int num_sge;
 };
 
-struct invalidate_command_table {
-       unsigned short icd;
-       unsigned short cid;
-} __packed;
-
 #define BEISCSI_GET_ULP_FROM_CRI(phwi_ctrlr, cri) \
        (phwi_ctrlr->wrb_context[cri].ulp_num)
 struct hwi_wrb_context {
@@ -334,7 +321,6 @@ struct beiscsi_hba {
        struct be_bus_address pci_pa;   /* CSR */
        /* PCI representation of our HBA */
        struct pci_dev *pcidev;
-       unsigned short asic_revision;
        unsigned int num_cpus;
        unsigned int nxt_cqid;
        struct msix_entry msix_entries[MAX_CPUS];
@@ -355,9 +341,9 @@ struct beiscsi_hba {
        spinlock_t io_sgl_lock;
        spinlock_t mgmt_sgl_lock;
        spinlock_t async_pdu_lock;
-       unsigned int age;
        struct list_head hba_queue;
 #define BE_MAX_SESSION 2048
+#define BE_INVALID_CID 0xffff
 #define BE_SET_CID_TO_CRI(cri_index, cid) \
                          (phba->cid_to_cri_map[cid] = cri_index)
 #define BE_GET_CRI_FROM_CID(cid) (phba->cid_to_cri_map[cid])
@@ -425,12 +411,10 @@ struct beiscsi_hba {
        u8 port_name;
        u8 port_speed;
        char fw_ver_str[BEISCSI_VER_STRLEN];
-       char wq_name[20];
        struct workqueue_struct *wq;    /* The actuak work queue */
        struct be_ctrl_info ctrl;
        unsigned int generation;
        unsigned int interface_handle;
-       struct invalidate_command_table inv_tbl[128];
 
        struct be_aic_obj aic_obj[MAX_CPUS];
        unsigned int attr_log_enable;
@@ -525,10 +509,6 @@ struct beiscsi_io_task {
        struct scsi_cmnd *scsi_cmnd;
        int num_sg;
        struct hwi_wrb_context *pwrb_context;
-       unsigned int cmd_sn;
-       unsigned int flags;
-       unsigned short cid;
-       unsigned short header_len;
        itt_t libiscsi_itt;
        struct be_cmd_bhs *cmd_bhs;
        struct be_bus_address bhs_pa;
@@ -842,7 +822,7 @@ struct amap_iscsi_wrb_v2 {
        u8 diff_enbl;   /* DWORD 11 */
        u8 u_run;       /* DWORD 11 */
        u8 o_run;       /* DWORD 11 */
-       u8 invalid;     /* DWORD 11 */
+       u8 invld;     /* DWORD 11 */
        u8 dsp;         /* DWORD 11 */
        u8 dmsg;        /* DWORD 11 */
        u8 rsvd4;       /* DWORD 11 */
@@ -1042,10 +1022,8 @@ struct hwi_controller {
        struct list_head io_sgl_list;
        struct list_head eh_sgl_list;
        struct sgl_handle *psgl_handle_base;
-       unsigned int wrb_mem_index;
 
        struct hwi_wrb_context *wrb_context;
-       struct mcc_wrb *pmcc_wrb_base;
        struct be_ring default_pdu_hdr[BEISCSI_ULP_COUNT];
        struct be_ring default_pdu_data[BEISCSI_ULP_COUNT];
        struct hwi_context_memory *phwi_ctxt;
@@ -1062,9 +1040,7 @@ enum hwh_type_enum {
 };
 
 struct wrb_handle {
-       enum hwh_type_enum type;
        unsigned short wrb_index;
-
        struct iscsi_task *pio_handle;
        struct iscsi_wrb *pwrb;
 };
index ac05317bba7f3342d016e581b91ae6feffa18eff..2f6d5c2ac32901c84627edabbceb29848a62e694 100644 (file)
@@ -66,7 +66,6 @@ unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl,
                                         struct bsg_job *job,
                                         struct be_dma_mem *nonemb_cmd)
 {
-       struct be_cmd_resp_hdr *resp;
        struct be_mcc_wrb *wrb;
        struct be_sge *mcc_sge;
        unsigned int tag = 0;
@@ -76,7 +75,6 @@ unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl,
 
        nonemb_cmd->size = job->request_payload.payload_len;
        memset(nonemb_cmd->va, 0, nonemb_cmd->size);
-       resp = nonemb_cmd->va;
        region =  bsg_req->rqst_data.h_vendor.vendor_cmd[1];
        sector_size =  bsg_req->rqst_data.h_vendor.vendor_cmd[2];
        sector =  bsg_req->rqst_data.h_vendor.vendor_cmd[3];
@@ -128,50 +126,6 @@ unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl,
        return tag;
 }
 
-unsigned int  mgmt_invalidate_icds(struct beiscsi_hba *phba,
-                               struct invalidate_command_table *inv_tbl,
-                               unsigned int num_invalidate, unsigned int cid,
-                               struct be_dma_mem *nonemb_cmd)
-
-{
-       struct be_ctrl_info *ctrl = &phba->ctrl;
-       struct be_mcc_wrb *wrb;
-       struct be_sge *sge;
-       struct invalidate_commands_params_in *req;
-       unsigned int i, tag;
-
-       mutex_lock(&ctrl->mbox_lock);
-       wrb = alloc_mcc_wrb(phba, &tag);
-       if (!wrb) {
-               mutex_unlock(&ctrl->mbox_lock);
-               return 0;
-       }
-
-       req = nonemb_cmd->va;
-       memset(req, 0, sizeof(*req));
-       sge = nonembedded_sgl(wrb);
-
-       be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1);
-       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
-                       OPCODE_COMMON_ISCSI_ERROR_RECOVERY_INVALIDATE_COMMANDS,
-                       sizeof(*req));
-       req->ref_handle = 0;
-       req->cleanup_type = CMD_ISCSI_COMMAND_INVALIDATE;
-       for (i = 0; i < num_invalidate; i++) {
-               req->table[i].icd = inv_tbl->icd;
-               req->table[i].cid = inv_tbl->cid;
-               req->icd_count++;
-               inv_tbl++;
-       }
-       sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
-       sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
-       sge->len = cpu_to_le32(nonemb_cmd->size);
-
-       be_mcc_notify(phba, tag);
-       mutex_unlock(&ctrl->mbox_lock);
-       return tag;
-}
-
 unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba,
                                         struct beiscsi_endpoint *beiscsi_ep,
                                         unsigned short cid,
@@ -1066,7 +1020,6 @@ unsigned int beiscsi_boot_reopen_sess(struct beiscsi_hba *phba)
 unsigned int beiscsi_boot_get_sinfo(struct beiscsi_hba *phba)
 {
        struct be_ctrl_info *ctrl = &phba->ctrl;
-       struct be_cmd_get_session_resp *resp;
        struct be_cmd_get_session_req *req;
        struct be_dma_mem *nonemb_cmd;
        struct be_mcc_wrb *wrb;
@@ -1081,7 +1034,7 @@ unsigned int beiscsi_boot_get_sinfo(struct beiscsi_hba *phba)
        }
 
        nonemb_cmd = &phba->boot_struct.nonemb_cmd;
-       nonemb_cmd->size = sizeof(*resp);
+       nonemb_cmd->size = sizeof(struct be_cmd_get_session_resp);
        nonemb_cmd->va = pci_alloc_consistent(phba->ctrl.pdev,
                                              nonemb_cmd->size,
                                              &nonemb_cmd->dma);
@@ -1096,7 +1049,7 @@ unsigned int beiscsi_boot_get_sinfo(struct beiscsi_hba *phba)
        be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1);
        be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
                           OPCODE_ISCSI_INI_SESSION_GET_A_SESSION,
-                          sizeof(*resp));
+                          sizeof(struct be_cmd_get_session_resp));
        req->session_handle = phba->boot_struct.s_handle;
        sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
        sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
@@ -1309,7 +1262,8 @@ beiscsi_adap_family_disp(struct device *dev, struct device_attribute *attr,
        case BE_DEVICE_ID1:
        case OC_DEVICE_ID1:
        case OC_DEVICE_ID2:
-               return snprintf(buf, PAGE_SIZE, "BE2 Adapter Family\n");
+               return snprintf(buf, PAGE_SIZE,
+                               "Obsolete/Unsupported BE2 Adapter Family\n");
                break;
        case BE_DEVICE_ID2:
        case OC_DEVICE_ID3:
@@ -1341,7 +1295,7 @@ beiscsi_phys_port_disp(struct device *dev, struct device_attribute *attr,
        struct Scsi_Host *shost = class_to_shost(dev);
        struct beiscsi_hba *phba = iscsi_host_priv(shost);
 
-       return snprintf(buf, PAGE_SIZE, "Port Identifier : %d\n",
+       return snprintf(buf, PAGE_SIZE, "Port Identifier : %u\n",
                        phba->fw_config.phys_port);
 }
 
@@ -1494,3 +1448,64 @@ void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params,
                     (params->dw[offsetof(struct amap_beiscsi_offload_params,
                      exp_statsn) / 32] + 1));
 }
+
+int beiscsi_mgmt_invalidate_icds(struct beiscsi_hba *phba,
+                                struct invldt_cmd_tbl *inv_tbl,
+                                unsigned int nents)
+{
+       struct be_ctrl_info *ctrl = &phba->ctrl;
+       struct invldt_cmds_params_in *req;
+       struct be_dma_mem nonemb_cmd;
+       struct be_mcc_wrb *wrb;
+       unsigned int i, tag;
+       struct be_sge *sge;
+       int rc;
+
+       if (!nents || nents > BE_INVLDT_CMD_TBL_SZ)
+               return -EINVAL;
+
+       nonemb_cmd.size = sizeof(union be_invldt_cmds_params);
+       nonemb_cmd.va = pci_zalloc_consistent(phba->ctrl.pdev,
+                                             nonemb_cmd.size,
+                                             &nonemb_cmd.dma);
+       if (!nonemb_cmd.va) {
+               beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_EH,
+                           "BM_%d : invldt_cmds_params alloc failed\n");
+               return -ENOMEM;
+       }
+
+       mutex_lock(&ctrl->mbox_lock);
+       wrb = alloc_mcc_wrb(phba, &tag);
+       if (!wrb) {
+               mutex_unlock(&ctrl->mbox_lock);
+               pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+                                   nonemb_cmd.va, nonemb_cmd.dma);
+               return -ENOMEM;
+       }
+
+       req = nonemb_cmd.va;
+       be_wrb_hdr_prepare(wrb, nonemb_cmd.size, false, 1);
+       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
+                       OPCODE_COMMON_ISCSI_ERROR_RECOVERY_INVALIDATE_COMMANDS,
+                       sizeof(*req));
+       req->ref_handle = 0;
+       req->cleanup_type = CMD_ISCSI_COMMAND_INVALIDATE;
+       for (i = 0; i < nents; i++) {
+               req->table[i].icd = inv_tbl[i].icd;
+               req->table[i].cid = inv_tbl[i].cid;
+               req->icd_count++;
+       }
+       sge = nonembedded_sgl(wrb);
+       sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd.dma));
+       sge->pa_lo = cpu_to_le32(lower_32_bits(nonemb_cmd.dma));
+       sge->len = cpu_to_le32(nonemb_cmd.size);
+
+       be_mcc_notify(phba, tag);
+       mutex_unlock(&ctrl->mbox_lock);
+
+       rc = beiscsi_mccq_compl_wait(phba, tag, NULL, &nonemb_cmd);
+       if (rc != -EBUSY)
+               pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+                                   nonemb_cmd.va, nonemb_cmd.dma);
+       return rc;
+}
index b897cfd57c72a3ff52ede0d86418218b764773dc..308f1472f98ae85e0138dcb945d183c1017e3c33 100644 (file)
 #define PCICFG_UE_STATUS_MASK_LOW       0xA8
 #define PCICFG_UE_STATUS_MASK_HI        0xAC
 
-/**
- * Pseudo amap definition in which each bit of the actual structure is defined
- * as a byte: used to calculate offset/shift/mask of each field
- */
-struct amap_mcc_sge {
-       u8 pa_lo[32];           /* dword 0 */
-       u8 pa_hi[32];           /* dword 1 */
-       u8 length[32];          /* DWORD 2 */
-} __packed;
-
-/**
- * Pseudo amap definition in which each bit of the actual structure is defined
- * as a byte: used to calculate offset/shift/mask of each field
- */
-struct amap_mcc_wrb_payload {
-       union {
-               struct amap_mcc_sge sgl[19];
-               u8 embedded[59 * 32];   /* DWORDS 57 to 115 */
-       } u;
-} __packed;
-
-/**
- * Pseudo amap definition in which each bit of the actual structure is defined
- * as a byte: used to calculate offset/shift/mask of each field
- */
-struct amap_mcc_wrb {
-       u8 embedded;            /* DWORD 0 */
-       u8 rsvd0[2];            /* DWORD 0 */
-       u8 sge_count[5];        /* DWORD 0 */
-       u8 rsvd1[16];           /* DWORD 0 */
-       u8 special[8];          /* DWORD 0 */
-       u8 payload_length[32];
-       u8 tag[64];             /* DWORD 2 */
-       u8 rsvd2[32];           /* DWORD 4 */
-       struct amap_mcc_wrb_payload payload;
-};
-
-struct mcc_sge {
-       u32 pa_lo;              /* dword 0 */
-       u32 pa_hi;              /* dword 1 */
-       u32 length;             /* DWORD 2 */
-} __packed;
-
-struct mcc_wrb_payload {
-       union {
-               struct mcc_sge sgl[19];
-               u32 embedded[59];       /* DWORDS 57 to 115 */
-       } u;
-} __packed;
-
-#define MCC_WRB_EMBEDDED_MASK                0x00000001
-
-struct mcc_wrb {
-       u32 dw[0];              /* DWORD 0 */
-       u32 payload_length;
-       u32 tag[2];             /* DWORD 2 */
-       u32 rsvd2[1];           /* DWORD 4 */
-       struct mcc_wrb_payload payload;
-};
-
 int mgmt_open_connection(struct beiscsi_hba *phba,
                         struct sockaddr *dst_addr,
                         struct beiscsi_endpoint *beiscsi_ep,
@@ -104,10 +44,6 @@ int mgmt_open_connection(struct beiscsi_hba *phba,
 unsigned int mgmt_upload_connection(struct beiscsi_hba *phba,
                                     unsigned short cid,
                                     unsigned int upload_flag);
-unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba,
-                               struct invalidate_command_table *inv_tbl,
-                               unsigned int num_invalidate, unsigned int cid,
-                               struct be_dma_mem *nonemb_cmd);
 unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl,
                                         struct beiscsi_hba *phba,
                                         struct bsg_job *job,
@@ -134,24 +70,31 @@ union iscsi_invalidate_connection_params {
        struct iscsi_invalidate_connection_params_out response;
 } __packed;
 
-struct invalidate_commands_params_in {
+#define BE_INVLDT_CMD_TBL_SZ   128
+struct invldt_cmd_tbl {
+       unsigned short icd;
+       unsigned short cid;
+} __packed;
+
+struct invldt_cmds_params_in {
        struct be_cmd_req_hdr hdr;
        unsigned int ref_handle;
        unsigned int icd_count;
-       struct invalidate_command_table table[128];
+       struct invldt_cmd_tbl table[BE_INVLDT_CMD_TBL_SZ];
        unsigned short cleanup_type;
        unsigned short unused;
 } __packed;
 
-struct invalidate_commands_params_out {
+struct invldt_cmds_params_out {
+       struct be_cmd_resp_hdr hdr;
        unsigned int ref_handle;
        unsigned int icd_count;
-       unsigned int icd_status[128];
+       unsigned int icd_status[BE_INVLDT_CMD_TBL_SZ];
 } __packed;
 
-union invalidate_commands_params {
-       struct invalidate_commands_params_in request;
-       struct invalidate_commands_params_out response;
+union be_invldt_cmds_params {
+       struct invldt_cmds_params_in request;
+       struct invldt_cmds_params_out response;
 } __packed;
 
 struct mgmt_hba_attributes {
@@ -231,16 +174,6 @@ struct be_bsg_vendor_cmd {
 
 #define GET_MGMT_CONTROLLER_WS(phba)    (phba->pmgmt_ws)
 
-/* MGMT CMD flags */
-
-#define MGMT_CMDH_FREE                (1<<0)
-
-/*  --- MGMT_ERROR_CODES --- */
-/*  Error Codes returned in the status field of the CMD response header */
-#define MGMT_STATUS_SUCCESS 0  /* The CMD completed without errors */
-#define MGMT_STATUS_FAILED 1   /* Error status in the Status field of */
-                               /* the CMD_RESPONSE_HEADER  */
-
 #define ISCSI_GET_PDU_TEMPLATE_ADDRESS(pc, pa) {\
        pa->lo = phba->init_mem[ISCSI_MEM_GLOBAL_HEADER].mem_array[0].\
                                        bus_address.u.a32.address_lo;  \
@@ -270,6 +203,9 @@ unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba,
                                         unsigned short cid,
                                         unsigned short issue_reset,
                                         unsigned short savecfg_flag);
+int beiscsi_mgmt_invalidate_icds(struct beiscsi_hba *phba,
+                                struct invldt_cmd_tbl *inv_tbl,
+                                unsigned int nents);
 
 int beiscsi_if_en_dhcp(struct beiscsi_hba *phba, u32 ip_type);
 
index 1e7e139d71eabd1bbdc9e1daa4b589f640e231e6..4aa61e20e82d71b3072c8ce4a96ee2a7f0eb385c 100644 (file)
 
 BFA_TRC_FILE(FCS, FCS);
 
-/*
- * FCS sub-modules
- */
-struct bfa_fcs_mod_s {
-       void            (*attach) (struct bfa_fcs_s *fcs);
-       void            (*modinit) (struct bfa_fcs_s *fcs);
-       void            (*modexit) (struct bfa_fcs_s *fcs);
-};
-
-#define BFA_FCS_MODULE(_mod) { _mod ## _modinit, _mod ## _modexit }
-
-static struct bfa_fcs_mod_s fcs_modules[] = {
-       { bfa_fcs_port_attach, NULL, NULL },
-       { bfa_fcs_uf_attach, NULL, NULL },
-       { bfa_fcs_fabric_attach, bfa_fcs_fabric_modinit,
-         bfa_fcs_fabric_modexit },
-};
-
 /*
  *  fcs_api BFA FCS API
  */
@@ -58,52 +40,19 @@ bfa_fcs_exit_comp(void *fcs_cbarg)
        complete(&bfad->comp);
 }
 
-
-
 /*
- *  fcs_api BFA FCS API
- */
-
-/*
- * fcs attach -- called once to initialize data structures at driver attach time
+ * fcs initialization, called once after bfa initialization is complete
  */
 void
-bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad,
-              bfa_boolean_t min_cfg)
+bfa_fcs_init(struct bfa_fcs_s *fcs)
 {
-       int             i;
-       struct bfa_fcs_mod_s  *mod;
-
-       fcs->bfa = bfa;
-       fcs->bfad = bfad;
-       fcs->min_cfg = min_cfg;
-       fcs->num_rport_logins = 0;
-
-       bfa->fcs = BFA_TRUE;
-       fcbuild_init();
-
-       for (i = 0; i < ARRAY_SIZE(fcs_modules); i++) {
-               mod = &fcs_modules[i];
-               if (mod->attach)
-                       mod->attach(fcs);
-       }
+       bfa_sm_send_event(&fcs->fabric, BFA_FCS_FABRIC_SM_CREATE);
+       bfa_trc(fcs, 0);
 }
 
 /*
- * fcs initialization, called once after bfa initialization is complete
+ *  fcs_api BFA FCS API
  */
-void
-bfa_fcs_init(struct bfa_fcs_s *fcs)
-{
-       int     i;
-       struct bfa_fcs_mod_s  *mod;
-
-       for (i = 0; i < ARRAY_SIZE(fcs_modules); i++) {
-               mod = &fcs_modules[i];
-               if (mod->modinit)
-                       mod->modinit(fcs);
-       }
-}
 
 /*
  * FCS update cfg - reset the pwwn/nwwn of fabric base logical port
@@ -180,26 +129,14 @@ bfa_fcs_driver_info_init(struct bfa_fcs_s *fcs,
 void
 bfa_fcs_exit(struct bfa_fcs_s *fcs)
 {
-       struct bfa_fcs_mod_s  *mod;
-       int             nmods, i;
-
        bfa_wc_init(&fcs->wc, bfa_fcs_exit_comp, fcs);
-
-       nmods = ARRAY_SIZE(fcs_modules);
-
-       for (i = 0; i < nmods; i++) {
-
-               mod = &fcs_modules[i];
-               if (mod->modexit) {
-                       bfa_wc_up(&fcs->wc);
-                       mod->modexit(fcs);
-               }
-       }
-
+       bfa_wc_up(&fcs->wc);
+       bfa_trc(fcs, 0);
+       bfa_lps_delete(fcs->fabric.lps);
+       bfa_sm_send_event(&fcs->fabric, BFA_FCS_FABRIC_SM_DELETE);
        bfa_wc_wait(&fcs->wc);
 }
 
-
 /*
  * Fabric module implementation.
  */
@@ -1127,62 +1064,6 @@ bfa_fcs_fabric_stop_comp(void *cbarg)
  *  fcs_fabric_public fabric public functions
  */
 
-/*
- * Attach time initialization.
- */
-void
-bfa_fcs_fabric_attach(struct bfa_fcs_s *fcs)
-{
-       struct bfa_fcs_fabric_s *fabric;
-
-       fabric = &fcs->fabric;
-       memset(fabric, 0, sizeof(struct bfa_fcs_fabric_s));
-
-       /*
-        * Initialize base fabric.
-        */
-       fabric->fcs = fcs;
-       INIT_LIST_HEAD(&fabric->vport_q);
-       INIT_LIST_HEAD(&fabric->vf_q);
-       fabric->lps = bfa_lps_alloc(fcs->bfa);
-       WARN_ON(!fabric->lps);
-
-       /*
-        * Initialize fabric delete completion handler. Fabric deletion is
-        * complete when the last vport delete is complete.
-        */
-       bfa_wc_init(&fabric->wc, bfa_fcs_fabric_delete_comp, fabric);
-       bfa_wc_up(&fabric->wc); /* For the base port */
-
-       bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit);
-       bfa_fcs_lport_attach(&fabric->bport, fabric->fcs, FC_VF_ID_NULL, NULL);
-}
-
-void
-bfa_fcs_fabric_modinit(struct bfa_fcs_s *fcs)
-{
-       bfa_sm_send_event(&fcs->fabric, BFA_FCS_FABRIC_SM_CREATE);
-       bfa_trc(fcs, 0);
-}
-
-/*
- *   Module cleanup
- */
-void
-bfa_fcs_fabric_modexit(struct bfa_fcs_s *fcs)
-{
-       struct bfa_fcs_fabric_s *fabric;
-
-       bfa_trc(fcs, 0);
-
-       /*
-        * Cleanup base fabric.
-        */
-       fabric = &fcs->fabric;
-       bfa_lps_delete(fabric->lps);
-       bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELETE);
-}
-
 /*
  * Fabric module stop -- stop FCS actions
  */
@@ -1633,12 +1514,6 @@ bfa_fcs_port_event_handler(void *cbarg, enum bfa_port_linkstate event)
        }
 }
 
-void
-bfa_fcs_port_attach(struct bfa_fcs_s *fcs)
-{
-       bfa_fcport_event_register(fcs->bfa, bfa_fcs_port_event_handler, fcs);
-}
-
 /*
  * BFA FCS UF ( Unsolicited Frames)
  */
@@ -1706,8 +1581,44 @@ bfa_fcs_uf_recv(void *cbarg, struct bfa_uf_s *uf)
        bfa_uf_free(uf);
 }
 
+/*
+ * fcs attach -- called once to initialize data structures at driver attach time
+ */
 void
-bfa_fcs_uf_attach(struct bfa_fcs_s *fcs)
+bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad,
+              bfa_boolean_t min_cfg)
 {
+       struct bfa_fcs_fabric_s *fabric = &fcs->fabric;
+
+       fcs->bfa = bfa;
+       fcs->bfad = bfad;
+       fcs->min_cfg = min_cfg;
+       fcs->num_rport_logins = 0;
+
+       bfa->fcs = BFA_TRUE;
+       fcbuild_init();
+
+       bfa_fcport_event_register(fcs->bfa, bfa_fcs_port_event_handler, fcs);
        bfa_uf_recv_register(fcs->bfa, bfa_fcs_uf_recv, fcs);
+
+       memset(fabric, 0, sizeof(struct bfa_fcs_fabric_s));
+
+       /*
+        * Initialize base fabric.
+        */
+       fabric->fcs = fcs;
+       INIT_LIST_HEAD(&fabric->vport_q);
+       INIT_LIST_HEAD(&fabric->vf_q);
+       fabric->lps = bfa_lps_alloc(fcs->bfa);
+       WARN_ON(!fabric->lps);
+
+       /*
+        * Initialize fabric delete completion handler. Fabric deletion is
+        * complete when the last vport delete is complete.
+        */
+       bfa_wc_init(&fabric->wc, bfa_fcs_fabric_delete_comp, fabric);
+       bfa_wc_up(&fabric->wc); /* For the base port */
+
+       bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit);
+       bfa_fcs_lport_attach(&fabric->bport, fabric->fcs, FC_VF_ID_NULL, NULL);
 }
index 0f797a55d5044dc942353532ba0c1ba7b2fc1f07..e60f72b766ea5c91bf90e7837906090c59f21d89 100644 (file)
@@ -808,9 +808,7 @@ void bfa_fcs_vf_get_ports(bfa_fcs_vf_t *vf, wwn_t vpwwn[], int *nports);
 /*
  * fabric protected interface functions
  */
-void bfa_fcs_fabric_attach(struct bfa_fcs_s *fcs);
 void bfa_fcs_fabric_modinit(struct bfa_fcs_s *fcs);
-void bfa_fcs_fabric_modexit(struct bfa_fcs_s *fcs);
 void bfa_fcs_fabric_link_up(struct bfa_fcs_fabric_s *fabric);
 void bfa_fcs_fabric_link_down(struct bfa_fcs_fabric_s *fabric);
 void bfa_fcs_fabric_addvport(struct bfa_fcs_fabric_s *fabric,
@@ -827,8 +825,6 @@ void        bfa_fcs_fabric_nsymb_init(struct bfa_fcs_fabric_s *fabric);
 void bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric,
               wwn_t fabric_name);
 u16 bfa_fcs_fabric_get_switch_oui(struct bfa_fcs_fabric_s *fabric);
-void bfa_fcs_uf_attach(struct bfa_fcs_s *fcs);
-void bfa_fcs_port_attach(struct bfa_fcs_s *fcs);
 void bfa_fcs_fabric_modstop(struct bfa_fcs_s *fcs);
 void bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric,
                        enum bfa_fcs_fabric_event event);
index 02d806012fa12c26530d61513d82b7dce932e8e9..7eb0eef18fddfe8fed96f8d7a058146b2c85def3 100644 (file)
@@ -813,6 +813,7 @@ struct scsi_host_template bfad_im_scsi_host_template = {
        .name = BFAD_DRIVER_NAME,
        .info = bfad_im_info,
        .queuecommand = bfad_im_queuecommand,
+       .eh_timed_out = fc_eh_timed_out,
        .eh_abort_handler = bfad_im_abort_handler,
        .eh_device_reset_handler = bfad_im_reset_lun_handler,
        .eh_bus_reset_handler = bfad_im_reset_bus_handler,
@@ -835,6 +836,7 @@ struct scsi_host_template bfad_im_vport_template = {
        .name = BFAD_DRIVER_NAME,
        .info = bfad_im_info,
        .queuecommand = bfad_im_queuecommand,
+       .eh_timed_out = fc_eh_timed_out,
        .eh_abort_handler = bfad_im_abort_handler,
        .eh_device_reset_handler = bfad_im_reset_lun_handler,
        .eh_bus_reset_handler = bfad_im_reset_bus_handler,
index c639d5a02656abf9678f1ef358c4166e5db04a66..b1e39f985ec9dbf9e72d4a6b47f65185f7220470 100644 (file)
@@ -2947,6 +2947,7 @@ static struct scsi_host_template bnx2fc_shost_template = {
        .module                 = THIS_MODULE,
        .name                   = "QLogic Offload FCoE Initiator",
        .queuecommand           = bnx2fc_queuecommand,
+       .eh_timed_out           = fc_eh_timed_out,
        .eh_abort_handler       = bnx2fc_eh_abort,        /* abts */
        .eh_device_reset_handler = bnx2fc_eh_device_reset, /* lun reset */
        .eh_target_reset_handler = bnx2fc_eh_target_reset, /* tgt reset */
index 133901fd3e35f2b02194481c3a93f7b9b1097c1c..f32a66f89d25b44bd235ca80003040d594020045 100644 (file)
@@ -2259,6 +2259,7 @@ static struct scsi_host_template bnx2i_host_template = {
        .name                   = "QLogic Offload iSCSI Initiator",
        .proc_name              = "bnx2i",
        .queuecommand           = iscsi_queuecommand,
+       .eh_timed_out           = iscsi_eh_cmd_timed_out,
        .eh_abort_handler       = iscsi_eh_abort,
        .eh_device_reset_handler = iscsi_eh_device_reset,
        .eh_target_reset_handler = iscsi_eh_recover_target,
index 89a52b941ea8d6b9a5b7fe7aff11e31f77f72957..a1ff75f1384f4e96e3c6e8456a78513659533135 100644 (file)
@@ -2270,6 +2270,7 @@ struct scsi_host_template csio_fcoe_shost_template = {
        .name                   = CSIO_DRV_DESC,
        .proc_name              = KBUILD_MODNAME,
        .queuecommand           = csio_queuecommand,
+       .eh_timed_out           = fc_eh_timed_out,
        .eh_abort_handler       = csio_eh_abort_handler,
        .eh_device_reset_handler = csio_eh_lun_reset_handler,
        .slave_alloc            = csio_slave_alloc,
@@ -2289,6 +2290,7 @@ struct scsi_host_template csio_fcoe_shost_vport_template = {
        .name                   = CSIO_DRV_DESC,
        .proc_name              = KBUILD_MODNAME,
        .queuecommand           = csio_queuecommand,
+       .eh_timed_out           = fc_eh_timed_out,
        .eh_abort_handler       = csio_eh_abort_handler,
        .eh_device_reset_handler = csio_eh_lun_reset_handler,
        .slave_alloc            = csio_slave_alloc,
index 33e83464e091e7508b2bfeede75ff97b2ababf09..1880eb6c68f73ca2168975d1e7514b8c1ea943ef 100644 (file)
@@ -90,6 +90,7 @@ static struct scsi_host_template cxgb3i_host_template = {
        .sg_tablesize   = SG_ALL,
        .max_sectors    = 0xFFFF,
        .cmd_per_lun    = ISCSI_DEF_CMD_PER_LUN,
+       .eh_timed_out   = iscsi_eh_cmd_timed_out,
        .eh_abort_handler = iscsi_eh_abort,
        .eh_device_reset_handler = iscsi_eh_device_reset,
        .eh_target_reset_handler = iscsi_eh_recover_target,
index 9a2fdc305cf2a9a0c7b4f4fabae4191bb9f12ad1..3fb3f5708ff706d4cf7c7ec07250642b081e3a09 100644 (file)
@@ -103,6 +103,7 @@ static struct scsi_host_template cxgb4i_host_template = {
        .sg_tablesize   = SG_ALL,
        .max_sectors    = 0xFFFF,
        .cmd_per_lun    = ISCSI_DEF_CMD_PER_LUN,
+       .eh_timed_out   = iscsi_eh_cmd_timed_out,
        .eh_abort_handler = iscsi_eh_abort,
        .eh_device_reset_handler = iscsi_eh_device_reset,
        .eh_target_reset_handler = iscsi_eh_recover_target,
index 0e9de5d62da25f56bcb0645a35a98582896fc37b..d11dcc59ff46b40b058e69b96fe01d4c09ca34d3 100644 (file)
@@ -54,6 +54,9 @@ extern const struct file_operations cxlflash_cxl_fops;
 /* RRQ for master issued cmds */
 #define NUM_RRQ_ENTRY                   CXLFLASH_MAX_CMDS
 
+/* SQ for master issued cmds */
+#define NUM_SQ_ENTRY                   CXLFLASH_MAX_CMDS
+
 
 static inline void check_sizes(void)
 {
@@ -155,8 +158,8 @@ static inline struct afu_cmd *sc_to_afucz(struct scsi_cmnd *sc)
 
 struct afu {
        /* Stuff requiring alignment go first. */
-
-       u64 rrq_entry[NUM_RRQ_ENTRY];   /* 2K RRQ */
+       struct sisl_ioarcb sq[NUM_SQ_ENTRY];            /* 16K SQ */
+       u64 rrq_entry[NUM_RRQ_ENTRY];                   /* 2K RRQ */
 
        /* Beware of alignment till here. Preferably introduce new
         * fields after this point
@@ -171,9 +174,13 @@ struct afu {
        struct sisl_host_map __iomem *host_map;         /* MC host map */
        struct sisl_ctrl_map __iomem *ctrl_map;         /* MC control map */
 
-       struct kref mapcount;
-
        ctx_hndl_t ctx_hndl;    /* master's context handle */
+
+       atomic_t hsq_credits;
+       spinlock_t hsq_slock;
+       struct sisl_ioarcb *hsq_start;
+       struct sisl_ioarcb *hsq_end;
+       struct sisl_ioarcb *hsq_curr;
        u64 *hrrq_start;
        u64 *hrrq_end;
        u64 *hrrq_curr;
@@ -191,6 +198,23 @@ struct afu {
 
 };
 
+static inline bool afu_is_cmd_mode(struct afu *afu, u64 cmd_mode)
+{
+       u64 afu_cap = afu->interface_version >> SISL_INTVER_CAP_SHIFT;
+
+       return afu_cap & cmd_mode;
+}
+
+static inline bool afu_is_sq_cmd_mode(struct afu *afu)
+{
+       return afu_is_cmd_mode(afu, SISL_INTVER_CAP_SQ_CMD_MODE);
+}
+
+static inline bool afu_is_ioarrin_cmd_mode(struct afu *afu)
+{
+       return afu_is_cmd_mode(afu, SISL_INTVER_CAP_IOARRIN_CMD_MODE);
+}
+
 static inline u64 lun_to_lunid(u64 lun)
 {
        __be64 lun_id;
index 6c318db90c85cee7e02019ee06a757f26102bf06..0efed177cc8bd31c9cc1a80c62fcafc70a3a19f5 100644 (file)
  */
 static struct llun_info *create_local(struct scsi_device *sdev, u8 *wwid)
 {
+       struct cxlflash_cfg *cfg = shost_priv(sdev->host);
+       struct device *dev = &cfg->dev->dev;
        struct llun_info *lli = NULL;
 
        lli = kzalloc(sizeof(*lli), GFP_KERNEL);
        if (unlikely(!lli)) {
-               pr_err("%s: could not allocate lli\n", __func__);
+               dev_err(dev, "%s: could not allocate lli\n", __func__);
                goto out;
        }
 
@@ -58,11 +60,13 @@ out:
  */
 static struct glun_info *create_global(struct scsi_device *sdev, u8 *wwid)
 {
+       struct cxlflash_cfg *cfg = shost_priv(sdev->host);
+       struct device *dev = &cfg->dev->dev;
        struct glun_info *gli = NULL;
 
        gli = kzalloc(sizeof(*gli), GFP_KERNEL);
        if (unlikely(!gli)) {
-               pr_err("%s: could not allocate gli\n", __func__);
+               dev_err(dev, "%s: could not allocate gli\n", __func__);
                goto out;
        }
 
@@ -129,10 +133,10 @@ static struct glun_info *lookup_global(u8 *wwid)
  */
 static struct llun_info *find_and_create_lun(struct scsi_device *sdev, u8 *wwid)
 {
+       struct cxlflash_cfg *cfg = shost_priv(sdev->host);
+       struct device *dev = &cfg->dev->dev;
        struct llun_info *lli = NULL;
        struct glun_info *gli = NULL;
-       struct Scsi_Host *shost = sdev->host;
-       struct cxlflash_cfg *cfg = shost_priv(shost);
 
        if (unlikely(!wwid))
                goto out;
@@ -165,7 +169,7 @@ static struct llun_info *find_and_create_lun(struct scsi_device *sdev, u8 *wwid)
        list_add(&gli->list, &global.gluns);
 
 out:
-       pr_debug("%s: returning %p\n", __func__, lli);
+       dev_dbg(dev, "%s: returning lli=%p, gli=%p\n", __func__, lli, gli);
        return lli;
 }
 
@@ -225,17 +229,18 @@ void cxlflash_term_global_luns(void)
 int cxlflash_manage_lun(struct scsi_device *sdev,
                        struct dk_cxlflash_manage_lun *manage)
 {
-       int rc = 0;
+       struct cxlflash_cfg *cfg = shost_priv(sdev->host);
+       struct device *dev = &cfg->dev->dev;
        struct llun_info *lli = NULL;
+       int rc = 0;
        u64 flags = manage->hdr.flags;
        u32 chan = sdev->channel;
 
        mutex_lock(&global.mutex);
        lli = find_and_create_lun(sdev, manage->wwid);
-       pr_debug("%s: ENTER: WWID = %016llX%016llX, flags = %016llX li = %p\n",
-                __func__, get_unaligned_be64(&manage->wwid[0]),
-                get_unaligned_be64(&manage->wwid[8]),
-                manage->hdr.flags, lli);
+       dev_dbg(dev, "%s: WWID=%016llx%016llx, flags=%016llx lli=%p\n",
+               __func__, get_unaligned_be64(&manage->wwid[0]),
+               get_unaligned_be64(&manage->wwid[8]), manage->hdr.flags, lli);
        if (unlikely(!lli)) {
                rc = -ENOMEM;
                goto out;
@@ -265,11 +270,11 @@ int cxlflash_manage_lun(struct scsi_device *sdev,
                }
        }
 
-       pr_debug("%s: port_sel = %08X chan = %u lun_id = %016llX\n", __func__,
-                lli->port_sel, chan, lli->lun_id[chan]);
+       dev_dbg(dev, "%s: port_sel=%08x chan=%u lun_id=%016llx\n",
+               __func__, lli->port_sel, chan, lli->lun_id[chan]);
 
 out:
        mutex_unlock(&global.mutex);
-       pr_debug("%s: returning rc=%d\n", __func__, rc);
+       dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
        return rc;
 }
index b17ebf6d0a7e2b49b237ee244ce7c115487906af..7069639e92bc404093b47a77405e94d1165e055d 100644 (file)
@@ -43,6 +43,9 @@ MODULE_LICENSE("GPL");
  */
 static void process_cmd_err(struct afu_cmd *cmd, struct scsi_cmnd *scp)
 {
+       struct afu *afu = cmd->parent;
+       struct cxlflash_cfg *cfg = afu->parent;
+       struct device *dev = &cfg->dev->dev;
        struct sisl_ioarcb *ioarcb;
        struct sisl_ioasa *ioasa;
        u32 resid;
@@ -56,21 +59,20 @@ static void process_cmd_err(struct afu_cmd *cmd, struct scsi_cmnd *scp)
        if (ioasa->rc.flags & SISL_RC_FLAGS_UNDERRUN) {
                resid = ioasa->resid;
                scsi_set_resid(scp, resid);
-               pr_debug("%s: cmd underrun cmd = %p scp = %p, resid = %d\n",
-                        __func__, cmd, scp, resid);
+               dev_dbg(dev, "%s: cmd underrun cmd = %p scp = %p, resid = %d\n",
+                       __func__, cmd, scp, resid);
        }
 
        if (ioasa->rc.flags & SISL_RC_FLAGS_OVERRUN) {
-               pr_debug("%s: cmd underrun cmd = %p scp = %p\n",
-                        __func__, cmd, scp);
+               dev_dbg(dev, "%s: cmd underrun cmd = %p scp = %p\n",
+                       __func__, cmd, scp);
                scp->result = (DID_ERROR << 16);
        }
 
-       pr_debug("%s: cmd failed afu_rc=%d scsi_rc=%d fc_rc=%d "
-                "afu_extra=0x%X, scsi_extra=0x%X, fc_extra=0x%X\n",
-                __func__, ioasa->rc.afu_rc, ioasa->rc.scsi_rc,
-                ioasa->rc.fc_rc, ioasa->afu_extra, ioasa->scsi_extra,
-                ioasa->fc_extra);
+       dev_dbg(dev, "%s: cmd failed afu_rc=%02x scsi_rc=%02x fc_rc=%02x "
+               "afu_extra=%02x scsi_extra=%02x fc_extra=%02x\n", __func__,
+               ioasa->rc.afu_rc, ioasa->rc.scsi_rc, ioasa->rc.fc_rc,
+               ioasa->afu_extra, ioasa->scsi_extra, ioasa->fc_extra);
 
        if (ioasa->rc.scsi_rc) {
                /* We have a SCSI status */
@@ -159,6 +161,7 @@ static void cmd_complete(struct afu_cmd *cmd)
        ulong lock_flags;
        struct afu *afu = cmd->parent;
        struct cxlflash_cfg *cfg = afu->parent;
+       struct device *dev = &cfg->dev->dev;
        bool cmd_is_tmf;
 
        if (cmd->scp) {
@@ -170,9 +173,8 @@ static void cmd_complete(struct afu_cmd *cmd)
 
                cmd_is_tmf = cmd->cmd_tmf;
 
-               pr_debug_ratelimited("%s: calling scsi_done scp=%p result=%X "
-                                    "ioasc=%d\n", __func__, scp, scp->result,
-                                    cmd->sa.ioasc);
+               dev_dbg_ratelimited(dev, "%s:scp=%p result=%08x ioasc=%08x\n",
+                                   __func__, scp, scp->result, cmd->sa.ioasc);
 
                scsi_dma_unmap(scp);
                scp->scsi_done(scp);
@@ -188,10 +190,11 @@ static void cmd_complete(struct afu_cmd *cmd)
 }
 
 /**
- * context_reset_ioarrin() - reset command owner context via IOARRIN register
+ * context_reset() - reset command owner context via specified register
  * @cmd:       AFU command that timed out.
+ * @reset_reg: MMIO register to perform reset.
  */
-static void context_reset_ioarrin(struct afu_cmd *cmd)
+static void context_reset(struct afu_cmd *cmd, __be64 __iomem *reset_reg)
 {
        int nretry = 0;
        u64 rrin = 0x1;
@@ -199,21 +202,43 @@ static void context_reset_ioarrin(struct afu_cmd *cmd)
        struct cxlflash_cfg *cfg = afu->parent;
        struct device *dev = &cfg->dev->dev;
 
-       pr_debug("%s: cmd=%p\n", __func__, cmd);
+       dev_dbg(dev, "%s: cmd=%p\n", __func__, cmd);
 
-       writeq_be(rrin, &afu->host_map->ioarrin);
+       writeq_be(rrin, reset_reg);
        do {
-               rrin = readq_be(&afu->host_map->ioarrin);
+               rrin = readq_be(reset_reg);
                if (rrin != 0x1)
                        break;
                /* Double delay each time */
                udelay(1 << nretry);
        } while (nretry++ < MC_ROOM_RETRY_CNT);
 
-       dev_dbg(dev, "%s: returning rrin=0x%016llX nretry=%d\n",
+       dev_dbg(dev, "%s: returning rrin=%016llx nretry=%d\n",
                __func__, rrin, nretry);
 }
 
+/**
+ * context_reset_ioarrin() - reset command owner context via IOARRIN register
+ * @cmd:       AFU command that timed out.
+ */
+static void context_reset_ioarrin(struct afu_cmd *cmd)
+{
+       struct afu *afu = cmd->parent;
+
+       context_reset(cmd, &afu->host_map->ioarrin);
+}
+
+/**
+ * context_reset_sq() - reset command owner context w/ SQ Context Reset register
+ * @cmd:       AFU command that timed out.
+ */
+static void context_reset_sq(struct afu_cmd *cmd)
+{
+       struct afu *afu = cmd->parent;
+
+       context_reset(cmd, &afu->host_map->sq_ctx_reset);
+}
+
 /**
  * send_cmd_ioarrin() - sends an AFU command via IOARRIN register
  * @afu:       AFU associated with the host.
@@ -251,8 +276,51 @@ static int send_cmd_ioarrin(struct afu *afu, struct afu_cmd *cmd)
        writeq_be((u64)&cmd->rcb, &afu->host_map->ioarrin);
 out:
        spin_unlock_irqrestore(&afu->rrin_slock, lock_flags);
-       pr_devel("%s: cmd=%p len=%d ea=%p rc=%d\n", __func__, cmd,
-                cmd->rcb.data_len, (void *)cmd->rcb.data_ea, rc);
+       dev_dbg(dev, "%s: cmd=%p len=%u ea=%016llx rc=%d\n", __func__,
+               cmd, cmd->rcb.data_len, cmd->rcb.data_ea, rc);
+       return rc;
+}
+
+/**
+ * send_cmd_sq() - sends an AFU command via SQ ring
+ * @afu:       AFU associated with the host.
+ * @cmd:       AFU command to send.
+ *
+ * Return:
+ *     0 on success, SCSI_MLQUEUE_HOST_BUSY on failure
+ */
+static int send_cmd_sq(struct afu *afu, struct afu_cmd *cmd)
+{
+       struct cxlflash_cfg *cfg = afu->parent;
+       struct device *dev = &cfg->dev->dev;
+       int rc = 0;
+       int newval;
+       ulong lock_flags;
+
+       newval = atomic_dec_if_positive(&afu->hsq_credits);
+       if (newval <= 0) {
+               rc = SCSI_MLQUEUE_HOST_BUSY;
+               goto out;
+       }
+
+       cmd->rcb.ioasa = &cmd->sa;
+
+       spin_lock_irqsave(&afu->hsq_slock, lock_flags);
+
+       *afu->hsq_curr = cmd->rcb;
+       if (afu->hsq_curr < afu->hsq_end)
+               afu->hsq_curr++;
+       else
+               afu->hsq_curr = afu->hsq_start;
+       writeq_be((u64)afu->hsq_curr, &afu->host_map->sq_tail);
+
+       spin_unlock_irqrestore(&afu->hsq_slock, lock_flags);
+out:
+       dev_dbg(dev, "%s: cmd=%p len=%u ea=%016llx ioasa=%p rc=%d curr=%p "
+              "head=%016llx tail=%016llx\n", __func__, cmd, cmd->rcb.data_len,
+              cmd->rcb.data_ea, cmd->rcb.ioasa, rc, afu->hsq_curr,
+              readq_be(&afu->host_map->sq_head),
+              readq_be(&afu->host_map->sq_tail));
        return rc;
 }
 
@@ -266,6 +334,8 @@ out:
  */
 static int wait_resp(struct afu *afu, struct afu_cmd *cmd)
 {
+       struct cxlflash_cfg *cfg = afu->parent;
+       struct device *dev = &cfg->dev->dev;
        int rc = 0;
        ulong timeout = msecs_to_jiffies(cmd->rcb.timeout * 2 * 1000);
 
@@ -276,10 +346,8 @@ static int wait_resp(struct afu *afu, struct afu_cmd *cmd)
        }
 
        if (unlikely(cmd->sa.ioasc != 0)) {
-               pr_err("%s: CMD 0x%X failed, IOASC: flags 0x%X, afu_rc 0x%X, "
-                      "scsi_rc 0x%X, fc_rc 0x%X\n", __func__, cmd->rcb.cdb[0],
-                      cmd->sa.rc.flags, cmd->sa.rc.afu_rc, cmd->sa.rc.scsi_rc,
-                      cmd->sa.rc.fc_rc);
+               dev_err(dev, "%s: cmd %02x failed, ioasc=%08x\n",
+                       __func__, cmd->rcb.cdb[0], cmd->sa.ioasc);
                rc = -1;
        }
 
@@ -298,8 +366,7 @@ static int wait_resp(struct afu *afu, struct afu_cmd *cmd)
 static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd)
 {
        u32 port_sel = scp->device->channel + 1;
-       struct Scsi_Host *host = scp->device->host;
-       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata;
+       struct cxlflash_cfg *cfg = shost_priv(scp->device->host);
        struct afu_cmd *cmd = sc_to_afucz(scp);
        struct device *dev = &cfg->dev->dev;
        ulong lock_flags;
@@ -344,7 +411,7 @@ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd)
                                                       to);
        if (!to) {
                cfg->tmf_active = false;
-               dev_err(dev, "%s: TMF timed out!\n", __func__);
+               dev_err(dev, "%s: TMF timed out\n", __func__);
                rc = -1;
        }
        spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags);
@@ -352,16 +419,6 @@ out:
        return rc;
 }
 
-static void afu_unmap(struct kref *ref)
-{
-       struct afu *afu = container_of(ref, struct afu, mapcount);
-
-       if (likely(afu->afu_map)) {
-               cxl_psa_unmap((void __iomem *)afu->afu_map);
-               afu->afu_map = NULL;
-       }
-}
-
 /**
  * cxlflash_driver_info() - information handler for this host driver
  * @host:      SCSI host associated with device.
@@ -382,7 +439,7 @@ static const char *cxlflash_driver_info(struct Scsi_Host *host)
  */
 static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
 {
-       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata;
+       struct cxlflash_cfg *cfg = shost_priv(host);
        struct afu *afu = cfg->afu;
        struct device *dev = &cfg->dev->dev;
        struct afu_cmd *cmd = sc_to_afucz(scp);
@@ -392,10 +449,9 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
        ulong lock_flags;
        int nseg = 0;
        int rc = 0;
-       int kref_got = 0;
 
        dev_dbg_ratelimited(dev, "%s: (scp=%p) %d/%d/%d/%llu "
-                           "cdb=(%08X-%08X-%08X-%08X)\n",
+                           "cdb=(%08x-%08x-%08x-%08x)\n",
                            __func__, scp, host->host_no, scp->device->channel,
                            scp->device->id, scp->device->lun,
                            get_unaligned_be32(&((u32 *)scp->cmnd)[0]),
@@ -417,11 +473,11 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
 
        switch (cfg->state) {
        case STATE_RESET:
-               dev_dbg_ratelimited(dev, "%s: device is in reset!\n", __func__);
+               dev_dbg_ratelimited(dev, "%s: device is in reset\n", __func__);
                rc = SCSI_MLQUEUE_HOST_BUSY;
                goto out;
        case STATE_FAILTERM:
-               dev_dbg_ratelimited(dev, "%s: device has failed!\n", __func__);
+               dev_dbg_ratelimited(dev, "%s: device has failed\n", __func__);
                scp->result = (DID_NO_CONNECT << 16);
                scp->scsi_done(scp);
                rc = 0;
@@ -430,13 +486,10 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
                break;
        }
 
-       kref_get(&cfg->afu->mapcount);
-       kref_got = 1;
-
        if (likely(sg)) {
                nseg = scsi_dma_map(scp);
                if (unlikely(nseg < 0)) {
-                       dev_err(dev, "%s: Fail DMA map!\n", __func__);
+                       dev_err(dev, "%s: Fail DMA map\n", __func__);
                        rc = SCSI_MLQUEUE_HOST_BUSY;
                        goto out;
                }
@@ -463,9 +516,6 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
        if (unlikely(rc))
                scsi_dma_unmap(scp);
 out:
-       if (kref_got)
-               kref_put(&afu->mapcount, afu_unmap);
-       pr_devel("%s: returning rc=%d\n", __func__, rc);
        return rc;
 }
 
@@ -503,13 +553,15 @@ static void free_mem(struct cxlflash_cfg *cfg)
  *
  * Safe to call with AFU in a partially allocated/initialized state.
  *
- * Waits for any active internal AFU commands to timeout and then unmaps
- * the MMIO space.
+ * Cancels scheduled worker threads, waits for any active internal AFU
+ * commands to timeout and then unmaps the MMIO space.
  */
 static void stop_afu(struct cxlflash_cfg *cfg)
 {
        struct afu *afu = cfg->afu;
 
+       cancel_work_sync(&cfg->work_q);
+
        if (likely(afu)) {
                while (atomic_read(&afu->cmds_active))
                        ssleep(1);
@@ -517,7 +569,6 @@ static void stop_afu(struct cxlflash_cfg *cfg)
                        cxl_psa_unmap((void __iomem *)afu->afu_map);
                        afu->afu_map = NULL;
                }
-               kref_put(&afu->mapcount, afu_unmap);
        }
 }
 
@@ -585,6 +636,8 @@ static void term_mc(struct cxlflash_cfg *cfg)
  */
 static void term_afu(struct cxlflash_cfg *cfg)
 {
+       struct device *dev = &cfg->dev->dev;
+
        /*
         * Tear down is carefully orchestrated to ensure
         * no interrupts can come in when the problem state
@@ -600,7 +653,7 @@ static void term_afu(struct cxlflash_cfg *cfg)
 
        term_mc(cfg);
 
-       pr_debug("%s: returning\n", __func__);
+       dev_dbg(dev, "%s: returning\n", __func__);
 }
 
 /**
@@ -627,8 +680,7 @@ static void notify_shutdown(struct cxlflash_cfg *cfg, bool wait)
                return;
 
        if (!afu || !afu->afu_map) {
-               dev_dbg(dev, "%s: The problem state area is not mapped\n",
-                       __func__);
+               dev_dbg(dev, "%s: Problem state area not mapped\n", __func__);
                return;
        }
 
@@ -670,10 +722,11 @@ static void notify_shutdown(struct cxlflash_cfg *cfg, bool wait)
 static void cxlflash_remove(struct pci_dev *pdev)
 {
        struct cxlflash_cfg *cfg = pci_get_drvdata(pdev);
+       struct device *dev = &pdev->dev;
        ulong lock_flags;
 
        if (!pci_is_enabled(pdev)) {
-               pr_debug("%s: Device is disabled\n", __func__);
+               dev_dbg(dev, "%s: Device is disabled\n", __func__);
                return;
        }
 
@@ -699,7 +752,6 @@ static void cxlflash_remove(struct pci_dev *pdev)
                scsi_remove_host(cfg->host);
                /* fall through */
        case INIT_STATE_AFU:
-               cancel_work_sync(&cfg->work_q);
                term_afu(cfg);
        case INIT_STATE_PCI:
                pci_disable_device(pdev);
@@ -709,7 +761,7 @@ static void cxlflash_remove(struct pci_dev *pdev)
                break;
        }
 
-       pr_debug("%s: returning\n", __func__);
+       dev_dbg(dev, "%s: returning\n", __func__);
 }
 
 /**
@@ -727,7 +779,7 @@ static int alloc_mem(struct cxlflash_cfg *cfg)
        int rc = 0;
        struct device *dev = &cfg->dev->dev;
 
-       /* AFU is ~12k, i.e. only one 64k page or up to four 4k pages */
+       /* AFU is ~28k, i.e. only one 64k page or up to seven 4k pages */
        cfg->afu = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
                                            get_order(sizeof(struct afu)));
        if (unlikely(!cfg->afu)) {
@@ -751,6 +803,7 @@ out:
 static int init_pci(struct cxlflash_cfg *cfg)
 {
        struct pci_dev *pdev = cfg->dev;
+       struct device *dev = &cfg->dev->dev;
        int rc = 0;
 
        rc = pci_enable_device(pdev);
@@ -761,15 +814,14 @@ static int init_pci(struct cxlflash_cfg *cfg)
                }
 
                if (rc) {
-                       dev_err(&pdev->dev, "%s: Cannot enable adapter\n",
-                               __func__);
+                       dev_err(dev, "%s: Cannot enable adapter\n", __func__);
                        cxlflash_wait_for_pci_err_recovery(cfg);
                        goto out;
                }
        }
 
 out:
-       pr_debug("%s: returning rc=%d\n", __func__, rc);
+       dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
        return rc;
 }
 
@@ -782,19 +834,19 @@ out:
 static int init_scsi(struct cxlflash_cfg *cfg)
 {
        struct pci_dev *pdev = cfg->dev;
+       struct device *dev = &cfg->dev->dev;
        int rc = 0;
 
        rc = scsi_add_host(cfg->host, &pdev->dev);
        if (rc) {
-               dev_err(&pdev->dev, "%s: scsi_add_host failed (rc=%d)\n",
-                       __func__, rc);
+               dev_err(dev, "%s: scsi_add_host failed rc=%d\n", __func__, rc);
                goto out;
        }
 
        scsi_scan_host(cfg->host);
 
 out:
-       pr_debug("%s: returning rc=%d\n", __func__, rc);
+       dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
        return rc;
 }
 
@@ -844,16 +896,12 @@ static void set_port_offline(__be64 __iomem *fc_regs)
  * Return:
  *     TRUE (1) when the specified port is online
  *     FALSE (0) when the specified port fails to come online after timeout
- *     -EINVAL when @delay_us is less than 1000
  */
-static int wait_port_online(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry)
+static bool wait_port_online(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry)
 {
        u64 status;
 
-       if (delay_us < 1000) {
-               pr_err("%s: invalid delay specified %d\n", __func__, delay_us);
-               return -EINVAL;
-       }
+       WARN_ON(delay_us < 1000);
 
        do {
                msleep(delay_us / 1000);
@@ -877,16 +925,12 @@ static int wait_port_online(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry)
  * Return:
  *     TRUE (1) when the specified port is offline
  *     FALSE (0) when the specified port fails to go offline after timeout
- *     -EINVAL when @delay_us is less than 1000
  */
-static int wait_port_offline(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry)
+static bool wait_port_offline(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry)
 {
        u64 status;
 
-       if (delay_us < 1000) {
-               pr_err("%s: invalid delay specified %d\n", __func__, delay_us);
-               return -EINVAL;
-       }
+       WARN_ON(delay_us < 1000);
 
        do {
                msleep(delay_us / 1000);
@@ -915,11 +959,14 @@ static int wait_port_offline(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry)
 static void afu_set_wwpn(struct afu *afu, int port, __be64 __iomem *fc_regs,
                         u64 wwpn)
 {
+       struct cxlflash_cfg *cfg = afu->parent;
+       struct device *dev = &cfg->dev->dev;
+
        set_port_offline(fc_regs);
        if (!wait_port_offline(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US,
                               FC_PORT_STATUS_RETRY_CNT)) {
-               pr_debug("%s: wait on port %d to go offline timed out\n",
-                        __func__, port);
+               dev_dbg(dev, "%s: wait on port %d to go offline timed out\n",
+                       __func__, port);
        }
 
        writeq_be(wwpn, &fc_regs[FC_PNAME / 8]);
@@ -927,8 +974,8 @@ static void afu_set_wwpn(struct afu *afu, int port, __be64 __iomem *fc_regs,
        set_port_online(fc_regs);
        if (!wait_port_online(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US,
                              FC_PORT_STATUS_RETRY_CNT)) {
-               pr_debug("%s: wait on port %d to go online timed out\n",
-                        __func__, port);
+               dev_dbg(dev, "%s: wait on port %d to go online timed out\n",
+                       __func__, port);
        }
 }
 
@@ -947,6 +994,8 @@ static void afu_set_wwpn(struct afu *afu, int port, __be64 __iomem *fc_regs,
  */
 static void afu_link_reset(struct afu *afu, int port, __be64 __iomem *fc_regs)
 {
+       struct cxlflash_cfg *cfg = afu->parent;
+       struct device *dev = &cfg->dev->dev;
        u64 port_sel;
 
        /* first switch the AFU to the other links, if any */
@@ -958,21 +1007,21 @@ static void afu_link_reset(struct afu *afu, int port, __be64 __iomem *fc_regs)
        set_port_offline(fc_regs);
        if (!wait_port_offline(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US,
                               FC_PORT_STATUS_RETRY_CNT))
-               pr_err("%s: wait on port %d to go offline timed out\n",
-                      __func__, port);
+               dev_err(dev, "%s: wait on port %d to go offline timed out\n",
+                       __func__, port);
 
        set_port_online(fc_regs);
        if (!wait_port_online(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US,
                              FC_PORT_STATUS_RETRY_CNT))
-               pr_err("%s: wait on port %d to go online timed out\n",
-                      __func__, port);
+               dev_err(dev, "%s: wait on port %d to go online timed out\n",
+                       __func__, port);
 
        /* switch back to include this port */
        port_sel |= (1ULL << port);
        writeq_be(port_sel, &afu->afu_map->global.regs.afu_port_sel);
        cxlflash_afu_sync(afu, 0, 0, AFU_GSYNC);
 
-       pr_debug("%s: returning port_sel=%lld\n", __func__, port_sel);
+       dev_dbg(dev, "%s: returning port_sel=%016llx\n", __func__, port_sel);
 }
 
 /*
@@ -1082,6 +1131,8 @@ static void afu_err_intr_init(struct afu *afu)
 static irqreturn_t cxlflash_sync_err_irq(int irq, void *data)
 {
        struct afu *afu = (struct afu *)data;
+       struct cxlflash_cfg *cfg = afu->parent;
+       struct device *dev = &cfg->dev->dev;
        u64 reg;
        u64 reg_unmasked;
 
@@ -1089,18 +1140,17 @@ static irqreturn_t cxlflash_sync_err_irq(int irq, void *data)
        reg_unmasked = (reg & SISL_ISTATUS_UNMASK);
 
        if (reg_unmasked == 0UL) {
-               pr_err("%s: %llX: spurious interrupt, intr_status %016llX\n",
-                      __func__, (u64)afu, reg);
+               dev_err(dev, "%s: spurious interrupt, intr_status=%016llx\n",
+                       __func__, reg);
                goto cxlflash_sync_err_irq_exit;
        }
 
-       pr_err("%s: %llX: unexpected interrupt, intr_status %016llX\n",
-              __func__, (u64)afu, reg);
+       dev_err(dev, "%s: unexpected interrupt, intr_status=%016llx\n",
+               __func__, reg);
 
        writeq_be(reg_unmasked, &afu->host_map->intr_clear);
 
 cxlflash_sync_err_irq_exit:
-       pr_debug("%s: returning rc=%d\n", __func__, IRQ_HANDLED);
        return IRQ_HANDLED;
 }
 
@@ -1115,6 +1165,8 @@ static irqreturn_t cxlflash_rrq_irq(int irq, void *data)
 {
        struct afu *afu = (struct afu *)data;
        struct afu_cmd *cmd;
+       struct sisl_ioasa *ioasa;
+       struct sisl_ioarcb *ioarcb;
        bool toggle = afu->toggle;
        u64 entry,
            *hrrq_start = afu->hrrq_start,
@@ -1128,7 +1180,16 @@ static irqreturn_t cxlflash_rrq_irq(int irq, void *data)
                if ((entry & SISL_RESP_HANDLE_T_BIT) != toggle)
                        break;
 
-               cmd = (struct afu_cmd *)(entry & ~SISL_RESP_HANDLE_T_BIT);
+               entry &= ~SISL_RESP_HANDLE_T_BIT;
+
+               if (afu_is_sq_cmd_mode(afu)) {
+                       ioasa = (struct sisl_ioasa *)entry;
+                       cmd = container_of(ioasa, struct afu_cmd, sa);
+               } else {
+                       ioarcb = (struct sisl_ioarcb *)entry;
+                       cmd = container_of(ioarcb, struct afu_cmd, rcb);
+               }
+
                cmd_complete(cmd);
 
                /* Advance to next entry or wrap and flip the toggle bit */
@@ -1138,6 +1199,8 @@ static irqreturn_t cxlflash_rrq_irq(int irq, void *data)
                        hrrq_curr = hrrq_start;
                        toggle ^= SISL_RESP_HANDLE_T_BIT;
                }
+
+               atomic_inc(&afu->hsq_credits);
        }
 
        afu->hrrq_curr = hrrq_curr;
@@ -1169,7 +1232,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data)
        reg_unmasked = (reg & SISL_ASTATUS_UNMASK);
 
        if (reg_unmasked == 0) {
-               dev_err(dev, "%s: spurious interrupt, aintr_status 0x%016llX\n",
+               dev_err(dev, "%s: spurious interrupt, aintr_status=%016llx\n",
                        __func__, reg);
                goto out;
        }
@@ -1185,7 +1248,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data)
 
                port = info->port;
 
-               dev_err(dev, "%s: FC Port %d -> %s, fc_status 0x%08llX\n",
+               dev_err(dev, "%s: FC Port %d -> %s, fc_status=%016llx\n",
                        __func__, port, info->desc,
                       readq_be(&global->fc_regs[port][FC_STATUS / 8]));
 
@@ -1198,7 +1261,6 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data)
                                __func__, port);
                        cfg->lr_state = LINK_RESET_REQUIRED;
                        cfg->lr_port = port;
-                       kref_get(&cfg->afu->mapcount);
                        schedule_work(&cfg->work_q);
                }
 
@@ -1210,7 +1272,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data)
                         * should be the same and tracing one is sufficient.
                         */
 
-                       dev_err(dev, "%s: fc %d: clearing fc_error 0x%08llX\n",
+                       dev_err(dev, "%s: fc %d: clearing fc_error=%016llx\n",
                                __func__, port, reg);
 
                        writeq_be(reg, &global->fc_regs[port][FC_ERROR / 8]);
@@ -1219,13 +1281,11 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data)
 
                if (info->action & SCAN_HOST) {
                        atomic_inc(&cfg->scan_host_needed);
-                       kref_get(&cfg->afu->mapcount);
                        schedule_work(&cfg->work_q);
                }
        }
 
 out:
-       dev_dbg(dev, "%s: returning IRQ_HANDLED, afu=%p\n", __func__, afu);
        return IRQ_HANDLED;
 }
 
@@ -1237,13 +1297,14 @@ out:
  */
 static int start_context(struct cxlflash_cfg *cfg)
 {
+       struct device *dev = &cfg->dev->dev;
        int rc = 0;
 
        rc = cxl_start_context(cfg->mcctx,
                               cfg->afu->work.work_element_descriptor,
                               NULL);
 
-       pr_debug("%s: returning rc=%d\n", __func__, rc);
+       dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
        return rc;
 }
 
@@ -1256,7 +1317,8 @@ static int start_context(struct cxlflash_cfg *cfg)
  */
 static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[])
 {
-       struct pci_dev *dev = cfg->dev;
+       struct device *dev = &cfg->dev->dev;
+       struct pci_dev *pdev = cfg->dev;
        int rc = 0;
        int ro_start, ro_size, i, j, k;
        ssize_t vpd_size;
@@ -1265,10 +1327,10 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[])
        char *wwpn_vpd_tags[NUM_FC_PORTS] = { "V5", "V6" };
 
        /* Get the VPD data from the device */
-       vpd_size = cxl_read_adapter_vpd(dev, vpd_data, sizeof(vpd_data));
+       vpd_size = cxl_read_adapter_vpd(pdev, vpd_data, sizeof(vpd_data));
        if (unlikely(vpd_size <= 0)) {
-               dev_err(&dev->dev, "%s: Unable to read VPD (size = %ld)\n",
-                      __func__, vpd_size);
+               dev_err(dev, "%s: Unable to read VPD (size = %ld)\n",
+                       __func__, vpd_size);
                rc = -ENODEV;
                goto out;
        }
@@ -1277,8 +1339,7 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[])
        ro_start = pci_vpd_find_tag(vpd_data, 0, vpd_size,
                                    PCI_VPD_LRDT_RO_DATA);
        if (unlikely(ro_start < 0)) {
-               dev_err(&dev->dev, "%s: VPD Read-only data not found\n",
-                       __func__);
+               dev_err(dev, "%s: VPD Read-only data not found\n", __func__);
                rc = -ENODEV;
                goto out;
        }
@@ -1288,8 +1349,8 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[])
        j = ro_size;
        i = ro_start + PCI_VPD_LRDT_TAG_SIZE;
        if (unlikely((i + j) > vpd_size)) {
-               pr_debug("%s: Might need to read more VPD (%d > %ld)\n",
-                        __func__, (i + j), vpd_size);
+               dev_dbg(dev, "%s: Might need to read more VPD (%d > %ld)\n",
+                       __func__, (i + j), vpd_size);
                ro_size = vpd_size - i;
        }
 
@@ -1307,8 +1368,8 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[])
 
                i = pci_vpd_find_info_keyword(vpd_data, i, j, wwpn_vpd_tags[k]);
                if (unlikely(i < 0)) {
-                       dev_err(&dev->dev, "%s: Port %d WWPN not found "
-                               "in VPD\n", __func__, k);
+                       dev_err(dev, "%s: Port %d WWPN not found in VPD\n",
+                               __func__, k);
                        rc = -ENODEV;
                        goto out;
                }
@@ -1316,9 +1377,8 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[])
                j = pci_vpd_info_field_size(&vpd_data[i]);
                i += PCI_VPD_INFO_FLD_HDR_SIZE;
                if (unlikely((i + j > vpd_size) || (j != WWPN_LEN))) {
-                       dev_err(&dev->dev, "%s: Port %d WWPN incomplete or "
-                               "VPD corrupt\n",
-                              __func__, k);
+                       dev_err(dev, "%s: Port %d WWPN incomplete or bad VPD\n",
+                               __func__, k);
                        rc = -ENODEV;
                        goto out;
                }
@@ -1326,15 +1386,15 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[])
                memcpy(tmp_buf, &vpd_data[i], WWPN_LEN);
                rc = kstrtoul(tmp_buf, WWPN_LEN, (ulong *)&wwpn[k]);
                if (unlikely(rc)) {
-                       dev_err(&dev->dev, "%s: Fail to convert port %d WWPN "
-                               "to integer\n", __func__, k);
+                       dev_err(dev, "%s: WWPN conversion failed for port %d\n",
+                               __func__, k);
                        rc = -ENODEV;
                        goto out;
                }
        }
 
 out:
-       pr_debug("%s: returning rc=%d\n", __func__, rc);
+       dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
        return rc;
 }
 
@@ -1388,12 +1448,18 @@ static int init_global(struct cxlflash_cfg *cfg)
                goto out;
        }
 
-       pr_debug("%s: wwpn0=0x%llX wwpn1=0x%llX\n", __func__, wwpn[0], wwpn[1]);
+       dev_dbg(dev, "%s: wwpn0=%016llx wwpn1=%016llx\n",
+               __func__, wwpn[0], wwpn[1]);
 
-       /* Set up RRQ in AFU for master issued cmds */
+       /* Set up RRQ and SQ in AFU for master issued cmds */
        writeq_be((u64) afu->hrrq_start, &afu->host_map->rrq_start);
        writeq_be((u64) afu->hrrq_end, &afu->host_map->rrq_end);
 
+       if (afu_is_sq_cmd_mode(afu)) {
+               writeq_be((u64)afu->hsq_start, &afu->host_map->sq_start);
+               writeq_be((u64)afu->hsq_end, &afu->host_map->sq_end);
+       }
+
        /* AFU configuration */
        reg = readq_be(&afu->afu_map->global.regs.afu_config);
        reg |= SISL_AFUCONF_AR_ALL|SISL_AFUCONF_ENDIAN;
@@ -1443,7 +1509,6 @@ static int init_global(struct cxlflash_cfg *cfg)
                  &afu->ctrl_map->ctx_cap);
        /* Initialize heartbeat */
        afu->hb = readq_be(&afu->afu_map->global.regs.afu_hb);
-
 out:
        return rc;
 }
@@ -1455,6 +1520,7 @@ out:
 static int start_afu(struct cxlflash_cfg *cfg)
 {
        struct afu *afu = cfg->afu;
+       struct device *dev = &cfg->dev->dev;
        int rc = 0;
 
        init_pcr(cfg);
@@ -1468,9 +1534,20 @@ static int start_afu(struct cxlflash_cfg *cfg)
        afu->hrrq_curr = afu->hrrq_start;
        afu->toggle = 1;
 
+       /* Initialize SQ */
+       if (afu_is_sq_cmd_mode(afu)) {
+               memset(&afu->sq, 0, sizeof(afu->sq));
+               afu->hsq_start = &afu->sq[0];
+               afu->hsq_end = &afu->sq[NUM_SQ_ENTRY - 1];
+               afu->hsq_curr = afu->hsq_start;
+
+               spin_lock_init(&afu->hsq_slock);
+               atomic_set(&afu->hsq_credits, NUM_SQ_ENTRY - 1);
+       }
+
        rc = init_global(cfg);
 
-       pr_debug("%s: returning rc=%d\n", __func__, rc);
+       dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
        return rc;
 }
 
@@ -1490,7 +1567,7 @@ static enum undo_level init_intr(struct cxlflash_cfg *cfg,
 
        rc = cxl_allocate_afu_irqs(ctx, 3);
        if (unlikely(rc)) {
-               dev_err(dev, "%s: call to allocate_afu_irqs failed rc=%d!\n",
+               dev_err(dev, "%s: allocate_afu_irqs failed rc=%d\n",
                        __func__, rc);
                level = UNDO_NOOP;
                goto out;
@@ -1499,8 +1576,7 @@ static enum undo_level init_intr(struct cxlflash_cfg *cfg,
        rc = cxl_map_afu_irq(ctx, 1, cxlflash_sync_err_irq, afu,
                             "SISL_MSI_SYNC_ERROR");
        if (unlikely(rc <= 0)) {
-               dev_err(dev, "%s: IRQ 1 (SISL_MSI_SYNC_ERROR) map failed!\n",
-                       __func__);
+               dev_err(dev, "%s: SISL_MSI_SYNC_ERROR map failed\n", __func__);
                level = FREE_IRQ;
                goto out;
        }
@@ -1508,8 +1584,7 @@ static enum undo_level init_intr(struct cxlflash_cfg *cfg,
        rc = cxl_map_afu_irq(ctx, 2, cxlflash_rrq_irq, afu,
                             "SISL_MSI_RRQ_UPDATED");
        if (unlikely(rc <= 0)) {
-               dev_err(dev, "%s: IRQ 2 (SISL_MSI_RRQ_UPDATED) map failed!\n",
-                       __func__);
+               dev_err(dev, "%s: SISL_MSI_RRQ_UPDATED map failed\n", __func__);
                level = UNMAP_ONE;
                goto out;
        }
@@ -1517,8 +1592,7 @@ static enum undo_level init_intr(struct cxlflash_cfg *cfg,
        rc = cxl_map_afu_irq(ctx, 3, cxlflash_async_err_irq, afu,
                             "SISL_MSI_ASYNC_ERROR");
        if (unlikely(rc <= 0)) {
-               dev_err(dev, "%s: IRQ 3 (SISL_MSI_ASYNC_ERROR) map failed!\n",
-                       __func__);
+               dev_err(dev, "%s: SISL_MSI_ASYNC_ERROR map failed\n", __func__);
                level = UNMAP_TWO;
                goto out;
        }
@@ -1552,15 +1626,13 @@ static int init_mc(struct cxlflash_cfg *cfg)
        /* During initialization reset the AFU to start from a clean slate */
        rc = cxl_afu_reset(cfg->mcctx);
        if (unlikely(rc)) {
-               dev_err(dev, "%s: initial AFU reset failed rc=%d\n",
-                       __func__, rc);
+               dev_err(dev, "%s: AFU reset failed rc=%d\n", __func__, rc);
                goto ret;
        }
 
        level = init_intr(cfg, ctx);
        if (unlikely(level)) {
-               dev_err(dev, "%s: setting up interrupts failed rc=%d\n",
-                       __func__, rc);
+               dev_err(dev, "%s: interrupt init failed rc=%d\n", __func__, rc);
                goto out;
        }
 
@@ -1575,7 +1647,7 @@ static int init_mc(struct cxlflash_cfg *cfg)
                goto out;
        }
 ret:
-       pr_debug("%s: returning rc=%d\n", __func__, rc);
+       dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
        return rc;
 out:
        term_intr(cfg, level);
@@ -1602,7 +1674,7 @@ static int init_afu(struct cxlflash_cfg *cfg)
 
        rc = init_mc(cfg);
        if (rc) {
-               dev_err(dev, "%s: call to init_mc failed, rc=%d!\n",
+               dev_err(dev, "%s: init_mc failed rc=%d\n",
                        __func__, rc);
                goto out;
        }
@@ -1610,11 +1682,10 @@ static int init_afu(struct cxlflash_cfg *cfg)
        /* Map the entire MMIO space of the AFU */
        afu->afu_map = cxl_psa_map(cfg->mcctx);
        if (!afu->afu_map) {
-               dev_err(dev, "%s: call to cxl_psa_map failed!\n", __func__);
+               dev_err(dev, "%s: cxl_psa_map failed\n", __func__);
                rc = -ENOMEM;
                goto err1;
        }
-       kref_init(&afu->mapcount);
 
        /* No byte reverse on reading afu_version or string will be backwards */
        reg = readq(&afu->afu_map->global.regs.afu_version);
@@ -1622,24 +1693,28 @@ static int init_afu(struct cxlflash_cfg *cfg)
        afu->interface_version =
            readq_be(&afu->afu_map->global.regs.interface_version);
        if ((afu->interface_version + 1) == 0) {
-               pr_err("Back level AFU, please upgrade. AFU version %s "
-                      "interface version 0x%llx\n", afu->version,
+               dev_err(dev, "Back level AFU, please upgrade. AFU version %s "
+                       "interface version %016llx\n", afu->version,
                       afu->interface_version);
                rc = -EINVAL;
-               goto err2;
+               goto err1;
        }
 
-       afu->send_cmd = send_cmd_ioarrin;
-       afu->context_reset = context_reset_ioarrin;
+       if (afu_is_sq_cmd_mode(afu)) {
+               afu->send_cmd = send_cmd_sq;
+               afu->context_reset = context_reset_sq;
+       } else {
+               afu->send_cmd = send_cmd_ioarrin;
+               afu->context_reset = context_reset_ioarrin;
+       }
 
-       pr_debug("%s: afu version %s, interface version 0x%llX\n", __func__,
-                afu->version, afu->interface_version);
+       dev_dbg(dev, "%s: afu_ver=%s interface_ver=%016llx\n", __func__,
+               afu->version, afu->interface_version);
 
        rc = start_afu(cfg);
        if (rc) {
-               dev_err(dev, "%s: call to start_afu failed, rc=%d!\n",
-                       __func__, rc);
-               goto err2;
+               dev_err(dev, "%s: start_afu failed, rc=%d\n", __func__, rc);
+               goto err1;
        }
 
        afu_err_intr_init(cfg->afu);
@@ -1649,11 +1724,9 @@ static int init_afu(struct cxlflash_cfg *cfg)
        /* Restore the LUN mappings */
        cxlflash_restore_luntable(cfg);
 out:
-       pr_debug("%s: returning rc=%d\n", __func__, rc);
+       dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
        return rc;
 
-err2:
-       kref_put(&afu->mapcount, afu_unmap);
 err1:
        term_intr(cfg, UNMAP_THREE);
        term_mc(cfg);
@@ -1693,7 +1766,8 @@ int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t ctx_hndl_u,
        static DEFINE_MUTEX(sync_active);
 
        if (cfg->state != STATE_NORMAL) {
-               pr_debug("%s: Sync not required! (%u)\n", __func__, cfg->state);
+               dev_dbg(dev, "%s: Sync not required state=%u\n",
+                       __func__, cfg->state);
                return 0;
        }
 
@@ -1710,7 +1784,7 @@ int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t ctx_hndl_u,
        init_completion(&cmd->cevent);
        cmd->parent = afu;
 
-       pr_debug("%s: afu=%p cmd=%p %d\n", __func__, afu, cmd, ctx_hndl_u);
+       dev_dbg(dev, "%s: afu=%p cmd=%p %d\n", __func__, afu, cmd, ctx_hndl_u);
 
        cmd->rcb.req_flags = SISL_REQ_FLAGS_AFU_CMD;
        cmd->rcb.ctx_id = afu->ctx_hndl;
@@ -1735,7 +1809,7 @@ out:
        atomic_dec(&afu->cmds_active);
        mutex_unlock(&sync_active);
        kfree(buf);
-       pr_debug("%s: returning rc=%d\n", __func__, rc);
+       dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
        return rc;
 }
 
@@ -1747,16 +1821,17 @@ out:
  */
 static int afu_reset(struct cxlflash_cfg *cfg)
 {
+       struct device *dev = &cfg->dev->dev;
        int rc = 0;
+
        /* Stop the context before the reset. Since the context is
         * no longer available restart it after the reset is complete
         */
-
        term_afu(cfg);
 
        rc = init_afu(cfg);
 
-       pr_debug("%s: returning rc=%d\n", __func__, rc);
+       dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
        return rc;
 }
 
@@ -1785,18 +1860,18 @@ static int cxlflash_eh_device_reset_handler(struct scsi_cmnd *scp)
 {
        int rc = SUCCESS;
        struct Scsi_Host *host = scp->device->host;
-       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata;
+       struct cxlflash_cfg *cfg = shost_priv(host);
+       struct device *dev = &cfg->dev->dev;
        struct afu *afu = cfg->afu;
        int rcr = 0;
 
-       pr_debug("%s: (scp=%p) %d/%d/%d/%llu "
-                "cdb=(%08X-%08X-%08X-%08X)\n", __func__, scp,
-                host->host_no, scp->device->channel,
-                scp->device->id, scp->device->lun,
-                get_unaligned_be32(&((u32 *)scp->cmnd)[0]),
-                get_unaligned_be32(&((u32 *)scp->cmnd)[1]),
-                get_unaligned_be32(&((u32 *)scp->cmnd)[2]),
-                get_unaligned_be32(&((u32 *)scp->cmnd)[3]));
+       dev_dbg(dev, "%s: (scp=%p) %d/%d/%d/%llu "
+               "cdb=(%08x-%08x-%08x-%08x)\n", __func__, scp, host->host_no,
+               scp->device->channel, scp->device->id, scp->device->lun,
+               get_unaligned_be32(&((u32 *)scp->cmnd)[0]),
+               get_unaligned_be32(&((u32 *)scp->cmnd)[1]),
+               get_unaligned_be32(&((u32 *)scp->cmnd)[2]),
+               get_unaligned_be32(&((u32 *)scp->cmnd)[3]));
 
 retry:
        switch (cfg->state) {
@@ -1813,7 +1888,7 @@ retry:
                break;
        }
 
-       pr_debug("%s: returning rc=%d\n", __func__, rc);
+       dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
        return rc;
 }
 
@@ -1835,16 +1910,16 @@ static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp)
        int rc = SUCCESS;
        int rcr = 0;
        struct Scsi_Host *host = scp->device->host;
-       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata;
+       struct cxlflash_cfg *cfg = shost_priv(host);
+       struct device *dev = &cfg->dev->dev;
 
-       pr_debug("%s: (scp=%p) %d/%d/%d/%llu "
-                "cdb=(%08X-%08X-%08X-%08X)\n", __func__, scp,
-                host->host_no, scp->device->channel,
-                scp->device->id, scp->device->lun,
-                get_unaligned_be32(&((u32 *)scp->cmnd)[0]),
-                get_unaligned_be32(&((u32 *)scp->cmnd)[1]),
-                get_unaligned_be32(&((u32 *)scp->cmnd)[2]),
-                get_unaligned_be32(&((u32 *)scp->cmnd)[3]));
+       dev_dbg(dev, "%s: (scp=%p) %d/%d/%d/%llu "
+               "cdb=(%08x-%08x-%08x-%08x)\n", __func__, scp, host->host_no,
+               scp->device->channel, scp->device->id, scp->device->lun,
+               get_unaligned_be32(&((u32 *)scp->cmnd)[0]),
+               get_unaligned_be32(&((u32 *)scp->cmnd)[1]),
+               get_unaligned_be32(&((u32 *)scp->cmnd)[2]),
+               get_unaligned_be32(&((u32 *)scp->cmnd)[3]));
 
        switch (cfg->state) {
        case STATE_NORMAL:
@@ -1870,7 +1945,7 @@ static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp)
                break;
        }
 
-       pr_debug("%s: returning rc=%d\n", __func__, rc);
+       dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
        return rc;
 }
 
@@ -1936,8 +2011,7 @@ static ssize_t port0_show(struct device *dev,
                          struct device_attribute *attr,
                          char *buf)
 {
-       struct Scsi_Host *shost = class_to_shost(dev);
-       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata;
+       struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev));
        struct afu *afu = cfg->afu;
 
        return cxlflash_show_port_status(0, afu, buf);
@@ -1955,8 +2029,7 @@ static ssize_t port1_show(struct device *dev,
                          struct device_attribute *attr,
                          char *buf)
 {
-       struct Scsi_Host *shost = class_to_shost(dev);
-       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata;
+       struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev));
        struct afu *afu = cfg->afu;
 
        return cxlflash_show_port_status(1, afu, buf);
@@ -1973,8 +2046,7 @@ static ssize_t port1_show(struct device *dev,
 static ssize_t lun_mode_show(struct device *dev,
                             struct device_attribute *attr, char *buf)
 {
-       struct Scsi_Host *shost = class_to_shost(dev);
-       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata;
+       struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev));
        struct afu *afu = cfg->afu;
 
        return scnprintf(buf, PAGE_SIZE, "%u\n", afu->internal_lun);
@@ -2007,7 +2079,7 @@ static ssize_t lun_mode_store(struct device *dev,
                              const char *buf, size_t count)
 {
        struct Scsi_Host *shost = class_to_shost(dev);
-       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata;
+       struct cxlflash_cfg *cfg = shost_priv(shost);
        struct afu *afu = cfg->afu;
        int rc;
        u32 lun_mode;
@@ -2069,7 +2141,7 @@ static ssize_t cxlflash_show_port_lun_table(u32 port,
 
        for (i = 0; i < CXLFLASH_NUM_VLUNS; i++)
                bytes += scnprintf(buf + bytes, PAGE_SIZE - bytes,
-                                  "%03d: %016llX\n", i, readq_be(&fc_port[i]));
+                                  "%03d: %016llx\n", i, readq_be(&fc_port[i]));
        return bytes;
 }
 
@@ -2085,8 +2157,7 @@ static ssize_t port0_lun_table_show(struct device *dev,
                                    struct device_attribute *attr,
                                    char *buf)
 {
-       struct Scsi_Host *shost = class_to_shost(dev);
-       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata;
+       struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev));
        struct afu *afu = cfg->afu;
 
        return cxlflash_show_port_lun_table(0, afu, buf);
@@ -2104,8 +2175,7 @@ static ssize_t port1_lun_table_show(struct device *dev,
                                    struct device_attribute *attr,
                                    char *buf)
 {
-       struct Scsi_Host *shost = class_to_shost(dev);
-       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata;
+       struct cxlflash_cfg *cfg = shost_priv(class_to_shost(dev));
        struct afu *afu = cfg->afu;
 
        return cxlflash_show_port_lun_table(1, afu, buf);
@@ -2250,7 +2320,6 @@ static void cxlflash_worker_thread(struct work_struct *work)
 
        if (atomic_dec_if_positive(&cfg->scan_host_needed) >= 0)
                scsi_scan_host(cfg->host);
-       kref_put(&afu->mapcount, afu_unmap);
 }
 
 /**
@@ -2265,6 +2334,7 @@ static int cxlflash_probe(struct pci_dev *pdev,
 {
        struct Scsi_Host *host;
        struct cxlflash_cfg *cfg = NULL;
+       struct device *dev = &pdev->dev;
        struct dev_dependent_vals *ddv;
        int rc = 0;
 
@@ -2276,8 +2346,7 @@ static int cxlflash_probe(struct pci_dev *pdev,
 
        host = scsi_host_alloc(&driver_template, sizeof(struct cxlflash_cfg));
        if (!host) {
-               dev_err(&pdev->dev, "%s: call to scsi_host_alloc failed!\n",
-                       __func__);
+               dev_err(dev, "%s: scsi_host_alloc failed\n", __func__);
                rc = -ENOMEM;
                goto out;
        }
@@ -2288,12 +2357,11 @@ static int cxlflash_probe(struct pci_dev *pdev,
        host->unique_id = host->host_no;
        host->max_cmd_len = CXLFLASH_MAX_CDB_LEN;
 
-       cfg = (struct cxlflash_cfg *)host->hostdata;
+       cfg = shost_priv(host);
        cfg->host = host;
        rc = alloc_mem(cfg);
        if (rc) {
-               dev_err(&pdev->dev, "%s: call to alloc_mem failed!\n",
-                       __func__);
+               dev_err(dev, "%s: alloc_mem failed\n", __func__);
                rc = -ENOMEM;
                scsi_host_put(cfg->host);
                goto out;
@@ -2334,30 +2402,27 @@ static int cxlflash_probe(struct pci_dev *pdev,
 
        rc = init_pci(cfg);
        if (rc) {
-               dev_err(&pdev->dev, "%s: call to init_pci "
-                       "failed rc=%d!\n", __func__, rc);
+               dev_err(dev, "%s: init_pci failed rc=%d\n", __func__, rc);
                goto out_remove;
        }
        cfg->init_state = INIT_STATE_PCI;
 
        rc = init_afu(cfg);
        if (rc) {
-               dev_err(&pdev->dev, "%s: call to init_afu "
-                       "failed rc=%d!\n", __func__, rc);
+               dev_err(dev, "%s: init_afu failed rc=%d\n", __func__, rc);
                goto out_remove;
        }
        cfg->init_state = INIT_STATE_AFU;
 
        rc = init_scsi(cfg);
        if (rc) {
-               dev_err(&pdev->dev, "%s: call to init_scsi "
-                       "failed rc=%d!\n", __func__, rc);
+               dev_err(dev, "%s: init_scsi failed rc=%d\n", __func__, rc);
                goto out_remove;
        }
        cfg->init_state = INIT_STATE_SCSI;
 
 out:
-       pr_debug("%s: returning rc=%d\n", __func__, rc);
+       dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
        return rc;
 
 out_remove:
@@ -2395,7 +2460,7 @@ static pci_ers_result_t cxlflash_pci_error_detected(struct pci_dev *pdev,
                drain_ioctls(cfg);
                rc = cxlflash_mark_contexts_error(cfg);
                if (unlikely(rc))
-                       dev_err(dev, "%s: Failed to mark user contexts!(%d)\n",
+                       dev_err(dev, "%s: Failed to mark user contexts rc=%d\n",
                                __func__, rc);
                term_afu(cfg);
                return PCI_ERS_RESULT_NEED_RESET;
@@ -2429,7 +2494,7 @@ static pci_ers_result_t cxlflash_pci_slot_reset(struct pci_dev *pdev)
 
        rc = init_afu(cfg);
        if (unlikely(rc)) {
-               dev_err(dev, "%s: EEH recovery failed! (%d)\n", __func__, rc);
+               dev_err(dev, "%s: EEH recovery failed rc=%d\n", __func__, rc);
                return PCI_ERS_RESULT_DISCONNECT;
        }
 
@@ -2477,8 +2542,6 @@ static struct pci_driver cxlflash_driver = {
  */
 static int __init init_cxlflash(void)
 {
-       pr_info("%s: %s\n", __func__, CXLFLASH_ADAPTER_NAME);
-
        cxlflash_list_init();
 
        return pci_register_driver(&cxlflash_driver);
index 1a2d09c148b34a7bec8f9295eda4ec912fbdffce..a6e48a893fefb6659136c2a81959acd036070d70 100644 (file)
@@ -72,7 +72,10 @@ struct sisl_ioarcb {
        u16 timeout;            /* in units specified by req_flags */
        u32 rsvd1;
        u8 cdb[16];             /* must be in big endian */
-       u64 reserved;           /* Reserved area */
+       union {
+               u64 reserved;                   /* Reserved for IOARRIN mode */
+               struct sisl_ioasa *ioasa;       /* IOASA EA for SQ Mode */
+       };
 } __packed;
 
 struct sisl_rc {
@@ -260,6 +263,11 @@ struct sisl_host_map {
        __be64 cmd_room;
        __be64 ctx_ctrl;        /* least significant byte or b56:63 is LISN# */
        __be64 mbox_w;          /* restricted use */
+       __be64 sq_start;        /* Submission Queue (R/W): write sequence and */
+       __be64 sq_end;          /* inclusion semantics are the same as RRQ    */
+       __be64 sq_head;         /* Submission Queue Head (R): for debugging   */
+       __be64 sq_tail;         /* Submission Queue TAIL (R/W): next IOARCB   */
+       __be64 sq_ctx_reset;    /* Submission Queue Context Reset (R/W)       */
 };
 
 /* per context provisioning & control MMIO */
@@ -348,6 +356,15 @@ struct sisl_global_regs {
        __be64 rsvd[0xf8];
        __le64 afu_version;
        __be64 interface_version;
+#define SISL_INTVER_CAP_SHIFT                  16
+#define SISL_INTVER_MAJ_SHIFT                  8
+#define SISL_INTVER_CAP_MASK                   0xFFFFFFFF00000000ULL
+#define SISL_INTVER_MAJ_MASK                   0x00000000FFFF0000ULL
+#define SISL_INTVER_MIN_MASK                   0x000000000000FFFFULL
+#define SISL_INTVER_CAP_IOARRIN_CMD_MODE       0x800000000000ULL
+#define SISL_INTVER_CAP_SQ_CMD_MODE            0x400000000000ULL
+#define SISL_INTVER_CAP_RESERVED_CMD_MODE_A    0x200000000000ULL
+#define SISL_INTVER_CAP_RESERVED_CMD_MODE_B    0x100000000000ULL
 };
 
 #define CXLFLASH_NUM_FC_PORTS   2
index 9636970d96116107be34ed08201bd099bc0603f6..90869cee2b20b2bcf682d54425dd9fe66b72b519 100644 (file)
@@ -212,7 +212,7 @@ struct ctx_info *get_context(struct cxlflash_cfg *cfg, u64 rctxid,
        }
 
 out:
-       dev_dbg(dev, "%s: rctxid=%016llX ctxinfo=%p ctxpid=%u pid=%u "
+       dev_dbg(dev, "%s: rctxid=%016llx ctxinfo=%p ctxpid=%u pid=%u "
                "ctx_ctrl=%u\n", __func__, rctxid, ctxi, ctxpid, pid,
                ctx_ctrl);
 
@@ -260,7 +260,7 @@ static int afu_attach(struct cxlflash_cfg *cfg, struct ctx_info *ctxi)
        writeq_be(val, &ctrl_map->ctx_cap);
        val = readq_be(&ctrl_map->ctx_cap);
        if (val != (SISL_CTX_CAP_READ_CMD | SISL_CTX_CAP_WRITE_CMD)) {
-               dev_err(dev, "%s: ctx may be closed val=%016llX\n",
+               dev_err(dev, "%s: ctx may be closed val=%016llx\n",
                        __func__, val);
                rc = -EAGAIN;
                goto out;
@@ -302,7 +302,7 @@ out:
  */
 static int read_cap16(struct scsi_device *sdev, struct llun_info *lli)
 {
-       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata;
+       struct cxlflash_cfg *cfg = shost_priv(sdev->host);
        struct device *dev = &cfg->dev->dev;
        struct glun_info *gli = lli->parent;
        u8 *cmd_buf = NULL;
@@ -326,7 +326,7 @@ retry:
        scsi_cmd[1] = SAI_READ_CAPACITY_16;     /* service action */
        put_unaligned_be32(CMD_BUFSIZE, &scsi_cmd[10]);
 
-       dev_dbg(dev, "%s: %ssending cmd(0x%x)\n", __func__,
+       dev_dbg(dev, "%s: %ssending cmd(%02x)\n", __func__,
                retry_cnt ? "re" : "", scsi_cmd[0]);
 
        /* Drop the ioctl read semahpore across lengthy call */
@@ -336,7 +336,7 @@ retry:
        down_read(&cfg->ioctl_rwsem);
        rc = check_state(cfg);
        if (rc) {
-               dev_err(dev, "%s: Failed state! result=0x08%X\n",
+               dev_err(dev, "%s: Failed state result=%08x\n",
                        __func__, result);
                rc = -ENODEV;
                goto out;
@@ -378,7 +378,7 @@ retry:
        }
 
        if (result) {
-               dev_err(dev, "%s: command failed, result=0x%x\n",
+               dev_err(dev, "%s: command failed, result=%08x\n",
                        __func__, result);
                rc = -EIO;
                goto out;
@@ -415,29 +415,32 @@ out:
 struct sisl_rht_entry *get_rhte(struct ctx_info *ctxi, res_hndl_t rhndl,
                                struct llun_info *lli)
 {
+       struct cxlflash_cfg *cfg = ctxi->cfg;
+       struct device *dev = &cfg->dev->dev;
        struct sisl_rht_entry *rhte = NULL;
 
        if (unlikely(!ctxi->rht_start)) {
-               pr_debug("%s: Context does not have allocated RHT!\n",
+               dev_dbg(dev, "%s: Context does not have allocated RHT\n",
                         __func__);
                goto out;
        }
 
        if (unlikely(rhndl >= MAX_RHT_PER_CONTEXT)) {
-               pr_debug("%s: Bad resource handle! (%d)\n", __func__, rhndl);
+               dev_dbg(dev, "%s: Bad resource handle rhndl=%d\n",
+                       __func__, rhndl);
                goto out;
        }
 
        if (unlikely(ctxi->rht_lun[rhndl] != lli)) {
-               pr_debug("%s: Bad resource handle LUN! (%d)\n",
-                        __func__, rhndl);
+               dev_dbg(dev, "%s: Bad resource handle LUN rhndl=%d\n",
+                       __func__, rhndl);
                goto out;
        }
 
        rhte = &ctxi->rht_start[rhndl];
        if (unlikely(rhte->nmask == 0)) {
-               pr_debug("%s: Unopened resource handle! (%d)\n",
-                        __func__, rhndl);
+               dev_dbg(dev, "%s: Unopened resource handle rhndl=%d\n",
+                       __func__, rhndl);
                rhte = NULL;
                goto out;
        }
@@ -456,6 +459,8 @@ out:
 struct sisl_rht_entry *rhte_checkout(struct ctx_info *ctxi,
                                     struct llun_info *lli)
 {
+       struct cxlflash_cfg *cfg = ctxi->cfg;
+       struct device *dev = &cfg->dev->dev;
        struct sisl_rht_entry *rhte = NULL;
        int i;
 
@@ -470,7 +475,7 @@ struct sisl_rht_entry *rhte_checkout(struct ctx_info *ctxi,
        if (likely(rhte))
                ctxi->rht_lun[i] = lli;
 
-       pr_debug("%s: returning rhte=%p (%d)\n", __func__, rhte, i);
+       dev_dbg(dev, "%s: returning rhte=%p index=%d\n", __func__, rhte, i);
        return rhte;
 }
 
@@ -547,7 +552,7 @@ int cxlflash_lun_attach(struct glun_info *gli, enum lun_mode mode, bool locked)
        if (gli->mode == MODE_NONE)
                gli->mode = mode;
        else if (gli->mode != mode) {
-               pr_debug("%s: LUN operating in mode %d, requested mode %d\n",
+               pr_debug("%s: gli_mode=%d requested_mode=%d\n",
                         __func__, gli->mode, mode);
                rc = -EINVAL;
                goto out;
@@ -605,7 +610,7 @@ int _cxlflash_disk_release(struct scsi_device *sdev,
                           struct ctx_info *ctxi,
                           struct dk_cxlflash_release *release)
 {
-       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata;
+       struct cxlflash_cfg *cfg = shost_priv(sdev->host);
        struct device *dev = &cfg->dev->dev;
        struct llun_info *lli = sdev->hostdata;
        struct glun_info *gli = lli->parent;
@@ -622,13 +627,13 @@ int _cxlflash_disk_release(struct scsi_device *sdev,
        struct sisl_rht_entry *rhte;
        struct sisl_rht_entry_f1 *rhte_f1;
 
-       dev_dbg(dev, "%s: ctxid=%llu rhndl=0x%llx gli->mode=%u gli->users=%u\n",
+       dev_dbg(dev, "%s: ctxid=%llu rhndl=%llu gli->mode=%u gli->users=%u\n",
                __func__, ctxid, release->rsrc_handle, gli->mode, gli->users);
 
        if (!ctxi) {
                ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK);
                if (unlikely(!ctxi)) {
-                       dev_dbg(dev, "%s: Bad context! (%llu)\n",
+                       dev_dbg(dev, "%s: Bad context ctxid=%llu\n",
                                __func__, ctxid);
                        rc = -EINVAL;
                        goto out;
@@ -639,7 +644,7 @@ int _cxlflash_disk_release(struct scsi_device *sdev,
 
        rhte = get_rhte(ctxi, rhndl, lli);
        if (unlikely(!rhte)) {
-               dev_dbg(dev, "%s: Bad resource handle! (%d)\n",
+               dev_dbg(dev, "%s: Bad resource handle rhndl=%d\n",
                        __func__, rhndl);
                rc = -EINVAL;
                goto out;
@@ -758,13 +763,13 @@ static struct ctx_info *create_context(struct cxlflash_cfg *cfg)
        lli = kzalloc((MAX_RHT_PER_CONTEXT * sizeof(*lli)), GFP_KERNEL);
        ws = kzalloc((MAX_RHT_PER_CONTEXT * sizeof(*ws)), GFP_KERNEL);
        if (unlikely(!ctxi || !lli || !ws)) {
-               dev_err(dev, "%s: Unable to allocate context!\n", __func__);
+               dev_err(dev, "%s: Unable to allocate context\n", __func__);
                goto err;
        }
 
        rhte = (struct sisl_rht_entry *)get_zeroed_page(GFP_KERNEL);
        if (unlikely(!rhte)) {
-               dev_err(dev, "%s: Unable to allocate RHT!\n", __func__);
+               dev_err(dev, "%s: Unable to allocate RHT\n", __func__);
                goto err;
        }
 
@@ -858,7 +863,7 @@ static int _cxlflash_disk_detach(struct scsi_device *sdev,
                                 struct ctx_info *ctxi,
                                 struct dk_cxlflash_detach *detach)
 {
-       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata;
+       struct cxlflash_cfg *cfg = shost_priv(sdev->host);
        struct device *dev = &cfg->dev->dev;
        struct llun_info *lli = sdev->hostdata;
        struct lun_access *lun_access, *t;
@@ -875,7 +880,7 @@ static int _cxlflash_disk_detach(struct scsi_device *sdev,
        if (!ctxi) {
                ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK);
                if (unlikely(!ctxi)) {
-                       dev_dbg(dev, "%s: Bad context! (%llu)\n",
+                       dev_dbg(dev, "%s: Bad context ctxid=%llu\n",
                                __func__, ctxid);
                        rc = -EINVAL;
                        goto out;
@@ -964,7 +969,7 @@ static int cxlflash_cxl_release(struct inode *inode, struct file *file)
 
        ctxid = cxl_process_element(ctx);
        if (unlikely(ctxid < 0)) {
-               dev_err(dev, "%s: Context %p was closed! (%d)\n",
+               dev_err(dev, "%s: Context %p was closed ctxid=%d\n",
                        __func__, ctx, ctxid);
                goto out;
        }
@@ -973,18 +978,18 @@ static int cxlflash_cxl_release(struct inode *inode, struct file *file)
        if (unlikely(!ctxi)) {
                ctxi = get_context(cfg, ctxid, file, ctrl | CTX_CTRL_CLONE);
                if (!ctxi) {
-                       dev_dbg(dev, "%s: Context %d already free!\n",
+                       dev_dbg(dev, "%s: ctxid=%d already free\n",
                                __func__, ctxid);
                        goto out_release;
                }
 
-               dev_dbg(dev, "%s: Another process owns context %d!\n",
+               dev_dbg(dev, "%s: Another process owns ctxid=%d\n",
                        __func__, ctxid);
                put_context(ctxi);
                goto out;
        }
 
-       dev_dbg(dev, "%s: close for context %d\n", __func__, ctxid);
+       dev_dbg(dev, "%s: close for ctxid=%d\n", __func__, ctxid);
 
        detach.context_id = ctxi->ctxid;
        list_for_each_entry_safe(lun_access, t, &ctxi->luns, list)
@@ -1011,17 +1016,20 @@ static void unmap_context(struct ctx_info *ctxi)
 
 /**
  * get_err_page() - obtains and allocates the error notification page
+ * @cfg:       Internal structure associated with the host.
  *
  * Return: error notification page on success, NULL on failure
  */
-static struct page *get_err_page(void)
+static struct page *get_err_page(struct cxlflash_cfg *cfg)
 {
        struct page *err_page = global.err_page;
+       struct device *dev = &cfg->dev->dev;
 
        if (unlikely(!err_page)) {
                err_page = alloc_page(GFP_KERNEL);
                if (unlikely(!err_page)) {
-                       pr_err("%s: Unable to allocate err_page!\n", __func__);
+                       dev_err(dev, "%s: Unable to allocate err_page\n",
+                               __func__);
                        goto out;
                }
 
@@ -1039,7 +1047,7 @@ static struct page *get_err_page(void)
        }
 
 out:
-       pr_debug("%s: returning err_page=%p\n", __func__, err_page);
+       dev_dbg(dev, "%s: returning err_page=%p\n", __func__, err_page);
        return err_page;
 }
 
@@ -1074,14 +1082,14 @@ static int cxlflash_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 
        ctxid = cxl_process_element(ctx);
        if (unlikely(ctxid < 0)) {
-               dev_err(dev, "%s: Context %p was closed! (%d)\n",
+               dev_err(dev, "%s: Context %p was closed ctxid=%d\n",
                        __func__, ctx, ctxid);
                goto err;
        }
 
        ctxi = get_context(cfg, ctxid, file, ctrl);
        if (unlikely(!ctxi)) {
-               dev_dbg(dev, "%s: Bad context! (%d)\n", __func__, ctxid);
+               dev_dbg(dev, "%s: Bad context ctxid=%d\n", __func__, ctxid);
                goto err;
        }
 
@@ -1091,13 +1099,12 @@ static int cxlflash_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
                vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
                rc = ctxi->cxl_mmap_vmops->fault(vma, vmf);
        } else {
-               dev_dbg(dev, "%s: err recovery active, use err_page!\n",
+               dev_dbg(dev, "%s: err recovery active, use err_page\n",
                        __func__);
 
-               err_page = get_err_page();
+               err_page = get_err_page(cfg);
                if (unlikely(!err_page)) {
-                       dev_err(dev, "%s: Could not obtain error page!\n",
-                               __func__);
+                       dev_err(dev, "%s: Could not get err_page\n", __func__);
                        rc = VM_FAULT_RETRY;
                        goto out;
                }
@@ -1147,7 +1154,7 @@ static int cxlflash_cxl_mmap(struct file *file, struct vm_area_struct *vma)
 
        ctxid = cxl_process_element(ctx);
        if (unlikely(ctxid < 0)) {
-               dev_err(dev, "%s: Context %p was closed! (%d)\n",
+               dev_err(dev, "%s: Context %p was closed ctxid=%d\n",
                        __func__, ctx, ctxid);
                rc = -EIO;
                goto out;
@@ -1155,7 +1162,7 @@ static int cxlflash_cxl_mmap(struct file *file, struct vm_area_struct *vma)
 
        ctxi = get_context(cfg, ctxid, file, ctrl);
        if (unlikely(!ctxi)) {
-               dev_dbg(dev, "%s: Bad context! (%d)\n", __func__, ctxid);
+               dev_dbg(dev, "%s: Bad context ctxid=%d\n", __func__, ctxid);
                rc = -EIO;
                goto out;
        }
@@ -1251,7 +1258,7 @@ retry:
                        break;
                goto retry;
        case STATE_FAILTERM:
-               dev_dbg(dev, "%s: Failed/Terminating!\n", __func__);
+               dev_dbg(dev, "%s: Failed/Terminating\n", __func__);
                rc = -ENODEV;
                break;
        default:
@@ -1276,7 +1283,7 @@ retry:
 static int cxlflash_disk_attach(struct scsi_device *sdev,
                                struct dk_cxlflash_attach *attach)
 {
-       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata;
+       struct cxlflash_cfg *cfg = shost_priv(sdev->host);
        struct device *dev = &cfg->dev->dev;
        struct afu *afu = cfg->afu;
        struct llun_info *lli = sdev->hostdata;
@@ -1287,6 +1294,7 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,
        int rc = 0;
        u32 perms;
        int ctxid = -1;
+       u64 flags = 0UL;
        u64 rctxid = 0UL;
        struct file *file = NULL;
 
@@ -1302,24 +1310,24 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,
        }
 
        if (gli->max_lba == 0) {
-               dev_dbg(dev, "%s: No capacity info for this LUN (%016llX)\n",
+               dev_dbg(dev, "%s: No capacity info for LUN=%016llx\n",
                        __func__, lli->lun_id[sdev->channel]);
                rc = read_cap16(sdev, lli);
                if (rc) {
-                       dev_err(dev, "%s: Invalid device! (%d)\n",
+                       dev_err(dev, "%s: Invalid device rc=%d\n",
                                __func__, rc);
                        rc = -ENODEV;
                        goto out;
                }
-               dev_dbg(dev, "%s: LBA = %016llX\n", __func__, gli->max_lba);
-               dev_dbg(dev, "%s: BLK_LEN = %08X\n", __func__, gli->blk_len);
+               dev_dbg(dev, "%s: LBA = %016llx\n", __func__, gli->max_lba);
+               dev_dbg(dev, "%s: BLK_LEN = %08x\n", __func__, gli->blk_len);
        }
 
        if (attach->hdr.flags & DK_CXLFLASH_ATTACH_REUSE_CONTEXT) {
                rctxid = attach->context_id;
                ctxi = get_context(cfg, rctxid, NULL, 0);
                if (!ctxi) {
-                       dev_dbg(dev, "%s: Bad context! (%016llX)\n",
+                       dev_dbg(dev, "%s: Bad context rctxid=%016llx\n",
                                __func__, rctxid);
                        rc = -EINVAL;
                        goto out;
@@ -1327,7 +1335,7 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,
 
                list_for_each_entry(lun_access, &ctxi->luns, list)
                        if (lun_access->lli == lli) {
-                               dev_dbg(dev, "%s: Already attached!\n",
+                               dev_dbg(dev, "%s: Already attached\n",
                                        __func__);
                                rc = -EINVAL;
                                goto out;
@@ -1336,13 +1344,13 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,
 
        rc = scsi_device_get(sdev);
        if (unlikely(rc)) {
-               dev_err(dev, "%s: Unable to get sdev reference!\n", __func__);
+               dev_err(dev, "%s: Unable to get sdev reference\n", __func__);
                goto out;
        }
 
        lun_access = kzalloc(sizeof(*lun_access), GFP_KERNEL);
        if (unlikely(!lun_access)) {
-               dev_err(dev, "%s: Unable to allocate lun_access!\n", __func__);
+               dev_err(dev, "%s: Unable to allocate lun_access\n", __func__);
                rc = -ENOMEM;
                goto err;
        }
@@ -1352,7 +1360,7 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,
 
        /* Non-NULL context indicates reuse (another context reference) */
        if (ctxi) {
-               dev_dbg(dev, "%s: Reusing context for LUN! (%016llX)\n",
+               dev_dbg(dev, "%s: Reusing context for LUN rctxid=%016llx\n",
                        __func__, rctxid);
                kref_get(&ctxi->kref);
                list_add(&lun_access->list, &ctxi->luns);
@@ -1361,7 +1369,7 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,
 
        ctxi = create_context(cfg);
        if (unlikely(!ctxi)) {
-               dev_err(dev, "%s: Failed to create context! (%d)\n",
+               dev_err(dev, "%s: Failed to create context ctxid=%d\n",
                        __func__, ctxid);
                goto err;
        }
@@ -1387,7 +1395,7 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,
 
        ctxid = cxl_process_element(ctx);
        if (unlikely((ctxid >= MAX_CONTEXT) || (ctxid < 0))) {
-               dev_err(dev, "%s: ctxid (%d) invalid!\n", __func__, ctxid);
+               dev_err(dev, "%s: ctxid=%d invalid\n", __func__, ctxid);
                rc = -EPERM;
                goto err;
        }
@@ -1426,10 +1434,11 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,
 
 out_attach:
        if (fd != -1)
-               attach->hdr.return_flags = DK_CXLFLASH_APP_CLOSE_ADAP_FD;
-       else
-               attach->hdr.return_flags = 0;
+               flags |= DK_CXLFLASH_APP_CLOSE_ADAP_FD;
+       if (afu_is_sq_cmd_mode(afu))
+               flags |= DK_CXLFLASH_CONTEXT_SQ_CMD_MODE;
 
+       attach->hdr.return_flags = flags;
        attach->context_id = ctxi->ctxid;
        attach->block_size = gli->blk_len;
        attach->mmio_size = sizeof(afu->afu_map->hosts[0].harea);
@@ -1520,7 +1529,7 @@ static int recover_context(struct cxlflash_cfg *cfg,
 
        ctxid = cxl_process_element(ctx);
        if (unlikely((ctxid >= MAX_CONTEXT) || (ctxid < 0))) {
-               dev_err(dev, "%s: ctxid (%d) invalid!\n", __func__, ctxid);
+               dev_err(dev, "%s: ctxid=%d invalid\n", __func__, ctxid);
                rc = -EPERM;
                goto err2;
        }
@@ -1611,12 +1620,13 @@ err1:
 static int cxlflash_afu_recover(struct scsi_device *sdev,
                                struct dk_cxlflash_recover_afu *recover)
 {
-       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata;
+       struct cxlflash_cfg *cfg = shost_priv(sdev->host);
        struct device *dev = &cfg->dev->dev;
        struct llun_info *lli = sdev->hostdata;
        struct afu *afu = cfg->afu;
        struct ctx_info *ctxi = NULL;
        struct mutex *mutex = &cfg->ctx_recovery_mutex;
+       u64 flags;
        u64 ctxid = DECODE_CTXID(recover->context_id),
            rctxid = recover->context_id;
        long reg;
@@ -1632,19 +1642,19 @@ static int cxlflash_afu_recover(struct scsi_device *sdev,
                goto out;
        rc = check_state(cfg);
        if (rc) {
-               dev_err(dev, "%s: Failed state! rc=%d\n", __func__, rc);
+               dev_err(dev, "%s: Failed state rc=%d\n", __func__, rc);
                rc = -ENODEV;
                goto out;
        }
 
-       dev_dbg(dev, "%s: reason 0x%016llX rctxid=%016llX\n",
+       dev_dbg(dev, "%s: reason=%016llx rctxid=%016llx\n",
                __func__, recover->reason, rctxid);
 
 retry:
        /* Ensure that this process is attached to the context */
        ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK);
        if (unlikely(!ctxi)) {
-               dev_dbg(dev, "%s: Bad context! (%llu)\n", __func__, ctxid);
+               dev_dbg(dev, "%s: Bad context ctxid=%llu\n", __func__, ctxid);
                rc = -EINVAL;
                goto out;
        }
@@ -1653,12 +1663,12 @@ retry:
 retry_recover:
                rc = recover_context(cfg, ctxi, &new_adap_fd);
                if (unlikely(rc)) {
-                       dev_err(dev, "%s: Recovery failed for context %llu (rc=%d)\n",
+                       dev_err(dev, "%s: Recovery failed ctxid=%llu rc=%d\n",
                                __func__, ctxid, rc);
                        if ((rc == -ENODEV) &&
                            ((atomic_read(&cfg->recovery_threads) > 1) ||
                             (lretry--))) {
-                               dev_dbg(dev, "%s: Going to try again!\n",
+                               dev_dbg(dev, "%s: Going to try again\n",
                                        __func__);
                                mutex_unlock(mutex);
                                msleep(100);
@@ -1672,11 +1682,16 @@ retry_recover:
                }
 
                ctxi->err_recovery_active = false;
+
+               flags = DK_CXLFLASH_APP_CLOSE_ADAP_FD |
+                       DK_CXLFLASH_RECOVER_AFU_CONTEXT_RESET;
+               if (afu_is_sq_cmd_mode(afu))
+                       flags |= DK_CXLFLASH_CONTEXT_SQ_CMD_MODE;
+
+               recover->hdr.return_flags = flags;
                recover->context_id = ctxi->ctxid;
                recover->adap_fd = new_adap_fd;
                recover->mmio_size = sizeof(afu->afu_map->hosts[0].harea);
-               recover->hdr.return_flags = DK_CXLFLASH_APP_CLOSE_ADAP_FD |
-                       DK_CXLFLASH_RECOVER_AFU_CONTEXT_RESET;
                goto out;
        }
 
@@ -1699,7 +1714,7 @@ retry_recover:
                goto retry;
        }
 
-       dev_dbg(dev, "%s: MMIO working, no recovery required!\n", __func__);
+       dev_dbg(dev, "%s: MMIO working, no recovery required\n", __func__);
 out:
        if (likely(ctxi))
                put_context(ctxi);
@@ -1718,7 +1733,7 @@ out:
 static int process_sense(struct scsi_device *sdev,
                         struct dk_cxlflash_verify *verify)
 {
-       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata;
+       struct cxlflash_cfg *cfg = shost_priv(sdev->host);
        struct device *dev = &cfg->dev->dev;
        struct llun_info *lli = sdev->hostdata;
        struct glun_info *gli = lli->parent;
@@ -1729,7 +1744,7 @@ static int process_sense(struct scsi_device *sdev,
        rc = scsi_normalize_sense((const u8 *)&verify->sense_data,
                                  DK_CXLFLASH_VERIFY_SENSE_LEN, &sshdr);
        if (!rc) {
-               dev_err(dev, "%s: Failed to normalize sense data!\n", __func__);
+               dev_err(dev, "%s: Failed to normalize sense data\n", __func__);
                rc = -EINVAL;
                goto out;
        }
@@ -1785,7 +1800,7 @@ static int cxlflash_disk_verify(struct scsi_device *sdev,
 {
        int rc = 0;
        struct ctx_info *ctxi = NULL;
-       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata;
+       struct cxlflash_cfg *cfg = shost_priv(sdev->host);
        struct device *dev = &cfg->dev->dev;
        struct llun_info *lli = sdev->hostdata;
        struct glun_info *gli = lli->parent;
@@ -1795,20 +1810,20 @@ static int cxlflash_disk_verify(struct scsi_device *sdev,
            rctxid = verify->context_id;
        u64 last_lba = 0;
 
-       dev_dbg(dev, "%s: ctxid=%llu rhndl=%016llX, hint=%016llX, "
-               "flags=%016llX\n", __func__, ctxid, verify->rsrc_handle,
+       dev_dbg(dev, "%s: ctxid=%llu rhndl=%016llx, hint=%016llx, "
+               "flags=%016llx\n", __func__, ctxid, verify->rsrc_handle,
                verify->hint, verify->hdr.flags);
 
        ctxi = get_context(cfg, rctxid, lli, 0);
        if (unlikely(!ctxi)) {
-               dev_dbg(dev, "%s: Bad context! (%llu)\n", __func__, ctxid);
+               dev_dbg(dev, "%s: Bad context ctxid=%llu\n", __func__, ctxid);
                rc = -EINVAL;
                goto out;
        }
 
        rhte = get_rhte(ctxi, rhndl, lli);
        if (unlikely(!rhte)) {
-               dev_dbg(dev, "%s: Bad resource handle! (%d)\n",
+               dev_dbg(dev, "%s: Bad resource handle rhndl=%d\n",
                        __func__, rhndl);
                rc = -EINVAL;
                goto out;
@@ -1855,7 +1870,7 @@ static int cxlflash_disk_verify(struct scsi_device *sdev,
 out:
        if (likely(ctxi))
                put_context(ctxi);
-       dev_dbg(dev, "%s: returning rc=%d llba=%llX\n",
+       dev_dbg(dev, "%s: returning rc=%d llba=%llx\n",
                __func__, rc, verify->last_lba);
        return rc;
 }
@@ -1907,7 +1922,7 @@ static char *decode_ioctl(int cmd)
  */
 static int cxlflash_disk_direct_open(struct scsi_device *sdev, void *arg)
 {
-       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata;
+       struct cxlflash_cfg *cfg = shost_priv(sdev->host);
        struct device *dev = &cfg->dev->dev;
        struct afu *afu = cfg->afu;
        struct llun_info *lli = sdev->hostdata;
@@ -1927,25 +1942,25 @@ static int cxlflash_disk_direct_open(struct scsi_device *sdev, void *arg)
        struct ctx_info *ctxi = NULL;
        struct sisl_rht_entry *rhte = NULL;
 
-       pr_debug("%s: ctxid=%llu ls=0x%llx\n", __func__, ctxid, lun_size);
+       dev_dbg(dev, "%s: ctxid=%llu ls=%llu\n", __func__, ctxid, lun_size);
 
        rc = cxlflash_lun_attach(gli, MODE_PHYSICAL, false);
        if (unlikely(rc)) {
-               dev_dbg(dev, "%s: Failed to attach to LUN! (PHYSICAL)\n",
-                       __func__);
+               dev_dbg(dev, "%s: Failed attach to LUN (PHYSICAL)\n", __func__);
                goto out;
        }
 
        ctxi = get_context(cfg, rctxid, lli, 0);
        if (unlikely(!ctxi)) {
-               dev_dbg(dev, "%s: Bad context! (%llu)\n", __func__, ctxid);
+               dev_dbg(dev, "%s: Bad context ctxid=%llu\n", __func__, ctxid);
                rc = -EINVAL;
                goto err1;
        }
 
        rhte = rhte_checkout(ctxi, lli);
        if (unlikely(!rhte)) {
-               dev_dbg(dev, "%s: too many opens for this context\n", __func__);
+               dev_dbg(dev, "%s: Too many opens ctxid=%lld\n",
+                       __func__, ctxid);
                rc = -EMFILE;   /* too many opens  */
                goto err1;
        }
@@ -1963,7 +1978,7 @@ static int cxlflash_disk_direct_open(struct scsi_device *sdev, void *arg)
 out:
        if (likely(ctxi))
                put_context(ctxi);
-       dev_dbg(dev, "%s: returning handle 0x%llx rc=%d llba %lld\n",
+       dev_dbg(dev, "%s: returning handle=%llu rc=%d llba=%llu\n",
                __func__, rsrc_handle, rc, last_lba);
        return rc;
 
@@ -1985,7 +2000,7 @@ err1:
  */
 static int ioctl_common(struct scsi_device *sdev, int cmd)
 {
-       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata;
+       struct cxlflash_cfg *cfg = shost_priv(sdev->host);
        struct device *dev = &cfg->dev->dev;
        struct llun_info *lli = sdev->hostdata;
        int rc = 0;
@@ -2002,7 +2017,7 @@ static int ioctl_common(struct scsi_device *sdev, int cmd)
                case DK_CXLFLASH_VLUN_RESIZE:
                case DK_CXLFLASH_RELEASE:
                case DK_CXLFLASH_DETACH:
-                       dev_dbg(dev, "%s: Command override! (%d)\n",
+                       dev_dbg(dev, "%s: Command override rc=%d\n",
                                __func__, rc);
                        rc = 0;
                        break;
@@ -2032,7 +2047,7 @@ int cxlflash_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
 {
        typedef int (*sioctl) (struct scsi_device *, void *);
 
-       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata;
+       struct cxlflash_cfg *cfg = shost_priv(sdev->host);
        struct device *dev = &cfg->dev->dev;
        struct afu *afu = cfg->afu;
        struct dk_cxlflash_hdr *hdr;
@@ -2111,7 +2126,7 @@ int cxlflash_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
        }
 
        if (unlikely(copy_from_user(&buf, arg, size))) {
-               dev_err(dev, "%s: copy_from_user() fail! "
+               dev_err(dev, "%s: copy_from_user() fail "
                        "size=%lu cmd=%d (%s) arg=%p\n",
                        __func__, size, cmd, decode_ioctl(cmd), arg);
                rc = -EFAULT;
@@ -2127,7 +2142,7 @@ int cxlflash_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
        }
 
        if (hdr->rsvd[0] || hdr->rsvd[1] || hdr->rsvd[2] || hdr->return_flags) {
-               dev_dbg(dev, "%s: Reserved/rflags populated!\n", __func__);
+               dev_dbg(dev, "%s: Reserved/rflags populated\n", __func__);
                rc = -EINVAL;
                goto cxlflash_ioctl_exit;
        }
@@ -2135,7 +2150,7 @@ int cxlflash_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
        rc = do_ioctl(sdev, (void *)&buf);
        if (likely(!rc))
                if (unlikely(copy_to_user(arg, &buf, size))) {
-                       dev_err(dev, "%s: copy_to_user() fail! "
+                       dev_err(dev, "%s: copy_to_user() fail "
                                "size=%lu cmd=%d (%s) arg=%p\n",
                                __func__, size, cmd, decode_ioctl(cmd), arg);
                        rc = -EFAULT;
index 90c5d7f5278e2350c4b65098c6a3124d76fd7f6c..8fcc804dbef9d94a5c0ec87665392edec63887f5 100644 (file)
@@ -66,8 +66,8 @@ static int ba_init(struct ba_lun *ba_lun)
        int last_word_underflow = 0;
        u64 *lam;
 
-       pr_debug("%s: Initializing LUN: lun_id = %llX, "
-                "ba_lun->lsize = %lX, ba_lun->au_size = %lX\n",
+       pr_debug("%s: Initializing LUN: lun_id=%016llx "
+                "ba_lun->lsize=%lx ba_lun->au_size=%lX\n",
                __func__, ba_lun->lun_id, ba_lun->lsize, ba_lun->au_size);
 
        /* Calculate bit map size */
@@ -80,7 +80,7 @@ static int ba_init(struct ba_lun *ba_lun)
        /* Allocate lun information container */
        bali = kzalloc(sizeof(struct ba_lun_info), GFP_KERNEL);
        if (unlikely(!bali)) {
-               pr_err("%s: Failed to allocate lun_info for lun_id %llX\n",
+               pr_err("%s: Failed to allocate lun_info lun_id=%016llx\n",
                       __func__, ba_lun->lun_id);
                return -ENOMEM;
        }
@@ -96,7 +96,7 @@ static int ba_init(struct ba_lun *ba_lun)
                                      GFP_KERNEL);
        if (unlikely(!bali->lun_alloc_map)) {
                pr_err("%s: Failed to allocate lun allocation map: "
-                      "lun_id = %llX\n", __func__, ba_lun->lun_id);
+                      "lun_id=%016llx\n", __func__, ba_lun->lun_id);
                kfree(bali);
                return -ENOMEM;
        }
@@ -125,7 +125,7 @@ static int ba_init(struct ba_lun *ba_lun)
        bali->aun_clone_map = kzalloc((bali->total_aus * sizeof(u8)),
                                      GFP_KERNEL);
        if (unlikely(!bali->aun_clone_map)) {
-               pr_err("%s: Failed to allocate clone map: lun_id = %llX\n",
+               pr_err("%s: Failed to allocate clone map: lun_id=%016llx\n",
                       __func__, ba_lun->lun_id);
                kfree(bali->lun_alloc_map);
                kfree(bali);
@@ -136,7 +136,7 @@ static int ba_init(struct ba_lun *ba_lun)
        ba_lun->ba_lun_handle = bali;
 
        pr_debug("%s: Successfully initialized the LUN: "
-                "lun_id = %llX, bitmap size = %X, free_aun_cnt = %llX\n",
+                "lun_id=%016llx bitmap size=%x, free_aun_cnt=%llx\n",
                __func__, ba_lun->lun_id, bali->lun_bmap_size,
                bali->free_aun_cnt);
        return 0;
@@ -165,10 +165,9 @@ static int find_free_range(u32 low,
                        num_bits = (sizeof(*lam) * BITS_PER_BYTE);
                        bit_pos = find_first_bit(lam, num_bits);
 
-                       pr_devel("%s: Found free bit %llX in LUN "
-                                "map entry %llX at bitmap index = %X\n",
-                                __func__, bit_pos, bali->lun_alloc_map[i],
-                                i);
+                       pr_devel("%s: Found free bit %llu in LUN "
+                                "map entry %016llx at bitmap index = %d\n",
+                                __func__, bit_pos, bali->lun_alloc_map[i], i);
 
                        *bit_word = i;
                        bali->free_aun_cnt--;
@@ -194,11 +193,11 @@ static u64 ba_alloc(struct ba_lun *ba_lun)
        bali = ba_lun->ba_lun_handle;
 
        pr_debug("%s: Received block allocation request: "
-                "lun_id = %llX, free_aun_cnt = %llX\n",
+                "lun_id=%016llx free_aun_cnt=%llx\n",
                 __func__, ba_lun->lun_id, bali->free_aun_cnt);
 
        if (bali->free_aun_cnt == 0) {
-               pr_debug("%s: No space left on LUN: lun_id = %llX\n",
+               pr_debug("%s: No space left on LUN: lun_id=%016llx\n",
                         __func__, ba_lun->lun_id);
                return -1ULL;
        }
@@ -212,7 +211,7 @@ static u64 ba_alloc(struct ba_lun *ba_lun)
                                          bali, &bit_word);
                if (bit_pos == -1) {
                        pr_debug("%s: Could not find an allocation unit on LUN:"
-                                " lun_id = %llX\n", __func__, ba_lun->lun_id);
+                                " lun_id=%016llx\n", __func__, ba_lun->lun_id);
                        return -1ULL;
                }
        }
@@ -223,8 +222,8 @@ static u64 ba_alloc(struct ba_lun *ba_lun)
        else
                bali->free_curr_idx = bit_word;
 
-       pr_debug("%s: Allocating AU number %llX, on lun_id %llX, "
-                "free_aun_cnt = %llX\n", __func__,
+       pr_debug("%s: Allocating AU number=%llx lun_id=%016llx "
+                "free_aun_cnt=%llx\n", __func__,
                 ((bit_word * BITS_PER_LONG) + bit_pos), ba_lun->lun_id,
                 bali->free_aun_cnt);
 
@@ -266,18 +265,18 @@ static int ba_free(struct ba_lun *ba_lun, u64 to_free)
        bali = ba_lun->ba_lun_handle;
 
        if (validate_alloc(bali, to_free)) {
-               pr_debug("%s: The AUN %llX is not allocated on lun_id %llX\n",
+               pr_debug("%s: AUN %llx is not allocated on lun_id=%016llx\n",
                         __func__, to_free, ba_lun->lun_id);
                return -1;
        }
 
-       pr_debug("%s: Received a request to free AU %llX on lun_id %llX, "
-                "free_aun_cnt = %llX\n", __func__, to_free, ba_lun->lun_id,
+       pr_debug("%s: Received a request to free AU=%llx lun_id=%016llx "
+                "free_aun_cnt=%llx\n", __func__, to_free, ba_lun->lun_id,
                 bali->free_aun_cnt);
 
        if (bali->aun_clone_map[to_free] > 0) {
-               pr_debug("%s: AUN %llX on lun_id %llX has been cloned. Clone "
-                        "count = %X\n", __func__, to_free, ba_lun->lun_id,
+               pr_debug("%s: AUN %llx lun_id=%016llx cloned. Clone count=%x\n",
+                        __func__, to_free, ba_lun->lun_id,
                         bali->aun_clone_map[to_free]);
                bali->aun_clone_map[to_free]--;
                return 0;
@@ -294,8 +293,8 @@ static int ba_free(struct ba_lun *ba_lun, u64 to_free)
        else if (idx > bali->free_high_idx)
                bali->free_high_idx = idx;
 
-       pr_debug("%s: Successfully freed AU at bit_pos %X, bit map index %X on "
-                "lun_id %llX, free_aun_cnt = %llX\n", __func__, bit_pos, idx,
+       pr_debug("%s: Successfully freed AU bit_pos=%x bit map index=%x "
+                "lun_id=%016llx free_aun_cnt=%llx\n", __func__, bit_pos, idx,
                 ba_lun->lun_id, bali->free_aun_cnt);
 
        return 0;
@@ -313,16 +312,16 @@ static int ba_clone(struct ba_lun *ba_lun, u64 to_clone)
        struct ba_lun_info *bali = ba_lun->ba_lun_handle;
 
        if (validate_alloc(bali, to_clone)) {
-               pr_debug("%s: AUN %llX is not allocated on lun_id %llX\n",
+               pr_debug("%s: AUN=%llx not allocated on lun_id=%016llx\n",
                         __func__, to_clone, ba_lun->lun_id);
                return -1;
        }
 
-       pr_debug("%s: Received a request to clone AUN %llX on lun_id %llX\n",
+       pr_debug("%s: Received a request to clone AUN %llx on lun_id=%016llx\n",
                 __func__, to_clone, ba_lun->lun_id);
 
        if (bali->aun_clone_map[to_clone] == MAX_AUN_CLONE_CNT) {
-               pr_debug("%s: AUN %llX on lun_id %llX hit max clones already\n",
+               pr_debug("%s: AUN %llx on lun_id=%016llx hit max clones already\n",
                         __func__, to_clone, ba_lun->lun_id);
                return -1;
        }
@@ -433,7 +432,7 @@ static int write_same16(struct scsi_device *sdev,
        u64 offset = lba;
        int left = nblks;
        u32 to = sdev->request_queue->rq_timeout;
-       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata;
+       struct cxlflash_cfg *cfg = shost_priv(sdev->host);
        struct device *dev = &cfg->dev->dev;
 
        cmd_buf = kzalloc(CMD_BUFSIZE, GFP_KERNEL);
@@ -459,7 +458,7 @@ static int write_same16(struct scsi_device *sdev,
                down_read(&cfg->ioctl_rwsem);
                rc = check_state(cfg);
                if (rc) {
-                       dev_err(dev, "%s: Failed state! result=0x08%X\n",
+                       dev_err(dev, "%s: Failed state result=%08x\n",
                                __func__, result);
                        rc = -ENODEV;
                        goto out;
@@ -467,7 +466,7 @@ static int write_same16(struct scsi_device *sdev,
 
                if (result) {
                        dev_err_ratelimited(dev, "%s: command failed for "
-                                           "offset %lld result=0x%x\n",
+                                           "offset=%lld result=%08x\n",
                                            __func__, offset, result);
                        rc = -EIO;
                        goto out;
@@ -480,7 +479,7 @@ out:
        kfree(cmd_buf);
        kfree(scsi_cmd);
        kfree(sense_buf);
-       pr_debug("%s: returning rc=%d\n", __func__, rc);
+       dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
        return rc;
 }
 
@@ -508,6 +507,8 @@ static int grow_lxt(struct afu *afu,
                    struct sisl_rht_entry *rhte,
                    u64 *new_size)
 {
+       struct cxlflash_cfg *cfg = shost_priv(sdev->host);
+       struct device *dev = &cfg->dev->dev;
        struct sisl_lxt_entry *lxt = NULL, *lxt_old = NULL;
        struct llun_info *lli = sdev->hostdata;
        struct glun_info *gli = lli->parent;
@@ -527,7 +528,8 @@ static int grow_lxt(struct afu *afu,
        mutex_lock(&blka->mutex);
        av_size = ba_space(&blka->ba_lun);
        if (unlikely(av_size <= 0)) {
-               pr_debug("%s: ba_space error: av_size %d\n", __func__, av_size);
+               dev_dbg(dev, "%s: ba_space error av_size=%d\n",
+                       __func__, av_size);
                mutex_unlock(&blka->mutex);
                rc = -ENOSPC;
                goto out;
@@ -568,8 +570,8 @@ static int grow_lxt(struct afu *afu,
                 */
                aun = ba_alloc(&blka->ba_lun);
                if ((aun == -1ULL) || (aun >= blka->nchunk))
-                       pr_debug("%s: ba_alloc error: allocated chunk# %llX, "
-                                "max %llX\n", __func__, aun, blka->nchunk - 1);
+                       dev_dbg(dev, "%s: ba_alloc error allocated chunk=%llu "
+                               "max=%llu\n", __func__, aun, blka->nchunk - 1);
 
                /* select both ports, use r/w perms from RHT */
                lxt[i].rlba_base = ((aun << MC_CHUNK_SHIFT) |
@@ -599,7 +601,7 @@ static int grow_lxt(struct afu *afu,
                kfree(lxt_old);
        *new_size = my_new_size;
 out:
-       pr_debug("%s: returning rc=%d\n", __func__, rc);
+       dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
        return rc;
 }
 
@@ -621,6 +623,8 @@ static int shrink_lxt(struct afu *afu,
                      struct ctx_info *ctxi,
                      u64 *new_size)
 {
+       struct cxlflash_cfg *cfg = shost_priv(sdev->host);
+       struct device *dev = &cfg->dev->dev;
        struct sisl_lxt_entry *lxt, *lxt_old;
        struct llun_info *lli = sdev->hostdata;
        struct glun_info *gli = lli->parent;
@@ -706,7 +710,7 @@ static int shrink_lxt(struct afu *afu,
                kfree(lxt_old);
        *new_size = my_new_size;
 out:
-       pr_debug("%s: returning rc=%d\n", __func__, rc);
+       dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
        return rc;
 }
 
@@ -728,7 +732,8 @@ int _cxlflash_vlun_resize(struct scsi_device *sdev,
                          struct ctx_info *ctxi,
                          struct dk_cxlflash_resize *resize)
 {
-       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata;
+       struct cxlflash_cfg *cfg = shost_priv(sdev->host);
+       struct device *dev = &cfg->dev->dev;
        struct llun_info *lli = sdev->hostdata;
        struct glun_info *gli = lli->parent;
        struct afu *afu = cfg->afu;
@@ -751,13 +756,13 @@ int _cxlflash_vlun_resize(struct scsi_device *sdev,
        nsectors = (resize->req_size * CXLFLASH_BLOCK_SIZE) / gli->blk_len;
        new_size = DIV_ROUND_UP(nsectors, MC_CHUNK_SIZE);
 
-       pr_debug("%s: ctxid=%llu rhndl=0x%llx, req_size=0x%llx,"
-                "new_size=%llx\n", __func__, ctxid, resize->rsrc_handle,
-                resize->req_size, new_size);
+       dev_dbg(dev, "%s: ctxid=%llu rhndl=%llu req_size=%llu new_size=%llu\n",
+               __func__, ctxid, resize->rsrc_handle, resize->req_size,
+               new_size);
 
        if (unlikely(gli->mode != MODE_VIRTUAL)) {
-               pr_debug("%s: LUN mode does not support resize! (%d)\n",
-                        __func__, gli->mode);
+               dev_dbg(dev, "%s: LUN mode does not support resize mode=%d\n",
+                       __func__, gli->mode);
                rc = -EINVAL;
                goto out;
 
@@ -766,7 +771,8 @@ int _cxlflash_vlun_resize(struct scsi_device *sdev,
        if (!ctxi) {
                ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK);
                if (unlikely(!ctxi)) {
-                       pr_debug("%s: Bad context! (%llu)\n", __func__, ctxid);
+                       dev_dbg(dev, "%s: Bad context ctxid=%llu\n",
+                               __func__, ctxid);
                        rc = -EINVAL;
                        goto out;
                }
@@ -776,7 +782,8 @@ int _cxlflash_vlun_resize(struct scsi_device *sdev,
 
        rhte = get_rhte(ctxi, rhndl, lli);
        if (unlikely(!rhte)) {
-               pr_debug("%s: Bad resource handle! (%u)\n", __func__, rhndl);
+               dev_dbg(dev, "%s: Bad resource handle rhndl=%u\n",
+                       __func__, rhndl);
                rc = -EINVAL;
                goto out;
        }
@@ -794,8 +801,8 @@ int _cxlflash_vlun_resize(struct scsi_device *sdev,
 out:
        if (put_ctx)
                put_context(ctxi);
-       pr_debug("%s: resized to %lld returning rc=%d\n",
-                __func__, resize->last_lba, rc);
+       dev_dbg(dev, "%s: resized to %llu returning rc=%d\n",
+               __func__, resize->last_lba, rc);
        return rc;
 }
 
@@ -815,6 +822,7 @@ void cxlflash_restore_luntable(struct cxlflash_cfg *cfg)
        u32 chan;
        u32 lind;
        struct afu *afu = cfg->afu;
+       struct device *dev = &cfg->dev->dev;
        struct sisl_global_map __iomem *agm = &afu->afu_map->global;
 
        mutex_lock(&global.mutex);
@@ -828,15 +836,15 @@ void cxlflash_restore_luntable(struct cxlflash_cfg *cfg)
                if (lli->port_sel == BOTH_PORTS) {
                        writeq_be(lli->lun_id[0], &agm->fc_port[0][lind]);
                        writeq_be(lli->lun_id[1], &agm->fc_port[1][lind]);
-                       pr_debug("%s: Virtual LUN on slot %d  id0=%llx, "
-                                "id1=%llx\n", __func__, lind,
-                                lli->lun_id[0], lli->lun_id[1]);
+                       dev_dbg(dev, "%s: Virtual LUN on slot %d  id0=%llx "
+                               "id1=%llx\n", __func__, lind,
+                               lli->lun_id[0], lli->lun_id[1]);
                } else {
                        chan = PORT2CHAN(lli->port_sel);
                        writeq_be(lli->lun_id[chan], &agm->fc_port[chan][lind]);
-                       pr_debug("%s: Virtual LUN on slot %d chan=%d, "
-                                "id=%llx\n", __func__, lind, chan,
-                                lli->lun_id[chan]);
+                       dev_dbg(dev, "%s: Virtual LUN on slot %d chan=%d "
+                               "id=%llx\n", __func__, lind, chan,
+                               lli->lun_id[chan]);
                }
        }
 
@@ -860,6 +868,7 @@ static int init_luntable(struct cxlflash_cfg *cfg, struct llun_info *lli)
        u32 lind;
        int rc = 0;
        struct afu *afu = cfg->afu;
+       struct device *dev = &cfg->dev->dev;
        struct sisl_global_map __iomem *agm = &afu->afu_map->global;
 
        mutex_lock(&global.mutex);
@@ -882,8 +891,8 @@ static int init_luntable(struct cxlflash_cfg *cfg, struct llun_info *lli)
                writeq_be(lli->lun_id[0], &agm->fc_port[0][lind]);
                writeq_be(lli->lun_id[1], &agm->fc_port[1][lind]);
                cfg->promote_lun_index++;
-               pr_debug("%s: Virtual LUN on slot %d  id0=%llx, id1=%llx\n",
-                        __func__, lind, lli->lun_id[0], lli->lun_id[1]);
+               dev_dbg(dev, "%s: Virtual LUN on slot %d  id0=%llx id1=%llx\n",
+                       __func__, lind, lli->lun_id[0], lli->lun_id[1]);
        } else {
                /*
                 * If this LUN is visible only from one port, we will put
@@ -898,14 +907,14 @@ static int init_luntable(struct cxlflash_cfg *cfg, struct llun_info *lli)
                lind = lli->lun_index = cfg->last_lun_index[chan];
                writeq_be(lli->lun_id[chan], &agm->fc_port[chan][lind]);
                cfg->last_lun_index[chan]--;
-               pr_debug("%s: Virtual LUN on slot %d  chan=%d, id=%llx\n",
-                        __func__, lind, chan, lli->lun_id[chan]);
+               dev_dbg(dev, "%s: Virtual LUN on slot %d  chan=%d id=%llx\n",
+                       __func__, lind, chan, lli->lun_id[chan]);
        }
 
        lli->in_table = true;
 out:
        mutex_unlock(&global.mutex);
-       pr_debug("%s: returning rc=%d\n", __func__, rc);
+       dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
        return rc;
 }
 
@@ -923,7 +932,7 @@ out:
  */
 int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg)
 {
-       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata;
+       struct cxlflash_cfg *cfg = shost_priv(sdev->host);
        struct device *dev = &cfg->dev->dev;
        struct llun_info *lli = sdev->hostdata;
        struct glun_info *gli = lli->parent;
@@ -942,14 +951,14 @@ int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg)
        struct ctx_info *ctxi = NULL;
        struct sisl_rht_entry *rhte = NULL;
 
-       pr_debug("%s: ctxid=%llu ls=0x%llx\n", __func__, ctxid, lun_size);
+       dev_dbg(dev, "%s: ctxid=%llu ls=%llu\n", __func__, ctxid, lun_size);
 
        /* Setup the LUNs block allocator on first call */
        mutex_lock(&gli->mutex);
        if (gli->mode == MODE_NONE) {
                rc = init_vlun(lli);
                if (rc) {
-                       dev_err(dev, "%s: call to init_vlun failed rc=%d!\n",
+                       dev_err(dev, "%s: init_vlun failed rc=%d\n",
                                __func__, rc);
                        rc = -ENOMEM;
                        goto err0;
@@ -958,29 +967,28 @@ int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg)
 
        rc = cxlflash_lun_attach(gli, MODE_VIRTUAL, true);
        if (unlikely(rc)) {
-               dev_err(dev, "%s: Failed to attach to LUN! (VIRTUAL)\n",
-                       __func__);
+               dev_err(dev, "%s: Failed attach to LUN (VIRTUAL)\n", __func__);
                goto err0;
        }
        mutex_unlock(&gli->mutex);
 
        rc = init_luntable(cfg, lli);
        if (rc) {
-               dev_err(dev, "%s: call to init_luntable failed rc=%d!\n",
-                       __func__, rc);
+               dev_err(dev, "%s: init_luntable failed rc=%d\n", __func__, rc);
                goto err1;
        }
 
        ctxi = get_context(cfg, rctxid, lli, 0);
        if (unlikely(!ctxi)) {
-               dev_err(dev, "%s: Bad context! (%llu)\n", __func__, ctxid);
+               dev_err(dev, "%s: Bad context ctxid=%llu\n", __func__, ctxid);
                rc = -EINVAL;
                goto err1;
        }
 
        rhte = rhte_checkout(ctxi, lli);
        if (unlikely(!rhte)) {
-               dev_err(dev, "%s: too many opens for this context\n", __func__);
+               dev_err(dev, "%s: too many opens ctxid=%llu\n",
+                       __func__, ctxid);
                rc = -EMFILE;   /* too many opens  */
                goto err1;
        }
@@ -996,7 +1004,7 @@ int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg)
        resize.rsrc_handle = rsrc_handle;
        rc = _cxlflash_vlun_resize(sdev, ctxi, &resize);
        if (rc) {
-               dev_err(dev, "%s: resize failed rc %d\n", __func__, rc);
+               dev_err(dev, "%s: resize failed rc=%d\n", __func__, rc);
                goto err2;
        }
        last_lba = resize.last_lba;
@@ -1013,8 +1021,8 @@ int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg)
 out:
        if (likely(ctxi))
                put_context(ctxi);
-       pr_debug("%s: returning handle 0x%llx rc=%d llba %lld\n",
-                __func__, rsrc_handle, rc, last_lba);
+       dev_dbg(dev, "%s: returning handle=%llu rc=%d llba=%llu\n",
+               __func__, rsrc_handle, rc, last_lba);
        return rc;
 
 err2:
@@ -1047,6 +1055,8 @@ static int clone_lxt(struct afu *afu,
                     struct sisl_rht_entry *rhte,
                     struct sisl_rht_entry *rhte_src)
 {
+       struct cxlflash_cfg *cfg = afu->parent;
+       struct device *dev = &cfg->dev->dev;
        struct sisl_lxt_entry *lxt;
        u32 ngrps;
        u64 aun;                /* chunk# allocated by block allocator */
@@ -1101,7 +1111,7 @@ static int clone_lxt(struct afu *afu,
 
        cxlflash_afu_sync(afu, ctxid, rhndl, AFU_LW_SYNC);
 
-       pr_debug("%s: returning\n", __func__);
+       dev_dbg(dev, "%s: returning\n", __func__);
        return 0;
 }
 
@@ -1120,7 +1130,8 @@ static int clone_lxt(struct afu *afu,
 int cxlflash_disk_clone(struct scsi_device *sdev,
                        struct dk_cxlflash_clone *clone)
 {
-       struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata;
+       struct cxlflash_cfg *cfg = shost_priv(sdev->host);
+       struct device *dev = &cfg->dev->dev;
        struct llun_info *lli = sdev->hostdata;
        struct glun_info *gli = lli->parent;
        struct blka *blka = &gli->blka;
@@ -1140,8 +1151,8 @@ int cxlflash_disk_clone(struct scsi_device *sdev,
        bool found;
        LIST_HEAD(sidecar);
 
-       pr_debug("%s: ctxid_src=%llu ctxid_dst=%llu\n",
-                __func__, ctxid_src, ctxid_dst);
+       dev_dbg(dev, "%s: ctxid_src=%llu ctxid_dst=%llu\n",
+               __func__, ctxid_src, ctxid_dst);
 
        /* Do not clone yourself */
        if (unlikely(rctxid_src == rctxid_dst)) {
@@ -1151,16 +1162,16 @@ int cxlflash_disk_clone(struct scsi_device *sdev,
 
        if (unlikely(gli->mode != MODE_VIRTUAL)) {
                rc = -EINVAL;
-               pr_debug("%s: Clone not supported on physical LUNs! (%d)\n",
-                        __func__, gli->mode);
+               dev_dbg(dev, "%s: Only supported on virtual LUNs mode=%u\n",
+                       __func__, gli->mode);
                goto out;
        }
 
        ctxi_src = get_context(cfg, rctxid_src, lli, CTX_CTRL_CLONE);
        ctxi_dst = get_context(cfg, rctxid_dst, lli, 0);
        if (unlikely(!ctxi_src || !ctxi_dst)) {
-               pr_debug("%s: Bad context! (%llu,%llu)\n", __func__,
-                        ctxid_src, ctxid_dst);
+               dev_dbg(dev, "%s: Bad context ctxid_src=%llu ctxid_dst=%llu\n",
+                       __func__, ctxid_src, ctxid_dst);
                rc = -EINVAL;
                goto out;
        }
@@ -1185,8 +1196,8 @@ int cxlflash_disk_clone(struct scsi_device *sdev,
                        lun_access_dst = kzalloc(sizeof(*lun_access_dst),
                                                 GFP_KERNEL);
                        if (unlikely(!lun_access_dst)) {
-                               pr_err("%s: Unable to allocate lun_access!\n",
-                                      __func__);
+                               dev_err(dev, "%s: lun_access allocation fail\n",
+                                       __func__);
                                rc = -ENOMEM;
                                goto out;
                        }
@@ -1197,7 +1208,7 @@ int cxlflash_disk_clone(struct scsi_device *sdev,
        }
 
        if (unlikely(!ctxi_src->rht_out)) {
-               pr_debug("%s: Nothing to clone!\n", __func__);
+               dev_dbg(dev, "%s: Nothing to clone\n", __func__);
                goto out_success;
        }
 
@@ -1256,7 +1267,7 @@ out:
                put_context(ctxi_src);
        if (ctxi_dst)
                put_context(ctxi_dst);
-       pr_debug("%s: returning rc=%d\n", __func__, rc);
+       dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
        return rc;
 
 err:
index 5b80746980b8fffef0345e4abd21b1bd5e1030dc..4a7679f6c73da04f5f57d20f822bef279a5d2643 100644 (file)
@@ -87,12 +87,6 @@ struct clariion_dh_data {
         * I/O buffer for both MODE_SELECT and INQUIRY commands.
         */
        unsigned char buffer[CLARIION_BUFFER_SIZE];
-       /*
-        * SCSI sense buffer for commands -- assumes serial issuance
-        * and completion sequence of all commands for same multipath.
-        */
-       unsigned char sense[SCSI_SENSE_BUFFERSIZE];
-       unsigned int senselen;
        /*
         * LUN state
         */
@@ -116,44 +110,38 @@ struct clariion_dh_data {
 /*
  * Parse MODE_SELECT cmd reply.
  */
-static int trespass_endio(struct scsi_device *sdev, char *sense)
+static int trespass_endio(struct scsi_device *sdev,
+                         struct scsi_sense_hdr *sshdr)
 {
        int err = SCSI_DH_IO;
-       struct scsi_sense_hdr sshdr;
-
-       if (!scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr)) {
-               sdev_printk(KERN_ERR, sdev, "%s: Found valid sense data 0x%2x, "
-                           "0x%2x, 0x%2x while sending CLARiiON trespass "
-                           "command.\n", CLARIION_NAME, sshdr.sense_key,
-                           sshdr.asc, sshdr.ascq);
 
-               if ((sshdr.sense_key == 0x05) && (sshdr.asc == 0x04) &&
-                    (sshdr.ascq == 0x00)) {
-                       /*
-                        * Array based copy in progress -- do not send
-                        * mode_select or copy will be aborted mid-stream.
-                        */
-                       sdev_printk(KERN_INFO, sdev, "%s: Array Based Copy in "
-                                   "progress while sending CLARiiON trespass "
-                                   "command.\n", CLARIION_NAME);
-                       err = SCSI_DH_DEV_TEMP_BUSY;
-               } else if ((sshdr.sense_key == 0x02) && (sshdr.asc == 0x04) &&
-                           (sshdr.ascq == 0x03)) {
-                       /*
-                        * LUN Not Ready - Manual Intervention Required
-                        * indicates in-progress ucode upgrade (NDU).
-                        */
-                       sdev_printk(KERN_INFO, sdev, "%s: Detected in-progress "
-                                   "ucode upgrade NDU operation while sending "
-                                   "CLARiiON trespass command.\n", CLARIION_NAME);
-                       err = SCSI_DH_DEV_TEMP_BUSY;
-               } else
-                       err = SCSI_DH_DEV_FAILED;
-       } else {
-               sdev_printk(KERN_INFO, sdev,
-                           "%s: failed to send MODE SELECT, no sense available\n",
-                           CLARIION_NAME);
-       }
+       sdev_printk(KERN_ERR, sdev, "%s: Found valid sense data 0x%2x, "
+                   "0x%2x, 0x%2x while sending CLARiiON trespass "
+                   "command.\n", CLARIION_NAME, sshdr->sense_key,
+                   sshdr->asc, sshdr->ascq);
+
+       if (sshdr->sense_key == 0x05 && sshdr->asc == 0x04 &&
+           sshdr->ascq == 0x00) {
+               /*
+                * Array based copy in progress -- do not send
+                * mode_select or copy will be aborted mid-stream.
+                */
+               sdev_printk(KERN_INFO, sdev, "%s: Array Based Copy in "
+                           "progress while sending CLARiiON trespass "
+                           "command.\n", CLARIION_NAME);
+               err = SCSI_DH_DEV_TEMP_BUSY;
+       } else if (sshdr->sense_key == 0x02 && sshdr->asc == 0x04 &&
+                  sshdr->ascq == 0x03) {
+               /*
+                * LUN Not Ready - Manual Intervention Required
+                * indicates in-progress ucode upgrade (NDU).
+                */
+               sdev_printk(KERN_INFO, sdev, "%s: Detected in-progress "
+                           "ucode upgrade NDU operation while sending "
+                           "CLARiiON trespass command.\n", CLARIION_NAME);
+               err = SCSI_DH_DEV_TEMP_BUSY;
+       } else
+               err = SCSI_DH_DEV_FAILED;
        return err;
 }
 
@@ -257,103 +245,15 @@ out:
        return sp_model;
 }
 
-/*
- * Get block request for REQ_BLOCK_PC command issued to path.  Currently
- * limited to MODE_SELECT (trespass) and INQUIRY (VPD page 0xC0) commands.
- *
- * Uses data and sense buffers in hardware handler context structure and
- * assumes serial servicing of commands, both issuance and completion.
- */
-static struct request *get_req(struct scsi_device *sdev, int cmd,
-                               unsigned char *buffer)
-{
-       struct request *rq;
-       int len = 0;
-
-       rq = blk_get_request(sdev->request_queue,
-                       (cmd != INQUIRY) ? WRITE : READ, GFP_NOIO);
-       if (IS_ERR(rq)) {
-               sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed");
-               return NULL;
-       }
-
-       blk_rq_set_block_pc(rq);
-       rq->cmd_len = COMMAND_SIZE(cmd);
-       rq->cmd[0] = cmd;
-
-       switch (cmd) {
-       case MODE_SELECT:
-               len = sizeof(short_trespass);
-               rq->cmd[1] = 0x10;
-               rq->cmd[4] = len;
-               break;
-       case MODE_SELECT_10:
-               len = sizeof(long_trespass);
-               rq->cmd[1] = 0x10;
-               rq->cmd[8] = len;
-               break;
-       case INQUIRY:
-               len = CLARIION_BUFFER_SIZE;
-               rq->cmd[4] = len;
-               memset(buffer, 0, len);
-               break;
-       default:
-               BUG_ON(1);
-               break;
-       }
-
-       rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
-                        REQ_FAILFAST_DRIVER;
-       rq->timeout = CLARIION_TIMEOUT;
-       rq->retries = CLARIION_RETRIES;
-
-       if (blk_rq_map_kern(rq->q, rq, buffer, len, GFP_NOIO)) {
-               blk_put_request(rq);
-               return NULL;
-       }
-
-       return rq;
-}
-
-static int send_inquiry_cmd(struct scsi_device *sdev, int page,
-                           struct clariion_dh_data *csdev)
-{
-       struct request *rq = get_req(sdev, INQUIRY, csdev->buffer);
-       int err;
-
-       if (!rq)
-               return SCSI_DH_RES_TEMP_UNAVAIL;
-
-       rq->sense = csdev->sense;
-       memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
-       rq->sense_len = csdev->senselen = 0;
-
-       rq->cmd[0] = INQUIRY;
-       if (page != 0) {
-               rq->cmd[1] = 1;
-               rq->cmd[2] = page;
-       }
-       err = blk_execute_rq(sdev->request_queue, NULL, rq, 1);
-       if (err == -EIO) {
-               sdev_printk(KERN_INFO, sdev,
-                           "%s: failed to send %s INQUIRY: %x\n",
-                           CLARIION_NAME, page?"EVPD":"standard",
-                           rq->errors);
-               csdev->senselen = rq->sense_len;
-               err = SCSI_DH_IO;
-       }
-
-       blk_put_request(rq);
-
-       return err;
-}
-
 static int send_trespass_cmd(struct scsi_device *sdev,
                            struct clariion_dh_data *csdev)
 {
-       struct request *rq;
        unsigned char *page22;
-       int err, len, cmd;
+       unsigned char cdb[COMMAND_SIZE(MODE_SELECT)];
+       int err, res = SCSI_DH_OK, len;
+       struct scsi_sense_hdr sshdr;
+       u64 req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
+               REQ_FAILFAST_DRIVER;
 
        if (csdev->flags & CLARIION_SHORT_TRESPASS) {
                page22 = short_trespass;
@@ -361,40 +261,37 @@ static int send_trespass_cmd(struct scsi_device *sdev,
                        /* Set Honor Reservations bit */
                        page22[6] |= 0x80;
                len = sizeof(short_trespass);
-               cmd = MODE_SELECT;
+               cdb[0] = MODE_SELECT;
+               cdb[1] = 0x10;
+               cdb[4] = len;
        } else {
                page22 = long_trespass;
                if (!(csdev->flags & CLARIION_HONOR_RESERVATIONS))
                        /* Set Honor Reservations bit */
                        page22[10] |= 0x80;
                len = sizeof(long_trespass);
-               cmd = MODE_SELECT_10;
+               cdb[0] = MODE_SELECT_10;
+               cdb[8] = len;
        }
        BUG_ON((len > CLARIION_BUFFER_SIZE));
        memcpy(csdev->buffer, page22, len);
 
-       rq = get_req(sdev, cmd, csdev->buffer);
-       if (!rq)
-               return SCSI_DH_RES_TEMP_UNAVAIL;
-
-       rq->sense = csdev->sense;
-       memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
-       rq->sense_len = csdev->senselen = 0;
-
-       err = blk_execute_rq(sdev->request_queue, NULL, rq, 1);
-       if (err == -EIO) {
-               if (rq->sense_len) {
-                       err = trespass_endio(sdev, csdev->sense);
-               } else {
+       err = scsi_execute_req_flags(sdev, cdb, DMA_TO_DEVICE,
+                                    csdev->buffer, len, &sshdr,
+                                    CLARIION_TIMEOUT * HZ, CLARIION_RETRIES,
+                                    NULL, req_flags, 0);
+       if (err) {
+               if (scsi_sense_valid(&sshdr))
+                       res = trespass_endio(sdev, &sshdr);
+               else {
                        sdev_printk(KERN_INFO, sdev,
                                    "%s: failed to send MODE SELECT: %x\n",
-                                   CLARIION_NAME, rq->errors);
+                                   CLARIION_NAME, err);
+                       res = SCSI_DH_IO;
                }
        }
 
-       blk_put_request(rq);
-
-       return err;
+       return res;
 }
 
 static int clariion_check_sense(struct scsi_device *sdev,
@@ -464,21 +361,7 @@ static int clariion_std_inquiry(struct scsi_device *sdev,
        int err;
        char *sp_model;
 
-       err = send_inquiry_cmd(sdev, 0, csdev);
-       if (err != SCSI_DH_OK && csdev->senselen) {
-               struct scsi_sense_hdr sshdr;
-
-               if (scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE,
-                                        &sshdr)) {
-                       sdev_printk(KERN_ERR, sdev, "%s: INQUIRY sense code "
-                                   "%02x/%02x/%02x\n", CLARIION_NAME,
-                                   sshdr.sense_key, sshdr.asc, sshdr.ascq);
-               }
-               err = SCSI_DH_IO;
-               goto out;
-       }
-
-       sp_model = parse_sp_model(sdev, csdev->buffer);
+       sp_model = parse_sp_model(sdev, sdev->inquiry);
        if (!sp_model) {
                err = SCSI_DH_DEV_UNSUPP;
                goto out;
@@ -500,30 +383,12 @@ out:
 static int clariion_send_inquiry(struct scsi_device *sdev,
                                 struct clariion_dh_data *csdev)
 {
-       int err, retry = CLARIION_RETRIES;
-
-retry:
-       err = send_inquiry_cmd(sdev, 0xC0, csdev);
-       if (err != SCSI_DH_OK && csdev->senselen) {
-               struct scsi_sense_hdr sshdr;
-
-               err = scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE,
-                                          &sshdr);
-               if (!err)
-                       return SCSI_DH_IO;
-
-               err = clariion_check_sense(sdev, &sshdr);
-               if (retry > 0 && err == ADD_TO_MLQUEUE) {
-                       retry--;
-                       goto retry;
-               }
-               sdev_printk(KERN_ERR, sdev, "%s: INQUIRY sense code "
-                           "%02x/%02x/%02x\n", CLARIION_NAME,
-                             sshdr.sense_key, sshdr.asc, sshdr.ascq);
-               err = SCSI_DH_IO;
-       } else {
+       int err = SCSI_DH_IO;
+
+       if (!scsi_get_vpd_page(sdev, 0xC0, csdev->buffer,
+                              CLARIION_BUFFER_SIZE))
                err = parse_sp_info_reply(sdev, csdev);
-       }
+
        return err;
 }
 
index 308e87195dc1ec60b076f03671000945fde56919..be43c940636df64127d19c050174bf4f189d9eb4 100644 (file)
 #define HP_SW_PATH_PASSIVE             1
 
 struct hp_sw_dh_data {
-       unsigned char sense[SCSI_SENSE_BUFFERSIZE];
        int path_state;
        int retries;
        int retry_cnt;
        struct scsi_device *sdev;
-       activate_complete       callback_fn;
-       void                    *callback_data;
 };
 
 static int hp_sw_start_stop(struct hp_sw_dh_data *);
@@ -56,43 +53,34 @@ static int hp_sw_start_stop(struct hp_sw_dh_data *);
  *
  * Returns SCSI_DH_DEV_OFFLINED if the sdev is on the passive path
  */
-static int tur_done(struct scsi_device *sdev, unsigned char *sense)
+static int tur_done(struct scsi_device *sdev, struct hp_sw_dh_data *h,
+                   struct scsi_sense_hdr *sshdr)
 {
-       struct scsi_sense_hdr sshdr;
-       int ret;
+       int ret = SCSI_DH_IO;
 
-       ret = scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr);
-       if (!ret) {
-               sdev_printk(KERN_WARNING, sdev,
-                           "%s: sending tur failed, no sense available\n",
-                           HP_SW_NAME);
-               ret = SCSI_DH_IO;
-               goto done;
-       }
-       switch (sshdr.sense_key) {
+       switch (sshdr->sense_key) {
        case UNIT_ATTENTION:
                ret = SCSI_DH_IMM_RETRY;
                break;
        case NOT_READY:
-               if ((sshdr.asc == 0x04) && (sshdr.ascq == 2)) {
+               if (sshdr->asc == 0x04 && sshdr->ascq == 2) {
                        /*
                         * LUN not ready - Initialization command required
                         *
                         * This is the passive path
                         */
-                       ret = SCSI_DH_DEV_OFFLINED;
+                       h->path_state = HP_SW_PATH_PASSIVE;
+                       ret = SCSI_DH_OK;
                        break;
                }
                /* Fallthrough */
        default:
                sdev_printk(KERN_WARNING, sdev,
                           "%s: sending tur failed, sense %x/%x/%x\n",
-                          HP_SW_NAME, sshdr.sense_key, sshdr.asc,
-                          sshdr.ascq);
+                          HP_SW_NAME, sshdr->sense_key, sshdr->asc,
+                          sshdr->ascq);
                break;
        }
-
-done:
        return ret;
 }
 
@@ -105,130 +93,35 @@ done:
  */
 static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h)
 {
-       struct request *req;
-       int ret;
+       unsigned char cmd[6] = { TEST_UNIT_READY };
+       struct scsi_sense_hdr sshdr;
+       int ret = SCSI_DH_OK, res;
+       u64 req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
+               REQ_FAILFAST_DRIVER;
 
 retry:
-       req = blk_get_request(sdev->request_queue, WRITE, GFP_NOIO);
-       if (IS_ERR(req))
-               return SCSI_DH_RES_TEMP_UNAVAIL;
-
-       blk_rq_set_block_pc(req);
-       req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
-                         REQ_FAILFAST_DRIVER;
-       req->cmd_len = COMMAND_SIZE(TEST_UNIT_READY);
-       req->cmd[0] = TEST_UNIT_READY;
-       req->timeout = HP_SW_TIMEOUT;
-       req->sense = h->sense;
-       memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
-       req->sense_len = 0;
-
-       ret = blk_execute_rq(req->q, NULL, req, 1);
-       if (ret == -EIO) {
-               if (req->sense_len > 0) {
-                       ret = tur_done(sdev, h->sense);
-               } else {
+       res = scsi_execute_req_flags(sdev, cmd, DMA_NONE, NULL, 0, &sshdr,
+                                    HP_SW_TIMEOUT, HP_SW_RETRIES,
+                                    NULL, req_flags, 0);
+       if (res) {
+               if (scsi_sense_valid(&sshdr))
+                       ret = tur_done(sdev, h, &sshdr);
+               else {
                        sdev_printk(KERN_WARNING, sdev,
                                    "%s: sending tur failed with %x\n",
-                                   HP_SW_NAME, req->errors);
+                                   HP_SW_NAME, res);
                        ret = SCSI_DH_IO;
                }
        } else {
                h->path_state = HP_SW_PATH_ACTIVE;
                ret = SCSI_DH_OK;
        }
-       if (ret == SCSI_DH_IMM_RETRY) {
-               blk_put_request(req);
+       if (ret == SCSI_DH_IMM_RETRY)
                goto retry;
-       }
-       if (ret == SCSI_DH_DEV_OFFLINED) {
-               h->path_state = HP_SW_PATH_PASSIVE;
-               ret = SCSI_DH_OK;
-       }
-
-       blk_put_request(req);
 
        return ret;
 }
 
-/*
- * start_done - Handle START STOP UNIT return status
- * @sdev: sdev the command has been sent to
- * @errors: blk error code
- */
-static int start_done(struct scsi_device *sdev, unsigned char *sense)
-{
-       struct scsi_sense_hdr sshdr;
-       int rc;
-
-       rc = scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr);
-       if (!rc) {
-               sdev_printk(KERN_WARNING, sdev,
-                           "%s: sending start_stop_unit failed, "
-                           "no sense available\n",
-                           HP_SW_NAME);
-               return SCSI_DH_IO;
-       }
-       switch (sshdr.sense_key) {
-       case NOT_READY:
-               if ((sshdr.asc == 0x04) && (sshdr.ascq == 3)) {
-                       /*
-                        * LUN not ready - manual intervention required
-                        *
-                        * Switch-over in progress, retry.
-                        */
-                       rc = SCSI_DH_RETRY;
-                       break;
-               }
-               /* fall through */
-       default:
-               sdev_printk(KERN_WARNING, sdev,
-                          "%s: sending start_stop_unit failed, sense %x/%x/%x\n",
-                          HP_SW_NAME, sshdr.sense_key, sshdr.asc,
-                          sshdr.ascq);
-               rc = SCSI_DH_IO;
-       }
-
-       return rc;
-}
-
-static void start_stop_endio(struct request *req, int error)
-{
-       struct hp_sw_dh_data *h = req->end_io_data;
-       unsigned err = SCSI_DH_OK;
-
-       if (error || host_byte(req->errors) != DID_OK ||
-                       msg_byte(req->errors) != COMMAND_COMPLETE) {
-               sdev_printk(KERN_WARNING, h->sdev,
-                           "%s: sending start_stop_unit failed with %x\n",
-                           HP_SW_NAME, req->errors);
-               err = SCSI_DH_IO;
-               goto done;
-       }
-
-       if (req->sense_len > 0) {
-               err = start_done(h->sdev, h->sense);
-               if (err == SCSI_DH_RETRY) {
-                       err = SCSI_DH_IO;
-                       if (--h->retry_cnt) {
-                               blk_put_request(req);
-                               err = hp_sw_start_stop(h);
-                               if (err == SCSI_DH_OK)
-                                       return;
-                       }
-               }
-       }
-done:
-       req->end_io_data = NULL;
-       __blk_put_request(req->q, req);
-       if (h->callback_fn) {
-               h->callback_fn(h->callback_data, err);
-               h->callback_fn = h->callback_data = NULL;
-       }
-       return;
-
-}
-
 /*
  * hp_sw_start_stop - Send START STOP UNIT command
  * @sdev: sdev command should be sent to
@@ -237,26 +130,48 @@ done:
  */
 static int hp_sw_start_stop(struct hp_sw_dh_data *h)
 {
-       struct request *req;
-
-       req = blk_get_request(h->sdev->request_queue, WRITE, GFP_ATOMIC);
-       if (IS_ERR(req))
-               return SCSI_DH_RES_TEMP_UNAVAIL;
-
-       blk_rq_set_block_pc(req);
-       req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
-                         REQ_FAILFAST_DRIVER;
-       req->cmd_len = COMMAND_SIZE(START_STOP);
-       req->cmd[0] = START_STOP;
-       req->cmd[4] = 1;        /* Start spin cycle */
-       req->timeout = HP_SW_TIMEOUT;
-       req->sense = h->sense;
-       memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
-       req->sense_len = 0;
-       req->end_io_data = h;
+       unsigned char cmd[6] = { START_STOP, 0, 0, 0, 1, 0 };
+       struct scsi_sense_hdr sshdr;
+       struct scsi_device *sdev = h->sdev;
+       int res, rc = SCSI_DH_OK;
+       int retry_cnt = HP_SW_RETRIES;
+       u64 req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
+               REQ_FAILFAST_DRIVER;
 
-       blk_execute_rq_nowait(req->q, NULL, req, 1, start_stop_endio);
-       return SCSI_DH_OK;
+retry:
+       res = scsi_execute_req_flags(sdev, cmd, DMA_NONE, NULL, 0, &sshdr,
+                                    HP_SW_TIMEOUT, HP_SW_RETRIES,
+                                    NULL, req_flags, 0);
+       if (res) {
+               if (!scsi_sense_valid(&sshdr)) {
+                       sdev_printk(KERN_WARNING, sdev,
+                                   "%s: sending start_stop_unit failed, "
+                                   "no sense available\n", HP_SW_NAME);
+                       return SCSI_DH_IO;
+               }
+               switch (sshdr.sense_key) {
+               case NOT_READY:
+                       if (sshdr.asc == 0x04 && sshdr.ascq == 3) {
+                               /*
+                                * LUN not ready - manual intervention required
+                                *
+                                * Switch-over in progress, retry.
+                                */
+                               if (--retry_cnt)
+                                       goto retry;
+                               rc = SCSI_DH_RETRY;
+                               break;
+                       }
+                       /* fall through */
+               default:
+                       sdev_printk(KERN_WARNING, sdev,
+                                   "%s: sending start_stop_unit failed, "
+                                   "sense %x/%x/%x\n", HP_SW_NAME,
+                                   sshdr.sense_key, sshdr.asc, sshdr.ascq);
+                       rc = SCSI_DH_IO;
+               }
+       }
+       return rc;
 }
 
 static int hp_sw_prep_fn(struct scsi_device *sdev, struct request *req)
@@ -290,15 +205,8 @@ static int hp_sw_activate(struct scsi_device *sdev,
 
        ret = hp_sw_tur(sdev, h);
 
-       if (ret == SCSI_DH_OK && h->path_state == HP_SW_PATH_PASSIVE) {
-               h->retry_cnt = h->retries;
-               h->callback_fn = fn;
-               h->callback_data = data;
+       if (ret == SCSI_DH_OK && h->path_state == HP_SW_PATH_PASSIVE)
                ret = hp_sw_start_stop(h);
-               if (ret == SCSI_DH_OK)
-                       return 0;
-               h->callback_fn = h->callback_data = NULL;
-       }
 
        if (fn)
                fn(data, ret);
index 00d9c326158eba8f4e94777e674873a9d3cd0c8d..b64eaae8533d99ce807a3957beac8e048052495a 100644 (file)
@@ -205,7 +205,6 @@ struct rdac_dh_data {
 #define RDAC_NON_PREFERRED     1
        char                    preferred;
 
-       unsigned char           sense[SCSI_SENSE_BUFFERSIZE];
        union                   {
                struct c2_inquiry c2;
                struct c4_inquiry c4;
@@ -262,40 +261,12 @@ do { \
                sdev_printk(KERN_INFO, sdev, RDAC_NAME ": " f "\n", ## arg); \
 } while (0);
 
-static struct request *get_rdac_req(struct scsi_device *sdev,
-                       void *buffer, unsigned buflen, int rw)
+static unsigned int rdac_failover_get(struct rdac_controller *ctlr,
+                                     struct list_head *list,
+                                     unsigned char *cdb)
 {
-       struct request *rq;
-       struct request_queue *q = sdev->request_queue;
-
-       rq = blk_get_request(q, rw, GFP_NOIO);
-
-       if (IS_ERR(rq)) {
-               sdev_printk(KERN_INFO, sdev,
-                               "get_rdac_req: blk_get_request failed.\n");
-               return NULL;
-       }
-       blk_rq_set_block_pc(rq);
-
-       if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_NOIO)) {
-               blk_put_request(rq);
-               sdev_printk(KERN_INFO, sdev,
-                               "get_rdac_req: blk_rq_map_kern failed.\n");
-               return NULL;
-       }
-
-       rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
-                        REQ_FAILFAST_DRIVER;
-       rq->retries = RDAC_RETRIES;
-       rq->timeout = RDAC_TIMEOUT;
-
-       return rq;
-}
-
-static struct request *rdac_failover_get(struct scsi_device *sdev,
-                       struct rdac_dh_data *h, struct list_head *list)
-{
-       struct request *rq;
+       struct scsi_device *sdev = ctlr->ms_sdev;
+       struct rdac_dh_data *h = sdev->handler_data;
        struct rdac_mode_common *common;
        unsigned data_size;
        struct rdac_queue_data *qdata;
@@ -332,27 +303,17 @@ static struct request *rdac_failover_get(struct scsi_device *sdev,
                lun_table[qdata->h->lun] = 0x81;
        }
 
-       /* get request for block layer packet command */
-       rq = get_rdac_req(sdev, &h->ctlr->mode_select, data_size, WRITE);
-       if (!rq)
-               return NULL;
-
        /* Prepare the command. */
        if (h->ctlr->use_ms10) {
-               rq->cmd[0] = MODE_SELECT_10;
-               rq->cmd[7] = data_size >> 8;
-               rq->cmd[8] = data_size & 0xff;
+               cdb[0] = MODE_SELECT_10;
+               cdb[7] = data_size >> 8;
+               cdb[8] = data_size & 0xff;
        } else {
-               rq->cmd[0] = MODE_SELECT;
-               rq->cmd[4] = data_size;
+               cdb[0] = MODE_SELECT;
+               cdb[4] = data_size;
        }
-       rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);
-
-       rq->sense = h->sense;
-       memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
-       rq->sense_len = 0;
 
-       return rq;
+       return data_size;
 }
 
 static void release_controller(struct kref *kref)
@@ -400,46 +361,14 @@ static struct rdac_controller *get_controller(int index, char *array_name,
        return ctlr;
 }
 
-static int submit_inquiry(struct scsi_device *sdev, int page_code,
-                         unsigned int len, struct rdac_dh_data *h)
-{
-       struct request *rq;
-       struct request_queue *q = sdev->request_queue;
-       int err = SCSI_DH_RES_TEMP_UNAVAIL;
-
-       rq = get_rdac_req(sdev, &h->inq, len, READ);
-       if (!rq)
-               goto done;
-
-       /* Prepare the command. */
-       rq->cmd[0] = INQUIRY;
-       rq->cmd[1] = 1;
-       rq->cmd[2] = page_code;
-       rq->cmd[4] = len;
-       rq->cmd_len = COMMAND_SIZE(INQUIRY);
-
-       rq->sense = h->sense;
-       memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
-       rq->sense_len = 0;
-
-       err = blk_execute_rq(q, NULL, rq, 1);
-       if (err == -EIO)
-               err = SCSI_DH_IO;
-
-       blk_put_request(rq);
-done:
-       return err;
-}
-
 static int get_lun_info(struct scsi_device *sdev, struct rdac_dh_data *h,
                        char *array_name, u8 *array_id)
 {
-       int err, i;
-       struct c8_inquiry *inqp;
+       int err = SCSI_DH_IO, i;
+       struct c8_inquiry *inqp = &h->inq.c8;
 
-       err = submit_inquiry(sdev, 0xC8, sizeof(struct c8_inquiry), h);
-       if (err == SCSI_DH_OK) {
-               inqp = &h->inq.c8;
+       if (!scsi_get_vpd_page(sdev, 0xC8, (unsigned char *)inqp,
+                              sizeof(struct c8_inquiry))) {
                if (inqp->page_code != 0xc8)
                        return SCSI_DH_NOSYS;
                if (inqp->page_id[0] != 'e' || inqp->page_id[1] != 'd' ||
@@ -453,20 +382,20 @@ static int get_lun_info(struct scsi_device *sdev, struct rdac_dh_data *h,
                *(array_name+ARRAY_LABEL_LEN-1) = '\0';
                memset(array_id, 0, UNIQUE_ID_LEN);
                memcpy(array_id, inqp->array_unique_id, inqp->array_uniq_id_len);
+               err = SCSI_DH_OK;
        }
        return err;
 }
 
 static int check_ownership(struct scsi_device *sdev, struct rdac_dh_data *h)
 {
-       int err, access_state;
+       int err = SCSI_DH_IO, access_state;
        struct rdac_dh_data *tmp;
-       struct c9_inquiry *inqp;
+       struct c9_inquiry *inqp = &h->inq.c9;
 
        h->state = RDAC_STATE_ACTIVE;
-       err = submit_inquiry(sdev, 0xC9, sizeof(struct c9_inquiry), h);
-       if (err == SCSI_DH_OK) {
-               inqp = &h->inq.c9;
+       if (!scsi_get_vpd_page(sdev, 0xC9, (unsigned char *)inqp,
+                              sizeof(struct c9_inquiry))) {
                /* detect the operating mode */
                if ((inqp->avte_cvp >> 5) & 0x1)
                        h->mode = RDAC_MODE_IOSHIP; /* LUN in IOSHIP mode */
@@ -501,6 +430,7 @@ static int check_ownership(struct scsi_device *sdev, struct rdac_dh_data *h)
                        tmp->sdev->access_state = access_state;
                }
                rcu_read_unlock();
+               err = SCSI_DH_OK;
        }
 
        return err;
@@ -509,12 +439,11 @@ static int check_ownership(struct scsi_device *sdev, struct rdac_dh_data *h)
 static int initialize_controller(struct scsi_device *sdev,
                struct rdac_dh_data *h, char *array_name, u8 *array_id)
 {
-       int err, index;
-       struct c4_inquiry *inqp;
+       int err = SCSI_DH_IO, index;
+       struct c4_inquiry *inqp = &h->inq.c4;
 
-       err = submit_inquiry(sdev, 0xC4, sizeof(struct c4_inquiry), h);
-       if (err == SCSI_DH_OK) {
-               inqp = &h->inq.c4;
+       if (!scsi_get_vpd_page(sdev, 0xC4, (unsigned char *)inqp,
+                              sizeof(struct c4_inquiry))) {
                /* get the controller index */
                if (inqp->slot_id[1] == 0x31)
                        index = 0;
@@ -530,18 +459,18 @@ static int initialize_controller(struct scsi_device *sdev,
                        h->sdev = sdev;
                }
                spin_unlock(&list_lock);
+               err = SCSI_DH_OK;
        }
        return err;
 }
 
 static int set_mode_select(struct scsi_device *sdev, struct rdac_dh_data *h)
 {
-       int err;
-       struct c2_inquiry *inqp;
+       int err = SCSI_DH_IO;
+       struct c2_inquiry *inqp = &h->inq.c2;
 
-       err = submit_inquiry(sdev, 0xC2, sizeof(struct c2_inquiry), h);
-       if (err == SCSI_DH_OK) {
-               inqp = &h->inq.c2;
+       if (!scsi_get_vpd_page(sdev, 0xC2, (unsigned char *)inqp,
+                              sizeof(struct c2_inquiry))) {
                /*
                 * If more than MODE6_MAX_LUN luns are supported, use
                 * mode select 10
@@ -550,36 +479,35 @@ static int set_mode_select(struct scsi_device *sdev, struct rdac_dh_data *h)
                        h->ctlr->use_ms10 = 1;
                else
                        h->ctlr->use_ms10 = 0;
+               err = SCSI_DH_OK;
        }
        return err;
 }
 
 static int mode_select_handle_sense(struct scsi_device *sdev,
-                                       unsigned char *sensebuf)
+                                   struct scsi_sense_hdr *sense_hdr)
 {
-       struct scsi_sense_hdr sense_hdr;
-       int err = SCSI_DH_IO, ret;
+       int err = SCSI_DH_IO;
        struct rdac_dh_data *h = sdev->handler_data;
 
-       ret = scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE, &sense_hdr);
-       if (!ret)
+       if (!scsi_sense_valid(sense_hdr))
                goto done;
 
-       switch (sense_hdr.sense_key) {
+       switch (sense_hdr->sense_key) {
        case NO_SENSE:
        case ABORTED_COMMAND:
        case UNIT_ATTENTION:
                err = SCSI_DH_RETRY;
                break;
        case NOT_READY:
-               if (sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x01)
+               if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x01)
                        /* LUN Not Ready and is in the Process of Becoming
                         * Ready
                         */
                        err = SCSI_DH_RETRY;
                break;
        case ILLEGAL_REQUEST:
-               if (sense_hdr.asc == 0x91 && sense_hdr.ascq == 0x36)
+               if (sense_hdr->asc == 0x91 && sense_hdr->ascq == 0x36)
                        /*
                         * Command Lock contention
                         */
@@ -592,7 +520,7 @@ static int mode_select_handle_sense(struct scsi_device *sdev,
        RDAC_LOG(RDAC_LOG_FAILOVER, sdev, "array %s, ctlr %d, "
                "MODE_SELECT returned with sense %02x/%02x/%02x",
                (char *) h->ctlr->array_name, h->ctlr->index,
-               sense_hdr.sense_key, sense_hdr.asc, sense_hdr.ascq);
+               sense_hdr->sense_key, sense_hdr->asc, sense_hdr->ascq);
 
 done:
        return err;
@@ -602,13 +530,16 @@ static void send_mode_select(struct work_struct *work)
 {
        struct rdac_controller *ctlr =
                container_of(work, struct rdac_controller, ms_work);
-       struct request *rq;
        struct scsi_device *sdev = ctlr->ms_sdev;
        struct rdac_dh_data *h = sdev->handler_data;
-       struct request_queue *q = sdev->request_queue;
-       int err, retry_cnt = RDAC_RETRY_COUNT;
+       int err = SCSI_DH_OK, retry_cnt = RDAC_RETRY_COUNT;
        struct rdac_queue_data *tmp, *qdata;
        LIST_HEAD(list);
+       unsigned char cdb[COMMAND_SIZE(MODE_SELECT_10)];
+       struct scsi_sense_hdr sshdr;
+       unsigned int data_size;
+       u64 req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
+               REQ_FAILFAST_DRIVER;
 
        spin_lock(&ctlr->ms_lock);
        list_splice_init(&ctlr->ms_head, &list);
@@ -616,21 +547,19 @@ static void send_mode_select(struct work_struct *work)
        ctlr->ms_sdev = NULL;
        spin_unlock(&ctlr->ms_lock);
 
-retry:
-       err = SCSI_DH_RES_TEMP_UNAVAIL;
-       rq = rdac_failover_get(sdev, h, &list);
-       if (!rq)
-               goto done;
+ retry:
+       data_size = rdac_failover_get(ctlr, &list, cdb);
 
        RDAC_LOG(RDAC_LOG_FAILOVER, sdev, "array %s, ctlr %d, "
                "%s MODE_SELECT command",
                (char *) h->ctlr->array_name, h->ctlr->index,
                (retry_cnt == RDAC_RETRY_COUNT) ? "queueing" : "retrying");
 
-       err = blk_execute_rq(q, NULL, rq, 1);
-       blk_put_request(rq);
-       if (err != SCSI_DH_OK) {
-               err = mode_select_handle_sense(sdev, h->sense);
+       if (scsi_execute_req_flags(sdev, cdb, DMA_TO_DEVICE,
+                                  &h->ctlr->mode_select, data_size, &sshdr,
+                                  RDAC_TIMEOUT * HZ,
+                                  RDAC_RETRIES, NULL, req_flags, 0)) {
+               err = mode_select_handle_sense(sdev, &sshdr);
                if (err == SCSI_DH_RETRY && retry_cnt--)
                        goto retry;
                if (err == SCSI_DH_IMM_RETRY)
@@ -643,7 +572,6 @@ retry:
                                (char *) h->ctlr->array_name, h->ctlr->index);
        }
 
-done:
        list_for_each_entry_safe(qdata, tmp, &list, entry) {
                list_del(&qdata->entry);
                if (err == SCSI_DH_OK)
index 5f75e638ec95af5476f15780bf4fa6f7ea12a0b7..256dd6791fcc8bb0196e359ba6bd509c234080e3 100644 (file)
@@ -2768,16 +2768,12 @@ static int adpt_i2o_activate_hba(adpt_hba* pHba)
  
 static int adpt_i2o_online_hba(adpt_hba* pHba)
 {
-       if (adpt_i2o_systab_send(pHba) < 0) {
-               adpt_i2o_delete_hba(pHba);
+       if (adpt_i2o_systab_send(pHba) < 0)
                return -1;
-       }
        /* In READY state */
 
-       if (adpt_i2o_enable_hba(pHba) < 0) {
-               adpt_i2o_delete_hba(pHba);
+       if (adpt_i2o_enable_hba(pHba) < 0)
                return -1;
-       }
 
        /* In OPERATIONAL state  */
        return 0;
index d6e53aee22952190af34ce0f99fd1984a4d6a9c1..6432a50b26d853aaa2e6ede3f89e3d1982c42b2b 100644 (file)
@@ -237,7 +237,7 @@ static void esas2r_claim_interrupts(struct esas2r_adapter *a)
                flags |= IRQF_SHARED;
 
        esas2r_log(ESAS2R_LOG_INFO,
-                  "esas2r_claim_interrupts irq=%d (%p, %s, %x)",
+                  "esas2r_claim_interrupts irq=%d (%p, %s, %lx)",
                   a->pcid->irq, a, a->name, flags);
 
        if (request_irq(a->pcid->irq,
index 3e8483410f610997746edf9ab65585a1b8982153..b35ed382942120a91588102150ba014c9539f2f5 100644 (file)
@@ -1301,7 +1301,7 @@ int esas2r_ioctl_handler(void *hostdata, int cmd, void __user *arg)
        ioctl = kzalloc(sizeof(struct atto_express_ioctl), GFP_KERNEL);
        if (ioctl == NULL) {
                esas2r_log(ESAS2R_LOG_WARN,
-                          "ioctl_handler kzalloc failed for %d bytes",
+                          "ioctl_handler kzalloc failed for %zu bytes",
                           sizeof(struct atto_express_ioctl));
                return -ENOMEM;
        }
index 7b6397bb5b9438184db03887e262aa8501e20b42..75b9d23cd736307d7da13d9adc972294b7fb470a 100644 (file)
@@ -61,8 +61,8 @@ enum {
 #endif
 };
 
-int esas2r_log(const long level, const char *format, ...);
-int esas2r_log_dev(const long level,
+__printf(2, 3) int esas2r_log(const long level, const char *format, ...);
+__printf(3, 4) int esas2r_log_dev(const long level,
                   const struct device *dev,
                   const char *format,
                   ...);
index 5092c821d0887d09c23679bde31e1295eb71d518..f2e9d8aa979ca66c0f9226834b3d7ae8bd62769d 100644 (file)
@@ -198,7 +198,7 @@ static ssize_t write_hw(struct file *file, struct kobject *kobj,
                                              GFP_KERNEL);
                if (a->local_atto_ioctl == NULL) {
                        esas2r_log(ESAS2R_LOG_WARN,
-                                  "write_hw kzalloc failed for %d bytes",
+                                  "write_hw kzalloc failed for %zu bytes",
                                   sizeof(struct atto_ioctl));
                        return -ENOMEM;
                }
@@ -1186,7 +1186,7 @@ retry:
                } else {
                        esas2r_log(ESAS2R_LOG_CRIT,
                                   "unable to allocate a request for a "
-                                  "device reset (%d:%d)!",
+                                  "device reset (%d:%llu)!",
                                   cmd->device->id,
                                   cmd->device->lun);
                }
index 59150cad03532e1e1ee15ad0d8fcdf35229d07c3..86af57f7c11aa8356accd41ee71b44cc221582ef 100644 (file)
@@ -277,6 +277,7 @@ static struct scsi_host_template fcoe_shost_template = {
        .name = "FCoE Driver",
        .proc_name = FCOE_NAME,
        .queuecommand = fc_queuecommand,
+       .eh_timed_out = fc_eh_timed_out,
        .eh_abort_handler = fc_eh_abort,
        .eh_device_reset_handler = fc_eh_device_reset,
        .eh_host_reset_handler = fc_eh_host_reset,
index 58ce9020d69c5882eebfa46f3ec685fb7b63fef6..ba58b7953263af4d211ccce6abebca907d7b802c 100644 (file)
@@ -106,6 +106,7 @@ static struct scsi_host_template fnic_host_template = {
        .module = THIS_MODULE,
        .name = DRV_NAME,
        .queuecommand = fnic_queuecommand,
+       .eh_timed_out = fc_eh_timed_out,
        .eh_abort_handler = fnic_abort_cmd,
        .eh_device_reset_handler = fnic_device_reset,
        .eh_host_reset_handler = fnic_host_reset,
index 6f9665d50d84bb485d3ba9cf99da05bae0f1c018..67c8dac321ad217895f7ef877e1439748d5456e1 100644 (file)
 #include <linux/blkdev.h>
 #include <linux/module.h>
 #include <scsi/scsi_host.h>
-#include "g_NCR5380.h"
-#include "NCR5380.h"
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/isa.h>
 #include <linux/pnp.h>
 #include <linux/interrupt.h>
 
+/* Definitions for the core NCR5380 driver. */
+
+#define NCR5380_read(reg) \
+       ioread8(hostdata->io + hostdata->offset + (reg))
+#define NCR5380_write(reg, value) \
+       iowrite8(value, hostdata->io + hostdata->offset + (reg))
+
+#define NCR5380_implementation_fields \
+       int offset; \
+       int c400_ctl_status; \
+       int c400_blk_cnt; \
+       int c400_host_buf; \
+       int io_width
+
+#define NCR5380_dma_xfer_len            generic_NCR5380_dma_xfer_len
+#define NCR5380_dma_recv_setup          generic_NCR5380_pread
+#define NCR5380_dma_send_setup          generic_NCR5380_pwrite
+#define NCR5380_dma_residual            NCR5380_dma_residual_none
+
+#define NCR5380_intr                    generic_NCR5380_intr
+#define NCR5380_queue_command           generic_NCR5380_queue_command
+#define NCR5380_abort                   generic_NCR5380_abort
+#define NCR5380_bus_reset               generic_NCR5380_bus_reset
+#define NCR5380_info                    generic_NCR5380_info
+
+#define NCR5380_io_delay(x)             udelay(x)
+
+#include "NCR5380.h"
+
+#define DRV_MODULE_NAME "g_NCR5380"
+
+#define NCR53C400_mem_base 0x3880
+#define NCR53C400_host_buffer 0x3900
+#define NCR53C400_region_size 0x3a00
+
+#define BOARD_NCR5380 0
+#define BOARD_NCR53C400 1
+#define BOARD_NCR53C400A 2
+#define BOARD_DTC3181E 3
+#define BOARD_HP_C2502 4
+
+#define IRQ_AUTO 254
+
 #define MAX_CARDS 8
 
 /* old-style parameters for compatibility */
diff --git a/drivers/scsi/g_NCR5380.h b/drivers/scsi/g_NCR5380.h
deleted file mode 100644 (file)
index 81b22d9..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Generic Generic NCR5380 driver defines
- *
- * Copyright 1993, Drew Eckhardt
- *     Visionary Computing
- *     (Unix and Linux consulting and custom programming)
- *     drew@colorado.edu
- *      +1 (303) 440-4894
- *
- * NCR53C400 extensions (c) 1994,1995,1996, Kevin Lentin
- *    K.Lentin@cs.monash.edu.au
- */
-
-#ifndef GENERIC_NCR5380_H
-#define GENERIC_NCR5380_H
-
-#define DRV_MODULE_NAME "g_NCR5380"
-
-#define NCR5380_read(reg) \
-       ioread8(hostdata->io + hostdata->offset + (reg))
-#define NCR5380_write(reg, value) \
-       iowrite8(value, hostdata->io + hostdata->offset + (reg))
-
-#define NCR5380_implementation_fields \
-       int offset; \
-       int c400_ctl_status; \
-       int c400_blk_cnt; \
-       int c400_host_buf; \
-       int io_width;
-
-#define NCR53C400_mem_base 0x3880
-#define NCR53C400_host_buffer 0x3900
-#define NCR53C400_region_size 0x3a00
-
-#define NCR5380_dma_xfer_len           generic_NCR5380_dma_xfer_len
-#define NCR5380_dma_recv_setup         generic_NCR5380_pread
-#define NCR5380_dma_send_setup         generic_NCR5380_pwrite
-#define NCR5380_dma_residual           NCR5380_dma_residual_none
-
-#define NCR5380_intr generic_NCR5380_intr
-#define NCR5380_queue_command generic_NCR5380_queue_command
-#define NCR5380_abort generic_NCR5380_abort
-#define NCR5380_bus_reset generic_NCR5380_bus_reset
-#define NCR5380_info generic_NCR5380_info
-
-#define NCR5380_io_delay(x)            udelay(x)
-
-#define BOARD_NCR5380  0
-#define BOARD_NCR53C400        1
-#define BOARD_NCR53C400A 2
-#define BOARD_DTC3181E 3
-#define BOARD_HP_C2502 4
-
-#define IRQ_AUTO       254
-
-#endif /* GENERIC_NCR5380_H */
index c0cd505a9ef79caed37cf4a4ee71429d13482ce0..9216deaa3ff5fb2db49cfd786ee809b9426633c7 100644 (file)
@@ -95,6 +95,7 @@ struct hisi_sas_port {
 
 struct hisi_sas_cq {
        struct hisi_hba *hisi_hba;
+       struct tasklet_struct tasklet;
        int     rd_point;
        int     id;
 };
index d50e9cfefd240fb962b10b1a764af910ab94e791..53637a941b94a918d5dc5b15d519d5476c9ba195 100644 (file)
@@ -71,6 +71,8 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task,
                             struct hisi_sas_slot *slot)
 {
        struct device *dev = &hisi_hba->pdev->dev;
+       struct domain_device *device = task->dev;
+       struct hisi_sas_device *sas_dev = device->lldd_dev;
 
        if (!slot->task)
                return;
@@ -97,6 +99,8 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task,
        slot->task = NULL;
        slot->port = NULL;
        hisi_sas_slot_index_free(hisi_hba, slot->idx);
+       if (sas_dev)
+               atomic64_dec(&sas_dev->running_req);
        /* slot memory is fully zeroed when it is reused */
 }
 EXPORT_SYMBOL_GPL(hisi_sas_slot_task_free);
@@ -141,11 +145,10 @@ static void hisi_sas_slot_abort(struct work_struct *work)
        struct hisi_hba *hisi_hba = dev_to_hisi_hba(task->dev);
        struct scsi_cmnd *cmnd = task->uldd_task;
        struct hisi_sas_tmf_task tmf_task;
-       struct domain_device *device = task->dev;
-       struct hisi_sas_device *sas_dev = device->lldd_dev;
        struct scsi_lun lun;
        struct device *dev = &hisi_hba->pdev->dev;
        int tag = abort_slot->idx;
+       unsigned long flags;
 
        if (!(task->task_proto & SAS_PROTOCOL_SSP)) {
                dev_err(dev, "cannot abort slot for non-ssp task\n");
@@ -159,11 +162,11 @@ static void hisi_sas_slot_abort(struct work_struct *work)
        hisi_sas_debug_issue_ssp_tmf(task->dev, lun.scsi_lun, &tmf_task);
 out:
        /* Do cleanup for this task */
+       spin_lock_irqsave(&hisi_hba->lock, flags);
        hisi_sas_slot_task_free(hisi_hba, task, abort_slot);
+       spin_unlock_irqrestore(&hisi_hba->lock, flags);
        if (task->task_done)
                task->task_done(task);
-       if (sas_dev)
-               atomic64_dec(&sas_dev->running_req);
 }
 
 static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba,
@@ -1118,7 +1121,7 @@ hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
        }
 
 exit:
-       dev_info(dev, "internal task abort: task to dev %016llx task=%p "
+       dev_dbg(dev, "internal task abort: task to dev %016llx task=%p "
                "resp: 0x%x sts 0x%x\n",
                SAS_ADDR(device->sas_addr),
                task,
@@ -1450,7 +1453,7 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev,
 
        refclk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(refclk))
-               dev_info(dev, "no ref clk property\n");
+               dev_dbg(dev, "no ref clk property\n");
        else
                hisi_hba->refclk_frequency_mhz = clk_get_rate(refclk) / 1000000;
 
@@ -1549,10 +1552,6 @@ int hisi_sas_probe(struct platform_device *pdev,
 
        hisi_sas_init_add(hisi_hba);
 
-       rc = hisi_hba->hw->hw_init(hisi_hba);
-       if (rc)
-               goto err_out_ha;
-
        rc = scsi_add_host(shost, &pdev->dev);
        if (rc)
                goto err_out_ha;
@@ -1561,6 +1560,10 @@ int hisi_sas_probe(struct platform_device *pdev,
        if (rc)
                goto err_out_register_ha;
 
+       rc = hisi_hba->hw->hw_init(hisi_hba);
+       if (rc)
+               goto err_out_register_ha;
+
        scsi_scan_host(shost);
 
        return 0;
index 8a1be0ba8a22d399002de66c766f0d85f0ea3a4b..854fbeaade3e9c3010f6d2aa18d790e6a2b75fc6 100644 (file)
@@ -1596,6 +1596,7 @@ static irqreturn_t cq_interrupt_v1_hw(int irq, void *p)
                        hisi_hba->complete_hdr[queue];
        u32 irq_value, rd_point = cq->rd_point, wr_point;
 
+       spin_lock(&hisi_hba->lock);
        irq_value = hisi_sas_read32(hisi_hba, OQ_INT_SRC);
 
        hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue);
@@ -1628,6 +1629,7 @@ static irqreturn_t cq_interrupt_v1_hw(int irq, void *p)
        /* update rd_point */
        cq->rd_point = rd_point;
        hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point);
+       spin_unlock(&hisi_hba->lock);
 
        return IRQ_HANDLED;
 }
index b934aec1eebba87ef31ac7c4dc0a831492e4748e..1b214450dcb5df485c89ecfe723957b4d3ae55ae 100644 (file)
 #define TXID_AUTO                      (PORT_BASE + 0xb8)
 #define TXID_AUTO_CT3_OFF              1
 #define TXID_AUTO_CT3_MSK              (0x1 << TXID_AUTO_CT3_OFF)
+#define TX_HARDRST_OFF          2
+#define TX_HARDRST_MSK          (0x1 << TX_HARDRST_OFF)
 #define RX_IDAF_DWORD0                 (PORT_BASE + 0xc4)
 #define RX_IDAF_DWORD1                 (PORT_BASE + 0xc8)
 #define RX_IDAF_DWORD2                 (PORT_BASE + 0xcc)
 #define RX_IDAF_DWORD5                 (PORT_BASE + 0xd8)
 #define RX_IDAF_DWORD6                 (PORT_BASE + 0xdc)
 #define RXOP_CHECK_CFG_H               (PORT_BASE + 0xfc)
+#define CON_CONTROL                    (PORT_BASE + 0x118)
 #define DONE_RECEIVED_TIME             (PORT_BASE + 0x11c)
 #define CHL_INT0                       (PORT_BASE + 0x1b4)
 #define CHL_INT0_HOTPLUG_TOUT_OFF      0
 #define ITCT_HDR_MCR_MSK               (0xf << ITCT_HDR_MCR_OFF)
 #define ITCT_HDR_VLN_OFF               9
 #define ITCT_HDR_VLN_MSK               (0xf << ITCT_HDR_VLN_OFF)
+#define ITCT_HDR_SMP_TIMEOUT_OFF       16
+#define ITCT_HDR_SMP_TIMEOUT_8US       1
+#define ITCT_HDR_SMP_TIMEOUT           (ITCT_HDR_SMP_TIMEOUT_8US * \
+                                        250) /* 2ms */
+#define ITCT_HDR_AWT_CONTINUE_OFF      25
 #define ITCT_HDR_PORT_ID_OFF           28
 #define ITCT_HDR_PORT_ID_MSK           (0xf << ITCT_HDR_PORT_ID_OFF)
 /* qw2 */
@@ -526,6 +534,8 @@ enum {
 #define SATA_PROTOCOL_FPDMA            0x8
 #define SATA_PROTOCOL_ATAPI            0x10
 
+static void hisi_sas_link_timeout_disable_link(unsigned long data);
+
 static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off)
 {
        void __iomem *regs = hisi_hba->regs + off;
@@ -693,6 +703,8 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba,
        qw0 |= ((1 << ITCT_HDR_VALID_OFF) |
                (device->linkrate << ITCT_HDR_MCR_OFF) |
                (1 << ITCT_HDR_VLN_OFF) |
+               (ITCT_HDR_SMP_TIMEOUT << ITCT_HDR_SMP_TIMEOUT_OFF) |
+               (1 << ITCT_HDR_AWT_CONTINUE_OFF) |
                (port->id << ITCT_HDR_PORT_ID_OFF));
        itct->qw0 = cpu_to_le64(qw0);
 
@@ -702,7 +714,7 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba,
 
        /* qw2 */
        if (!dev_is_sata(device))
-               itct->qw2 = cpu_to_le64((500ULL << ITCT_HDR_INLT_OFF) |
+               itct->qw2 = cpu_to_le64((5000ULL << ITCT_HDR_INLT_OFF) |
                                        (0x1ULL << ITCT_HDR_BITLT_OFF) |
                                        (0x32ULL << ITCT_HDR_MCTLT_OFF) |
                                        (0x1ULL << ITCT_HDR_RTOLT_OFF));
@@ -711,7 +723,7 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba,
 static void free_device_v2_hw(struct hisi_hba *hisi_hba,
                              struct hisi_sas_device *sas_dev)
 {
-       u64 qw0, dev_id = sas_dev->device_id;
+       u64 dev_id = sas_dev->device_id;
        struct device *dev = &hisi_hba->pdev->dev;
        struct hisi_sas_itct *itct = &hisi_hba->itct[dev_id];
        u32 reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3);
@@ -735,8 +747,7 @@ static void free_device_v2_hw(struct hisi_hba *hisi_hba,
                        dev_dbg(dev, "got clear ITCT done interrupt\n");
 
                        /* invalid the itct state*/
-                       qw0 = cpu_to_le64(itct->qw0);
-                       qw0 &= ~(1 << ITCT_HDR_VALID_OFF);
+                       memset(itct, 0, sizeof(struct hisi_sas_itct));
                        hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
                                         ENT_INT_SRC3_ITC_INT_MSK);
 
@@ -978,6 +989,50 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
                         upper_32_bits(hisi_hba->initial_fis_dma));
 }
 
+static void hisi_sas_link_timeout_enable_link(unsigned long data)
+{
+       struct hisi_hba *hisi_hba = (struct hisi_hba *)data;
+       int i, reg_val;
+
+       for (i = 0; i < hisi_hba->n_phy; i++) {
+               reg_val = hisi_sas_phy_read32(hisi_hba, i, CON_CONTROL);
+               if (!(reg_val & BIT(0))) {
+                       hisi_sas_phy_write32(hisi_hba, i,
+                                       CON_CONTROL, 0x7);
+                       break;
+               }
+       }
+
+       hisi_hba->timer.function = hisi_sas_link_timeout_disable_link;
+       mod_timer(&hisi_hba->timer, jiffies + msecs_to_jiffies(900));
+}
+
+static void hisi_sas_link_timeout_disable_link(unsigned long data)
+{
+       struct hisi_hba *hisi_hba = (struct hisi_hba *)data;
+       int i, reg_val;
+
+       reg_val = hisi_sas_read32(hisi_hba, PHY_STATE);
+       for (i = 0; i < hisi_hba->n_phy && reg_val; i++) {
+               if (reg_val & BIT(i)) {
+                       hisi_sas_phy_write32(hisi_hba, i,
+                                       CON_CONTROL, 0x6);
+                       break;
+               }
+       }
+
+       hisi_hba->timer.function = hisi_sas_link_timeout_enable_link;
+       mod_timer(&hisi_hba->timer, jiffies + msecs_to_jiffies(100));
+}
+
+static void set_link_timer_quirk(struct hisi_hba *hisi_hba)
+{
+       hisi_hba->timer.data = (unsigned long)hisi_hba;
+       hisi_hba->timer.function = hisi_sas_link_timeout_disable_link;
+       hisi_hba->timer.expires = jiffies + msecs_to_jiffies(1000);
+       add_timer(&hisi_hba->timer);
+}
+
 static int hw_init_v2_hw(struct hisi_hba *hisi_hba)
 {
        struct device *dev = &hisi_hba->pdev->dev;
@@ -1025,14 +1080,21 @@ static void stop_phy_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
 
 static void phy_hard_reset_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
 {
+       struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+       u32 txid_auto;
+
        stop_phy_v2_hw(hisi_hba, phy_no);
+       if (phy->identify.device_type == SAS_END_DEVICE) {
+               txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no, TXID_AUTO);
+               hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO,
+                                       txid_auto | TX_HARDRST_MSK);
+       }
        msleep(100);
        start_phy_v2_hw(hisi_hba, phy_no);
 }
 
-static void start_phys_v2_hw(unsigned long data)
+static void start_phys_v2_hw(struct hisi_hba *hisi_hba)
 {
-       struct hisi_hba *hisi_hba = (struct hisi_hba *)data;
        int i;
 
        for (i = 0; i < hisi_hba->n_phy; i++)
@@ -1041,10 +1103,7 @@ static void start_phys_v2_hw(unsigned long data)
 
 static void phys_init_v2_hw(struct hisi_hba *hisi_hba)
 {
-       struct timer_list *timer = &hisi_hba->timer;
-
-       setup_timer(timer, start_phys_v2_hw, (unsigned long)hisi_hba);
-       mod_timer(timer, jiffies + HZ);
+       start_phys_v2_hw(hisi_hba);
 }
 
 static void sl_notify_v2_hw(struct hisi_hba *hisi_hba, int phy_no)
@@ -1771,8 +1830,6 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot,
        }
 
 out:
-       if (sas_dev)
-               atomic64_dec(&sas_dev->running_req);
 
        hisi_sas_slot_task_free(hisi_hba, task, slot);
        sts = ts->stat;
@@ -2020,9 +2077,12 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
        if (phy->identify.device_type == SAS_END_DEVICE)
                phy->identify.target_port_protocols =
                        SAS_PROTOCOL_SSP;
-       else if (phy->identify.device_type != SAS_PHY_UNUSED)
+       else if (phy->identify.device_type != SAS_PHY_UNUSED) {
                phy->identify.target_port_protocols =
                        SAS_PROTOCOL_SMP;
+               if (!timer_pending(&hisi_hba->timer))
+                       set_link_timer_quirk(hisi_hba);
+       }
        queue_work(hisi_hba->wq, &phy->phyup_ws);
 
 end:
@@ -2033,10 +2093,23 @@ end:
        return res;
 }
 
+static bool check_any_wideports_v2_hw(struct hisi_hba *hisi_hba)
+{
+       u32 port_state;
+
+       port_state = hisi_sas_read32(hisi_hba, PORT_STATE);
+       if (port_state & 0x1ff)
+               return true;
+
+       return false;
+}
+
 static int phy_down_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
 {
        int res = 0;
        u32 phy_state, sl_ctrl, txid_auto;
+       struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+       struct hisi_sas_port *port = phy->port;
 
        hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 1);
 
@@ -2046,6 +2119,10 @@ static int phy_down_v2_hw(int phy_no, struct hisi_hba *hisi_hba)
        sl_ctrl = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL);
        hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL,
                             sl_ctrl & ~SL_CONTROL_CTA_MSK);
+       if (port && !get_wideport_bitmap_v2_hw(hisi_hba, port->id))
+               if (!check_any_wideports_v2_hw(hisi_hba) &&
+                               timer_pending(&hisi_hba->timer))
+                       del_timer(&hisi_hba->timer);
 
        txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no, TXID_AUTO);
        hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO,
@@ -2481,21 +2558,19 @@ static irqreturn_t fatal_axi_int_v2_hw(int irq_no, void *p)
        return IRQ_HANDLED;
 }
 
-static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p)
+static void cq_tasklet_v2_hw(unsigned long val)
 {
-       struct hisi_sas_cq *cq = p;
+       struct hisi_sas_cq *cq = (struct hisi_sas_cq *)val;
        struct hisi_hba *hisi_hba = cq->hisi_hba;
        struct hisi_sas_slot *slot;
        struct hisi_sas_itct *itct;
        struct hisi_sas_complete_v2_hdr *complete_queue;
-       u32 irq_value, rd_point = cq->rd_point, wr_point, dev_id;
+       u32 rd_point = cq->rd_point, wr_point, dev_id;
        int queue = cq->id;
 
        complete_queue = hisi_hba->complete_hdr[queue];
-       irq_value = hisi_sas_read32(hisi_hba, OQ_INT_SRC);
-
-       hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue);
 
+       spin_lock(&hisi_hba->lock);
        wr_point = hisi_sas_read32(hisi_hba, COMPL_Q_0_WR_PTR +
                                   (0x14 * queue));
 
@@ -2545,6 +2620,19 @@ static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p)
        /* update rd_point */
        cq->rd_point = rd_point;
        hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point);
+       spin_unlock(&hisi_hba->lock);
+}
+
+static irqreturn_t cq_interrupt_v2_hw(int irq_no, void *p)
+{
+       struct hisi_sas_cq *cq = p;
+       struct hisi_hba *hisi_hba = cq->hisi_hba;
+       int queue = cq->id;
+
+       hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue);
+
+       tasklet_schedule(&cq->tasklet);
+
        return IRQ_HANDLED;
 }
 
@@ -2726,6 +2814,8 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba)
 
        for (i = 0; i < hisi_hba->queue_count; i++) {
                int idx = i + 96; /* First cq interrupt is irq96 */
+               struct hisi_sas_cq *cq = &hisi_hba->cq[i];
+               struct tasklet_struct *t = &cq->tasklet;
 
                irq = irq_map[idx];
                if (!irq) {
@@ -2742,6 +2832,7 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba)
                                irq, rc);
                        return -ENOENT;
                }
+               tasklet_init(t, cq_tasklet_v2_hw, (unsigned long)cq);
        }
 
        return 0;
@@ -2807,6 +2898,12 @@ static int hisi_sas_v2_probe(struct platform_device *pdev)
 
 static int hisi_sas_v2_remove(struct platform_device *pdev)
 {
+       struct sas_ha_struct *sha = platform_get_drvdata(pdev);
+       struct hisi_hba *hisi_hba = sha->lldd_ha;
+
+       if (timer_pending(&hisi_hba->timer))
+               del_timer(&hisi_hba->timer);
+
        return hisi_sas_remove(pdev);
 }
 
index 258a3f9a25197d4177958f646dc8bca655989312..831a1c8b9f89f4e4eb7376dfde91450f0105e022 100644 (file)
@@ -213,6 +213,10 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
                goto fail;
        }
 
+       error = scsi_init_sense_cache(shost);
+       if (error)
+               goto fail;
+
        if (shost_use_blk_mq(shost)) {
                error = scsi_mq_setup_tags(shost);
                if (error)
@@ -226,19 +230,6 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
                }
        }
 
-       /*
-        * Note that we allocate the freelist even for the MQ case for now,
-        * as we need a command set aside for scsi_reset_provider.  Having
-        * the full host freelist and one command available for that is a
-        * little heavy-handed, but avoids introducing a special allocator
-        * just for this.  Eventually the structure of scsi_reset_provider
-        * will need a major overhaul.
-        */
-       error = scsi_setup_command_freelist(shost);
-       if (error)
-               goto out_destroy_tags;
-
-
        if (!shost->shost_gendev.parent)
                shost->shost_gendev.parent = dev ? dev : &platform_bus;
        if (!dma_dev)
@@ -258,7 +249,7 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
 
        error = device_add(&shost->shost_gendev);
        if (error)
-               goto out_destroy_freelist;
+               goto out_disable_runtime_pm;
 
        scsi_host_set_state(shost, SHOST_RUNNING);
        get_device(shost->shost_gendev.parent);
@@ -308,13 +299,11 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
        device_del(&shost->shost_dev);
  out_del_gendev:
        device_del(&shost->shost_gendev);
- out_destroy_freelist:
+ out_disable_runtime_pm:
        device_disable_async_suspend(&shost->shost_gendev);
        pm_runtime_disable(&shost->shost_gendev);
        pm_runtime_set_suspended(&shost->shost_gendev);
        pm_runtime_put_noidle(&shost->shost_gendev);
-       scsi_destroy_command_freelist(shost);
- out_destroy_tags:
        if (shost_use_blk_mq(shost))
                scsi_mq_destroy_tags(shost);
  fail:
@@ -355,7 +344,6 @@ static void scsi_host_dev_release(struct device *dev)
                kfree(dev_name(&shost->shost_dev));
        }
 
-       scsi_destroy_command_freelist(shost);
        if (shost_use_blk_mq(shost)) {
                if (shost->tag_set.tags)
                        scsi_mq_destroy_tags(shost);
index cbc0c5fe5a60188515dab3dd99be83ce62732e1c..524a0c755ed7e74cd790778ec7c04ae452cc853d 100644 (file)
@@ -5539,8 +5539,8 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
         * Retries always go down the normal I/O path.
         */
        if (likely(cmd->retries == 0 &&
-               cmd->request->cmd_type == REQ_TYPE_FS &&
-               h->acciopath_status)) {
+                       !blk_rq_is_passthrough(cmd->request) &&
+                       h->acciopath_status)) {
                rc = hpsa_ioaccel_submit(h, c, cmd, scsi3addr);
                if (rc == 0)
                        return 0;
@@ -9263,13 +9263,9 @@ static int hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support)
                access = SA5_ioaccel_mode1_access;
                writel(10, &h->cfgtable->HostWrite.CoalIntDelay);
                writel(4, &h->cfgtable->HostWrite.CoalIntCount);
-       } else {
-               if (trans_support & CFGTBL_Trans_io_accel2) {
+       } else
+               if (trans_support & CFGTBL_Trans_io_accel2)
                        access = SA5_ioaccel_mode2_access;
-                       writel(10, &h->cfgtable->HostWrite.CoalIntDelay);
-                       writel(4, &h->cfgtable->HostWrite.CoalIntCount);
-               }
-       }
        writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
        if (hpsa_wait_for_mode_change_ack(h)) {
                dev_err(&h->pdev->dev,
index 64e98295b70703bdf1d9a07a483f472da75a35c5..bf6cdc1066544fa5fe2df6f5396d17ca4b4c8909 100644 (file)
@@ -578,38 +578,38 @@ static unsigned long SA5_ioaccel_mode1_completed(struct ctlr_info *h, u8 q)
 }
 
 static struct access_method SA5_access = {
-       SA5_submit_command,
-       SA5_intr_mask,
-       SA5_intr_pending,
-       SA5_completed,
+       .submit_command = SA5_submit_command,
+       .set_intr_mask = SA5_intr_mask,
+       .intr_pending = SA5_intr_pending,
+       .command_completed = SA5_completed,
 };
 
 static struct access_method SA5_ioaccel_mode1_access = {
-       SA5_submit_command,
-       SA5_performant_intr_mask,
-       SA5_ioaccel_mode1_intr_pending,
-       SA5_ioaccel_mode1_completed,
+       .submit_command = SA5_submit_command,
+       .set_intr_mask = SA5_performant_intr_mask,
+       .intr_pending = SA5_ioaccel_mode1_intr_pending,
+       .command_completed = SA5_ioaccel_mode1_completed,
 };
 
 static struct access_method SA5_ioaccel_mode2_access = {
-       SA5_submit_command_ioaccel2,
-       SA5_performant_intr_mask,
-       SA5_performant_intr_pending,
-       SA5_performant_completed,
+       .submit_command = SA5_submit_command_ioaccel2,
+       .set_intr_mask = SA5_performant_intr_mask,
+       .intr_pending = SA5_performant_intr_pending,
+       .command_completed = SA5_performant_completed,
 };
 
 static struct access_method SA5_performant_access = {
-       SA5_submit_command,
-       SA5_performant_intr_mask,
-       SA5_performant_intr_pending,
-       SA5_performant_completed,
+       .submit_command = SA5_submit_command,
+       .set_intr_mask = SA5_performant_intr_mask,
+       .intr_pending = SA5_performant_intr_pending,
+       .command_completed = SA5_performant_completed,
 };
 
 static struct access_method SA5_performant_access_no_read = {
-       SA5_submit_command_no_read,
-       SA5_performant_intr_mask,
-       SA5_performant_intr_pending,
-       SA5_performant_completed,
+       .submit_command = SA5_submit_command_no_read,
+       .set_intr_mask = SA5_performant_intr_mask,
+       .intr_pending = SA5_performant_intr_pending,
+       .command_completed = SA5_performant_completed,
 };
 
 struct board_type {
index 78b72c28a55df36eaf3f03babde02dfe13598e05..2c92dabb55f6fff07e6a58d48870cc639ec677f7 100644 (file)
@@ -3090,6 +3090,7 @@ static struct scsi_host_template driver_template = {
        .name = "IBM POWER Virtual FC Adapter",
        .proc_name = IBMVFC_NAME,
        .queuecommand = ibmvfc_queuecommand,
+       .eh_timed_out = fc_eh_timed_out,
        .eh_abort_handler = ibmvfc_eh_abort_handler,
        .eh_device_reset_handler = ibmvfc_eh_device_reset_handler,
        .eh_target_reset_handler = ibmvfc_eh_target_reset_handler,
index 50cd01165e355b092fb954d2399f42798d5e3e00..1deb0a9f14a66dcb9f95cd40e0289b32bfee7370 100644 (file)
@@ -2072,6 +2072,7 @@ static struct scsi_host_template driver_template = {
        .name = "IBM POWER Virtual SCSI Adapter " IBMVSCSI_VERSION,
        .proc_name = "ibmvscsi",
        .queuecommand = ibmvscsi_queuecommand,
+       .eh_timed_out = srp_timed_out,
        .eh_abort_handler = ibmvscsi_eh_abort_handler,
        .eh_device_reset_handler = ibmvscsi_eh_device_reset_handler,
        .eh_host_reset_handler = ibmvscsi_eh_host_reset_handler,
index ace4f1f41b8e0bf196e7330cfd3f51d3eadbfc2a..4228aba1f654e10b6d18bf32153a1a0825ce6dc2 100644 (file)
@@ -967,6 +967,7 @@ static struct scsi_host_template iscsi_sw_tcp_sht = {
        .sg_tablesize           = 4096,
        .max_sectors            = 0xFFFF,
        .cmd_per_lun            = ISCSI_DEF_CMD_PER_LUN,
+       .eh_timed_out           = iscsi_eh_cmd_timed_out,
        .eh_abort_handler       = iscsi_eh_abort,
        .eh_device_reset_handler= iscsi_eh_device_reset,
        .eh_target_reset_handler = iscsi_eh_recover_target,
index 919736a74ffa6e8b46e1f87b042968f42eae71b8..aa76f36abe030eb4db330e8ba03115e9a0909a13 100644 (file)
@@ -2095,7 +2095,7 @@ int fc_lport_bsg_request(struct bsg_job *job)
 
        bsg_reply->reply_payload_rcv_len = 0;
        if (rsp)
-               rsp->resid_len = job->reply_payload.payload_len;
+               scsi_req(rsp)->resid_len = job->reply_payload.payload_len;
 
        mutex_lock(&lport->lp_mutex);
 
index f9b6fba689ffb41c6806cdabeb80debe38e25189..834d1212b6d506d37c10d35105e4c5808690f377 100644 (file)
@@ -1930,7 +1930,7 @@ static int iscsi_has_ping_timed_out(struct iscsi_conn *conn)
                return 0;
 }
 
-static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
+enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
 {
        enum blk_eh_timer_return rc = BLK_EH_NOT_HANDLED;
        struct iscsi_task *task = NULL, *running_task;
@@ -2063,6 +2063,7 @@ done:
                     "timer reset" : "nh");
        return rc;
 }
+EXPORT_SYMBOL_GPL(iscsi_eh_cmd_timed_out);
 
 static void iscsi_check_transport_timeouts(unsigned long data)
 {
@@ -2585,8 +2586,6 @@ int iscsi_host_add(struct Scsi_Host *shost, struct device *pdev)
        if (!shost->cmd_per_lun)
                shost->cmd_per_lun = ISCSI_DEF_CMD_PER_LUN;
 
-       if (!shost->transportt->eh_timed_out)
-               shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out;
        return scsi_add_host(shost, pdev);
 }
 EXPORT_SYMBOL_GPL(iscsi_host_add);
index 022bb6e10d985b69839753ac9521f9b5b1562320..570b2cb2da43921f8fc65cae4235ca3bb0ee6748 100644 (file)
@@ -2174,12 +2174,12 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
                               bio_data(rsp->bio), blk_rq_bytes(rsp));
        if (ret > 0) {
                /* positive number is the untransferred residual */
-               rsp->resid_len = ret;
-               req->resid_len = 0;
+               scsi_req(rsp)->resid_len = ret;
+               scsi_req(req)->resid_len = 0;
                ret = 0;
        } else if (ret == 0) {
-               rsp->resid_len = 0;
-               req->resid_len = 0;
+               scsi_req(rsp)->resid_len = 0;
+               scsi_req(req)->resid_len = 0;
        }
 
        return ret;
index d24792575169f2bff3918bbe4c64763df7cce859..45cbbc44f4d7d9d74923fbccc813294aa4c73b9e 100644 (file)
@@ -274,15 +274,15 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
 
        switch (req_data[1]) {
        case SMP_REPORT_GENERAL:
-               req->resid_len -= 8;
-               rsp->resid_len -= 32;
+               scsi_req(req)->resid_len -= 8;
+               scsi_req(rsp)->resid_len -= 32;
                resp_data[2] = SMP_RESP_FUNC_ACC;
                resp_data[9] = sas_ha->num_phys;
                break;
 
        case SMP_REPORT_MANUF_INFO:
-               req->resid_len -= 8;
-               rsp->resid_len -= 64;
+               scsi_req(req)->resid_len -= 8;
+               scsi_req(rsp)->resid_len -= 64;
                resp_data[2] = SMP_RESP_FUNC_ACC;
                memcpy(resp_data + 12, shost->hostt->name,
                       SAS_EXPANDER_VENDOR_ID_LEN);
@@ -295,13 +295,13 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
                break;
 
        case SMP_DISCOVER:
-               req->resid_len -= 16;
-               if ((int)req->resid_len < 0) {
-                       req->resid_len = 0;
+               scsi_req(req)->resid_len -= 16;
+               if ((int)scsi_req(req)->resid_len < 0) {
+                       scsi_req(req)->resid_len = 0;
                        error = -EINVAL;
                        goto out;
                }
-               rsp->resid_len -= 56;
+               scsi_req(rsp)->resid_len -= 56;
                sas_host_smp_discover(sas_ha, resp_data, req_data[9]);
                break;
 
@@ -311,13 +311,13 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
                break;
 
        case SMP_REPORT_PHY_SATA:
-               req->resid_len -= 16;
-               if ((int)req->resid_len < 0) {
-                       req->resid_len = 0;
+               scsi_req(req)->resid_len -= 16;
+               if ((int)scsi_req(req)->resid_len < 0) {
+                       scsi_req(req)->resid_len = 0;
                        error = -EINVAL;
                        goto out;
                }
-               rsp->resid_len -= 60;
+               scsi_req(rsp)->resid_len -= 60;
                sas_report_phy_sata(sas_ha, resp_data, req_data[9]);
                break;
 
@@ -331,15 +331,15 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
                int to_write = req_data[4];
 
                if (blk_rq_bytes(req) < base_frame_size + to_write * 4 ||
-                   req->resid_len < base_frame_size + to_write * 4) {
+                   scsi_req(req)->resid_len < base_frame_size + to_write * 4) {
                        resp_data[2] = SMP_RESP_INV_FRM_LEN;
                        break;
                }
 
                to_write = sas_host_smp_write_gpio(sas_ha, resp_data, req_data[2],
                                                   req_data[3], to_write, &req_data[8]);
-               req->resid_len -= base_frame_size + to_write * 4;
-               rsp->resid_len -= 8;
+               scsi_req(req)->resid_len -= base_frame_size + to_write * 4;
+               scsi_req(rsp)->resid_len -= 8;
                break;
        }
 
@@ -348,13 +348,13 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
                break;
 
        case SMP_PHY_CONTROL:
-               req->resid_len -= 44;
-               if ((int)req->resid_len < 0) {
-                       req->resid_len = 0;
+               scsi_req(req)->resid_len -= 44;
+               if ((int)scsi_req(req)->resid_len < 0) {
+                       scsi_req(req)->resid_len = 0;
                        error = -EINVAL;
                        goto out;
                }
-               rsp->resid_len -= 8;
+               scsi_req(rsp)->resid_len -= 8;
                sas_phy_control(sas_ha, req_data[9], req_data[10],
                                req_data[32] >> 4, req_data[33] >> 4,
                                resp_data);
index 362da44f2948eb3533cef40cb1b72da0625f1b05..15ef8e2e685c5cd094c3d0784de4aab45159e62e 100644 (file)
@@ -560,7 +560,6 @@ sas_domain_attach_transport(struct sas_domain_function_template *dft)
        i = to_sas_internal(stt);
        i->dft = dft;
        stt->create_work_queue = 1;
-       stt->eh_timed_out = sas_scsi_timed_out;
        stt->eh_strategy_handler = sas_scsi_recover_host;
 
        return stt;
index 9cf0bc260b0e78ac3c929aafc00315cbad819caa..b306b7843d999014dd6f57bd6321c3cfbe9729be 100644 (file)
@@ -64,8 +64,6 @@ void sas_unregister_phys(struct sas_ha_struct *sas_ha);
 int  sas_register_ports(struct sas_ha_struct *sas_ha);
 void sas_unregister_ports(struct sas_ha_struct *sas_ha);
 
-enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *);
-
 int  sas_init_events(struct sas_ha_struct *sas_ha);
 void sas_disable_revalidation(struct sas_ha_struct *ha);
 void sas_enable_revalidation(struct sas_ha_struct *ha);
index 519dac4e341e3d05af47d35fd2580a8a8ecc2c67..9bd55bce83afb62b4a0bb8500c8d05a65e046926 100644 (file)
@@ -803,13 +803,6 @@ out:
                    shost->host_failed, tries);
 }
 
-enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
-{
-       scmd_dbg(cmd, "command %p timed out\n", cmd);
-
-       return BLK_EH_NOT_HANDLED;
-}
-
 int sas_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
 {
        struct domain_device *dev = sdev_to_domain_dev(sdev);
index 8a20b4e862241c7333e0eb927347816919e51a8f..6593b073c52483c52b8dcd31adf5248566d2f80f 100644 (file)
@@ -727,7 +727,6 @@ struct lpfc_hba {
        uint32_t cfg_fcp_io_channel;
        uint32_t cfg_total_seg_cnt;
        uint32_t cfg_sg_seg_cnt;
-       uint32_t cfg_prot_sg_seg_cnt;
        uint32_t cfg_sg_dma_buf_size;
        uint64_t cfg_soft_wwnn;
        uint64_t cfg_soft_wwpn;
index c84775562c65e9b486eee549594c800c03945fd7..50cf402dea298119ddcc88c4e3d2ec0669dba204 100644 (file)
@@ -2073,6 +2073,13 @@ lpfc_soft_wwn_enable_store(struct device *dev, struct device_attribute *attr,
                return -EINVAL;
 
        phba->soft_wwn_enable = 1;
+
+       dev_printk(KERN_WARNING, &phba->pcidev->dev,
+                  "lpfc%d: soft_wwpn assignment has been enabled.\n",
+                  phba->brd_no);
+       dev_printk(KERN_WARNING, &phba->pcidev->dev,
+                  "  The soft_wwpn feature is not supported by Broadcom.");
+
        return count;
 }
 static DEVICE_ATTR(lpfc_soft_wwn_enable, S_IWUSR, NULL,
@@ -2143,7 +2150,7 @@ lpfc_soft_wwpn_store(struct device *dev, struct device_attribute *attr,
        phba->soft_wwn_enable = 0;
 
        rc = lpfc_wwn_set(buf, cnt, wwpn);
-       if (!rc) {
+       if (rc) {
                /* not able to set wwpn, unlock it */
                phba->soft_wwn_enable = 1;
                return rc;
@@ -2224,7 +2231,7 @@ lpfc_soft_wwnn_store(struct device *dev, struct device_attribute *attr,
                return -EINVAL;
 
        rc = lpfc_wwn_set(buf, cnt, wwnn);
-       if (!rc) {
+       if (rc) {
                /* Allow wwnn to be set many times, as long as the enable
                 * is set. However, once the wwpn is set, everything locks.
                 */
@@ -2435,7 +2442,8 @@ lpfc_oas_vpt_store(struct device *dev, struct device_attribute *attr,
        else
                phba->cfg_oas_flags &= ~OAS_FIND_ANY_VPORT;
        phba->cfg_oas_flags &= ~OAS_LUN_VALID;
-       phba->cfg_oas_priority = phba->cfg_XLanePriority;
+       if (phba->cfg_oas_priority == 0)
+               phba->cfg_oas_priority = phba->cfg_XLanePriority;
        phba->sli4_hba.oas_next_lun = FIND_FIRST_OAS_LUN;
        return count;
 }
@@ -2561,7 +2569,7 @@ lpfc_oas_lun_state_set(struct lpfc_hba *phba, uint8_t vpt_wwpn[],
                        rc = -ENOMEM;
        } else {
                lpfc_disable_oas_lun(phba, (struct lpfc_name *)vpt_wwpn,
-                                    (struct lpfc_name *)tgt_wwpn, lun);
+                                    (struct lpfc_name *)tgt_wwpn, lun, pri);
        }
        return rc;
 
@@ -2585,7 +2593,8 @@ lpfc_oas_lun_state_set(struct lpfc_hba *phba, uint8_t vpt_wwpn[],
  */
 static uint64_t
 lpfc_oas_lun_get_next(struct lpfc_hba *phba, uint8_t vpt_wwpn[],
-                     uint8_t tgt_wwpn[], uint32_t *lun_status)
+                     uint8_t tgt_wwpn[], uint32_t *lun_status,
+                     uint32_t *lun_pri)
 {
        uint64_t found_lun;
 
@@ -2598,7 +2607,7 @@ lpfc_oas_lun_get_next(struct lpfc_hba *phba, uint8_t vpt_wwpn[],
                                   &phba->sli4_hba.oas_next_lun,
                                   (struct lpfc_name *)vpt_wwpn,
                                   (struct lpfc_name *)tgt_wwpn,
-                                  &found_lun, lun_status))
+                                  &found_lun, lun_status, lun_pri))
                return found_lun;
        else
                return NOT_OAS_ENABLED_LUN;
@@ -2670,7 +2679,8 @@ lpfc_oas_lun_show(struct device *dev, struct device_attribute *attr,
 
        oas_lun = lpfc_oas_lun_get_next(phba, phba->cfg_oas_vpt_wwpn,
                                        phba->cfg_oas_tgt_wwpn,
-                                       &phba->cfg_oas_lun_status);
+                                       &phba->cfg_oas_lun_status,
+                                       &phba->cfg_oas_priority);
        if (oas_lun != NOT_OAS_ENABLED_LUN)
                phba->cfg_oas_flags |= OAS_LUN_VALID;
 
@@ -2701,6 +2711,7 @@ lpfc_oas_lun_store(struct device *dev, struct device_attribute *attr,
        struct Scsi_Host *shost = class_to_shost(dev);
        struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
        uint64_t scsi_lun;
+       uint32_t pri;
        ssize_t rc;
 
        if (!phba->cfg_fof)
@@ -2718,17 +2729,20 @@ lpfc_oas_lun_store(struct device *dev, struct device_attribute *attr,
        if (sscanf(buf, "0x%llx", &scsi_lun) != 1)
                return -EINVAL;
 
+       pri = phba->cfg_oas_priority;
+       if (pri == 0)
+               pri = phba->cfg_XLanePriority;
+
        lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
                        "3372 Try to set vport 0x%llx target 0x%llx lun:0x%llx "
                        "priority 0x%x with oas state %d\n",
                        wwn_to_u64(phba->cfg_oas_vpt_wwpn),
                        wwn_to_u64(phba->cfg_oas_tgt_wwpn), scsi_lun,
-                       phba->cfg_oas_priority, phba->cfg_oas_lun_state);
+                       pri, phba->cfg_oas_lun_state);
 
        rc = lpfc_oas_lun_state_change(phba, phba->cfg_oas_vpt_wwpn,
                                       phba->cfg_oas_tgt_wwpn, scsi_lun,
-                                      phba->cfg_oas_lun_state,
-                                      phba->cfg_oas_priority);
+                                      phba->cfg_oas_lun_state, pri);
        if (rc)
                return rc;
 
@@ -4669,14 +4683,6 @@ LPFC_ATTR(delay_discovery, 0, 0, 1,
 LPFC_ATTR_R(sg_seg_cnt, LPFC_DEFAULT_SG_SEG_CNT, LPFC_DEFAULT_SG_SEG_CNT,
            LPFC_MAX_SG_SEG_CNT, "Max Scatter Gather Segment Count");
 
-/*
- * This parameter will be depricated, the driver cannot limit the
- * protection data s/g list.
- */
-LPFC_ATTR_R(prot_sg_seg_cnt, LPFC_DEFAULT_SG_SEG_CNT,
-           LPFC_DEFAULT_SG_SEG_CNT, LPFC_MAX_SG_SEG_CNT,
-           "Max Protection Scatter Gather Segment Count");
-
 /*
  * lpfc_enable_mds_diags: Enable MDS Diagnostics
  *       0  = MDS Diagnostics disabled (default)
@@ -4766,7 +4772,6 @@ struct device_attribute *lpfc_hba_attrs[] = {
        &dev_attr_lpfc_sg_seg_cnt,
        &dev_attr_lpfc_max_scsicmpl_time,
        &dev_attr_lpfc_stat_data_ctrl,
-       &dev_attr_lpfc_prot_sg_seg_cnt,
        &dev_attr_lpfc_aer_support,
        &dev_attr_lpfc_aer_state_cleanup,
        &dev_attr_lpfc_sriov_nr_virtfn,
@@ -5060,6 +5065,19 @@ lpfc_free_sysfs_attr(struct lpfc_vport *vport)
  * Dynamic FC Host Attributes Support
  */
 
+/**
+ * lpfc_get_host_symbolic_name - Copy symbolic name into the scsi host
+ * @shost: kernel scsi host pointer.
+ **/
+static void
+lpfc_get_host_symbolic_name(struct Scsi_Host *shost)
+{
+       struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata;
+
+       lpfc_vport_symbolic_node_name(vport, fc_host_symbolic_name(shost),
+                                     sizeof fc_host_symbolic_name(shost));
+}
+
 /**
  * lpfc_get_host_port_id - Copy the vport DID into the scsi host port id
  * @shost: kernel scsi host pointer.
@@ -5597,6 +5615,8 @@ struct fc_function_template lpfc_transport_functions = {
        .show_host_supported_fc4s = 1,
        .show_host_supported_speeds = 1,
        .show_host_maxframe_size = 1,
+
+       .get_host_symbolic_name = lpfc_get_host_symbolic_name,
        .show_host_symbolic_name = 1,
 
        /* dynamic attributes the driver supports */
@@ -5664,6 +5684,8 @@ struct fc_function_template lpfc_vport_transport_functions = {
        .show_host_supported_fc4s = 1,
        .show_host_supported_speeds = 1,
        .show_host_maxframe_size = 1,
+
+       .get_host_symbolic_name = lpfc_get_host_symbolic_name,
        .show_host_symbolic_name = 1,
 
        /* dynamic attributes the driver supports */
@@ -5768,7 +5790,6 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
        phba->cfg_soft_wwnn = 0L;
        phba->cfg_soft_wwpn = 0L;
        lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt);
-       lpfc_prot_sg_seg_cnt_init(phba, lpfc_prot_sg_seg_cnt);
        lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth);
        lpfc_hba_log_verbose_init(phba, lpfc_log_verbose);
        lpfc_aer_support_init(phba, lpfc_aer_support);
index 15d2bfdf582dc73c99ca26951046d515e21b34c8..309643a2c55c7d0e99ab87118bfee5f43e74e194 100644 (file)
@@ -480,7 +480,7 @@ void lpfc_sli4_offline_eratt(struct lpfc_hba *);
 struct lpfc_device_data *lpfc_create_device_data(struct lpfc_hba *,
                                                struct lpfc_name *,
                                                struct lpfc_name *,
-                                               uint64_t, bool);
+                                               uint64_t, uint32_t,  bool);
 void lpfc_delete_device_data(struct lpfc_hba *, struct lpfc_device_data*);
 struct lpfc_device_data *__lpfc_get_device_data(struct lpfc_hba *,
                                        struct list_head *list,
@@ -489,9 +489,10 @@ struct lpfc_device_data *__lpfc_get_device_data(struct lpfc_hba *,
 bool lpfc_enable_oas_lun(struct lpfc_hba *, struct lpfc_name *,
                         struct lpfc_name *, uint64_t, uint8_t);
 bool lpfc_disable_oas_lun(struct lpfc_hba *, struct lpfc_name *,
-                         struct lpfc_name *, uint64_t);
+                         struct lpfc_name *, uint64_t, uint8_t);
 bool lpfc_find_next_oas_lun(struct lpfc_hba *, struct lpfc_name *,
                            struct lpfc_name *, uint64_t *, struct lpfc_name *,
-                           struct lpfc_name *, uint64_t *, uint32_t *);
+                           struct lpfc_name *, uint64_t *,
+                           uint32_t *, uint32_t *);
 int lpfc_sli4_dump_page_a0(struct lpfc_hba *phba, struct lpfcMboxq *mbox);
 void lpfc_mbx_cmpl_rdp_page_a0(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb);
index 63bef456654899a44e8fdc43745eb0abc621ebb8..3a1f1a2a2b559a20e5cea582e0a1543dd2a9fc77 100644 (file)
@@ -1999,6 +1999,9 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
        if (sp->cmn.fcphHigh < FC_PH3)
                sp->cmn.fcphHigh = FC_PH3;
 
+       sp->cmn.valid_vendor_ver_level = 0;
+       memset(sp->vendorVersion, 0, sizeof(sp->vendorVersion));
+
        lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
                "Issue PLOGI:     did:x%x",
                did, 0, 0);
@@ -3990,6 +3993,9 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
                } else {
                        memcpy(pcmd, &vport->fc_sparam,
                               sizeof(struct serv_parm));
+
+                       sp->cmn.valid_vendor_ver_level = 0;
+                       memset(sp->vendorVersion, 0, sizeof(sp->vendorVersion));
                }
 
                lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
@@ -8851,8 +8857,7 @@ lpfc_cmpl_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 {
        struct ls_rjt stat;
 
-       if ((cmdiocb->iocb_flag & LPFC_IO_FABRIC) != LPFC_IO_FABRIC)
-               BUG();
+       BUG_ON((cmdiocb->iocb_flag & LPFC_IO_FABRIC) != LPFC_IO_FABRIC);
 
        switch (rspiocb->iocb.ulpStatus) {
                case IOSTAT_NPORT_RJT:
index 822654322e67896b68a6fd2e023ebfbc7546ca04..3b970d3706008cc01604946419bbaa99dfc73798 100644 (file)
@@ -360,6 +360,12 @@ struct csp {
  * Word 1 Bit 30 in PLOGI request is random offset
  */
 #define virtual_fabric_support randomOffset /* Word 1, bit 30 */
+/*
+ * Word 1 Bit 29 in common service parameter is overloaded.
+ * Word 1 Bit 29 in FLOGI response is multiple NPort assignment
+ * Word 1 Bit 29 in FLOGI/PLOGI request is Valid Vendor Version Level
+ */
+#define valid_vendor_ver_level response_multiple_NPort /* Word 1, bit 29 */
 #ifdef __BIG_ENDIAN_BITFIELD
        uint16_t request_multiple_Nport:1;      /* FC Word 1, bit 31 */
        uint16_t randomOffset:1;        /* FC Word 1, bit 30 */
index ad350d969bdca637cc879ab54950e881022b11b8..1180a22beb435c83f6923d977f10c3ceaa2b4a40 100644 (file)
@@ -5452,7 +5452,9 @@ lpfc_slave_alloc(struct scsi_device *sdev)
                        device_data = lpfc_create_device_data(phba,
                                                        &vport->fc_portname,
                                                        &target_wwpn,
-                                                       sdev->lun, true);
+                                                       sdev->lun,
+                                                       phba->cfg_XLanePriority,
+                                                       true);
                        if (!device_data)
                                return -ENOMEM;
                        spin_lock_irqsave(&phba->devicelock, flags);
@@ -5587,7 +5589,7 @@ lpfc_slave_destroy(struct scsi_device *sdev)
 struct lpfc_device_data*
 lpfc_create_device_data(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,
                        struct lpfc_name *target_wwpn, uint64_t lun,
-                       bool atomic_create)
+                       uint32_t pri, bool atomic_create)
 {
 
        struct lpfc_device_data *lun_info;
@@ -5614,7 +5616,7 @@ lpfc_create_device_data(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,
               sizeof(struct lpfc_name));
        lun_info->device_id.lun = lun;
        lun_info->oas_enabled = false;
-       lun_info->priority = phba->cfg_XLanePriority;
+       lun_info->priority = pri;
        lun_info->available = false;
        return lun_info;
 }
@@ -5716,7 +5718,8 @@ lpfc_find_next_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,
                       struct lpfc_name *found_vport_wwpn,
                       struct lpfc_name *found_target_wwpn,
                       uint64_t *found_lun,
-                      uint32_t *found_lun_status)
+                      uint32_t *found_lun_status,
+                      uint32_t *found_lun_pri)
 {
 
        unsigned long flags;
@@ -5763,6 +5766,7 @@ lpfc_find_next_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,
                                                OAS_LUN_STATUS_EXISTS;
                                else
                                        *found_lun_status = 0;
+                               *found_lun_pri = lun_info->priority;
                                if (phba->cfg_oas_flags & OAS_FIND_ANY_VPORT)
                                        memset(vport_wwpn, 0x0,
                                               sizeof(struct lpfc_name));
@@ -5824,13 +5828,14 @@ lpfc_enable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,
        if (lun_info) {
                if (!lun_info->oas_enabled)
                        lun_info->oas_enabled = true;
+               lun_info->priority = pri;
                spin_unlock_irqrestore(&phba->devicelock, flags);
                return true;
        }
 
        /* Create an lun info structure and add to list of luns */
        lun_info = lpfc_create_device_data(phba, vport_wwpn, target_wwpn, lun,
-                                          false);
+                                          pri, false);
        if (lun_info) {
                lun_info->oas_enabled = true;
                lun_info->priority = pri;
@@ -5864,7 +5869,7 @@ lpfc_enable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,
  **/
 bool
 lpfc_disable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,
-                    struct lpfc_name *target_wwpn, uint64_t lun)
+                    struct lpfc_name *target_wwpn, uint64_t lun, uint8_t pri)
 {
 
        struct lpfc_device_data *lun_info;
@@ -5882,6 +5887,7 @@ lpfc_disable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn,
                                          target_wwpn, lun);
        if (lun_info) {
                lun_info->oas_enabled = false;
+               lun_info->priority = pri;
                if (!lun_info->available)
                        lpfc_delete_device_data(phba, lun_info);
                spin_unlock_irqrestore(&phba->devicelock, flags);
@@ -5923,6 +5929,7 @@ struct scsi_host_template lpfc_template = {
        .proc_name              = LPFC_DRIVER_NAME,
        .info                   = lpfc_info,
        .queuecommand           = lpfc_queuecommand,
+       .eh_timed_out           = fc_eh_timed_out,
        .eh_abort_handler       = lpfc_abort_handler,
        .eh_device_reset_handler = lpfc_device_reset_handler,
        .eh_target_reset_handler = lpfc_target_reset_handler,
@@ -5949,6 +5956,7 @@ struct scsi_host_template lpfc_vport_template = {
        .proc_name              = LPFC_DRIVER_NAME,
        .info                   = lpfc_info,
        .queuecommand           = lpfc_queuecommand,
+       .eh_timed_out           = fc_eh_timed_out,
        .eh_abort_handler       = lpfc_abort_handler,
        .eh_device_reset_handler = lpfc_device_reset_handler,
        .eh_target_reset_handler = lpfc_target_reset_handler,
index a78a3df68f679659eb9d05b24133312a663ab812..d977a472f89f0695940bef7a96584a798db22094 100644 (file)
@@ -120,6 +120,8 @@ lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe)
        if (q->phba->sli3_options & LPFC_SLI4_PHWQ_ENABLED)
                bf_set(wqe_wqid, &wqe->generic.wqe_com, q->queue_id);
        lpfc_sli_pcimem_bcopy(wqe, temp_wqe, q->entry_size);
+       /* ensure WQE bcopy flushed before doorbell write */
+       wmb();
 
        /* Update the host index before invoking device */
        host_index = q->host_index;
@@ -6313,7 +6315,8 @@ lpfc_set_host_data(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox)
                         LPFC_SLI4_MBX_EMBED);
 
        mbox->u.mqe.un.set_host_data.param_id = LPFC_SET_HOST_OS_DRIVER_VERSION;
-       mbox->u.mqe.un.set_host_data.param_len = 8;
+       mbox->u.mqe.un.set_host_data.param_len =
+                                       LPFC_HOST_OS_DRIVER_VERSION_SIZE;
        snprintf(mbox->u.mqe.un.set_host_data.data,
                 LPFC_HOST_OS_DRIVER_VERSION_SIZE,
                 "Linux %s v"LPFC_DRIVER_VERSION,
@@ -10035,6 +10038,7 @@ lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                iabt->ulpCommand = CMD_CLOSE_XRI_CN;
 
        abtsiocbp->iocb_cmpl = lpfc_sli_abort_els_cmpl;
+       abtsiocbp->vport = vport;
 
        lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI,
                         "0339 Abort xri x%x, original iotag x%x, "
@@ -17226,7 +17230,8 @@ lpfc_drain_txq(struct lpfc_hba *phba)
        unsigned long iflags = 0;
        char *fail_msg = NULL;
        struct lpfc_sglq *sglq;
-       union lpfc_wqe wqe;
+       union lpfc_wqe128 wqe128;
+       union lpfc_wqe *wqe = (union lpfc_wqe *) &wqe128;
        uint32_t txq_cnt = 0;
 
        spin_lock_irqsave(&pring->ring_lock, iflags);
@@ -17265,9 +17270,9 @@ lpfc_drain_txq(struct lpfc_hba *phba)
                piocbq->sli4_xritag = sglq->sli4_xritag;
                if (NO_XRI == lpfc_sli4_bpl2sgl(phba, piocbq, sglq))
                        fail_msg = "to convert bpl to sgl";
-               else if (lpfc_sli4_iocb2wqe(phba, piocbq, &wqe))
+               else if (lpfc_sli4_iocb2wqe(phba, piocbq, wqe))
                        fail_msg = "to convert iocb to wqe";
-               else if (lpfc_sli4_wq_put(phba->sli4_hba.els_wq, &wqe))
+               else if (lpfc_sli4_wq_put(phba->sli4_hba.els_wq, wqe))
                        fail_msg = " - Wq is full";
                else
                        lpfc_sli_ringtxcmpl_put(phba, pring, piocbq);
index 50bfc43ebcb01d4800e8ec8adf9b557a96e81e76..0ee0623a354c03f3b6c8eaeb869526fca3030f13 100644 (file)
@@ -18,7 +18,7 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "11.2.0.2"
+#define LPFC_DRIVER_VERSION "11.2.0.4"
 #define LPFC_DRIVER_NAME               "lpfc"
 
 /* Used for SLI 2/3 */
index c27f4b7245477ba5b3e454fd0dc39e8e1903819e..e18bbc66e83b1fdebd5b928da8b7a1d30022d0da 100644 (file)
@@ -537,6 +537,12 @@ enable_vport(struct fc_vport *fc_vport)
 
        spin_lock_irq(shost->host_lock);
        vport->load_flag |= FC_LOADING;
+       if (vport->fc_flag & FC_VPORT_NEEDS_INIT_VPI) {
+               spin_unlock_irq(shost->host_lock);
+               lpfc_issue_init_vpi(vport);
+               goto out;
+       }
+
        vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
        spin_unlock_irq(shost->host_lock);
 
@@ -557,6 +563,8 @@ enable_vport(struct fc_vport *fc_vport)
        } else {
                lpfc_vport_set_state(vport, FC_VPORT_FAILED);
        }
+
+out:
        lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
                         "1827 Vport Enabled.\n");
        return VPORT_OK;
index ccb68d12692c2beedaf653c2650cfe41c911d982..196acc79714b9da9cffa92c52a1c2c188da59508 100644 (file)
@@ -154,7 +154,7 @@ __asm__ __volatile__                                        \
 static inline int macscsi_pread(struct NCR5380_hostdata *hostdata,
                                 unsigned char *dst, int len)
 {
-       unsigned char *s = hostdata->pdma_io + (INPUT_DATA_REG << 4);
+       u8 __iomem *s = hostdata->pdma_io + (INPUT_DATA_REG << 4);
        unsigned char *d = dst;
        int n = len;
        int transferred;
@@ -257,7 +257,7 @@ static inline int macscsi_pwrite(struct NCR5380_hostdata *hostdata,
                                  unsigned char *src, int len)
 {
        unsigned char *s = src;
-       unsigned char *d = hostdata->pdma_io + (OUTPUT_DATA_REG << 4);
+       u8 __iomem *d = hostdata->pdma_io + (OUTPUT_DATA_REG << 4);
        int n = len;
        int transferred;
 
@@ -381,10 +381,10 @@ static int __init mac_scsi_probe(struct platform_device *pdev)
 
        hostdata = shost_priv(instance);
        hostdata->base = pio_mem->start;
-       hostdata->io = (void *)pio_mem->start;
+       hostdata->io = (u8 __iomem *)pio_mem->start;
 
        if (pdma_mem && setup_use_pdma)
-               hostdata->pdma_io = (void *)pdma_mem->start;
+               hostdata->pdma_io = (u8 __iomem *)pdma_mem->start;
        else
                host_flags |= FLAG_NO_PSEUDO_DMA;
 
index fdd519c1dd5753bc59dff5a11b7e2c19f89d52bd..e7e5974e1a2c435ef2ee0a79276e981fcb79cc87 100644 (file)
@@ -35,8 +35,8 @@
 /*
  * MegaRAID SAS Driver meta data
  */
-#define MEGASAS_VERSION                                "06.812.07.00-rc1"
-#define MEGASAS_RELDATE                                "August 22, 2016"
+#define MEGASAS_VERSION                                "07.701.16.00-rc1"
+#define MEGASAS_RELDATE                                "February 2, 2017"
 
 /*
  * Device IDs
 #define PCI_DEVICE_ID_LSI_INTRUDER_24          0x00cf
 #define PCI_DEVICE_ID_LSI_CUTLASS_52           0x0052
 #define PCI_DEVICE_ID_LSI_CUTLASS_53           0x0053
+#define PCI_DEVICE_ID_LSI_VENTURA                  0x0014
+#define PCI_DEVICE_ID_LSI_HARPOON                  0x0016
+#define PCI_DEVICE_ID_LSI_TOMCAT                   0x0017
+#define PCI_DEVICE_ID_LSI_VENTURA_4PORT                0x001B
+#define PCI_DEVICE_ID_LSI_CRUSADER_4PORT       0x001C
 
 /*
  * Intel HBA SSDIDs
  */
 
 /*
- * MFI stands for  MegaRAID SAS FW Interface. This is just a moniker for 
+ * MFI stands for  MegaRAID SAS FW Interface. This is just a moniker for
  * protocol between the software and firmware. Commands are issued using
  * "message frames"
  */
@@ -690,6 +695,18 @@ struct  MR_PD_INFO {
        u8 reserved1[512-428];
 } __packed;
 
+/*
+ * Definition of structure used to expose attributes of VD or JBOD
+ * (this structure is to be filled by firmware when MR_DCMD_DRV_GET_TARGET_PROP
+ * is fired by driver)
+ */
+struct MR_TARGET_PROPERTIES {
+       u32    max_io_size_kb;
+       u32    device_qdepth;
+       u32    sector_size;
+       u8     reserved[500];
+} __packed;
+
  /*
  * defines the physical drive address structure
  */
@@ -728,7 +745,6 @@ struct megasas_pd_list {
        u16             tid;
        u8             driveType;
        u8             driveState;
-       u8             interface;
 } __packed;
 
  /*
@@ -1312,7 +1328,55 @@ struct megasas_ctrl_info {
 #endif
        } adapterOperations3;
 
-       u8          pad[0x800-0x7EC];
+       struct {
+#if defined(__BIG_ENDIAN_BITFIELD)
+       u8 reserved:7;
+       /* Indicates whether the CPLD image is part of
+        *  the package and stored in flash
+        */
+       u8 cpld_in_flash:1;
+#else
+       u8 cpld_in_flash:1;
+       u8 reserved:7;
+#endif
+       u8 reserved1[3];
+       /* Null terminated string. Has the version
+        *  information if cpld_in_flash = FALSE
+        */
+       u8 userCodeDefinition[12];
+       } cpld;  /* Valid only if upgradableCPLD is TRUE */
+
+       struct {
+       #if defined(__BIG_ENDIAN_BITFIELD)
+               u16 reserved:8;
+               u16 fw_swaps_bbu_vpd_info:1;
+               u16 support_pd_map_target_id:1;
+               u16 support_ses_ctrl_in_multipathcfg:1;
+               u16 image_upload_supported:1;
+               u16 support_encrypted_mfc:1;
+               u16 supported_enc_algo:1;
+               u16 support_ibutton_less:1;
+               u16 ctrl_info_ext_supported:1;
+       #else
+
+               u16 ctrl_info_ext_supported:1;
+               u16 support_ibutton_less:1;
+               u16 supported_enc_algo:1;
+               u16 support_encrypted_mfc:1;
+               u16 image_upload_supported:1;
+               /* FW supports LUN based association and target port based */
+               u16 support_ses_ctrl_in_multipathcfg:1;
+               /* association for the SES device connected in multipath mode */
+               /* FW defines Jbod target Id within MR_PD_CFG_SEQ */
+               u16 support_pd_map_target_id:1;
+               /* FW swaps relevant fields in MR_BBU_VPD_INFO_FIXED to
+                *  provide the data in little endian order
+                */
+               u16 fw_swaps_bbu_vpd_info:1;
+               u16 reserved:8;
+       #endif
+               } adapter_operations4;
+       u8 pad[0x800 - 0x7FE]; /* 0x7FE pad to 2K for expansion */
 } __packed;
 
 /*
@@ -1339,12 +1403,15 @@ struct megasas_ctrl_info {
 
 #define MEGASAS_FW_BUSY                                1
 
-#define VD_EXT_DEBUG 0
+/* Driver's internal Logging levels*/
+#define OCR_LOGS    (1 << 0)
 
 #define SCAN_PD_CHANNEL        0x1
 #define SCAN_VD_CHANNEL        0x2
 
 #define MEGASAS_KDUMP_QUEUE_DEPTH               100
+#define MR_LARGE_IO_MIN_SIZE                   (32 * 1024)
+#define MR_R1_LDIO_PIGGYBACK_DEFAULT           4
 
 enum MR_SCSI_CMD_TYPE {
        READ_WRITE_LDIO = 0,
@@ -1391,7 +1458,7 @@ enum FW_BOOT_CONTEXT {
  */
 #define MEGASAS_INT_CMDS                       32
 #define MEGASAS_SKINNY_INT_CMDS                        5
-#define MEGASAS_FUSION_INTERNAL_CMDS           5
+#define MEGASAS_FUSION_INTERNAL_CMDS           8
 #define MEGASAS_FUSION_IOCTL_CMDS              3
 #define MEGASAS_MFI_IOCTL_CMDS                 27
 
@@ -1429,13 +1496,19 @@ enum FW_BOOT_CONTEXT {
 #define MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT    14
 #define MR_MAX_MSIX_REG_ARRAY                   16
 #define MR_RDPQ_MODE_OFFSET                    0X00800000
+
+#define MR_MAX_RAID_MAP_SIZE_OFFSET_SHIFT      16
+#define MR_MAX_RAID_MAP_SIZE_MASK              0x1FF
+#define MR_MIN_MAP_SIZE                                0x10000
+/* 64k */
+
 #define MR_CAN_HANDLE_SYNC_CACHE_OFFSET                0X01000000
 
 /*
 * register set for both 1068 and 1078 controllers
 * structure extended for 1078 registers
 */
+
 struct megasas_register_set {
        u32     doorbell;                       /*0000h*/
        u32     fusion_seq_offset;              /*0004h*/
@@ -1471,14 +1544,14 @@ struct megasas_register_set {
        u32     outbound_scratch_pad ;          /*00B0h*/
        u32     outbound_scratch_pad_2;         /*00B4h*/
        u32     outbound_scratch_pad_3;         /*00B8h*/
+       u32     outbound_scratch_pad_4;         /*00BCh*/
 
-       u32     reserved_4;                     /*00BCh*/
 
        u32     inbound_low_queue_port ;        /*00C0h*/
 
        u32     inbound_high_queue_port ;       /*00C4h*/
 
-       u32     reserved_5;                     /*00C8h*/
+       u32 inbound_single_queue_port;  /*00C8h*/
        u32     res_6[11];                      /*CCh*/
        u32     host_diag;
        u32     seq_offset;
@@ -1544,33 +1617,35 @@ union megasas_sgl_frame {
 typedef union _MFI_CAPABILITIES {
        struct {
 #if   defined(__BIG_ENDIAN_BITFIELD)
-               u32     reserved:20;
-               u32     support_qd_throttling:1;
-               u32     support_fp_rlbypass:1;
-               u32     support_vfid_in_ioframe:1;
-               u32     support_ext_io_size:1;
-               u32     support_ext_queue_depth:1;
-               u32     security_protocol_cmds_fw:1;
-               u32     support_core_affinity:1;
-               u32     support_ndrive_r1_lb:1;
-               u32     support_max_255lds:1;
-               u32     support_fastpath_wb:1;
-               u32     support_additional_msix:1;
-               u32     support_fp_remote_lun:1;
+       u32     reserved:19;
+       u32 support_pd_map_target_id:1;
+       u32     support_qd_throttling:1;
+       u32     support_fp_rlbypass:1;
+       u32     support_vfid_in_ioframe:1;
+       u32     support_ext_io_size:1;
+       u32             support_ext_queue_depth:1;
+       u32     security_protocol_cmds_fw:1;
+       u32     support_core_affinity:1;
+       u32     support_ndrive_r1_lb:1;
+       u32             support_max_255lds:1;
+       u32             support_fastpath_wb:1;
+       u32     support_additional_msix:1;
+       u32     support_fp_remote_lun:1;
 #else
-               u32     support_fp_remote_lun:1;
-               u32     support_additional_msix:1;
-               u32     support_fastpath_wb:1;
-               u32     support_max_255lds:1;
-               u32     support_ndrive_r1_lb:1;
-               u32     support_core_affinity:1;
-               u32     security_protocol_cmds_fw:1;
-               u32     support_ext_queue_depth:1;
-               u32     support_ext_io_size:1;
-               u32     support_vfid_in_ioframe:1;
-               u32     support_fp_rlbypass:1;
-               u32     support_qd_throttling:1;
-               u32     reserved:20;
+       u32     support_fp_remote_lun:1;
+       u32     support_additional_msix:1;
+       u32             support_fastpath_wb:1;
+       u32             support_max_255lds:1;
+       u32     support_ndrive_r1_lb:1;
+       u32     support_core_affinity:1;
+       u32     security_protocol_cmds_fw:1;
+       u32             support_ext_queue_depth:1;
+       u32     support_ext_io_size:1;
+       u32     support_vfid_in_ioframe:1;
+       u32     support_fp_rlbypass:1;
+       u32     support_qd_throttling:1;
+       u32     support_pd_map_target_id:1;
+       u32     reserved:19;
 #endif
        } mfi_capabilities;
        __le32          reg;
@@ -1803,6 +1878,8 @@ union megasas_frame {
 struct MR_PRIV_DEVICE {
        bool is_tm_capable;
        bool tm_busy;
+       atomic_t r1_ldio_hint;
+       u8   interface_type;
 };
 struct megasas_cmd;
 
@@ -1994,17 +2071,24 @@ struct MR_DRV_SYSTEM_INFO {
 };
 
 enum MR_PD_TYPE {
-                UNKNOWN_DRIVE = 0,
-                PARALLEL_SCSI = 1,
-                SAS_PD = 2,
-                SATA_PD = 3,
-                FC_PD = 4,
+       UNKNOWN_DRIVE = 0,
+       PARALLEL_SCSI = 1,
+       SAS_PD = 2,
+       SATA_PD = 3,
+       FC_PD = 4,
+       NVME_PD = 5,
 };
 
 /* JBOD Queue depth definitions */
 #define MEGASAS_SATA_QD        32
 #define MEGASAS_SAS_QD 64
 #define MEGASAS_DEFAULT_PD_QD  64
+#define MEGASAS_NVME_QD                32
+
+#define MR_DEFAULT_NVME_PAGE_SIZE      4096
+#define MR_DEFAULT_NVME_PAGE_SHIFT     12
+#define MR_DEFAULT_NVME_MDTS_KB                128
+#define MR_NVME_PAGE_SIZE_MASK         0x000000FF
 
 struct megasas_instance {
 
@@ -2022,6 +2106,8 @@ struct megasas_instance {
        dma_addr_t hb_host_mem_h;
        struct MR_PD_INFO *pd_info;
        dma_addr_t pd_info_h;
+       struct MR_TARGET_PROPERTIES *tgt_prop;
+       dma_addr_t tgt_prop_h;
 
        __le32 *reply_queue;
        dma_addr_t reply_queue_h;
@@ -2039,6 +2125,7 @@ struct megasas_instance {
        u32 crash_dump_drv_support;
        u32 crash_dump_app_support;
        u32 secure_jbod_support;
+       u32 support_morethan256jbod; /* FW support for more than 256 PD/JBOD */
        bool use_seqnum_jbod_fp;   /* Added for PD sequence */
        spinlock_t crashdump_lock;
 
@@ -2051,6 +2138,7 @@ struct megasas_instance {
 
        u16 max_num_sge;
        u16 max_fw_cmds;
+       u16 max_mpt_cmds;
        u16 max_mfi_cmds;
        u16 max_scsi_cmds;
        u16 ldio_threshold;
@@ -2065,6 +2153,7 @@ struct megasas_instance {
        /* used to sync fire the cmd to fw */
        spinlock_t hba_lock;
        /* used to synch producer, consumer ptrs in dpc */
+       spinlock_t stream_lock;
        spinlock_t completion_lock;
        struct dma_pool *frame_dma_pool;
        struct dma_pool *sense_dma_pool;
@@ -2087,6 +2176,11 @@ struct megasas_instance {
        atomic_t fw_outstanding;
        atomic_t ldio_outstanding;
        atomic_t fw_reset_no_pci_access;
+       atomic_t ieee_sgl;
+       atomic_t prp_sgl;
+       atomic_t sge_holes_type1;
+       atomic_t sge_holes_type2;
+       atomic_t sge_holes_type3;
 
        struct megasas_instance_template *instancet;
        struct tasklet_struct isr_tasklet;
@@ -2142,6 +2236,13 @@ struct megasas_instance {
        u8 is_rdpq;
        bool dev_handle;
        bool fw_sync_cache_support;
+       u32 mfi_frame_size;
+       bool is_ventura;
+       bool msix_combined;
+       u16 max_raid_mapsize;
+       /* preffered count to send as LDIO irrspective of FP capable.*/
+       u8  r1_ldio_hint_default;
+       u32 nvme_page_size;
 };
 struct MR_LD_VF_MAP {
        u32 size;
@@ -2230,12 +2331,12 @@ struct megasas_instance_template {
        u32 (*init_adapter)(struct megasas_instance *);
        u32 (*build_and_issue_cmd) (struct megasas_instance *,
                                    struct scsi_cmnd *);
-       int (*issue_dcmd)(struct megasas_instance *instance,
+       void (*issue_dcmd)(struct megasas_instance *instance,
                            struct megasas_cmd *cmd);
 };
 
-#define MEGASAS_IS_LOGICAL(scp)                                                \
-       ((scp->device->channel < MEGASAS_MAX_PD_CHANNELS) ? 0 : 1)
+#define MEGASAS_IS_LOGICAL(sdev)                                       \
+       ((sdev->channel < MEGASAS_MAX_PD_CHANNELS) ? 0 : 1)
 
 #define MEGASAS_DEV_INDEX(scp)                                         \
        (((scp->device->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) +   \
@@ -2346,7 +2447,7 @@ MR_BuildRaidContext(struct megasas_instance *instance,
                    struct IO_REQUEST_INFO *io_info,
                    struct RAID_CONTEXT *pRAID_Context,
                    struct MR_DRV_RAID_MAP_ALL *map, u8 **raidLUN);
-u8 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_DRV_RAID_MAP_ALL *map);
+u16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_DRV_RAID_MAP_ALL *map);
 struct MR_LD_RAID *MR_LdRaidGet(u32 ld, struct MR_DRV_RAID_MAP_ALL *map);
 u16 MR_ArPdGet(u32 ar, u32 arm, struct MR_DRV_RAID_MAP_ALL *map);
 u16 MR_LdSpanArrayGet(u32 ld, u32 span, struct MR_DRV_RAID_MAP_ALL *map);
@@ -2354,13 +2455,16 @@ __le16 MR_PdDevHandleGet(u32 pd, struct MR_DRV_RAID_MAP_ALL *map);
 u16 MR_GetLDTgtId(u32 ld, struct MR_DRV_RAID_MAP_ALL *map);
 
 __le16 get_updated_dev_handle(struct megasas_instance *instance,
-       struct LD_LOAD_BALANCE_INFO *lbInfo, struct IO_REQUEST_INFO *in_info);
+                             struct LD_LOAD_BALANCE_INFO *lbInfo,
+                             struct IO_REQUEST_INFO *in_info,
+                             struct MR_DRV_RAID_MAP_ALL *drv_map);
 void mr_update_load_balance_params(struct MR_DRV_RAID_MAP_ALL *map,
        struct LD_LOAD_BALANCE_INFO *lbInfo);
 int megasas_get_ctrl_info(struct megasas_instance *instance);
 /* PD sequence */
 int
 megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend);
+void megasas_set_dynamic_target_properties(struct scsi_device *sdev);
 int megasas_set_crash_dump_params(struct megasas_instance *instance,
        u8 crash_buf_state);
 void megasas_free_host_crash_buffer(struct megasas_instance *instance);
@@ -2382,4 +2486,7 @@ void megasas_update_sdev_properties(struct scsi_device *sdev);
 int megasas_reset_fusion(struct Scsi_Host *shost, int reason);
 int megasas_task_abort_fusion(struct scsi_cmnd *scmd);
 int megasas_reset_target_fusion(struct scsi_cmnd *scmd);
+u32 mega_mod64(u64 dividend, u32 divisor);
+int megasas_alloc_fusion_context(struct megasas_instance *instance);
+void megasas_free_fusion_context(struct megasas_instance *instance);
 #endif                         /*LSI_MEGARAID_SAS_H */
index d5cf15eb8c5e3e794803f95724e5f4a52a1ee9b2..7ac9a9ee9bd473c3cc0b6178975f46e3d32f3b77 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/uio.h>
 #include <linux/slab.h>
 #include <linux/uaccess.h>
+#include <asm/unaligned.h>
 #include <linux/fs.h>
 #include <linux/compat.h>
 #include <linux/blkdev.h>
@@ -116,8 +117,10 @@ static int megasas_ld_list_query(struct megasas_instance *instance,
 static int megasas_issue_init_mfi(struct megasas_instance *instance);
 static int megasas_register_aen(struct megasas_instance *instance,
                                u32 seq_num, u32 class_locale_word);
-static int
-megasas_get_pd_info(struct megasas_instance *instance, u16 device_id);
+static void megasas_get_pd_info(struct megasas_instance *instance,
+                               struct scsi_device *sdev);
+static int megasas_get_target_prop(struct megasas_instance *instance,
+                                  struct scsi_device *sdev);
 /*
  * PCI ID table for all supported controllers
  */
@@ -155,6 +158,12 @@ static struct pci_device_id megasas_pci_table[] = {
        /* Intruder 24 port*/
        {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_CUTLASS_52)},
        {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_CUTLASS_53)},
+       /* VENTURA */
+       {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_VENTURA)},
+       {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_HARPOON)},
+       {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_TOMCAT)},
+       {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_VENTURA_4PORT)},
+       {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_CRUSADER_4PORT)},
        {}
 };
 
@@ -196,12 +205,12 @@ void megasas_fusion_ocr_wq(struct work_struct *work);
 static int megasas_get_ld_vf_affiliation(struct megasas_instance *instance,
                                         int initial);
 
-int
+void
 megasas_issue_dcmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
 {
        instance->instancet->fire_cmd(instance,
                cmd->frame_phys_addr, 0, instance->reg_set);
-       return 0;
+       return;
 }
 
 /**
@@ -259,6 +268,8 @@ megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
        cmd->scmd = NULL;
        cmd->frame_count = 0;
        cmd->flags = 0;
+       memset(cmd->frame, 0, instance->mfi_frame_size);
+       cmd->frame->io.context = cpu_to_le32(cmd->index);
        if (!fusion && reset_devices)
                cmd->frame->hdr.cmd = MFI_CMD_INVALID;
        list_add(&cmd->list, (&instance->cmd_pool)->next);
@@ -989,13 +1000,14 @@ megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
        frame_hdr->cmd_status = MFI_STAT_INVALID_STATUS;
        frame_hdr->flags |= cpu_to_le16(MFI_FRAME_DONT_POST_IN_REPLY_QUEUE);
 
-       if ((atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) ||
-               (instance->instancet->issue_dcmd(instance, cmd))) {
+       if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
                dev_err(&instance->pdev->dev, "Failed from %s %d\n",
                        __func__, __LINE__);
                return DCMD_NOT_FIRED;
        }
 
+       instance->instancet->issue_dcmd(instance, cmd);
+
        return wait_and_poll(instance, cmd, instance->requestorId ?
                        MEGASAS_ROUTINE_WAIT_TIME_VF : MFI_IO_TIMEOUT_SECS);
 }
@@ -1017,13 +1029,14 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
        int ret = 0;
        cmd->cmd_status_drv = MFI_STAT_INVALID_STATUS;
 
-       if ((atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) ||
-               (instance->instancet->issue_dcmd(instance, cmd))) {
+       if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
                dev_err(&instance->pdev->dev, "Failed from %s %d\n",
                        __func__, __LINE__);
                return DCMD_NOT_FIRED;
        }
 
+       instance->instancet->issue_dcmd(instance, cmd);
+
        if (timeout) {
                ret = wait_event_timeout(instance->int_cmd_wait_q,
                                cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS, timeout * HZ);
@@ -1081,13 +1094,14 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
        cmd->sync_cmd = 1;
        cmd->cmd_status_drv = MFI_STAT_INVALID_STATUS;
 
-       if ((atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) ||
-               (instance->instancet->issue_dcmd(instance, cmd))) {
+       if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR) {
                dev_err(&instance->pdev->dev, "Failed from %s %d\n",
                        __func__, __LINE__);
                return DCMD_NOT_FIRED;
        }
 
+       instance->instancet->issue_dcmd(instance, cmd);
+
        if (timeout) {
                ret = wait_event_timeout(instance->abort_cmd_wait_q,
                                cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS, timeout * HZ);
@@ -1273,7 +1287,7 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
        u16 flags = 0;
        struct megasas_pthru_frame *pthru;
 
-       is_logical = MEGASAS_IS_LOGICAL(scp);
+       is_logical = MEGASAS_IS_LOGICAL(scp->device);
        device_id = MEGASAS_DEV_INDEX(scp);
        pthru = (struct megasas_pthru_frame *)cmd->frame;
 
@@ -1513,11 +1527,11 @@ inline int megasas_cmd_type(struct scsi_cmnd *cmd)
        case WRITE_6:
        case READ_16:
        case WRITE_16:
-               ret = (MEGASAS_IS_LOGICAL(cmd)) ?
+               ret = (MEGASAS_IS_LOGICAL(cmd->device)) ?
                        READ_WRITE_LDIO : READ_WRITE_SYSPDIO;
                break;
        default:
-               ret = (MEGASAS_IS_LOGICAL(cmd)) ?
+               ret = (MEGASAS_IS_LOGICAL(cmd->device)) ?
                        NON_READ_WRITE_LDIO : NON_READ_WRITE_SYSPDIO;
        }
        return ret;
@@ -1537,7 +1551,7 @@ megasas_dump_pending_frames(struct megasas_instance *instance)
        struct megasas_io_frame *ldio;
        struct megasas_pthru_frame *pthru;
        u32 sgcount;
-       u32 max_cmd = instance->max_fw_cmds;
+       u16 max_cmd = instance->max_fw_cmds;
 
        dev_err(&instance->pdev->dev, "[%d]: Dumping Frame Phys Address of all pending cmds in FW\n",instance->host->host_no);
        dev_err(&instance->pdev->dev, "[%d]: Total OS Pending cmds : %d\n",instance->host->host_no,atomic_read(&instance->fw_outstanding));
@@ -1662,7 +1676,7 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
        /* Check for an mpio path and adjust behavior */
        if (atomic_read(&instance->adprecovery) == MEGASAS_ADPRESET_SM_INFAULT) {
                if (megasas_check_mpio_paths(instance, scmd) ==
-                   (DID_RESET << 16)) {
+                   (DID_REQUEUE << 16)) {
                        return SCSI_MLQUEUE_HOST_BUSY;
                } else {
                        scmd->result = DID_NO_CONNECT << 16;
@@ -1693,15 +1707,16 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
 
        scmd->result = 0;
 
-       if (MEGASAS_IS_LOGICAL(scmd) &&
+       if (MEGASAS_IS_LOGICAL(scmd->device) &&
            (scmd->device->id >= instance->fw_supported_vd_count ||
                scmd->device->lun)) {
                scmd->result = DID_BAD_TARGET << 16;
                goto out_done;
        }
 
-       if ((scmd->cmnd[0] == SYNCHRONIZE_CACHE) && MEGASAS_IS_LOGICAL(scmd) &&
-               (!instance->fw_sync_cache_support)) {
+       if ((scmd->cmnd[0] == SYNCHRONIZE_CACHE) &&
+           MEGASAS_IS_LOGICAL(scmd->device) &&
+           (!instance->fw_sync_cache_support)) {
                scmd->result = DID_OK << 16;
                goto out_done;
        }
@@ -1728,16 +1743,21 @@ static struct megasas_instance *megasas_lookup_instance(u16 host_no)
 }
 
 /*
-* megasas_update_sdev_properties - Update sdev structure based on controller's FW capabilities
+* megasas_set_dynamic_target_properties -
+* Device property set by driver may not be static and it is required to be
+* updated after OCR
+*
+* set tm_capable.
+* set dma alignment (only for eedp protection enable vd).
 *
 * @sdev: OS provided scsi device
 *
 * Returns void
 */
-void megasas_update_sdev_properties(struct scsi_device *sdev)
+void megasas_set_dynamic_target_properties(struct scsi_device *sdev)
 {
-       u16 pd_index = 0;
-       u32 device_id, ld;
+       u16 pd_index = 0, ld;
+       u32 device_id;
        struct megasas_instance *instance;
        struct fusion_context *fusion;
        struct MR_PRIV_DEVICE *mr_device_priv_data;
@@ -1749,67 +1769,129 @@ void megasas_update_sdev_properties(struct scsi_device *sdev)
        fusion = instance->ctrl_context;
        mr_device_priv_data = sdev->hostdata;
 
-       if (!fusion)
+       if (!fusion || !mr_device_priv_data)
                return;
 
-       if (sdev->channel < MEGASAS_MAX_PD_CHANNELS &&
-               instance->use_seqnum_jbod_fp) {
-               pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
-                       sdev->id;
-               pd_sync = (void *)fusion->pd_seq_sync
-                               [(instance->pd_seq_map_id - 1) & 1];
-               mr_device_priv_data->is_tm_capable =
-                       pd_sync->seq[pd_index].capability.tmCapable;
-       } else {
+       if (MEGASAS_IS_LOGICAL(sdev)) {
                device_id = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL)
                                        + sdev->id;
                local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)];
                ld = MR_TargetIdToLdGet(device_id, local_map_ptr);
+               if (ld >= instance->fw_supported_vd_count)
+                       return;
                raid = MR_LdRaidGet(ld, local_map_ptr);
 
                if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER)
                blk_queue_update_dma_alignment(sdev->request_queue, 0x7);
+
                mr_device_priv_data->is_tm_capable =
                        raid->capability.tmCapable;
+       } else if (instance->use_seqnum_jbod_fp) {
+               pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
+                       sdev->id;
+               pd_sync = (void *)fusion->pd_seq_sync
+                               [(instance->pd_seq_map_id - 1) & 1];
+               mr_device_priv_data->is_tm_capable =
+                       pd_sync->seq[pd_index].capability.tmCapable;
        }
 }
 
-static void megasas_set_device_queue_depth(struct scsi_device *sdev)
+/*
+ * megasas_set_nvme_device_properties -
+ * set nomerges=2
+ * set virtual page boundary = 4K (current mr_nvme_pg_size is 4K).
+ * set maximum io transfer = MDTS of NVME device provided by MR firmware.
+ *
+ * MR firmware provides value in KB. Caller of this function converts
+ * kb into bytes.
+ *
+ * e.a MDTS=5 means 2^5 * nvme page size. (In case of 4K page size,
+ * MR firmware provides value 128 as (32 * 4K) = 128K.
+ *
+ * @sdev:                              scsi device
+ * @max_io_size:                               maximum io transfer size
+ *
+ */
+static inline void
+megasas_set_nvme_device_properties(struct scsi_device *sdev, u32 max_io_size)
 {
-       u16                             pd_index = 0;
-       int             ret = DCMD_FAILED;
        struct megasas_instance *instance;
+       u32 mr_nvme_pg_size;
 
-       instance = megasas_lookup_instance(sdev->host->host_no);
+       instance = (struct megasas_instance *)sdev->host->hostdata;
+       mr_nvme_pg_size = max_t(u32, instance->nvme_page_size,
+                               MR_DEFAULT_NVME_PAGE_SIZE);
 
-       if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) {
-               pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + sdev->id;
+       blk_queue_max_hw_sectors(sdev->request_queue, (max_io_size / 512));
 
-               if (instance->pd_info) {
-                       mutex_lock(&instance->hba_mutex);
-                       ret = megasas_get_pd_info(instance, pd_index);
-                       mutex_unlock(&instance->hba_mutex);
-               }
+       queue_flag_set_unlocked(QUEUE_FLAG_NOMERGES, sdev->request_queue);
+       blk_queue_virt_boundary(sdev->request_queue, mr_nvme_pg_size - 1);
+}
 
-               if (ret != DCMD_SUCCESS)
-                       return;
 
-               if (instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) {
+/*
+ * megasas_set_static_target_properties -
+ * Device property set by driver are static and it is not required to be
+ * updated after OCR.
+ *
+ * set io timeout
+ * set device queue depth
+ * set nvme device properties. see - megasas_set_nvme_device_properties
+ *
+ * @sdev:                              scsi device
+ * @is_target_prop                     true, if fw provided target properties.
+ */
+static void megasas_set_static_target_properties(struct scsi_device *sdev,
+                                                bool is_target_prop)
+{
+       u16     target_index = 0;
+       u8 interface_type;
+       u32 device_qd = MEGASAS_DEFAULT_CMD_PER_LUN;
+       u32 max_io_size_kb = MR_DEFAULT_NVME_MDTS_KB;
+       u32 tgt_device_qd;
+       struct megasas_instance *instance;
+       struct MR_PRIV_DEVICE *mr_device_priv_data;
 
-                       switch (instance->pd_list[pd_index].interface) {
-                       case SAS_PD:
-                               scsi_change_queue_depth(sdev, MEGASAS_SAS_QD);
-                               break;
+       instance = megasas_lookup_instance(sdev->host->host_no);
+       mr_device_priv_data = sdev->hostdata;
+       interface_type  = mr_device_priv_data->interface_type;
 
-                       case SATA_PD:
-                               scsi_change_queue_depth(sdev, MEGASAS_SATA_QD);
-                               break;
+       /*
+        * The RAID firmware may require extended timeouts.
+        */
+       blk_queue_rq_timeout(sdev->request_queue, scmd_timeout * HZ);
 
-                       default:
-                               scsi_change_queue_depth(sdev, MEGASAS_DEFAULT_PD_QD);
-                       }
-               }
+       target_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + sdev->id;
+
+       switch (interface_type) {
+       case SAS_PD:
+               device_qd = MEGASAS_SAS_QD;
+               break;
+       case SATA_PD:
+               device_qd = MEGASAS_SATA_QD;
+               break;
+       case NVME_PD:
+               device_qd = MEGASAS_NVME_QD;
+               break;
+       }
+
+       if (is_target_prop) {
+               tgt_device_qd = le32_to_cpu(instance->tgt_prop->device_qdepth);
+               if (tgt_device_qd &&
+                   (tgt_device_qd <= instance->host->can_queue))
+                       device_qd = tgt_device_qd;
+
+               /* max_io_size_kb will be set to non zero for
+                * nvme based vd and syspd.
+                */
+               max_io_size_kb = le32_to_cpu(instance->tgt_prop->max_io_size_kb);
        }
+
+       if (instance->nvme_page_size && max_io_size_kb)
+               megasas_set_nvme_device_properties(sdev, (max_io_size_kb << 10));
+
+       scsi_change_queue_depth(sdev, device_qd);
+
 }
 
 
@@ -1817,11 +1899,12 @@ static int megasas_slave_configure(struct scsi_device *sdev)
 {
        u16 pd_index = 0;
        struct megasas_instance *instance;
+       int ret_target_prop = DCMD_FAILED;
+       bool is_target_prop = false;
 
        instance = megasas_lookup_instance(sdev->host->host_no);
        if (instance->pd_list_not_supported) {
-               if (sdev->channel < MEGASAS_MAX_PD_CHANNELS &&
-                       sdev->type == TYPE_DISK) {
+               if (!MEGASAS_IS_LOGICAL(sdev) && sdev->type == TYPE_DISK) {
                        pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
                                sdev->id;
                        if (instance->pd_list[pd_index].driveState !=
@@ -1829,14 +1912,25 @@ static int megasas_slave_configure(struct scsi_device *sdev)
                                return -ENXIO;
                }
        }
-       megasas_set_device_queue_depth(sdev);
-       megasas_update_sdev_properties(sdev);
 
-       /*
-        * The RAID firmware may require extended timeouts.
+       mutex_lock(&instance->hba_mutex);
+       /* Send DCMD to Firmware and cache the information */
+       if ((instance->pd_info) && !MEGASAS_IS_LOGICAL(sdev))
+               megasas_get_pd_info(instance, sdev);
+
+       /* Some ventura firmware may not have instance->nvme_page_size set.
+        * Do not send MR_DCMD_DRV_GET_TARGET_PROP
         */
-       blk_queue_rq_timeout(sdev->request_queue,
-               scmd_timeout * HZ);
+       if ((instance->tgt_prop) && (instance->nvme_page_size))
+               ret_target_prop = megasas_get_target_prop(instance, sdev);
+
+       is_target_prop = (ret_target_prop == DCMD_SUCCESS) ? true : false;
+       megasas_set_static_target_properties(sdev, is_target_prop);
+
+       mutex_unlock(&instance->hba_mutex);
+
+       /* This sdev property may change post OCR */
+       megasas_set_dynamic_target_properties(sdev);
 
        return 0;
 }
@@ -1848,7 +1942,7 @@ static int megasas_slave_alloc(struct scsi_device *sdev)
        struct MR_PRIV_DEVICE *mr_device_priv_data;
 
        instance = megasas_lookup_instance(sdev->host->host_no);
-       if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) {
+       if (!MEGASAS_IS_LOGICAL(sdev)) {
                /*
                 * Open the OS scan to the SYSTEM PD
                 */
@@ -2483,7 +2577,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
                                                struct megasas_cmd, list);
                        list_del_init(&reset_cmd->list);
                        if (reset_cmd->scmd) {
-                               reset_cmd->scmd->result = DID_RESET << 16;
+                               reset_cmd->scmd->result = DID_REQUEUE << 16;
                                dev_notice(&instance->pdev->dev, "%d:%p reset [%02x]\n",
                                        reset_index, reset_cmd,
                                        reset_cmd->scmd->cmnd[0]);
@@ -2650,6 +2744,24 @@ blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
        return BLK_EH_RESET_TIMER;
 }
 
+/**
+ * megasas_dump_frame -        This function will dump MPT/MFI frame
+ */
+static inline void
+megasas_dump_frame(void *mpi_request, int sz)
+{
+       int i;
+       __le32 *mfp = (__le32 *)mpi_request;
+
+       printk(KERN_INFO "IO request frame:\n\t");
+       for (i = 0; i < sz / sizeof(__le32); i++) {
+               if (i && ((i % 8) == 0))
+                       printk("\n\t");
+               printk("%08x ", le32_to_cpu(mfp[i]));
+       }
+       printk("\n");
+}
+
 /**
  * megasas_reset_bus_host -    Bus & host reset handler entry point
  */
@@ -2660,12 +2772,26 @@ static int megasas_reset_bus_host(struct scsi_cmnd *scmd)
 
        instance = (struct megasas_instance *)scmd->device->host->hostdata;
 
+       scmd_printk(KERN_INFO, scmd,
+               "Controller reset is requested due to IO timeout\n"
+               "SCSI command pointer: (%p)\t SCSI host state: %d\t"
+               " SCSI host busy: %d\t FW outstanding: %d\n",
+               scmd, scmd->device->host->shost_state,
+               atomic_read((atomic_t *)&scmd->device->host->host_busy),
+               atomic_read(&instance->fw_outstanding));
+
        /*
         * First wait for all commands to complete
         */
-       if (instance->ctrl_context)
-               ret = megasas_reset_fusion(scmd->device->host, 1);
-       else
+       if (instance->ctrl_context) {
+               struct megasas_cmd_fusion *cmd;
+               cmd = (struct megasas_cmd_fusion *)scmd->SCp.ptr;
+               if (cmd)
+                       megasas_dump_frame(cmd->io_request,
+                               sizeof(struct MPI2_RAID_SCSI_IO_REQUEST));
+               ret = megasas_reset_fusion(scmd->device->host,
+                               SCSIIO_TIMEOUT_OCR);
+       } else
                ret = megasas_generic_reset(scmd);
 
        return ret;
@@ -3343,7 +3469,7 @@ megasas_internal_reset_defer_cmds(struct megasas_instance *instance)
 {
        struct megasas_cmd *cmd;
        int i;
-       u32 max_cmd = instance->max_fw_cmds;
+       u16 max_cmd = instance->max_fw_cmds;
        u32 defer_index;
        unsigned long flags;
 
@@ -3719,7 +3845,7 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
 static void megasas_teardown_frame_pool(struct megasas_instance *instance)
 {
        int i;
-       u32 max_cmd = instance->max_mfi_cmds;
+       u16 max_cmd = instance->max_mfi_cmds;
        struct megasas_cmd *cmd;
 
        if (!instance->frame_dma_pool)
@@ -3763,9 +3889,8 @@ static void megasas_teardown_frame_pool(struct megasas_instance *instance)
 static int megasas_create_frame_pool(struct megasas_instance *instance)
 {
        int i;
-       u32 max_cmd;
+       u16 max_cmd;
        u32 sge_sz;
-       u32 total_sz;
        u32 frame_count;
        struct megasas_cmd *cmd;
 
@@ -3793,12 +3918,13 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
         * Total 192 byte (3 MFI frame of 64 byte)
         */
        frame_count = instance->ctrl_context ? (3 + 1) : (15 + 1);
-       total_sz = MEGAMFI_FRAME_SIZE * frame_count;
+       instance->mfi_frame_size = MEGAMFI_FRAME_SIZE * frame_count;
        /*
         * Use DMA pool facility provided by PCI layer
         */
        instance->frame_dma_pool = pci_pool_create("megasas frame pool",
-                                       instance->pdev, total_sz, 256, 0);
+                                       instance->pdev, instance->mfi_frame_size,
+                                       256, 0);
 
        if (!instance->frame_dma_pool) {
                dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup frame pool\n");
@@ -3842,7 +3968,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
                        return -ENOMEM;
                }
 
-               memset(cmd->frame, 0, total_sz);
+               memset(cmd->frame, 0, instance->mfi_frame_size);
                cmd->frame->io.context = cpu_to_le32(cmd->index);
                cmd->frame->io.pad_0 = 0;
                if (!instance->ctrl_context && reset_devices)
@@ -3897,7 +4023,7 @@ int megasas_alloc_cmds(struct megasas_instance *instance)
 {
        int i;
        int j;
-       u32 max_cmd;
+       u16 max_cmd;
        struct megasas_cmd *cmd;
        struct fusion_context *fusion;
 
@@ -3974,18 +4100,22 @@ dcmd_timeout_ocr_possible(struct megasas_instance *instance) {
                return INITIATE_OCR;
 }
 
-static int
-megasas_get_pd_info(struct megasas_instance *instance, u16 device_id)
+static void
+megasas_get_pd_info(struct megasas_instance *instance, struct scsi_device *sdev)
 {
        int ret;
        struct megasas_cmd *cmd;
        struct megasas_dcmd_frame *dcmd;
 
+       struct MR_PRIV_DEVICE *mr_device_priv_data;
+       u16 device_id = 0;
+
+       device_id = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + sdev->id;
        cmd = megasas_get_cmd(instance);
 
        if (!cmd) {
                dev_err(&instance->pdev->dev, "Failed to get cmd %s\n", __func__);
-               return -ENOMEM;
+               return;
        }
 
        dcmd = &cmd->frame->dcmd;
@@ -4012,7 +4142,9 @@ megasas_get_pd_info(struct megasas_instance *instance, u16 device_id)
 
        switch (ret) {
        case DCMD_SUCCESS:
-               instance->pd_list[device_id].interface =
+               mr_device_priv_data = sdev->hostdata;
+               le16_to_cpus((u16 *)&instance->pd_info->state.ddf.pdType);
+               mr_device_priv_data->interface_type =
                                instance->pd_info->state.ddf.pdType.intf;
                break;
 
@@ -4039,7 +4171,7 @@ megasas_get_pd_info(struct megasas_instance *instance, u16 device_id)
        if (ret != DCMD_TIMEOUT)
                megasas_return_cmd(instance, cmd);
 
-       return ret;
+       return;
 }
 /*
  * megasas_get_pd_list_info -  Returns FW's pd_list structure
@@ -4418,8 +4550,7 @@ megasas_ld_list_query(struct megasas_instance *instance, u8 query_type)
 static void megasas_update_ext_vd_details(struct megasas_instance *instance)
 {
        struct fusion_context *fusion;
-       u32 old_map_sz;
-       u32 new_map_sz;
+       u32 ventura_map_sz = 0;
 
        fusion = instance->ctrl_context;
        /* For MFI based controllers return dummy success */
@@ -4449,21 +4580,27 @@ static void megasas_update_ext_vd_details(struct megasas_instance *instance)
                instance->supportmax256vd ? "Extended VD(240 VD)firmware" :
                "Legacy(64 VD) firmware");
 
-       old_map_sz = sizeof(struct MR_FW_RAID_MAP) +
-                               (sizeof(struct MR_LD_SPAN_MAP) *
-                               (instance->fw_supported_vd_count - 1));
-       new_map_sz = sizeof(struct MR_FW_RAID_MAP_EXT);
-       fusion->drv_map_sz = sizeof(struct MR_DRV_RAID_MAP) +
-                               (sizeof(struct MR_LD_SPAN_MAP) *
-                               (instance->drv_supported_vd_count - 1));
-
-       fusion->max_map_sz = max(old_map_sz, new_map_sz);
+       if (instance->max_raid_mapsize) {
+               ventura_map_sz = instance->max_raid_mapsize *
+                                               MR_MIN_MAP_SIZE; /* 64k */
+               fusion->current_map_sz = ventura_map_sz;
+               fusion->max_map_sz = ventura_map_sz;
+       } else {
+               fusion->old_map_sz =  sizeof(struct MR_FW_RAID_MAP) +
+                                       (sizeof(struct MR_LD_SPAN_MAP) *
+                                       (instance->fw_supported_vd_count - 1));
+               fusion->new_map_sz =  sizeof(struct MR_FW_RAID_MAP_EXT);
 
+               fusion->max_map_sz =
+                       max(fusion->old_map_sz, fusion->new_map_sz);
 
-       if (instance->supportmax256vd)
-               fusion->current_map_sz = new_map_sz;
-       else
-               fusion->current_map_sz = old_map_sz;
+               if (instance->supportmax256vd)
+                       fusion->current_map_sz = fusion->new_map_sz;
+               else
+                       fusion->current_map_sz = fusion->old_map_sz;
+       }
+       /* irrespective of FW raid maps, driver raid map is constant */
+       fusion->drv_map_sz = sizeof(struct MR_DRV_RAID_MAP_ALL);
 }
 
 /**
@@ -4533,6 +4670,7 @@ megasas_get_ctrl_info(struct megasas_instance *instance)
                le32_to_cpus((u32 *)&ctrl_info->properties.OnOffProperties);
                le32_to_cpus((u32 *)&ctrl_info->adapterOperations2);
                le32_to_cpus((u32 *)&ctrl_info->adapterOperations3);
+               le16_to_cpus((u16 *)&ctrl_info->adapter_operations4);
 
                /* Update the latest Ext VD info.
                 * From Init path, store current firmware details.
@@ -4542,6 +4680,8 @@ megasas_get_ctrl_info(struct megasas_instance *instance)
                megasas_update_ext_vd_details(instance);
                instance->use_seqnum_jbod_fp =
                        ctrl_info->adapterOperations3.useSeqNumJbodFP;
+               instance->support_morethan256jbod =
+                       ctrl_info->adapter_operations4.support_pd_map_target_id;
 
                /*Check whether controller is iMR or MR */
                instance->is_imr = (ctrl_info->memory_size ? 0 : 1);
@@ -4989,13 +5129,13 @@ skip_alloc:
 static int megasas_init_fw(struct megasas_instance *instance)
 {
        u32 max_sectors_1;
-       u32 max_sectors_2;
-       u32 tmp_sectors, msix_enable, scratch_pad_2;
+       u32 max_sectors_2, tmp_sectors, msix_enable;
+       u32 scratch_pad_2, scratch_pad_3, scratch_pad_4;
        resource_size_t base_addr;
        struct megasas_register_set __iomem *reg_set;
        struct megasas_ctrl_info *ctrl_info = NULL;
        unsigned long bar_list;
-       int i, loop, fw_msix_count = 0;
+       int i, j, loop, fw_msix_count = 0;
        struct IOV_111 *iovPtr;
        struct fusion_context *fusion;
 
@@ -5020,34 +5160,29 @@ static int megasas_init_fw(struct megasas_instance *instance)
 
        reg_set = instance->reg_set;
 
-       switch (instance->pdev->device) {
-       case PCI_DEVICE_ID_LSI_FUSION:
-       case PCI_DEVICE_ID_LSI_PLASMA:
-       case PCI_DEVICE_ID_LSI_INVADER:
-       case PCI_DEVICE_ID_LSI_FURY:
-       case PCI_DEVICE_ID_LSI_INTRUDER:
-       case PCI_DEVICE_ID_LSI_INTRUDER_24:
-       case PCI_DEVICE_ID_LSI_CUTLASS_52:
-       case PCI_DEVICE_ID_LSI_CUTLASS_53:
+       if (fusion)
                instance->instancet = &megasas_instance_template_fusion;
-               break;
-       case PCI_DEVICE_ID_LSI_SAS1078R:
-       case PCI_DEVICE_ID_LSI_SAS1078DE:
-               instance->instancet = &megasas_instance_template_ppc;
-               break;
-       case PCI_DEVICE_ID_LSI_SAS1078GEN2:
-       case PCI_DEVICE_ID_LSI_SAS0079GEN2:
-               instance->instancet = &megasas_instance_template_gen2;
-               break;
-       case PCI_DEVICE_ID_LSI_SAS0073SKINNY:
-       case PCI_DEVICE_ID_LSI_SAS0071SKINNY:
-               instance->instancet = &megasas_instance_template_skinny;
-               break;
-       case PCI_DEVICE_ID_LSI_SAS1064R:
-       case PCI_DEVICE_ID_DELL_PERC5:
-       default:
-               instance->instancet = &megasas_instance_template_xscale;
-               break;
+       else {
+               switch (instance->pdev->device) {
+               case PCI_DEVICE_ID_LSI_SAS1078R:
+               case PCI_DEVICE_ID_LSI_SAS1078DE:
+                       instance->instancet = &megasas_instance_template_ppc;
+                       break;
+               case PCI_DEVICE_ID_LSI_SAS1078GEN2:
+               case PCI_DEVICE_ID_LSI_SAS0079GEN2:
+                       instance->instancet = &megasas_instance_template_gen2;
+                       break;
+               case PCI_DEVICE_ID_LSI_SAS0073SKINNY:
+               case PCI_DEVICE_ID_LSI_SAS0071SKINNY:
+                       instance->instancet = &megasas_instance_template_skinny;
+                       break;
+               case PCI_DEVICE_ID_LSI_SAS1064R:
+               case PCI_DEVICE_ID_DELL_PERC5:
+               default:
+                       instance->instancet = &megasas_instance_template_xscale;
+                       instance->pd_list_not_supported = 1;
+                       break;
+               }
        }
 
        if (megasas_transition_to_ready(instance, 0)) {
@@ -5066,13 +5201,13 @@ static int megasas_init_fw(struct megasas_instance *instance)
                        goto fail_ready_state;
        }
 
-       /*
-        * MSI-X host index 0 is common for all adapter.
-        * It is used for all MPT based Adapters.
-        */
-       instance->reply_post_host_index_addr[0] =
-               (u32 __iomem *)((u8 __iomem *)instance->reg_set +
-               MPI2_REPLY_POST_HOST_INDEX_OFFSET);
+       if (instance->is_ventura) {
+               scratch_pad_3 =
+                       readl(&instance->reg_set->outbound_scratch_pad_3);
+               instance->max_raid_mapsize = ((scratch_pad_3 >>
+                       MR_MAX_RAID_MAP_SIZE_OFFSET_SHIFT) &
+                       MR_MAX_RAID_MAP_SIZE_MASK);
+       }
 
        /* Check if MSI-X is supported while in ready state */
        msix_enable = (instance->instancet->read_fw_status_reg(reg_set) &
@@ -5092,6 +5227,9 @@ static int megasas_init_fw(struct megasas_instance *instance)
                                instance->msix_vectors = ((scratch_pad_2
                                        & MR_MAX_REPLY_QUEUES_EXT_OFFSET)
                                        >> MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT) + 1;
+                               if (instance->msix_vectors > 16)
+                                       instance->msix_combined = true;
+
                                if (rdpq_enable)
                                        instance->is_rdpq = (scratch_pad_2 & MR_RDPQ_MODE_OFFSET) ?
                                                                1 : 0;
@@ -5125,6 +5263,20 @@ static int megasas_init_fw(struct megasas_instance *instance)
                else
                        instance->msix_vectors = 0;
        }
+       /*
+        * MSI-X host index 0 is common for all adapter.
+        * It is used for all MPT based Adapters.
+        */
+       if (instance->msix_combined) {
+               instance->reply_post_host_index_addr[0] =
+                               (u32 *)((u8 *)instance->reg_set +
+                               MPI2_SUP_REPLY_POST_HOST_INDEX_OFFSET);
+       } else {
+               instance->reply_post_host_index_addr[0] =
+                       (u32 *)((u8 *)instance->reg_set +
+                       MPI2_REPLY_POST_HOST_INDEX_OFFSET);
+       }
+
        i = pci_alloc_irq_vectors(instance->pdev, 1, 1, PCI_IRQ_LEGACY);
        if (i < 0)
                goto fail_setup_irqs;
@@ -5155,6 +5307,18 @@ static int megasas_init_fw(struct megasas_instance *instance)
        if (instance->instancet->init_adapter(instance))
                goto fail_init_adapter;
 
+       if (instance->is_ventura) {
+               scratch_pad_4 =
+                       readl(&instance->reg_set->outbound_scratch_pad_4);
+               if ((scratch_pad_4 & MR_NVME_PAGE_SIZE_MASK) >=
+                       MR_DEFAULT_NVME_PAGE_SHIFT)
+                       instance->nvme_page_size =
+                               (1 << (scratch_pad_4 & MR_NVME_PAGE_SIZE_MASK));
+
+               dev_info(&instance->pdev->dev,
+                        "NVME page size\t: (%d)\n", instance->nvme_page_size);
+       }
+
        if (instance->msix_vectors ?
                megasas_setup_irqs_msix(instance, 1) :
                megasas_setup_irqs_ioapic(instance))
@@ -5173,13 +5337,43 @@ static int megasas_init_fw(struct megasas_instance *instance)
                (MEGASAS_MAX_PD * sizeof(struct megasas_pd_list)));
        if (megasas_get_pd_list(instance) < 0) {
                dev_err(&instance->pdev->dev, "failed to get PD list\n");
-               goto fail_get_pd_list;
+               goto fail_get_ld_pd_list;
        }
 
        memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
+
+       /* stream detection initialization */
+       if (instance->is_ventura && fusion) {
+               fusion->stream_detect_by_ld =
+                       kzalloc(sizeof(struct LD_STREAM_DETECT *)
+                       * MAX_LOGICAL_DRIVES_EXT,
+                       GFP_KERNEL);
+               if (!fusion->stream_detect_by_ld) {
+                       dev_err(&instance->pdev->dev,
+                               "unable to allocate stream detection for pool of LDs\n");
+                       goto fail_get_ld_pd_list;
+               }
+               for (i = 0; i < MAX_LOGICAL_DRIVES_EXT; ++i) {
+                       fusion->stream_detect_by_ld[i] =
+                               kmalloc(sizeof(struct LD_STREAM_DETECT),
+                               GFP_KERNEL);
+                       if (!fusion->stream_detect_by_ld[i]) {
+                               dev_err(&instance->pdev->dev,
+                                       "unable to allocate stream detect by LD\n ");
+                               for (j = 0; j < i; ++j)
+                                       kfree(fusion->stream_detect_by_ld[j]);
+                               kfree(fusion->stream_detect_by_ld);
+                               fusion->stream_detect_by_ld = NULL;
+                               goto fail_get_ld_pd_list;
+                       }
+                       fusion->stream_detect_by_ld[i]->mru_bit_map
+                               = MR_STREAM_BITMAP;
+               }
+       }
+
        if (megasas_ld_list_query(instance,
                                  MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
-               megasas_get_ld_list(instance);
+               goto fail_get_ld_pd_list;
 
        /*
         * Compute the max allowed sectors per IO: The controller info has two
@@ -5296,7 +5490,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
 
        return 0;
 
-fail_get_pd_list:
+fail_get_ld_pd_list:
        instance->instancet->disable_intr(instance);
 fail_init_adapter:
        megasas_destroy_irqs(instance);
@@ -5309,9 +5503,11 @@ fail_ready_state:
        instance->ctrl_info = NULL;
        iounmap(instance->reg_set);
 
-      fail_ioremap:
+fail_ioremap:
        pci_release_selected_regions(instance->pdev, 1<<instance->bar);
 
+       dev_err(&instance->pdev->dev, "Failed from %s %d\n",
+               __func__, __LINE__);
        return -EINVAL;
 }
 
@@ -5531,6 +5727,98 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
        return 0;
 }
 
+/* megasas_get_target_prop - Send DCMD with below details to firmware.
+ *
+ * This DCMD will fetch few properties of LD/system PD defined
+ * in MR_TARGET_DEV_PROPERTIES. eg. Queue Depth, MDTS value.
+ *
+ * DCMD send by drivers whenever new target is added to the OS.
+ *
+ * dcmd.opcode         - MR_DCMD_DEV_GET_TARGET_PROP
+ * dcmd.mbox.b[0]      - DCMD is to be fired for LD or system PD.
+ *                       0 = system PD, 1 = LD.
+ * dcmd.mbox.s[1]      - TargetID for LD/system PD.
+ * dcmd.sge IN         - Pointer to return MR_TARGET_DEV_PROPERTIES.
+ *
+ * @instance:          Adapter soft state
+ * @sdev:              OS provided scsi device
+ *
+ * Returns 0 on success non-zero on failure.
+ */
+static int
+megasas_get_target_prop(struct megasas_instance *instance,
+                       struct scsi_device *sdev)
+{
+       int ret;
+       struct megasas_cmd *cmd;
+       struct megasas_dcmd_frame *dcmd;
+       u16 targetId = (sdev->channel % 2) + sdev->id;
+
+       cmd = megasas_get_cmd(instance);
+
+       if (!cmd) {
+               dev_err(&instance->pdev->dev,
+                       "Failed to get cmd %s\n", __func__);
+               return -ENOMEM;
+       }
+
+       dcmd = &cmd->frame->dcmd;
+
+       memset(instance->tgt_prop, 0, sizeof(*instance->tgt_prop));
+       memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+       dcmd->mbox.b[0] = MEGASAS_IS_LOGICAL(sdev);
+
+       dcmd->mbox.s[1] = cpu_to_le16(targetId);
+       dcmd->cmd = MFI_CMD_DCMD;
+       dcmd->cmd_status = 0xFF;
+       dcmd->sge_count = 1;
+       dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_READ);
+       dcmd->timeout = 0;
+       dcmd->pad_0 = 0;
+       dcmd->data_xfer_len =
+               cpu_to_le32(sizeof(struct MR_TARGET_PROPERTIES));
+       dcmd->opcode = cpu_to_le32(MR_DCMD_DRV_GET_TARGET_PROP);
+       dcmd->sgl.sge32[0].phys_addr =
+               cpu_to_le32(instance->tgt_prop_h);
+       dcmd->sgl.sge32[0].length =
+               cpu_to_le32(sizeof(struct MR_TARGET_PROPERTIES));
+
+       if (instance->ctrl_context && !instance->mask_interrupts)
+               ret = megasas_issue_blocked_cmd(instance,
+                                               cmd, MFI_IO_TIMEOUT_SECS);
+       else
+               ret = megasas_issue_polled(instance, cmd);
+
+       switch (ret) {
+       case DCMD_TIMEOUT:
+               switch (dcmd_timeout_ocr_possible(instance)) {
+               case INITIATE_OCR:
+                       cmd->flags |= DRV_DCMD_SKIP_REFIRE;
+                       megasas_reset_fusion(instance->host,
+                                            MFI_IO_TIMEOUT_OCR);
+                       break;
+               case KILL_ADAPTER:
+                       megaraid_sas_kill_hba(instance);
+                       break;
+               case IGNORE_TIMEOUT:
+                       dev_info(&instance->pdev->dev,
+                                "Ignore DCMD timeout: %s %d\n",
+                                __func__, __LINE__);
+                       break;
+               }
+               break;
+
+       default:
+               megasas_return_cmd(instance, cmd);
+       }
+       if (ret != DCMD_SUCCESS)
+               dev_err(&instance->pdev->dev,
+                       "return from %s %d return value %d\n",
+                       __func__, __LINE__, ret);
+
+       return ret;
+}
+
 /**
  * megasas_start_aen - Subscribes to AEN during driver load time
  * @instance:          Adapter soft state
@@ -5714,6 +6002,12 @@ static int megasas_probe_one(struct pci_dev *pdev,
        instance->pdev = pdev;
 
        switch (instance->pdev->device) {
+       case PCI_DEVICE_ID_LSI_VENTURA:
+       case PCI_DEVICE_ID_LSI_HARPOON:
+       case PCI_DEVICE_ID_LSI_TOMCAT:
+       case PCI_DEVICE_ID_LSI_VENTURA_4PORT:
+       case PCI_DEVICE_ID_LSI_CRUSADER_4PORT:
+            instance->is_ventura = true;
        case PCI_DEVICE_ID_LSI_FUSION:
        case PCI_DEVICE_ID_LSI_PLASMA:
        case PCI_DEVICE_ID_LSI_INVADER:
@@ -5723,21 +6017,17 @@ static int megasas_probe_one(struct pci_dev *pdev,
        case PCI_DEVICE_ID_LSI_CUTLASS_52:
        case PCI_DEVICE_ID_LSI_CUTLASS_53:
        {
-               instance->ctrl_context_pages =
-                       get_order(sizeof(struct fusion_context));
-               instance->ctrl_context = (void *)__get_free_pages(GFP_KERNEL,
-                               instance->ctrl_context_pages);
-               if (!instance->ctrl_context) {
-                       dev_printk(KERN_DEBUG, &pdev->dev, "Failed to allocate "
-                              "memory for Fusion context info\n");
+               if (megasas_alloc_fusion_context(instance)) {
+                       megasas_free_fusion_context(instance);
                        goto fail_alloc_dma_buf;
                }
                fusion = instance->ctrl_context;
-               memset(fusion, 0,
-                       ((1 << PAGE_SHIFT) << instance->ctrl_context_pages));
+
                if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
                        (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA))
                        fusion->adapter_type = THUNDERBOLT_SERIES;
+               else if (instance->is_ventura)
+                       fusion->adapter_type = VENTURA_SERIES;
                else
                        fusion->adapter_type = INVADER_SERIES;
        }
@@ -5799,9 +6089,17 @@ static int megasas_probe_one(struct pci_dev *pdev,
                instance->pd_info = pci_alloc_consistent(pdev,
                        sizeof(struct MR_PD_INFO), &instance->pd_info_h);
 
+               instance->pd_info = pci_alloc_consistent(pdev,
+                       sizeof(struct MR_PD_INFO), &instance->pd_info_h);
+               instance->tgt_prop = pci_alloc_consistent(pdev,
+                       sizeof(struct MR_TARGET_PROPERTIES), &instance->tgt_prop_h);
+
                if (!instance->pd_info)
                        dev_err(&instance->pdev->dev, "Failed to alloc mem for pd_info\n");
 
+               if (!instance->tgt_prop)
+                       dev_err(&instance->pdev->dev, "Failed to alloc mem for tgt_prop\n");
+
                instance->crash_dump_buf = pci_alloc_consistent(pdev,
                                                CRASH_DMA_BUF_SIZE,
                                                &instance->crash_dump_h);
@@ -5823,6 +6121,7 @@ static int megasas_probe_one(struct pci_dev *pdev,
 
        spin_lock_init(&instance->mfi_pool_lock);
        spin_lock_init(&instance->hba_lock);
+       spin_lock_init(&instance->stream_lock);
        spin_lock_init(&instance->completion_lock);
 
        mutex_init(&instance->reset_mutex);
@@ -5945,6 +6244,10 @@ fail_alloc_dma_buf:
                pci_free_consistent(pdev, sizeof(struct MR_PD_INFO),
                                        instance->pd_info,
                                        instance->pd_info_h);
+       if (instance->tgt_prop)
+               pci_free_consistent(pdev, sizeof(struct MR_TARGET_PROPERTIES),
+                                       instance->tgt_prop,
+                                       instance->tgt_prop_h);
        if (instance->producer)
                pci_free_consistent(pdev, sizeof(u32), instance->producer,
                                    instance->producer_h);
@@ -6217,6 +6520,10 @@ fail_init_mfi:
                pci_free_consistent(pdev, sizeof(struct MR_PD_INFO),
                                        instance->pd_info,
                                        instance->pd_info_h);
+       if (instance->tgt_prop)
+               pci_free_consistent(pdev, sizeof(struct MR_TARGET_PROPERTIES),
+                                       instance->tgt_prop,
+                                       instance->tgt_prop_h);
        if (instance->producer)
                pci_free_consistent(pdev, sizeof(u32), instance->producer,
                                instance->producer_h);
@@ -6330,6 +6637,14 @@ skip_firing_dcmds:
        if (instance->msix_vectors)
                pci_free_irq_vectors(instance->pdev);
 
+       if (instance->is_ventura) {
+               for (i = 0; i < MAX_LOGICAL_DRIVES_EXT; ++i)
+                       kfree(fusion->stream_detect_by_ld[i]);
+               kfree(fusion->stream_detect_by_ld);
+               fusion->stream_detect_by_ld = NULL;
+       }
+
+
        if (instance->ctrl_context) {
                megasas_release_fusion(instance);
                        pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) +
@@ -6350,8 +6665,7 @@ skip_firing_dcmds:
                                        fusion->pd_seq_sync[i],
                                        fusion->pd_seq_phys[i]);
                }
-               free_pages((ulong)instance->ctrl_context,
-                       instance->ctrl_context_pages);
+               megasas_free_fusion_context(instance);
        } else {
                megasas_release_mfi(instance);
                pci_free_consistent(pdev, sizeof(u32),
@@ -6367,11 +6681,14 @@ skip_firing_dcmds:
        if (instance->evt_detail)
                pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
                                instance->evt_detail, instance->evt_detail_h);
-
        if (instance->pd_info)
                pci_free_consistent(pdev, sizeof(struct MR_PD_INFO),
                                        instance->pd_info,
                                        instance->pd_info_h);
+       if (instance->tgt_prop)
+               pci_free_consistent(pdev, sizeof(struct MR_TARGET_PROPERTIES),
+                                       instance->tgt_prop,
+                                       instance->tgt_prop_h);
        if (instance->vf_affiliation)
                pci_free_consistent(pdev, (MAX_LOGICAL_DRIVES + 1) *
                                    sizeof(struct MR_LD_VF_AFFILIATION),
@@ -6570,6 +6887,13 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
                                               MFI_FRAME_SGL64 |
                                               MFI_FRAME_SENSE64));
 
+       if (cmd->frame->dcmd.opcode == MR_DCMD_CTRL_SHUTDOWN) {
+               if (megasas_get_ctrl_info(instance) != DCMD_SUCCESS) {
+                       megasas_return_cmd(instance, cmd);
+                       return -1;
+               }
+       }
+
        if (cmd->frame->dcmd.opcode == MR_DRIVER_SET_APP_CRASHDUMP_MODE) {
                error = megasas_set_crash_dump_params_ioctl(cmd);
                megasas_return_cmd(instance, cmd);
@@ -6678,7 +7002,8 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
                sense_ptr = (unsigned long *) ((unsigned long)ioc->frame.raw +
                                ioc->sense_off);
 
-               if (copy_to_user((void __user *)((unsigned long)(*sense_ptr)),
+               if (copy_to_user((void __user *)((unsigned long)
+                                get_unaligned((unsigned long *)sense_ptr)),
                                 sense, ioc->sense_len)) {
                        dev_err(&instance->pdev->dev, "Failed to copy out to user "
                                        "sense data\n");
@@ -7047,6 +7372,13 @@ megasas_sysfs_set_dbg_lvl(struct device_driver *dd, const char *buf, size_t coun
 static DRIVER_ATTR(dbg_lvl, S_IRUGO|S_IWUSR, megasas_sysfs_show_dbg_lvl,
                megasas_sysfs_set_dbg_lvl);
 
+static inline void megasas_remove_scsi_device(struct scsi_device *sdev)
+{
+       sdev_printk(KERN_INFO, sdev, "SCSI device is removed\n");
+       scsi_remove_device(sdev);
+       scsi_device_put(sdev);
+}
+
 static void
 megasas_aen_polling(struct work_struct *work)
 {
@@ -7151,10 +7483,8 @@ megasas_aen_polling(struct work_struct *work)
                                        else
                                                scsi_device_put(sdev1);
                                } else {
-                                       if (sdev1) {
-                                               scsi_remove_device(sdev1);
-                                               scsi_device_put(sdev1);
-                                       }
+                                       if (sdev1)
+                                               megasas_remove_scsi_device(sdev1);
                                }
                        }
                }
@@ -7171,10 +7501,8 @@ megasas_aen_polling(struct work_struct *work)
                                        else
                                                scsi_device_put(sdev1);
                                } else {
-                                       if (sdev1) {
-                                               scsi_remove_device(sdev1);
-                                               scsi_device_put(sdev1);
-                                       }
+                                       if (sdev1)
+                                               megasas_remove_scsi_device(sdev1);
                                }
                        }
                }
index f237d0003df363d276b8286adf120f6cd875ef64..62affa76133d330f59ad0d70e44fed119a1d46d7 100644 (file)
@@ -77,7 +77,6 @@ MODULE_PARM_DESC(lb_pending_cmds, "Change raid-1 load balancing outstanding "
 #endif
 #define TRUE 1
 
-#define SPAN_DEBUG 0
 #define SPAN_ROW_SIZE(map, ld, index_) (MR_LdSpanPtrGet(ld, index_, map)->spanRowSize)
 #define SPAN_ROW_DATA_SIZE(map_, ld, index_)   (MR_LdSpanPtrGet(ld, index_, map)->spanRowDataSize)
 #define SPAN_INVALID  0xff
@@ -155,12 +154,17 @@ __le16 MR_PdDevHandleGet(u32 pd, struct MR_DRV_RAID_MAP_ALL *map)
        return map->raidMap.devHndlInfo[pd].curDevHdl;
 }
 
+static u8 MR_PdInterfaceTypeGet(u32 pd, struct MR_DRV_RAID_MAP_ALL *map)
+{
+       return map->raidMap.devHndlInfo[pd].interfaceType;
+}
+
 u16 MR_GetLDTgtId(u32 ld, struct MR_DRV_RAID_MAP_ALL *map)
 {
        return le16_to_cpu(map->raidMap.ldSpanMap[ld].ldRaid.targetId);
 }
 
-u8 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_DRV_RAID_MAP_ALL *map)
+u16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_DRV_RAID_MAP_ALL *map)
 {
        return map->raidMap.ldTgtIdToLd[ldTgtId];
 }
@@ -179,18 +183,108 @@ void MR_PopulateDrvRaidMap(struct megasas_instance *instance)
        struct fusion_context *fusion = instance->ctrl_context;
        struct MR_FW_RAID_MAP_ALL     *fw_map_old    = NULL;
        struct MR_FW_RAID_MAP         *pFwRaidMap    = NULL;
-       int i;
+       int i, j;
        u16 ld_count;
+       struct MR_FW_RAID_MAP_DYNAMIC *fw_map_dyn;
+       struct MR_FW_RAID_MAP_EXT *fw_map_ext;
+       struct MR_RAID_MAP_DESC_TABLE *desc_table;
 
 
        struct MR_DRV_RAID_MAP_ALL *drv_map =
                        fusion->ld_drv_map[(instance->map_id & 1)];
        struct MR_DRV_RAID_MAP *pDrvRaidMap = &drv_map->raidMap;
+       void *raid_map_data = NULL;
+
+       memset(drv_map, 0, fusion->drv_map_sz);
+       memset(pDrvRaidMap->ldTgtIdToLd,
+              0xff, (sizeof(u16) * MAX_LOGICAL_DRIVES_DYN));
+
+       if (instance->max_raid_mapsize) {
+               fw_map_dyn = fusion->ld_map[(instance->map_id & 1)];
+               desc_table =
+               (struct MR_RAID_MAP_DESC_TABLE *)((void *)fw_map_dyn + le32_to_cpu(fw_map_dyn->desc_table_offset));
+               if (desc_table != fw_map_dyn->raid_map_desc_table)
+                       dev_dbg(&instance->pdev->dev, "offsets of desc table are not matching desc %p original %p\n",
+                               desc_table, fw_map_dyn->raid_map_desc_table);
+
+               ld_count = (u16)le16_to_cpu(fw_map_dyn->ld_count);
+               pDrvRaidMap->ldCount = (__le16)cpu_to_le16(ld_count);
+               pDrvRaidMap->fpPdIoTimeoutSec =
+                       fw_map_dyn->fp_pd_io_timeout_sec;
+               pDrvRaidMap->totalSize =
+                       cpu_to_le32(sizeof(struct MR_DRV_RAID_MAP_ALL));
+               /* point to actual data starting point*/
+               raid_map_data = (void *)fw_map_dyn +
+                       le32_to_cpu(fw_map_dyn->desc_table_offset) +
+                       le32_to_cpu(fw_map_dyn->desc_table_size);
+
+               for (i = 0; i < le32_to_cpu(fw_map_dyn->desc_table_num_elements); ++i) {
+                       switch (le32_to_cpu(desc_table->raid_map_desc_type)) {
+                       case RAID_MAP_DESC_TYPE_DEVHDL_INFO:
+                               fw_map_dyn->dev_hndl_info =
+                               (struct MR_DEV_HANDLE_INFO *)(raid_map_data + le32_to_cpu(desc_table->raid_map_desc_offset));
+                               memcpy(pDrvRaidMap->devHndlInfo,
+                                       fw_map_dyn->dev_hndl_info,
+                                       sizeof(struct MR_DEV_HANDLE_INFO) *
+                                       le32_to_cpu(desc_table->raid_map_desc_elements));
+                       break;
+                       case RAID_MAP_DESC_TYPE_TGTID_INFO:
+                               fw_map_dyn->ld_tgt_id_to_ld =
+                                       (u16 *)(raid_map_data +
+                                       le32_to_cpu(desc_table->raid_map_desc_offset));
+                               for (j = 0; j < le32_to_cpu(desc_table->raid_map_desc_elements); j++) {
+                                       pDrvRaidMap->ldTgtIdToLd[j] =
+                                               le16_to_cpu(fw_map_dyn->ld_tgt_id_to_ld[j]);
+                               }
+                       break;
+                       case RAID_MAP_DESC_TYPE_ARRAY_INFO:
+                               fw_map_dyn->ar_map_info =
+                                       (struct MR_ARRAY_INFO *)
+                                       (raid_map_data + le32_to_cpu(desc_table->raid_map_desc_offset));
+                               memcpy(pDrvRaidMap->arMapInfo,
+                                      fw_map_dyn->ar_map_info,
+                                      sizeof(struct MR_ARRAY_INFO) *
+                                      le32_to_cpu(desc_table->raid_map_desc_elements));
+                       break;
+                       case RAID_MAP_DESC_TYPE_SPAN_INFO:
+                               fw_map_dyn->ld_span_map =
+                                       (struct MR_LD_SPAN_MAP *)
+                                       (raid_map_data +
+                                       le32_to_cpu(desc_table->raid_map_desc_offset));
+                               memcpy(pDrvRaidMap->ldSpanMap,
+                                      fw_map_dyn->ld_span_map,
+                                      sizeof(struct MR_LD_SPAN_MAP) *
+                                      le32_to_cpu(desc_table->raid_map_desc_elements));
+                       break;
+                       default:
+                               dev_dbg(&instance->pdev->dev, "wrong number of desctableElements %d\n",
+                                       fw_map_dyn->desc_table_num_elements);
+                       }
+                       ++desc_table;
+               }
+
+       } else if (instance->supportmax256vd) {
+               fw_map_ext =
+                       (struct MR_FW_RAID_MAP_EXT *)fusion->ld_map[(instance->map_id & 1)];
+               ld_count = (u16)le16_to_cpu(fw_map_ext->ldCount);
+               if (ld_count > MAX_LOGICAL_DRIVES_EXT) {
+                       dev_dbg(&instance->pdev->dev, "megaraid_sas: LD count exposed in RAID map in not valid\n");
+                       return;
+               }
+
+               pDrvRaidMap->ldCount = (__le16)cpu_to_le16(ld_count);
+               pDrvRaidMap->fpPdIoTimeoutSec = fw_map_ext->fpPdIoTimeoutSec;
+               for (i = 0; i < (MAX_LOGICAL_DRIVES_EXT); i++)
+                       pDrvRaidMap->ldTgtIdToLd[i] =
+                               (u16)fw_map_ext->ldTgtIdToLd[i];
+               memcpy(pDrvRaidMap->ldSpanMap, fw_map_ext->ldSpanMap,
+                      sizeof(struct MR_LD_SPAN_MAP) * ld_count);
+               memcpy(pDrvRaidMap->arMapInfo, fw_map_ext->arMapInfo,
+                      sizeof(struct MR_ARRAY_INFO) * MAX_API_ARRAYS_EXT);
+               memcpy(pDrvRaidMap->devHndlInfo, fw_map_ext->devHndlInfo,
+                      sizeof(struct MR_DEV_HANDLE_INFO) *
+                      MAX_RAIDMAP_PHYSICAL_DEVICES);
 
-       if (instance->supportmax256vd) {
-               memcpy(fusion->ld_drv_map[instance->map_id & 1],
-                       fusion->ld_map[instance->map_id & 1],
-                       fusion->current_map_sz);
                /* New Raid map will not set totalSize, so keep expected value
                 * for legacy code in ValidateMapInfo
                 */
@@ -201,50 +295,14 @@ void MR_PopulateDrvRaidMap(struct megasas_instance *instance)
                        fusion->ld_map[(instance->map_id & 1)];
                pFwRaidMap = &fw_map_old->raidMap;
                ld_count = (u16)le32_to_cpu(pFwRaidMap->ldCount);
-
-#if VD_EXT_DEBUG
-               for (i = 0; i < ld_count; i++) {
-                       dev_dbg(&instance->pdev->dev, "(%d) :Index 0x%x "
-                               "Target Id 0x%x Seq Num 0x%x Size 0/%llx\n",
-                               instance->unique_id, i,
-                               fw_map_old->raidMap.ldSpanMap[i].ldRaid.targetId,
-                               fw_map_old->raidMap.ldSpanMap[i].ldRaid.seqNum,
-                               fw_map_old->raidMap.ldSpanMap[i].ldRaid.size);
-               }
-#endif
-
-               memset(drv_map, 0, fusion->drv_map_sz);
                pDrvRaidMap->totalSize = pFwRaidMap->totalSize;
                pDrvRaidMap->ldCount = (__le16)cpu_to_le16(ld_count);
                pDrvRaidMap->fpPdIoTimeoutSec = pFwRaidMap->fpPdIoTimeoutSec;
                for (i = 0; i < MAX_RAIDMAP_LOGICAL_DRIVES + MAX_RAIDMAP_VIEWS; i++)
                        pDrvRaidMap->ldTgtIdToLd[i] =
                                (u8)pFwRaidMap->ldTgtIdToLd[i];
-               for (i = (MAX_RAIDMAP_LOGICAL_DRIVES + MAX_RAIDMAP_VIEWS);
-                       i < MAX_LOGICAL_DRIVES_EXT; i++)
-                       pDrvRaidMap->ldTgtIdToLd[i] = 0xff;
                for (i = 0; i < ld_count; i++) {
                        pDrvRaidMap->ldSpanMap[i] = pFwRaidMap->ldSpanMap[i];
-#if VD_EXT_DEBUG
-                       dev_dbg(&instance->pdev->dev,
-                               "pFwRaidMap->ldSpanMap[%d].ldRaid.targetId 0x%x "
-                               "pFwRaidMap->ldSpanMap[%d].ldRaid.seqNum 0x%x "
-                               "size 0x%x\n", i, i,
-                               pFwRaidMap->ldSpanMap[i].ldRaid.targetId,
-                               pFwRaidMap->ldSpanMap[i].ldRaid.seqNum,
-                               (u32)pFwRaidMap->ldSpanMap[i].ldRaid.rowSize);
-                       dev_dbg(&instance->pdev->dev,
-                               "pDrvRaidMap->ldSpanMap[%d].ldRaid.targetId 0x%x "
-                               "pDrvRaidMap->ldSpanMap[%d].ldRaid.seqNum 0x%x "
-                               "size 0x%x\n", i, i,
-                               pDrvRaidMap->ldSpanMap[i].ldRaid.targetId,
-                               pDrvRaidMap->ldSpanMap[i].ldRaid.seqNum,
-                               (u32)pDrvRaidMap->ldSpanMap[i].ldRaid.rowSize);
-                       dev_dbg(&instance->pdev->dev, "Driver raid map all %p "
-                               "raid map %p LD RAID MAP %p/%p\n", drv_map,
-                               pDrvRaidMap, &pFwRaidMap->ldSpanMap[i].ldRaid,
-                               &pDrvRaidMap->ldSpanMap[i].ldRaid);
-#endif
                }
                memcpy(pDrvRaidMap->arMapInfo, pFwRaidMap->arMapInfo,
                        sizeof(struct MR_ARRAY_INFO) * MAX_RAIDMAP_ARRAYS);
@@ -265,7 +323,7 @@ u8 MR_ValidateMapInfo(struct megasas_instance *instance)
        struct LD_LOAD_BALANCE_INFO *lbInfo;
        PLD_SPAN_INFO ldSpanInfo;
        struct MR_LD_RAID         *raid;
-       u16 ldCount, num_lds;
+       u16 num_lds, i;
        u16 ld;
        u32 expected_size;
 
@@ -279,7 +337,9 @@ u8 MR_ValidateMapInfo(struct megasas_instance *instance)
        lbInfo = fusion->load_balance_info;
        ldSpanInfo = fusion->log_to_span;
 
-       if (instance->supportmax256vd)
+       if (instance->max_raid_mapsize)
+               expected_size = sizeof(struct MR_DRV_RAID_MAP_ALL);
+       else if (instance->supportmax256vd)
                expected_size = sizeof(struct MR_FW_RAID_MAP_EXT);
        else
                expected_size =
@@ -287,8 +347,10 @@ u8 MR_ValidateMapInfo(struct megasas_instance *instance)
                        (sizeof(struct MR_LD_SPAN_MAP) * le16_to_cpu(pDrvRaidMap->ldCount)));
 
        if (le32_to_cpu(pDrvRaidMap->totalSize) != expected_size) {
-               dev_err(&instance->pdev->dev, "map info structure size 0x%x is not matching with ld count\n",
-                      (unsigned int) expected_size);
+               dev_dbg(&instance->pdev->dev, "megasas: map info structure size 0x%x",
+                       le32_to_cpu(pDrvRaidMap->totalSize));
+               dev_dbg(&instance->pdev->dev, "is not matching expected size 0x%x\n",
+                       (unsigned int)expected_size);
                dev_err(&instance->pdev->dev, "megasas: span map %x, pDrvRaidMap->totalSize : %x\n",
                        (unsigned int)sizeof(struct MR_LD_SPAN_MAP),
                        le32_to_cpu(pDrvRaidMap->totalSize));
@@ -298,15 +360,23 @@ u8 MR_ValidateMapInfo(struct megasas_instance *instance)
        if (instance->UnevenSpanSupport)
                mr_update_span_set(drv_map, ldSpanInfo);
 
-       mr_update_load_balance_params(drv_map, lbInfo);
+       if (lbInfo)
+               mr_update_load_balance_params(drv_map, lbInfo);
 
        num_lds = le16_to_cpu(drv_map->raidMap.ldCount);
 
        /*Convert Raid capability values to CPU arch */
-       for (ldCount = 0; ldCount < num_lds; ldCount++) {
-               ld = MR_TargetIdToLdGet(ldCount, drv_map);
+       for (i = 0; (num_lds > 0) && (i < MAX_LOGICAL_DRIVES_EXT); i++) {
+               ld = MR_TargetIdToLdGet(i, drv_map);
+
+               /* For non existing VDs, iterate to next VD*/
+               if (ld >= (MAX_LOGICAL_DRIVES_EXT - 1))
+                       continue;
+
                raid = MR_LdRaidGet(ld, drv_map);
                le32_to_cpus((u32 *)&raid->capability);
+
+               num_lds--;
        }
 
        return 1;
@@ -345,91 +415,6 @@ u32 MR_GetSpanBlock(u32 ld, u64 row, u64 *span_blk,
        return SPAN_INVALID;
 }
 
-/*
-******************************************************************************
-*
-* Function to print info about span set created in driver from FW raid map
-*
-* Inputs :
-* map    - LD map
-* ldSpanInfo - ldSpanInfo per HBA instance
-*/
-#if SPAN_DEBUG
-static int getSpanInfo(struct MR_DRV_RAID_MAP_ALL *map,
-       PLD_SPAN_INFO ldSpanInfo)
-{
-
-       u8   span;
-       u32    element;
-       struct MR_LD_RAID *raid;
-       LD_SPAN_SET *span_set;
-       struct MR_QUAD_ELEMENT    *quad;
-       int ldCount;
-       u16 ld;
-
-       for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES_EXT; ldCount++) {
-               ld = MR_TargetIdToLdGet(ldCount, map);
-                       if (ld >= (MAX_LOGICAL_DRIVES_EXT - 1))
-                               continue;
-               raid = MR_LdRaidGet(ld, map);
-               dev_dbg(&instance->pdev->dev, "LD %x: span_depth=%x\n",
-                       ld, raid->spanDepth);
-               for (span = 0; span < raid->spanDepth; span++)
-                       dev_dbg(&instance->pdev->dev, "Span=%x,"
-                       " number of quads=%x\n", span,
-                       le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span].
-                       block_span_info.noElements));
-               for (element = 0; element < MAX_QUAD_DEPTH; element++) {
-                       span_set = &(ldSpanInfo[ld].span_set[element]);
-                       if (span_set->span_row_data_width == 0)
-                               break;
-
-                       dev_dbg(&instance->pdev->dev, "Span Set %x:"
-                               "width=%x, diff=%x\n", element,
-                               (unsigned int)span_set->span_row_data_width,
-                               (unsigned int)span_set->diff);
-                       dev_dbg(&instance->pdev->dev, "logical LBA"
-                               "start=0x%08lx, end=0x%08lx\n",
-                               (long unsigned int)span_set->log_start_lba,
-                               (long unsigned int)span_set->log_end_lba);
-                       dev_dbg(&instance->pdev->dev, "span row start=0x%08lx,"
-                               " end=0x%08lx\n",
-                               (long unsigned int)span_set->span_row_start,
-                               (long unsigned int)span_set->span_row_end);
-                       dev_dbg(&instance->pdev->dev, "data row start=0x%08lx,"
-                               " end=0x%08lx\n",
-                               (long unsigned int)span_set->data_row_start,
-                               (long unsigned int)span_set->data_row_end);
-                       dev_dbg(&instance->pdev->dev, "data strip start=0x%08lx,"
-                               " end=0x%08lx\n",
-                               (long unsigned int)span_set->data_strip_start,
-                               (long unsigned int)span_set->data_strip_end);
-
-                       for (span = 0; span < raid->spanDepth; span++) {
-                               if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span].
-                                       block_span_info.noElements) >=
-                                       element + 1) {
-                                       quad = &map->raidMap.ldSpanMap[ld].
-                                               spanBlock[span].block_span_info.
-                                               quad[element];
-                               dev_dbg(&instance->pdev->dev, "Span=%x,"
-                                       "Quad=%x, diff=%x\n", span,
-                                       element, le32_to_cpu(quad->diff));
-                               dev_dbg(&instance->pdev->dev,
-                                       "offset_in_span=0x%08lx\n",
-                                       (long unsigned int)le64_to_cpu(quad->offsetInSpan));
-                               dev_dbg(&instance->pdev->dev,
-                                       "logical start=0x%08lx, end=0x%08lx\n",
-                                       (long unsigned int)le64_to_cpu(quad->logStart),
-                                       (long unsigned int)le64_to_cpu(quad->logEnd));
-                               }
-                       }
-               }
-       }
-       return 0;
-}
-#endif
-
 /*
 ******************************************************************************
 *
@@ -543,19 +528,7 @@ static u64  get_row_from_strip(struct megasas_instance *instance,
                                else
                                        break;
                        }
-#if SPAN_DEBUG
-               dev_info(&instance->pdev->dev, "Strip 0x%llx,"
-                       "span_set_Strip 0x%llx, span_set_Row 0x%llx"
-                       "data width 0x%llx span offset 0x%x\n", strip,
-                       (unsigned long long)span_set_Strip,
-                       (unsigned long long)span_set_Row,
-                       (unsigned long long)span_set->span_row_data_width,
-                       span_offset);
-               dev_info(&instance->pdev->dev, "For strip 0x%llx"
-                       "row is 0x%llx\n", strip,
-                       (unsigned long long) span_set->data_row_start +
-                       (unsigned long long) span_set_Row + (span_offset - 1));
-#endif
+
                retval = (span_set->data_row_start + span_set_Row +
                                (span_offset - 1));
                return retval;
@@ -672,11 +645,7 @@ static u32 get_arm_from_strip(struct megasas_instance *instance,
                                else
                                        break;
                        }
-#if SPAN_DEBUG
-               dev_info(&instance->pdev->dev, "get_arm_from_strip:"
-                       "for ld=0x%x strip=0x%lx arm is  0x%x\n", ld,
-                       (long unsigned int)strip, (strip_offset - span_offset));
-#endif
+
                retval = (strip_offset - span_offset);
                return retval;
        }
@@ -737,16 +706,18 @@ static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld,
                struct MR_DRV_RAID_MAP_ALL *map)
 {
        struct MR_LD_RAID  *raid = MR_LdRaidGet(ld, map);
-       u32     pd, arRef;
+       u32     pd, arRef, r1_alt_pd;
        u8      physArm, span;
        u64     row;
        u8      retval = TRUE;
        u64     *pdBlock = &io_info->pdBlock;
        __le16  *pDevHandle = &io_info->devHandle;
+       u8      *pPdInterface = &io_info->pd_interface;
        u32     logArm, rowMod, armQ, arm;
        struct fusion_context *fusion;
 
        fusion = instance->ctrl_context;
+       *pDevHandle = cpu_to_le16(MR_DEVHANDLE_INVALID);
 
        /*Get row and span from io_info for Uneven Span IO.*/
        row         = io_info->start_row;
@@ -772,27 +743,46 @@ static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld,
        arRef       = MR_LdSpanArrayGet(ld, span, map);
        pd          = MR_ArPdGet(arRef, physArm, map);
 
-       if (pd != MR_PD_INVALID)
+       if (pd != MR_PD_INVALID) {
                *pDevHandle = MR_PdDevHandleGet(pd, map);
-       else {
-               *pDevHandle = cpu_to_le16(MR_PD_INVALID);
+               *pPdInterface = MR_PdInterfaceTypeGet(pd, map);
+               /* get second pd also for raid 1/10 fast path writes*/
+               if (instance->is_ventura &&
+                   (raid->level == 1) &&
+                   !io_info->isRead) {
+                       r1_alt_pd = MR_ArPdGet(arRef, physArm + 1, map);
+                       if (r1_alt_pd != MR_PD_INVALID)
+                               io_info->r1_alt_dev_handle =
+                               MR_PdDevHandleGet(r1_alt_pd, map);
+               }
+       } else {
                if ((raid->level >= 5) &&
                        ((fusion->adapter_type == THUNDERBOLT_SERIES)  ||
                        ((fusion->adapter_type == INVADER_SERIES) &&
                        (raid->regTypeReqOnRead != REGION_TYPE_UNUSED))))
-                       pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE;
+                       pRAID_Context->reg_lock_flags = REGION_TYPE_EXCLUSIVE;
                else if (raid->level == 1) {
                        physArm = physArm + 1;
                        pd = MR_ArPdGet(arRef, physArm, map);
-                       if (pd != MR_PD_INVALID)
+                       if (pd != MR_PD_INVALID) {
                                *pDevHandle = MR_PdDevHandleGet(pd, map);
+                               *pPdInterface = MR_PdInterfaceTypeGet(pd, map);
+                       }
                }
        }
 
        *pdBlock += stripRef + le64_to_cpu(MR_LdSpanPtrGet(ld, span, map)->startBlk);
-       pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) |
-                                       physArm;
-       io_info->span_arm = pRAID_Context->spanArm;
+       if (instance->is_ventura) {
+               ((struct RAID_CONTEXT_G35 *)pRAID_Context)->span_arm =
+                       (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm;
+               io_info->span_arm =
+                       (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm;
+       } else {
+               pRAID_Context->span_arm =
+                       (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm;
+               io_info->span_arm = pRAID_Context->span_arm;
+       }
+       io_info->pd_after_lb = pd;
        return retval;
 }
 
@@ -819,16 +809,17 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow,
                struct MR_DRV_RAID_MAP_ALL *map)
 {
        struct MR_LD_RAID  *raid = MR_LdRaidGet(ld, map);
-       u32         pd, arRef;
+       u32         pd, arRef, r1_alt_pd;
        u8          physArm, span;
        u64         row;
        u8          retval = TRUE;
        u64         *pdBlock = &io_info->pdBlock;
        __le16      *pDevHandle = &io_info->devHandle;
+       u8          *pPdInterface = &io_info->pd_interface;
        struct fusion_context *fusion;
 
        fusion = instance->ctrl_context;
-
+       *pDevHandle = cpu_to_le16(MR_DEVHANDLE_INVALID);
 
        row =  mega_div64_32(stripRow, raid->rowDataSize);
 
@@ -867,31 +858,49 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow,
        arRef       = MR_LdSpanArrayGet(ld, span, map);
        pd          = MR_ArPdGet(arRef, physArm, map); /* Get the pd */
 
-       if (pd != MR_PD_INVALID)
+       if (pd != MR_PD_INVALID) {
                /* Get dev handle from Pd. */
                *pDevHandle = MR_PdDevHandleGet(pd, map);
-       else {
-               /* set dev handle as invalid. */
-               *pDevHandle = cpu_to_le16(MR_PD_INVALID);
+               *pPdInterface = MR_PdInterfaceTypeGet(pd, map);
+               /* get second pd also for raid 1/10 fast path writes*/
+               if (instance->is_ventura &&
+                   (raid->level == 1) &&
+                   !io_info->isRead) {
+                       r1_alt_pd = MR_ArPdGet(arRef, physArm + 1, map);
+                       if (r1_alt_pd != MR_PD_INVALID)
+                               io_info->r1_alt_dev_handle =
+                                       MR_PdDevHandleGet(r1_alt_pd, map);
+               }
+       } else {
                if ((raid->level >= 5) &&
                        ((fusion->adapter_type == THUNDERBOLT_SERIES)  ||
                        ((fusion->adapter_type == INVADER_SERIES) &&
                        (raid->regTypeReqOnRead != REGION_TYPE_UNUSED))))
-                       pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE;
+                       pRAID_Context->reg_lock_flags = REGION_TYPE_EXCLUSIVE;
                else if (raid->level == 1) {
                        /* Get alternate Pd. */
                        physArm = physArm + 1;
                        pd = MR_ArPdGet(arRef, physArm, map);
-                       if (pd != MR_PD_INVALID)
+                       if (pd != MR_PD_INVALID) {
                                /* Get dev handle from Pd */
                                *pDevHandle = MR_PdDevHandleGet(pd, map);
+                               *pPdInterface = MR_PdInterfaceTypeGet(pd, map);
+                       }
                }
        }
 
        *pdBlock += stripRef + le64_to_cpu(MR_LdSpanPtrGet(ld, span, map)->startBlk);
-       pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) |
-               physArm;
-       io_info->span_arm = pRAID_Context->spanArm;
+       if (instance->is_ventura) {
+               ((struct RAID_CONTEXT_G35 *)pRAID_Context)->span_arm =
+                               (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm;
+               io_info->span_arm =
+                               (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm;
+       } else {
+               pRAID_Context->span_arm =
+                       (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm;
+               io_info->span_arm = pRAID_Context->span_arm;
+       }
+       io_info->pd_after_lb = pd;
        return retval;
 }
 
@@ -912,7 +921,7 @@ MR_BuildRaidContext(struct megasas_instance *instance,
 {
        struct fusion_context *fusion;
        struct MR_LD_RAID  *raid;
-       u32         ld, stripSize, stripe_mask;
+       u32         stripSize, stripe_mask;
        u64         endLba, endStrip, endRow, start_row, start_strip;
        u64         regStart;
        u32         regSize;
@@ -924,6 +933,7 @@ MR_BuildRaidContext(struct megasas_instance *instance,
        u8          retval = 0;
        u8          startlba_span = SPAN_INVALID;
        u64 *pdBlock = &io_info->pdBlock;
+       u16         ld;
 
        ldStartBlock = io_info->ldStartBlock;
        numBlocks = io_info->numBlocks;
@@ -935,6 +945,8 @@ MR_BuildRaidContext(struct megasas_instance *instance,
 
        ld = MR_TargetIdToLdGet(ldTgtId, map);
        raid = MR_LdRaidGet(ld, map);
+       /*check read ahead bit*/
+       io_info->ra_capable = raid->capability.ra_capable;
 
        /*
         * if rowDataSize @RAID map and spanRowDataSize @SPAN INFO are zero
@@ -996,17 +1008,6 @@ MR_BuildRaidContext(struct megasas_instance *instance,
                }
                io_info->start_span     = startlba_span;
                io_info->start_row      = start_row;
-#if SPAN_DEBUG
-               dev_dbg(&instance->pdev->dev, "Check Span number from %s %d"
-                       "for row 0x%llx, start strip 0x%llx end strip 0x%llx"
-                       " span 0x%x\n", __func__, __LINE__,
-                       (unsigned long long)start_row,
-                       (unsigned long long)start_strip,
-                       (unsigned long long)endStrip, startlba_span);
-               dev_dbg(&instance->pdev->dev, "start_row 0x%llx endRow 0x%llx"
-                       "Start span 0x%x\n", (unsigned long long)start_row,
-                       (unsigned long long)endRow, startlba_span);
-#endif
        } else {
                start_row = mega_div64_32(start_strip, raid->rowDataSize);
                endRow    = mega_div64_32(endStrip, raid->rowDataSize);
@@ -1093,20 +1094,20 @@ MR_BuildRaidContext(struct megasas_instance *instance,
                        regSize += stripSize;
        }
 
-       pRAID_Context->timeoutValue =
+       pRAID_Context->timeout_value =
                cpu_to_le16(raid->fpIoTimeoutForLd ?
                            raid->fpIoTimeoutForLd :
                            map->raidMap.fpPdIoTimeoutSec);
        if (fusion->adapter_type == INVADER_SERIES)
-               pRAID_Context->regLockFlags = (isRead) ?
+               pRAID_Context->reg_lock_flags = (isRead) ?
                        raid->regTypeReqOnRead : raid->regTypeReqOnWrite;
-       else
-               pRAID_Context->regLockFlags = (isRead) ?
+       else if (!instance->is_ventura)
+               pRAID_Context->reg_lock_flags = (isRead) ?
                        REGION_TYPE_SHARED_READ : raid->regTypeReqOnWrite;
-       pRAID_Context->VirtualDiskTgtId = raid->targetId;
-       pRAID_Context->regLockRowLBA    = cpu_to_le64(regStart);
-       pRAID_Context->regLockLength    = cpu_to_le32(regSize);
-       pRAID_Context->configSeqNum     = raid->seqNum;
+       pRAID_Context->virtual_disk_tgt_id = raid->targetId;
+       pRAID_Context->reg_lock_row_lba    = cpu_to_le64(regStart);
+       pRAID_Context->reg_lock_length    = cpu_to_le32(regSize);
+       pRAID_Context->config_seq_num   = raid->seqNum;
        /* save pointer to raid->LUN array */
        *raidLUN = raid->LUN;
 
@@ -1122,7 +1123,7 @@ MR_BuildRaidContext(struct megasas_instance *instance,
                                        ref_in_start_stripe, io_info,
                                        pRAID_Context, map);
                /* If IO on an invalid Pd, then FP is not possible.*/
-               if (io_info->devHandle == cpu_to_le16(MR_PD_INVALID))
+               if (io_info->devHandle == MR_DEVHANDLE_INVALID)
                        io_info->fpOkForIo = FALSE;
                return retval;
        } else if (isRead) {
@@ -1140,12 +1141,6 @@ MR_BuildRaidContext(struct megasas_instance *instance,
                                return TRUE;
                }
        }
-
-#if SPAN_DEBUG
-       /* Just for testing what arm we get for strip.*/
-       if (io_info->IoforUnevenSpan)
-               get_arm_from_strip(instance, ld, start_strip, map);
-#endif
        return TRUE;
 }
 
@@ -1259,10 +1254,6 @@ void mr_update_span_set(struct MR_DRV_RAID_MAP_ALL *map,
                        break;
            }
        }
-#if SPAN_DEBUG
-       getSpanInfo(map, ldSpanInfo);
-#endif
-
 }
 
 void mr_update_load_balance_params(struct MR_DRV_RAID_MAP_ALL *drv_map,
@@ -1293,11 +1284,12 @@ void mr_update_load_balance_params(struct MR_DRV_RAID_MAP_ALL *drv_map,
 }
 
 u8 megasas_get_best_arm_pd(struct megasas_instance *instance,
-       struct LD_LOAD_BALANCE_INFO *lbInfo, struct IO_REQUEST_INFO *io_info)
+                          struct LD_LOAD_BALANCE_INFO *lbInfo,
+                          struct IO_REQUEST_INFO *io_info,
+                          struct MR_DRV_RAID_MAP_ALL *drv_map)
 {
-       struct fusion_context *fusion;
        struct MR_LD_RAID  *raid;
-       struct MR_DRV_RAID_MAP_ALL *drv_map;
+       u16     pd1_dev_handle;
        u16     pend0, pend1, ld;
        u64     diff0, diff1;
        u8      bestArm, pd0, pd1, span, arm;
@@ -1310,9 +1302,6 @@ u8 megasas_get_best_arm_pd(struct megasas_instance *instance,
                        >> RAID_CTX_SPANARM_SPAN_SHIFT);
        arm = (io_info->span_arm & RAID_CTX_SPANARM_ARM_MASK);
 
-
-       fusion = instance->ctrl_context;
-       drv_map = fusion->ld_drv_map[(instance->map_id & 1)];
        ld = MR_TargetIdToLdGet(io_info->ldTgtId, drv_map);
        raid = MR_LdRaidGet(ld, drv_map);
        span_row_size = instance->UnevenSpanSupport ?
@@ -1323,47 +1312,52 @@ u8 megasas_get_best_arm_pd(struct megasas_instance *instance,
        pd1 = MR_ArPdGet(arRef, (arm + 1) >= span_row_size ?
                (arm + 1 - span_row_size) : arm + 1, drv_map);
 
-       /* get the pending cmds for the data and mirror arms */
-       pend0 = atomic_read(&lbInfo->scsi_pending_cmds[pd0]);
-       pend1 = atomic_read(&lbInfo->scsi_pending_cmds[pd1]);
+       /* Get PD1 Dev Handle */
+
+       pd1_dev_handle = MR_PdDevHandleGet(pd1, drv_map);
 
-       /* Determine the disk whose head is nearer to the req. block */
-       diff0 = ABS_DIFF(block, lbInfo->last_accessed_block[pd0]);
-       diff1 = ABS_DIFF(block, lbInfo->last_accessed_block[pd1]);
-       bestArm = (diff0 <= diff1 ? arm : arm ^ 1);
+       if (pd1_dev_handle == MR_DEVHANDLE_INVALID) {
+               bestArm = arm;
+       } else {
+               /* get the pending cmds for the data and mirror arms */
+               pend0 = atomic_read(&lbInfo->scsi_pending_cmds[pd0]);
+               pend1 = atomic_read(&lbInfo->scsi_pending_cmds[pd1]);
 
-       if ((bestArm == arm && pend0 > pend1 + lb_pending_cmds)  ||
-                       (bestArm != arm && pend1 > pend0 + lb_pending_cmds))
-               bestArm ^= 1;
+               /* Determine the disk whose head is nearer to the req. block */
+               diff0 = ABS_DIFF(block, lbInfo->last_accessed_block[pd0]);
+               diff1 = ABS_DIFF(block, lbInfo->last_accessed_block[pd1]);
+               bestArm = (diff0 <= diff1 ? arm : arm ^ 1);
+
+               /* Make balance count from 16 to 4 to
+                *  keep driver in sync with Firmware
+                */
+               if ((bestArm == arm && pend0 > pend1 + lb_pending_cmds)  ||
+                   (bestArm != arm && pend1 > pend0 + lb_pending_cmds))
+                       bestArm ^= 1;
+
+               /* Update the last accessed block on the correct pd */
+               io_info->span_arm =
+                       (span << RAID_CTX_SPANARM_SPAN_SHIFT) | bestArm;
+               io_info->pd_after_lb = (bestArm == arm) ? pd0 : pd1;
+       }
 
-       /* Update the last accessed block on the correct pd */
-       io_info->pd_after_lb = (bestArm == arm) ? pd0 : pd1;
        lbInfo->last_accessed_block[io_info->pd_after_lb] = block + count - 1;
-       io_info->span_arm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | bestArm;
-#if SPAN_DEBUG
-       if (arm != bestArm)
-               dev_dbg(&instance->pdev->dev, "LSI Debug R1 Load balance "
-                       "occur - span 0x%x arm 0x%x bestArm 0x%x "
-                       "io_info->span_arm 0x%x\n",
-                       span, arm, bestArm, io_info->span_arm);
-#endif
        return io_info->pd_after_lb;
 }
 
 __le16 get_updated_dev_handle(struct megasas_instance *instance,
-       struct LD_LOAD_BALANCE_INFO *lbInfo, struct IO_REQUEST_INFO *io_info)
+                             struct LD_LOAD_BALANCE_INFO *lbInfo,
+                             struct IO_REQUEST_INFO *io_info,
+                             struct MR_DRV_RAID_MAP_ALL *drv_map)
 {
        u8 arm_pd;
        __le16 devHandle;
-       struct fusion_context *fusion;
-       struct MR_DRV_RAID_MAP_ALL *drv_map;
-
-       fusion = instance->ctrl_context;
-       drv_map = fusion->ld_drv_map[(instance->map_id & 1)];
 
        /* get best new arm (PD ID) */
-       arm_pd  = megasas_get_best_arm_pd(instance, lbInfo, io_info);
+       arm_pd  = megasas_get_best_arm_pd(instance, lbInfo, io_info, drv_map);
        devHandle = MR_PdDevHandleGet(arm_pd, drv_map);
+       io_info->pd_interface = MR_PdInterfaceTypeGet(arm_pd, drv_map);
        atomic_inc(&lbInfo->scsi_pending_cmds[arm_pd]);
+
        return devHandle;
 }
index 24778ba4b6e8be0b4f2086b344031004ee982b89..29650ba669da58da099cf91e9de0aae504146bb0 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/blkdev.h>
 #include <linux/mutex.h>
 #include <linux/poll.h>
+#include <linux/vmalloc.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -181,32 +182,44 @@ inline void megasas_return_cmd_fusion(struct megasas_instance *instance,
        struct megasas_cmd_fusion *cmd)
 {
        cmd->scmd = NULL;
-       memset(cmd->io_request, 0, sizeof(struct MPI2_RAID_SCSI_IO_REQUEST));
+       memset(cmd->io_request, 0, MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE);
+       cmd->r1_alt_dev_handle = MR_DEVHANDLE_INVALID;
+       cmd->cmd_completed = false;
 }
 
 /**
  * megasas_fire_cmd_fusion -   Sends command to the FW
+ * @instance:                  Adapter soft state
+ * @req_desc:                  32bit or 64bit Request descriptor
+ *
+ * Perform PCI Write. Ventura supports 32 bit Descriptor.
+ * Prior to Ventura (12G) MR controller supports 64 bit Descriptor.
  */
+
 static void
 megasas_fire_cmd_fusion(struct megasas_instance *instance,
                union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc)
 {
+       if (instance->is_ventura)
+               writel(le32_to_cpu(req_desc->u.low),
+                       &instance->reg_set->inbound_single_queue_port);
+       else {
 #if defined(writeq) && defined(CONFIG_64BIT)
-       u64 req_data = (((u64)le32_to_cpu(req_desc->u.high) << 32) |
-                       le32_to_cpu(req_desc->u.low));
+               u64 req_data = (((u64)le32_to_cpu(req_desc->u.high) << 32) |
+                               le32_to_cpu(req_desc->u.low));
 
-       writeq(req_data, &instance->reg_set->inbound_low_queue_port);
+               writeq(req_data, &instance->reg_set->inbound_low_queue_port);
 #else
-       unsigned long flags;
-
-       spin_lock_irqsave(&instance->hba_lock, flags);
-       writel(le32_to_cpu(req_desc->u.low),
-               &instance->reg_set->inbound_low_queue_port);
-       writel(le32_to_cpu(req_desc->u.high),
-               &instance->reg_set->inbound_high_queue_port);
-       mmiowb();
-       spin_unlock_irqrestore(&instance->hba_lock, flags);
+               unsigned long flags;
+               spin_lock_irqsave(&instance->hba_lock, flags);
+               writel(le32_to_cpu(req_desc->u.low),
+                       &instance->reg_set->inbound_low_queue_port);
+               writel(le32_to_cpu(req_desc->u.high),
+                       &instance->reg_set->inbound_high_queue_port);
+               mmiowb();
+               spin_unlock_irqrestore(&instance->hba_lock, flags);
 #endif
+       }
 }
 
 /**
@@ -229,7 +242,10 @@ megasas_fusion_update_can_queue(struct megasas_instance *instance, int fw_boot_c
 
        reg_set = instance->reg_set;
 
-       cur_max_fw_cmds = readl(&instance->reg_set->outbound_scratch_pad_3) & 0x00FFFF;
+       /* ventura FW does not fill outbound_scratch_pad_3 with queue depth */
+       if (!instance->is_ventura)
+               cur_max_fw_cmds =
+               readl(&instance->reg_set->outbound_scratch_pad_3) & 0x00FFFF;
 
        if (dual_qdepth_disable || !cur_max_fw_cmds)
                cur_max_fw_cmds = instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;
@@ -243,7 +259,7 @@ megasas_fusion_update_can_queue(struct megasas_instance *instance, int fw_boot_c
 
        if (fw_boot_context == OCR_CONTEXT) {
                cur_max_fw_cmds = cur_max_fw_cmds - 1;
-               if (cur_max_fw_cmds <= instance->max_fw_cmds) {
+               if (cur_max_fw_cmds < instance->max_fw_cmds) {
                        instance->cur_can_queue =
                                cur_max_fw_cmds - (MEGASAS_FUSION_INTERNAL_CMDS +
                                                MEGASAS_FUSION_IOCTL_CMDS);
@@ -255,7 +271,8 @@ megasas_fusion_update_can_queue(struct megasas_instance *instance, int fw_boot_c
                instance->ldio_threshold = ldio_threshold;
 
                if (!instance->is_rdpq)
-                       instance->max_fw_cmds = min_t(u16, instance->max_fw_cmds, 1024);
+                       instance->max_fw_cmds =
+                               min_t(u16, instance->max_fw_cmds, 1024);
 
                if (reset_devices)
                        instance->max_fw_cmds = min(instance->max_fw_cmds,
@@ -271,7 +288,14 @@ megasas_fusion_update_can_queue(struct megasas_instance *instance, int fw_boot_c
                                (MEGASAS_FUSION_INTERNAL_CMDS +
                                MEGASAS_FUSION_IOCTL_CMDS);
                instance->cur_can_queue = instance->max_scsi_cmds;
+               instance->host->can_queue = instance->cur_can_queue;
        }
+
+       if (instance->is_ventura)
+               instance->max_mpt_cmds =
+               instance->max_fw_cmds * RAID_1_PEER_CMDS;
+       else
+               instance->max_mpt_cmds = instance->max_fw_cmds;
 }
 /**
  * megasas_free_cmds_fusion -  Free all the cmds in the free cmd pool
@@ -285,7 +309,7 @@ megasas_free_cmds_fusion(struct megasas_instance *instance)
        struct megasas_cmd_fusion *cmd;
 
        /* SG, Sense */
-       for (i = 0; i < instance->max_fw_cmds; i++) {
+       for (i = 0; i < instance->max_mpt_cmds; i++) {
                cmd = fusion->cmd_list[i];
                if (cmd) {
                        if (cmd->sg_frame)
@@ -329,7 +353,7 @@ megasas_free_cmds_fusion(struct megasas_instance *instance)
 
 
        /* cmd_list */
-       for (i = 0; i < instance->max_fw_cmds; i++)
+       for (i = 0; i < instance->max_mpt_cmds; i++)
                kfree(fusion->cmd_list[i]);
 
        kfree(fusion->cmd_list);
@@ -343,7 +367,7 @@ megasas_free_cmds_fusion(struct megasas_instance *instance)
 static int megasas_create_sg_sense_fusion(struct megasas_instance *instance)
 {
        int i;
-       u32 max_cmd;
+       u16 max_cmd;
        struct fusion_context *fusion;
        struct megasas_cmd_fusion *cmd;
 
@@ -353,7 +377,8 @@ static int megasas_create_sg_sense_fusion(struct megasas_instance *instance)
 
        fusion->sg_dma_pool =
                        pci_pool_create("mr_sg", instance->pdev,
-                               instance->max_chain_frame_sz, 4, 0);
+                               instance->max_chain_frame_sz,
+                               MR_DEFAULT_NVME_PAGE_SIZE, 0);
        /* SCSI_SENSE_BUFFERSIZE  = 96 bytes */
        fusion->sense_dma_pool =
                        pci_pool_create("mr_sense", instance->pdev,
@@ -381,33 +406,47 @@ static int megasas_create_sg_sense_fusion(struct megasas_instance *instance)
                        return -ENOMEM;
                }
        }
+
+       /* create sense buffer for the raid 1/10 fp */
+       for (i = max_cmd; i < instance->max_mpt_cmds; i++) {
+               cmd = fusion->cmd_list[i];
+               cmd->sense = pci_pool_alloc(fusion->sense_dma_pool,
+                       GFP_KERNEL, &cmd->sense_phys_addr);
+               if (!cmd->sense) {
+                       dev_err(&instance->pdev->dev,
+                               "Failed from %s %d\n",  __func__, __LINE__);
+                       return -ENOMEM;
+               }
+       }
+
        return 0;
 }
 
 int
 megasas_alloc_cmdlist_fusion(struct megasas_instance *instance)
 {
-       u32 max_cmd, i;
+       u32 max_mpt_cmd, i;
        struct fusion_context *fusion;
 
        fusion = instance->ctrl_context;
 
-       max_cmd = instance->max_fw_cmds;
+       max_mpt_cmd = instance->max_mpt_cmds;
 
        /*
         * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers.
         * Allocate the dynamic array first and then allocate individual
         * commands.
         */
-       fusion->cmd_list = kzalloc(sizeof(struct megasas_cmd_fusion *) * max_cmd,
-                                               GFP_KERNEL);
+       fusion->cmd_list =
+               kzalloc(sizeof(struct megasas_cmd_fusion *) * max_mpt_cmd,
+                       GFP_KERNEL);
        if (!fusion->cmd_list) {
                dev_err(&instance->pdev->dev,
                        "Failed from %s %d\n",  __func__, __LINE__);
                return -ENOMEM;
        }
 
-       for (i = 0; i < max_cmd; i++) {
+       for (i = 0; i < max_mpt_cmd; i++) {
                fusion->cmd_list[i] = kzalloc(sizeof(struct megasas_cmd_fusion),
                                              GFP_KERNEL);
                if (!fusion->cmd_list[i]) {
@@ -539,7 +578,7 @@ megasas_alloc_rdpq_fusion(struct megasas_instance *instance)
                }
 
                fusion->rdpq_virt[i].RDPQBaseAddress =
-                       fusion->reply_frames_desc_phys[i];
+                       cpu_to_le64(fusion->reply_frames_desc_phys[i]);
 
                reply_desc = fusion->reply_frames_desc[i];
                for (j = 0; j < fusion->reply_q_depth; j++, reply_desc++)
@@ -642,13 +681,14 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance)
         */
 
        /* SMID 0 is reserved. Set SMID/index from 1 */
-       for (i = 0; i < instance->max_fw_cmds; i++) {
+       for (i = 0; i < instance->max_mpt_cmds; i++) {
                cmd = fusion->cmd_list[i];
                offset = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * i;
                memset(cmd, 0, sizeof(struct megasas_cmd_fusion));
                cmd->index = i + 1;
                cmd->scmd = NULL;
-               cmd->sync_cmd_idx = (i >= instance->max_scsi_cmds) ?
+               cmd->sync_cmd_idx =
+               (i >= instance->max_scsi_cmds && i < instance->max_fw_cmds) ?
                                (i - instance->max_scsi_cmds) :
                                (u32)ULONG_MAX; /* Set to Invalid */
                cmd->instance = instance;
@@ -658,6 +698,7 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance)
                memset(cmd->io_request, 0,
                       sizeof(struct MPI2_RAID_SCSI_IO_REQUEST));
                cmd->io_request_phys_addr = io_req_base_phys + offset;
+               cmd->r1_alt_dev_handle = MR_DEVHANDLE_INVALID;
        }
 
        if (megasas_create_sg_sense_fusion(instance))
@@ -725,6 +766,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
        const char *sys_info;
        MFI_CAPABILITIES *drv_ops;
        u32 scratch_pad_2;
+       unsigned long flags;
 
        fusion = instance->ctrl_context;
 
@@ -781,6 +823,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
                        MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE : 0;
        IOCInitMessage->SystemRequestFrameBaseAddress = cpu_to_le64(fusion->io_request_frames_phys);
        IOCInitMessage->HostMSIxVectors = instance->msix_vectors;
+       IOCInitMessage->HostPageSize = MR_DEFAULT_NVME_PAGE_SHIFT;
        init_frame = (struct megasas_init_frame *)cmd->frame;
        memset(init_frame, 0, MEGAMFI_FRAME_SIZE);
 
@@ -796,7 +839,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
        drv_ops = (MFI_CAPABILITIES *) &(init_frame->driver_operations);
 
        /* driver support Extended MSIX */
-       if (fusion->adapter_type == INVADER_SERIES)
+       if (fusion->adapter_type >= INVADER_SERIES)
                drv_ops->mfi_capabilities.support_additional_msix = 1;
        /* driver supports HA / Remote LUN over Fast Path interface */
        drv_ops->mfi_capabilities.support_fp_remote_lun = 1;
@@ -813,6 +856,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
                drv_ops->mfi_capabilities.support_ext_queue_depth = 1;
 
        drv_ops->mfi_capabilities.support_qd_throttling = 1;
+       drv_ops->mfi_capabilities.support_pd_map_target_id = 1;
        /* Convert capability to LE32 */
        cpu_to_le32s((u32 *)&init_frame->driver_operations.mfi_capabilities);
 
@@ -850,7 +894,14 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
                        break;
        }
 
-       megasas_fire_cmd_fusion(instance, &req_desc);
+       /* For Ventura also IOC INIT required 64 bit Descriptor write. */
+       spin_lock_irqsave(&instance->hba_lock, flags);
+       writel(le32_to_cpu(req_desc.u.low),
+              &instance->reg_set->inbound_low_queue_port);
+       writel(le32_to_cpu(req_desc.u.high),
+              &instance->reg_set->inbound_high_queue_port);
+       mmiowb();
+       spin_unlock_irqrestore(&instance->hba_lock, flags);
 
        wait_and_poll(instance, cmd, MFI_POLL_TIMEOUT_SECS);
 
@@ -1009,11 +1060,6 @@ megasas_get_ld_map_info(struct megasas_instance *instance)
 
        memset(ci, 0, fusion->max_map_sz);
        memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
-#if VD_EXT_DEBUG
-       dev_dbg(&instance->pdev->dev,
-               "%s sending MR_DCMD_LD_MAP_GET_INFO with size %d\n",
-               __func__, cpu_to_le32(size_map_info));
-#endif
        dcmd->cmd = MFI_CMD_DCMD;
        dcmd->cmd_status = 0xFF;
        dcmd->sge_count = 1;
@@ -1065,10 +1111,11 @@ megasas_get_map_info(struct megasas_instance *instance)
 int
 megasas_sync_map_info(struct megasas_instance *instance)
 {
-       int ret = 0, i;
+       int i;
        struct megasas_cmd *cmd;
        struct megasas_dcmd_frame *dcmd;
-       u32 size_sync_info, num_lds;
+       u16 num_lds;
+       u32 size_sync_info;
        struct fusion_context *fusion;
        struct MR_LD_TARGET_SYNC *ci = NULL;
        struct MR_DRV_RAID_MAP_ALL *map;
@@ -1134,7 +1181,7 @@ megasas_sync_map_info(struct megasas_instance *instance)
 
        instance->instancet->issue_dcmd(instance, cmd);
 
-       return ret;
+       return 0;
 }
 
 /*
@@ -1220,7 +1267,8 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
 {
        struct megasas_register_set __iomem *reg_set;
        struct fusion_context *fusion;
-       u32 max_cmd, scratch_pad_2;
+       u16 max_cmd;
+       u32 scratch_pad_2;
        int i = 0, count;
 
        fusion = instance->ctrl_context;
@@ -1229,13 +1277,6 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
 
        megasas_fusion_update_can_queue(instance, PROBE_CONTEXT);
 
-       /*
-        * Reduce the max supported cmds by 1. This is to ensure that the
-        * reply_q_sz (1 more than the max cmd that driver may send)
-        * does not exceed max cmds that the FW can support
-        */
-       instance->max_fw_cmds = instance->max_fw_cmds-1;
-
        /*
         * Only Driver's internal DCMDs and IOCTL DCMDs needs to have MFI frames
         */
@@ -1247,12 +1288,12 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
        fusion->reply_q_depth = 2 * (((max_cmd + 1 + 15)/16)*16);
 
        fusion->request_alloc_sz =
-               sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) *max_cmd;
+       sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) * instance->max_mpt_cmds;
        fusion->reply_alloc_sz = sizeof(union MPI2_REPLY_DESCRIPTORS_UNION)
                *(fusion->reply_q_depth);
        fusion->io_frames_alloc_sz = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE +
-               (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE *
-                (max_cmd + 1)); /* Extra 1 for SMID 0 */
+               (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE
+               * (instance->max_mpt_cmds + 1)); /* Extra 1 for SMID 0 */
 
        scratch_pad_2 = readl(&instance->reg_set->outbound_scratch_pad_2);
        /* If scratch_pad_2 & MEGASAS_MAX_CHAIN_SIZE_UNITS_MASK is set,
@@ -1302,7 +1343,7 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
                fusion->last_reply_idx[i] = 0;
 
        /*
-        * For fusion adapters, 3 commands for IOCTL and 5 commands
+        * For fusion adapters, 3 commands for IOCTL and 8 commands
         * for driver's internal DCMDs.
         */
        instance->max_scsi_cmds = instance->max_fw_cmds -
@@ -1331,6 +1372,7 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
        }
 
        instance->flag_ieee = 1;
+       instance->r1_ldio_hint_default =  MR_R1_LDIO_PIGGYBACK_DEFAULT;
        fusion->fast_path_io = 0;
 
        fusion->drv_map_pages = get_order(fusion->drv_map_sz);
@@ -1388,96 +1430,348 @@ fail_alloc_mfi_cmds:
  */
 
 void
-map_cmd_status(struct megasas_cmd_fusion *cmd, u8 status, u8 ext_status)
+map_cmd_status(struct fusion_context *fusion,
+               struct scsi_cmnd *scmd, u8 status, u8 ext_status,
+               u32 data_length, u8 *sense)
 {
+       u8 cmd_type;
+       int resid;
 
+       cmd_type = megasas_cmd_type(scmd);
        switch (status) {
 
        case MFI_STAT_OK:
-               cmd->scmd->result = DID_OK << 16;
+               scmd->result = DID_OK << 16;
                break;
 
        case MFI_STAT_SCSI_IO_FAILED:
        case MFI_STAT_LD_INIT_IN_PROGRESS:
-               cmd->scmd->result = (DID_ERROR << 16) | ext_status;
+               scmd->result = (DID_ERROR << 16) | ext_status;
                break;
 
        case MFI_STAT_SCSI_DONE_WITH_ERROR:
 
-               cmd->scmd->result = (DID_OK << 16) | ext_status;
+               scmd->result = (DID_OK << 16) | ext_status;
                if (ext_status == SAM_STAT_CHECK_CONDITION) {
-                       memset(cmd->scmd->sense_buffer, 0,
+                       memset(scmd->sense_buffer, 0,
                               SCSI_SENSE_BUFFERSIZE);
-                       memcpy(cmd->scmd->sense_buffer, cmd->sense,
+                       memcpy(scmd->sense_buffer, sense,
                               SCSI_SENSE_BUFFERSIZE);
-                       cmd->scmd->result |= DRIVER_SENSE << 24;
+                       scmd->result |= DRIVER_SENSE << 24;
                }
+
+               /*
+                * If the  IO request is partially completed, then MR FW will
+                * update "io_request->DataLength" field with actual number of
+                * bytes transferred.Driver will set residual bytes count in
+                * SCSI command structure.
+                */
+               resid = (scsi_bufflen(scmd) - data_length);
+               scsi_set_resid(scmd, resid);
+
+               if (resid &&
+                       ((cmd_type == READ_WRITE_LDIO) ||
+                       (cmd_type == READ_WRITE_SYSPDIO)))
+                       scmd_printk(KERN_INFO, scmd, "BRCM Debug mfi stat 0x%x, data len"
+                               " requested/completed 0x%x/0x%x\n",
+                               status, scsi_bufflen(scmd), data_length);
                break;
 
        case MFI_STAT_LD_OFFLINE:
        case MFI_STAT_DEVICE_NOT_FOUND:
-               cmd->scmd->result = DID_BAD_TARGET << 16;
+               scmd->result = DID_BAD_TARGET << 16;
                break;
        case MFI_STAT_CONFIG_SEQ_MISMATCH:
-               cmd->scmd->result = DID_IMM_RETRY << 16;
+               scmd->result = DID_IMM_RETRY << 16;
                break;
        default:
-               dev_printk(KERN_DEBUG, &cmd->instance->pdev->dev, "FW status %#x\n", status);
-               cmd->scmd->result = DID_ERROR << 16;
+               scmd->result = DID_ERROR << 16;
                break;
        }
 }
 
+/**
+ * megasas_is_prp_possible -
+ * Checks if native NVMe PRPs can be built for the IO
+ *
+ * @instance:          Adapter soft state
+ * @scmd:              SCSI command from the mid-layer
+ * @sge_count:         scatter gather element count.
+ *
+ * Returns:            true: PRPs can be built
+ *                     false: IEEE SGLs needs to be built
+ */
+static bool
+megasas_is_prp_possible(struct megasas_instance *instance,
+                       struct scsi_cmnd *scmd, int sge_count)
+{
+       struct fusion_context *fusion;
+       int i;
+       u32 data_length = 0;
+       struct scatterlist *sg_scmd;
+       bool build_prp = false;
+       u32 mr_nvme_pg_size;
+
+       mr_nvme_pg_size = max_t(u32, instance->nvme_page_size,
+                               MR_DEFAULT_NVME_PAGE_SIZE);
+       fusion = instance->ctrl_context;
+       data_length = scsi_bufflen(scmd);
+       sg_scmd = scsi_sglist(scmd);
+
+       /*
+        * NVMe uses one PRP for each page (or part of a page)
+        * look at the data length - if 4 pages or less then IEEE is OK
+        * if  > 5 pages then we need to build a native SGL
+        * if > 4 and <= 5 pages, then check physical address of 1st SG entry
+        * if this first size in the page is >= the residual beyond 4 pages
+        * then use IEEE, otherwise use native SGL
+        */
+
+       if (data_length > (mr_nvme_pg_size * 5)) {
+               build_prp = true;
+       } else if ((data_length > (mr_nvme_pg_size * 4)) &&
+                       (data_length <= (mr_nvme_pg_size * 5)))  {
+               /* check if 1st SG entry size is < residual beyond 4 pages */
+               if (sg_dma_len(sg_scmd) < (data_length - (mr_nvme_pg_size * 4)))
+                       build_prp = true;
+       }
+
+/*
+ * Below code detects gaps/holes in IO data buffers.
+ * What does holes/gaps mean?
+ * Any SGE except first one in a SGL starts at non NVME page size
+ * aligned address OR Any SGE except last one in a SGL ends at
+ * non NVME page size boundary.
+ *
+ * Driver has already informed block layer by setting boundary rules for
+ * bio merging done at NVME page size boundary calling kernel API
+ * blk_queue_virt_boundary inside slave_config.
+ * Still there is possibility of IO coming with holes to driver because of
+ * IO merging done by IO scheduler.
+ *
+ * With SCSI BLK MQ enabled, there will be no IO with holes as there is no
+ * IO scheduling so no IO merging.
+ *
+ * With SCSI BLK MQ disabled, IO scheduler may attempt to merge IOs and
+ * then sending IOs with holes.
+ *
+ * Though driver can request block layer to disable IO merging by calling-
+ * queue_flag_set_unlocked(QUEUE_FLAG_NOMERGES, sdev->request_queue) but
+ * user may tune sysfs parameter- nomerges again to 0 or 1.
+ *
+ * If in future IO scheduling is enabled with SCSI BLK MQ,
+ * this algorithm to detect holes will be required in driver
+ * for SCSI BLK MQ enabled case as well.
+ *
+ *
+ */
+       scsi_for_each_sg(scmd, sg_scmd, sge_count, i) {
+               if ((i != 0) && (i != (sge_count - 1))) {
+                       if (mega_mod64(sg_dma_len(sg_scmd), mr_nvme_pg_size) ||
+                           mega_mod64(sg_dma_address(sg_scmd),
+                                      mr_nvme_pg_size)) {
+                               build_prp = false;
+                               atomic_inc(&instance->sge_holes_type1);
+                               break;
+                       }
+               }
+
+               if ((sge_count > 1) && (i == 0)) {
+                       if ((mega_mod64((sg_dma_address(sg_scmd) +
+                                       sg_dma_len(sg_scmd)),
+                                       mr_nvme_pg_size))) {
+                               build_prp = false;
+                               atomic_inc(&instance->sge_holes_type2);
+                               break;
+                       }
+               }
+
+               if ((sge_count > 1) && (i == (sge_count - 1))) {
+                       if (mega_mod64(sg_dma_address(sg_scmd),
+                                      mr_nvme_pg_size)) {
+                               build_prp = false;
+                               atomic_inc(&instance->sge_holes_type3);
+                               break;
+                       }
+               }
+       }
+
+       return build_prp;
+}
+
+/**
+ * megasas_make_prp_nvme -
+ * Prepare PRPs(Physical Region Page)- SGLs specific to NVMe drives only
+ *
+ * @instance:          Adapter soft state
+ * @scmd:              SCSI command from the mid-layer
+ * @sgl_ptr:           SGL to be filled in
+ * @cmd:               Fusion command frame
+ * @sge_count:         scatter gather element count.
+ *
+ * Returns:            true: PRPs are built
+ *                     false: IEEE SGLs needs to be built
+ */
+static bool
+megasas_make_prp_nvme(struct megasas_instance *instance, struct scsi_cmnd *scmd,
+                     struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr,
+                     struct megasas_cmd_fusion *cmd, int sge_count)
+{
+       int sge_len, offset, num_prp_in_chain = 0;
+       struct MPI25_IEEE_SGE_CHAIN64 *main_chain_element, *ptr_first_sgl;
+       u64 *ptr_sgl;
+       dma_addr_t ptr_sgl_phys;
+       u64 sge_addr;
+       u32 page_mask, page_mask_result;
+       struct scatterlist *sg_scmd;
+       u32 first_prp_len;
+       bool build_prp = false;
+       int data_len = scsi_bufflen(scmd);
+       struct fusion_context *fusion;
+       u32 mr_nvme_pg_size = max_t(u32, instance->nvme_page_size,
+                                       MR_DEFAULT_NVME_PAGE_SIZE);
+
+       fusion = instance->ctrl_context;
+
+       build_prp = megasas_is_prp_possible(instance, scmd, sge_count);
+
+       if (!build_prp)
+               return false;
+
+       /*
+        * Nvme has a very convoluted prp format.  One prp is required
+        * for each page or partial page. Driver need to split up OS sg_list
+        * entries if it is longer than one page or cross a page
+        * boundary.  Driver also have to insert a PRP list pointer entry as
+        * the last entry in each physical page of the PRP list.
+        *
+        * NOTE: The first PRP "entry" is actually placed in the first
+        * SGL entry in the main message as IEEE 64 format.  The 2nd
+        * entry in the main message is the chain element, and the rest
+        * of the PRP entries are built in the contiguous pcie buffer.
+        */
+       page_mask = mr_nvme_pg_size - 1;
+       ptr_sgl = (u64 *)cmd->sg_frame;
+       ptr_sgl_phys = cmd->sg_frame_phys_addr;
+       memset(ptr_sgl, 0, instance->max_chain_frame_sz);
+
+       /* Build chain frame element which holds all prps except first*/
+       main_chain_element = (struct MPI25_IEEE_SGE_CHAIN64 *)
+           ((u8 *)sgl_ptr + sizeof(struct MPI25_IEEE_SGE_CHAIN64));
+
+       main_chain_element->Address = cpu_to_le64(ptr_sgl_phys);
+       main_chain_element->NextChainOffset = 0;
+       main_chain_element->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT |
+                                       IEEE_SGE_FLAGS_SYSTEM_ADDR |
+                                       MPI26_IEEE_SGE_FLAGS_NSF_NVME_PRP;
+
+       /* Build first prp, sge need not to be page aligned*/
+       ptr_first_sgl = sgl_ptr;
+       sg_scmd = scsi_sglist(scmd);
+       sge_addr = sg_dma_address(sg_scmd);
+       sge_len = sg_dma_len(sg_scmd);
+
+       offset = (u32)(sge_addr & page_mask);
+       first_prp_len = mr_nvme_pg_size - offset;
+
+       ptr_first_sgl->Address = cpu_to_le64(sge_addr);
+       ptr_first_sgl->Length = cpu_to_le32(first_prp_len);
+
+       data_len -= first_prp_len;
+
+       if (sge_len > first_prp_len) {
+               sge_addr += first_prp_len;
+               sge_len -= first_prp_len;
+       } else if (sge_len == first_prp_len) {
+               sg_scmd = sg_next(sg_scmd);
+               sge_addr = sg_dma_address(sg_scmd);
+               sge_len = sg_dma_len(sg_scmd);
+       }
+
+       for (;;) {
+               offset = (u32)(sge_addr & page_mask);
+
+               /* Put PRP pointer due to page boundary*/
+               page_mask_result = (uintptr_t)(ptr_sgl + 1) & page_mask;
+               if (unlikely(!page_mask_result)) {
+                       scmd_printk(KERN_NOTICE,
+                                   scmd, "page boundary ptr_sgl: 0x%p\n",
+                                   ptr_sgl);
+                       ptr_sgl_phys += 8;
+                       *ptr_sgl = cpu_to_le64(ptr_sgl_phys);
+                       ptr_sgl++;
+                       num_prp_in_chain++;
+               }
+
+               *ptr_sgl = cpu_to_le64(sge_addr);
+               ptr_sgl++;
+               ptr_sgl_phys += 8;
+               num_prp_in_chain++;
+
+               sge_addr += mr_nvme_pg_size;
+               sge_len -= mr_nvme_pg_size;
+               data_len -= mr_nvme_pg_size;
+
+               if (data_len <= 0)
+                       break;
+
+               if (sge_len > 0)
+                       continue;
+
+               sg_scmd = sg_next(sg_scmd);
+               sge_addr = sg_dma_address(sg_scmd);
+               sge_len = sg_dma_len(sg_scmd);
+       }
+
+       main_chain_element->Length =
+                       cpu_to_le32(num_prp_in_chain * sizeof(u64));
+
+       atomic_inc(&instance->prp_sgl);
+       return build_prp;
+}
+
 /**
  * megasas_make_sgl_fusion -   Prepares 32-bit SGL
  * @instance:          Adapter soft state
  * @scp:               SCSI command from the mid-layer
  * @sgl_ptr:           SGL to be filled in
  * @cmd:               cmd we are working on
+ * @sge_count          sge count
  *
- * If successful, this function returns the number of SG elements.
  */
-static int
+static void
 megasas_make_sgl_fusion(struct megasas_instance *instance,
                        struct scsi_cmnd *scp,
                        struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr,
-                       struct megasas_cmd_fusion *cmd)
+                       struct megasas_cmd_fusion *cmd, int sge_count)
 {
-       int i, sg_processed, sge_count;
+       int i, sg_processed;
        struct scatterlist *os_sgl;
        struct fusion_context *fusion;
 
        fusion = instance->ctrl_context;
 
-       if (fusion->adapter_type == INVADER_SERIES) {
+       if (fusion->adapter_type >= INVADER_SERIES) {
                struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr_end = sgl_ptr;
                sgl_ptr_end += fusion->max_sge_in_main_msg - 1;
                sgl_ptr_end->Flags = 0;
        }
 
-       sge_count = scsi_dma_map(scp);
-
-       BUG_ON(sge_count < 0);
-
-       if (sge_count > instance->max_num_sge || !sge_count)
-               return sge_count;
-
        scsi_for_each_sg(scp, os_sgl, sge_count, i) {
                sgl_ptr->Length = cpu_to_le32(sg_dma_len(os_sgl));
                sgl_ptr->Address = cpu_to_le64(sg_dma_address(os_sgl));
                sgl_ptr->Flags = 0;
-               if (fusion->adapter_type == INVADER_SERIES)
+               if (fusion->adapter_type >= INVADER_SERIES)
                        if (i == sge_count - 1)
                                sgl_ptr->Flags = IEEE_SGE_FLAGS_END_OF_LIST;
                sgl_ptr++;
-
                sg_processed = i + 1;
 
                if ((sg_processed ==  (fusion->max_sge_in_main_msg - 1)) &&
                    (sge_count > fusion->max_sge_in_main_msg)) {
 
                        struct MPI25_IEEE_SGE_CHAIN64 *sg_chain;
-                       if (fusion->adapter_type == INVADER_SERIES) {
+                       if (fusion->adapter_type >= INVADER_SERIES) {
                                if ((le16_to_cpu(cmd->io_request->IoFlags) &
                                        MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) !=
                                        MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH)
@@ -1493,7 +1787,7 @@ megasas_make_sgl_fusion(struct megasas_instance *instance,
                        sg_chain = sgl_ptr;
                        /* Prepare chain element */
                        sg_chain->NextChainOffset = 0;
-                       if (fusion->adapter_type == INVADER_SERIES)
+                       if (fusion->adapter_type >= INVADER_SERIES)
                                sg_chain->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT;
                        else
                                sg_chain->Flags =
@@ -1507,6 +1801,45 @@ megasas_make_sgl_fusion(struct megasas_instance *instance,
                        memset(sgl_ptr, 0, instance->max_chain_frame_sz);
                }
        }
+       atomic_inc(&instance->ieee_sgl);
+}
+
+/**
+ * megasas_make_sgl -  Build Scatter Gather List(SGLs)
+ * @scp:               SCSI command pointer
+ * @instance:          Soft instance of controller
+ * @cmd:               Fusion command pointer
+ *
+ * This function will build sgls based on device type.
+ * For nvme drives, there is different way of building sgls in nvme native
+ * format- PRPs(Physical Region Page).
+ *
+ * Returns the number of sg lists actually used, zero if the sg lists
+ * is NULL, or -ENOMEM if the mapping failed
+ */
+static
+int megasas_make_sgl(struct megasas_instance *instance, struct scsi_cmnd *scp,
+                    struct megasas_cmd_fusion *cmd)
+{
+       int sge_count;
+       bool build_prp = false;
+       struct MPI25_IEEE_SGE_CHAIN64 *sgl_chain64;
+
+       sge_count = scsi_dma_map(scp);
+
+       if ((sge_count > instance->max_num_sge) || (sge_count <= 0))
+               return sge_count;
+
+       sgl_chain64 = (struct MPI25_IEEE_SGE_CHAIN64 *)&cmd->io_request->SGL;
+       if ((le16_to_cpu(cmd->io_request->IoFlags) &
+           MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) &&
+           (cmd->pd_interface == NVME_PD))
+               build_prp = megasas_make_prp_nvme(instance, scp, sgl_chain64,
+                                                 cmd, sge_count);
+
+       if (!build_prp)
+               megasas_make_sgl_fusion(instance, scp, sgl_chain64,
+                                       cmd, sge_count);
 
        return sge_count;
 }
@@ -1525,7 +1858,7 @@ megasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len,
                   struct MR_DRV_RAID_MAP_ALL *local_map_ptr, u32 ref_tag)
 {
        struct MR_LD_RAID *raid;
-       u32 ld;
+       u16 ld;
        u64 start_blk = io_info->pdBlock;
        u8 *cdb = io_request->CDB.CDB32;
        u32 num_blocks = io_info->numBlocks;
@@ -1574,6 +1907,7 @@ megasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len,
                                MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
                                MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP |
                                MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG |
+                               MPI25_SCSIIO_EEDPFLAGS_DO_NOT_DISABLE_MODE |
                                MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD);
                } else {
                        io_request->EEDPFlags = cpu_to_le16(
@@ -1687,6 +2021,166 @@ megasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len,
        }
 }
 
+/**
+ * megasas_stream_detect -     stream detection on read and and write IOs
+ * @instance:          Adapter soft state
+ * @cmd:                   Command to be prepared
+ * @io_info:           IO Request info
+ *
+ */
+
+/** stream detection on read and and write IOs */
+static void megasas_stream_detect(struct megasas_instance *instance,
+                                 struct megasas_cmd_fusion *cmd,
+                                 struct IO_REQUEST_INFO *io_info)
+{
+       struct fusion_context *fusion = instance->ctrl_context;
+       u32 device_id = io_info->ldTgtId;
+       struct LD_STREAM_DETECT *current_ld_sd
+               = fusion->stream_detect_by_ld[device_id];
+       u32 *track_stream = &current_ld_sd->mru_bit_map, stream_num;
+       u32 shifted_values, unshifted_values;
+       u32 index_value_mask, shifted_values_mask;
+       int i;
+       bool is_read_ahead = false;
+       struct STREAM_DETECT *current_sd;
+       /* find possible stream */
+       for (i = 0; i < MAX_STREAMS_TRACKED; ++i) {
+               stream_num = (*track_stream >>
+                       (i * BITS_PER_INDEX_STREAM)) &
+                       STREAM_MASK;
+               current_sd = &current_ld_sd->stream_track[stream_num];
+               /* if we found a stream, update the raid
+                *  context and also update the mruBitMap
+                */
+               /*      boundary condition */
+               if ((current_sd->next_seq_lba) &&
+                   (io_info->ldStartBlock >= current_sd->next_seq_lba) &&
+                   (io_info->ldStartBlock <= (current_sd->next_seq_lba + 32)) &&
+                   (current_sd->is_read == io_info->isRead)) {
+
+                       if ((io_info->ldStartBlock != current_sd->next_seq_lba) &&
+                           ((!io_info->isRead) || (!is_read_ahead)))
+                               /*
+                                * Once the API availible we need to change this.
+                                * At this point we are not allowing any gap
+                                */
+                               continue;
+
+                       SET_STREAM_DETECTED(cmd->io_request->RaidContext.raid_context_g35);
+                       current_sd->next_seq_lba =
+                       io_info->ldStartBlock + io_info->numBlocks;
+                       /*
+                        *      update the mruBitMap LRU
+                        */
+                       shifted_values_mask =
+                               (1 <<  i * BITS_PER_INDEX_STREAM) - 1;
+                       shifted_values = ((*track_stream & shifted_values_mask)
+                                               << BITS_PER_INDEX_STREAM);
+                       index_value_mask =
+                               STREAM_MASK << i * BITS_PER_INDEX_STREAM;
+                       unshifted_values =
+                               *track_stream & ~(shifted_values_mask |
+                               index_value_mask);
+                       *track_stream =
+                               unshifted_values | shifted_values | stream_num;
+                       return;
+               }
+       }
+       /*
+        * if we did not find any stream, create a new one
+        * from the least recently used
+        */
+       stream_num = (*track_stream >>
+               ((MAX_STREAMS_TRACKED - 1) * BITS_PER_INDEX_STREAM)) &
+               STREAM_MASK;
+       current_sd = &current_ld_sd->stream_track[stream_num];
+       current_sd->is_read = io_info->isRead;
+       current_sd->next_seq_lba = io_info->ldStartBlock + io_info->numBlocks;
+       *track_stream = (((*track_stream & ZERO_LAST_STREAM) << 4) | stream_num);
+       return;
+}
+
+/**
+ * megasas_set_raidflag_cpu_affinity - This function sets the cpu
+ * affinity (cpu of the controller) and raid_flags in the raid context
+ * based on IO type.
+ *
+ * @praid_context:     IO RAID context
+ * @raid:              LD raid map
+ * @fp_possible:       Is fast path possible?
+ * @is_read:           Is read IO?
+ *
+ */
+static void
+megasas_set_raidflag_cpu_affinity(union RAID_CONTEXT_UNION *praid_context,
+                                 struct MR_LD_RAID *raid, bool fp_possible,
+                                 u8 is_read, u32 scsi_buff_len)
+{
+       u8 cpu_sel = MR_RAID_CTX_CPUSEL_0;
+       struct RAID_CONTEXT_G35 *rctx_g35;
+
+       rctx_g35 = &praid_context->raid_context_g35;
+       if (fp_possible) {
+               if (is_read) {
+                       if ((raid->cpuAffinity.pdRead.cpu0) &&
+                           (raid->cpuAffinity.pdRead.cpu1))
+                               cpu_sel = MR_RAID_CTX_CPUSEL_FCFS;
+                       else if (raid->cpuAffinity.pdRead.cpu1)
+                               cpu_sel = MR_RAID_CTX_CPUSEL_1;
+               } else {
+                       if ((raid->cpuAffinity.pdWrite.cpu0) &&
+                           (raid->cpuAffinity.pdWrite.cpu1))
+                               cpu_sel = MR_RAID_CTX_CPUSEL_FCFS;
+                       else if (raid->cpuAffinity.pdWrite.cpu1)
+                               cpu_sel = MR_RAID_CTX_CPUSEL_1;
+                       /* Fast path cache by pass capable R0/R1 VD */
+                       if ((raid->level <= 1) &&
+                           (raid->capability.fp_cache_bypass_capable)) {
+                               rctx_g35->routing_flags |=
+                                       (1 << MR_RAID_CTX_ROUTINGFLAGS_SLD_SHIFT);
+                               rctx_g35->raid_flags =
+                                       (MR_RAID_FLAGS_IO_SUB_TYPE_CACHE_BYPASS
+                                       << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT);
+                       }
+               }
+       } else {
+               if (is_read) {
+                       if ((raid->cpuAffinity.ldRead.cpu0) &&
+                           (raid->cpuAffinity.ldRead.cpu1))
+                               cpu_sel = MR_RAID_CTX_CPUSEL_FCFS;
+                       else if (raid->cpuAffinity.ldRead.cpu1)
+                               cpu_sel = MR_RAID_CTX_CPUSEL_1;
+               } else {
+                       if ((raid->cpuAffinity.ldWrite.cpu0) &&
+                           (raid->cpuAffinity.ldWrite.cpu1))
+                               cpu_sel = MR_RAID_CTX_CPUSEL_FCFS;
+                       else if (raid->cpuAffinity.ldWrite.cpu1)
+                               cpu_sel = MR_RAID_CTX_CPUSEL_1;
+
+                       if (is_stream_detected(rctx_g35) &&
+                           (raid->level == 5) &&
+                           (raid->writeMode == MR_RL_WRITE_THROUGH_MODE) &&
+                           (cpu_sel == MR_RAID_CTX_CPUSEL_FCFS))
+                               cpu_sel = MR_RAID_CTX_CPUSEL_0;
+               }
+       }
+
+       rctx_g35->routing_flags |=
+               (cpu_sel << MR_RAID_CTX_ROUTINGFLAGS_CPUSEL_SHIFT);
+
+       /* Always give priority to MR_RAID_FLAGS_IO_SUB_TYPE_LDIO_BW_LIMIT
+        * vs MR_RAID_FLAGS_IO_SUB_TYPE_CACHE_BYPASS.
+        * IO Subtype is not bitmap.
+        */
+       if ((raid->level == 1) && (!is_read)) {
+               if (scsi_buff_len > MR_LARGE_IO_MIN_SIZE)
+                       praid_context->raid_context_g35.raid_flags =
+                               (MR_RAID_FLAGS_IO_SUB_TYPE_LDIO_BW_LIMIT
+                               << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT);
+       }
+}
+
 /**
  * megasas_build_ldio_fusion - Prepares IOs to devices
  * @instance:          Adapter soft state
@@ -1701,29 +2195,36 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
                          struct scsi_cmnd *scp,
                          struct megasas_cmd_fusion *cmd)
 {
-       u8 fp_possible;
+       bool fp_possible;
+       u16 ld;
        u32 start_lba_lo, start_lba_hi, device_id, datalength = 0;
+       u32 scsi_buff_len;
        struct MPI2_RAID_SCSI_IO_REQUEST *io_request;
        union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
        struct IO_REQUEST_INFO io_info;
        struct fusion_context *fusion;
        struct MR_DRV_RAID_MAP_ALL *local_map_ptr;
        u8 *raidLUN;
+       unsigned long spinlock_flags;
+       union RAID_CONTEXT_UNION *praid_context;
+       struct MR_LD_RAID *raid = NULL;
+       struct MR_PRIV_DEVICE *mrdev_priv;
 
        device_id = MEGASAS_DEV_INDEX(scp);
 
        fusion = instance->ctrl_context;
 
        io_request = cmd->io_request;
-       io_request->RaidContext.VirtualDiskTgtId = cpu_to_le16(device_id);
-       io_request->RaidContext.status = 0;
-       io_request->RaidContext.exStatus = 0;
+       io_request->RaidContext.raid_context.virtual_disk_tgt_id =
+               cpu_to_le16(device_id);
+       io_request->RaidContext.raid_context.status = 0;
+       io_request->RaidContext.raid_context.ex_status = 0;
 
        req_desc = (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)cmd->request_desc;
 
        start_lba_lo = 0;
        start_lba_hi = 0;
-       fp_possible = 0;
+       fp_possible = false;
 
        /*
         * 6-byte READ(0x08) or WRITE(0x0A) cdb
@@ -1779,22 +2280,27 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
        io_info.ldStartBlock = ((u64)start_lba_hi << 32) | start_lba_lo;
        io_info.numBlocks = datalength;
        io_info.ldTgtId = device_id;
-       io_request->DataLength = cpu_to_le32(scsi_bufflen(scp));
+       io_info.r1_alt_dev_handle = MR_DEVHANDLE_INVALID;
+       scsi_buff_len = scsi_bufflen(scp);
+       io_request->DataLength = cpu_to_le32(scsi_buff_len);
 
        if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)
                io_info.isRead = 1;
 
        local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)];
+       ld = MR_TargetIdToLdGet(device_id, local_map_ptr);
 
-       if ((MR_TargetIdToLdGet(device_id, local_map_ptr) >=
-               instance->fw_supported_vd_count) || (!fusion->fast_path_io)) {
-               io_request->RaidContext.regLockFlags  = 0;
-               fp_possible = 0;
+       if (ld < instance->fw_supported_vd_count)
+               raid = MR_LdRaidGet(ld, local_map_ptr);
+
+       if (!raid || (!fusion->fast_path_io)) {
+               io_request->RaidContext.raid_context.reg_lock_flags  = 0;
+               fp_possible = false;
        } else {
                if (MR_BuildRaidContext(instance, &io_info,
-                                       &io_request->RaidContext,
+                                       &io_request->RaidContext.raid_context,
                                        local_map_ptr, &raidLUN))
-                       fp_possible = io_info.fpOkForIo;
+                       fp_possible = (io_info.fpOkForIo > 0) ? true : false;
        }
 
        /* Use raw_smp_processor_id() for now until cmd->request->cpu is CPU
@@ -1803,6 +2309,54 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
        cmd->request_desc->SCSIIO.MSIxIndex = instance->msix_vectors ?
                raw_smp_processor_id() % instance->msix_vectors : 0;
 
+       praid_context = &io_request->RaidContext;
+
+       if (instance->is_ventura) {
+               spin_lock_irqsave(&instance->stream_lock, spinlock_flags);
+               megasas_stream_detect(instance, cmd, &io_info);
+               spin_unlock_irqrestore(&instance->stream_lock, spinlock_flags);
+               /* In ventura if stream detected for a read and it is read ahead
+                *  capable make this IO as LDIO
+                */
+               if (is_stream_detected(&io_request->RaidContext.raid_context_g35) &&
+                   io_info.isRead && io_info.ra_capable)
+                       fp_possible = false;
+
+               /* FP for Optimal raid level 1.
+                * All large RAID-1 writes (> 32 KiB, both WT and WB modes)
+                * are built by the driver as LD I/Os.
+                * All small RAID-1 WT writes (<= 32 KiB) are built as FP I/Os
+                * (there is never a reason to process these as buffered writes)
+                * All small RAID-1 WB writes (<= 32 KiB) are built as FP I/Os
+                * with the SLD bit asserted.
+                */
+               if (io_info.r1_alt_dev_handle != MR_DEVHANDLE_INVALID) {
+                       mrdev_priv = scp->device->hostdata;
+
+                       if (atomic_inc_return(&instance->fw_outstanding) >
+                               (instance->host->can_queue)) {
+                               fp_possible = false;
+                               atomic_dec(&instance->fw_outstanding);
+                       } else if ((scsi_buff_len > MR_LARGE_IO_MIN_SIZE) ||
+                                  atomic_dec_if_positive(&mrdev_priv->r1_ldio_hint)) {
+                               fp_possible = false;
+                               atomic_dec(&instance->fw_outstanding);
+                               if (scsi_buff_len > MR_LARGE_IO_MIN_SIZE)
+                                       atomic_set(&mrdev_priv->r1_ldio_hint,
+                                                  instance->r1_ldio_hint_default);
+                       }
+               }
+
+               /* If raid is NULL, set CPU affinity to default CPU0 */
+               if (raid)
+                       megasas_set_raidflag_cpu_affinity(praid_context,
+                               raid, fp_possible, io_info.isRead,
+                               scsi_buff_len);
+               else
+                       praid_context->raid_context_g35.routing_flags |=
+                               (MR_RAID_CTX_CPUSEL_0 << MR_RAID_CTX_ROUTINGFLAGS_CPUSEL_SHIFT);
+       }
+
        if (fp_possible) {
                megasas_set_pd_lba(io_request, scp->cmd_len, &io_info, scp,
                                   local_map_ptr, start_lba_lo);
@@ -1811,29 +2365,52 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
                        (MPI2_REQ_DESCRIPT_FLAGS_FP_IO
                         << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
                if (fusion->adapter_type == INVADER_SERIES) {
-                       if (io_request->RaidContext.regLockFlags ==
+                       if (io_request->RaidContext.raid_context.reg_lock_flags ==
                            REGION_TYPE_UNUSED)
                                cmd->request_desc->SCSIIO.RequestFlags =
                                        (MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK <<
                                        MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
-                       io_request->RaidContext.Type = MPI2_TYPE_CUDA;
-                       io_request->RaidContext.nseg = 0x1;
+                       io_request->RaidContext.raid_context.type
+                               = MPI2_TYPE_CUDA;
+                       io_request->RaidContext.raid_context.nseg = 0x1;
                        io_request->IoFlags |= cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH);
-                       io_request->RaidContext.regLockFlags |=
+                       io_request->RaidContext.raid_context.reg_lock_flags |=
                          (MR_RL_FLAGS_GRANT_DESTINATION_CUDA |
                           MR_RL_FLAGS_SEQ_NUM_ENABLE);
+               } else if (instance->is_ventura) {
+                       io_request->RaidContext.raid_context_g35.nseg_type |=
+                                               (1 << RAID_CONTEXT_NSEG_SHIFT);
+                       io_request->RaidContext.raid_context_g35.nseg_type |=
+                                               (MPI2_TYPE_CUDA << RAID_CONTEXT_TYPE_SHIFT);
+                       io_request->RaidContext.raid_context_g35.routing_flags |=
+                                               (1 << MR_RAID_CTX_ROUTINGFLAGS_SQN_SHIFT);
+                       io_request->IoFlags |=
+                               cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH);
                }
-               if ((fusion->load_balance_info[device_id].loadBalanceFlag) &&
-                   (io_info.isRead)) {
+               if (fusion->load_balance_info &&
+                       (fusion->load_balance_info[device_id].loadBalanceFlag) &&
+                       (io_info.isRead)) {
                        io_info.devHandle =
                                get_updated_dev_handle(instance,
                                        &fusion->load_balance_info[device_id],
-                                       &io_info);
+                                       &io_info, local_map_ptr);
                        scp->SCp.Status |= MEGASAS_LOAD_BALANCE_FLAG;
                        cmd->pd_r1_lb = io_info.pd_after_lb;
+                       if (instance->is_ventura)
+                               io_request->RaidContext.raid_context_g35.span_arm
+                                       = io_info.span_arm;
+                       else
+                               io_request->RaidContext.raid_context.span_arm
+                                       = io_info.span_arm;
+
                } else
                        scp->SCp.Status &= ~MEGASAS_LOAD_BALANCE_FLAG;
 
+               if (instance->is_ventura)
+                       cmd->r1_alt_dev_handle = io_info.r1_alt_dev_handle;
+               else
+                       cmd->r1_alt_dev_handle = MR_DEVHANDLE_INVALID;
+
                if ((raidLUN[0] == 1) &&
                        (local_map_ptr->raidMap.devHndlInfo[io_info.pd_after_lb].validHandles > 1)) {
                        instance->dev_handle = !(instance->dev_handle);
@@ -1843,28 +2420,39 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
 
                cmd->request_desc->SCSIIO.DevHandle = io_info.devHandle;
                io_request->DevHandle = io_info.devHandle;
+               cmd->pd_interface = io_info.pd_interface;
                /* populate the LUN field */
                memcpy(io_request->LUN, raidLUN, 8);
        } else {
-               io_request->RaidContext.timeoutValue =
+               io_request->RaidContext.raid_context.timeout_value =
                        cpu_to_le16(local_map_ptr->raidMap.fpPdIoTimeoutSec);
                cmd->request_desc->SCSIIO.RequestFlags =
                        (MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO
                         << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
                if (fusion->adapter_type == INVADER_SERIES) {
                        if (io_info.do_fp_rlbypass ||
-                               (io_request->RaidContext.regLockFlags == REGION_TYPE_UNUSED))
+                       (io_request->RaidContext.raid_context.reg_lock_flags
+                                       == REGION_TYPE_UNUSED))
                                cmd->request_desc->SCSIIO.RequestFlags =
                                        (MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK <<
                                        MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
-                       io_request->RaidContext.Type = MPI2_TYPE_CUDA;
-                       io_request->RaidContext.regLockFlags |=
+                       io_request->RaidContext.raid_context.type
+                               = MPI2_TYPE_CUDA;
+                       io_request->RaidContext.raid_context.reg_lock_flags |=
                                (MR_RL_FLAGS_GRANT_DESTINATION_CPU0 |
                                 MR_RL_FLAGS_SEQ_NUM_ENABLE);
-                       io_request->RaidContext.nseg = 0x1;
+                       io_request->RaidContext.raid_context.nseg = 0x1;
+               } else if (instance->is_ventura) {
+                       io_request->RaidContext.raid_context_g35.routing_flags |=
+                                       (1 << MR_RAID_CTX_ROUTINGFLAGS_SQN_SHIFT);
+                       io_request->RaidContext.raid_context_g35.nseg_type |=
+                                       (1 << RAID_CONTEXT_NSEG_SHIFT);
+                       io_request->RaidContext.raid_context_g35.nseg_type |=
+                                       (MPI2_TYPE_CUDA << RAID_CONTEXT_TYPE_SHIFT);
                }
                io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST;
                io_request->DevHandle = cpu_to_le16(device_id);
+
        } /* Not FP */
 }
 
@@ -1881,27 +2469,26 @@ static void megasas_build_ld_nonrw_fusion(struct megasas_instance *instance,
 {
        u32 device_id;
        struct MPI2_RAID_SCSI_IO_REQUEST *io_request;
-       u16 pd_index = 0;
+       u16 ld;
        struct MR_DRV_RAID_MAP_ALL *local_map_ptr;
        struct fusion_context *fusion = instance->ctrl_context;
        u8                          span, physArm;
        __le16                      devHandle;
-       u32                         ld, arRef, pd;
+       u32                         arRef, pd;
        struct MR_LD_RAID                  *raid;
        struct RAID_CONTEXT                *pRAID_Context;
        u8 fp_possible = 1;
 
        io_request = cmd->io_request;
        device_id = MEGASAS_DEV_INDEX(scmd);
-       pd_index = MEGASAS_PD_INDEX(scmd);
        local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)];
        io_request->DataLength = cpu_to_le32(scsi_bufflen(scmd));
        /* get RAID_Context pointer */
-       pRAID_Context = &io_request->RaidContext;
+       pRAID_Context = &io_request->RaidContext.raid_context;
        /* Check with FW team */
-       pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id);
-       pRAID_Context->regLockRowLBA    = 0;
-       pRAID_Context->regLockLength    = 0;
+       pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id);
+       pRAID_Context->reg_lock_row_lba    = 0;
+       pRAID_Context->reg_lock_length    = 0;
 
        if (fusion->fast_path_io && (
                device_id < instance->fw_supported_vd_count)) {
@@ -1909,10 +2496,11 @@ static void megasas_build_ld_nonrw_fusion(struct megasas_instance *instance,
                ld = MR_TargetIdToLdGet(device_id, local_map_ptr);
                if (ld >= instance->fw_supported_vd_count)
                        fp_possible = 0;
-
-               raid = MR_LdRaidGet(ld, local_map_ptr);
-               if (!(raid->capability.fpNonRWCapable))
-                       fp_possible = 0;
+               else {
+                       raid = MR_LdRaidGet(ld, local_map_ptr);
+                       if (!(raid->capability.fpNonRWCapable))
+                               fp_possible = 0;
+               }
        } else
                fp_possible = 0;
 
@@ -1920,7 +2508,7 @@ static void megasas_build_ld_nonrw_fusion(struct megasas_instance *instance,
                io_request->Function  = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST;
                io_request->DevHandle = cpu_to_le16(device_id);
                io_request->LUN[1] = scmd->device->lun;
-               pRAID_Context->timeoutValue =
+               pRAID_Context->timeout_value =
                        cpu_to_le16 (scmd->request->timeout / HZ);
                cmd->request_desc->SCSIIO.RequestFlags =
                        (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO <<
@@ -1928,9 +2516,11 @@ static void megasas_build_ld_nonrw_fusion(struct megasas_instance *instance,
        } else {
 
                /* set RAID context values */
-               pRAID_Context->configSeqNum = raid->seqNum;
-               pRAID_Context->regLockFlags = REGION_TYPE_SHARED_READ;
-               pRAID_Context->timeoutValue = cpu_to_le16(raid->fpIoTimeoutForLd);
+               pRAID_Context->config_seq_num = raid->seqNum;
+               if (!instance->is_ventura)
+                       pRAID_Context->reg_lock_flags = REGION_TYPE_SHARED_READ;
+               pRAID_Context->timeout_value =
+                       cpu_to_le16(raid->fpIoTimeoutForLd);
 
                /* get the DevHandle for the PD (since this is
                   fpNonRWCapable, this is a single disk RAID0) */
@@ -1965,7 +2555,8 @@ static void megasas_build_ld_nonrw_fusion(struct megasas_instance *instance,
  */
 static void
 megasas_build_syspd_fusion(struct megasas_instance *instance,
-       struct scsi_cmnd *scmd, struct megasas_cmd_fusion *cmd, u8 fp_possible)
+       struct scsi_cmnd *scmd, struct megasas_cmd_fusion *cmd,
+       bool fp_possible)
 {
        u32 device_id;
        struct MPI2_RAID_SCSI_IO_REQUEST *io_request;
@@ -1975,22 +2566,25 @@ megasas_build_syspd_fusion(struct megasas_instance *instance,
        struct MR_DRV_RAID_MAP_ALL *local_map_ptr;
        struct RAID_CONTEXT     *pRAID_Context;
        struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync;
+       struct MR_PRIV_DEVICE *mr_device_priv_data;
        struct fusion_context *fusion = instance->ctrl_context;
        pd_sync = (void *)fusion->pd_seq_sync[(instance->pd_seq_map_id - 1) & 1];
 
        device_id = MEGASAS_DEV_INDEX(scmd);
        pd_index = MEGASAS_PD_INDEX(scmd);
        os_timeout_value = scmd->request->timeout / HZ;
+       mr_device_priv_data = scmd->device->hostdata;
+       cmd->pd_interface = mr_device_priv_data->interface_type;
 
        io_request = cmd->io_request;
        /* get RAID_Context pointer */
-       pRAID_Context = &io_request->RaidContext;
-       pRAID_Context->regLockFlags = 0;
-       pRAID_Context->regLockRowLBA = 0;
-       pRAID_Context->regLockLength = 0;
+       pRAID_Context = &io_request->RaidContext.raid_context;
+       pRAID_Context->reg_lock_flags = 0;
+       pRAID_Context->reg_lock_row_lba = 0;
+       pRAID_Context->reg_lock_length = 0;
        io_request->DataLength = cpu_to_le32(scsi_bufflen(scmd));
        io_request->LUN[1] = scmd->device->lun;
-       pRAID_Context->RAIDFlags = MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD
+       pRAID_Context->raid_flags = MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD
                << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT;
 
        /* If FW supports PD sequence number */
@@ -1999,24 +2593,38 @@ megasas_build_syspd_fusion(struct megasas_instance *instance,
                /* TgtId must be incremented by 255 as jbod seq number is index
                 * below raid map
                 */
-               pRAID_Context->VirtualDiskTgtId =
-                       cpu_to_le16(device_id + (MAX_PHYSICAL_DEVICES - 1));
-               pRAID_Context->configSeqNum = pd_sync->seq[pd_index].seqNum;
+                /* More than 256 PD/JBOD support for Ventura */
+               if (instance->support_morethan256jbod)
+                       pRAID_Context->virtual_disk_tgt_id =
+                               pd_sync->seq[pd_index].pd_target_id;
+               else
+                       pRAID_Context->virtual_disk_tgt_id =
+                               cpu_to_le16(device_id + (MAX_PHYSICAL_DEVICES - 1));
+               pRAID_Context->config_seq_num = pd_sync->seq[pd_index].seqNum;
                io_request->DevHandle = pd_sync->seq[pd_index].devHandle;
-               pRAID_Context->regLockFlags |=
-                       (MR_RL_FLAGS_SEQ_NUM_ENABLE|MR_RL_FLAGS_GRANT_DESTINATION_CUDA);
-               pRAID_Context->Type = MPI2_TYPE_CUDA;
-               pRAID_Context->nseg = 0x1;
+               if (instance->is_ventura) {
+                       io_request->RaidContext.raid_context_g35.routing_flags |=
+                               (1 << MR_RAID_CTX_ROUTINGFLAGS_SQN_SHIFT);
+                       io_request->RaidContext.raid_context_g35.nseg_type |=
+                                                       (1 << RAID_CONTEXT_NSEG_SHIFT);
+                       io_request->RaidContext.raid_context_g35.nseg_type |=
+                                                       (MPI2_TYPE_CUDA << RAID_CONTEXT_TYPE_SHIFT);
+               } else {
+                       pRAID_Context->type = MPI2_TYPE_CUDA;
+                       pRAID_Context->nseg = 0x1;
+                       pRAID_Context->reg_lock_flags |=
+                               (MR_RL_FLAGS_SEQ_NUM_ENABLE|MR_RL_FLAGS_GRANT_DESTINATION_CUDA);
+               }
        } else if (fusion->fast_path_io) {
-               pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id);
-               pRAID_Context->configSeqNum = 0;
+               pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id);
+               pRAID_Context->config_seq_num = 0;
                local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)];
                io_request->DevHandle =
                        local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl;
        } else {
                /* Want to send all IO via FW path */
-               pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id);
-               pRAID_Context->configSeqNum = 0;
+               pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id);
+               pRAID_Context->config_seq_num = 0;
                io_request->DevHandle = cpu_to_le16(0xFFFF);
        }
 
@@ -2032,17 +2640,17 @@ megasas_build_syspd_fusion(struct megasas_instance *instance,
                cmd->request_desc->SCSIIO.RequestFlags =
                        (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO <<
                                MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
-               pRAID_Context->timeoutValue = cpu_to_le16(os_timeout_value);
-               pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id);
+               pRAID_Context->timeout_value = cpu_to_le16(os_timeout_value);
+               pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id);
        } else {
                /* system pd Fast Path */
                io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
                timeout_limit = (scmd->device->type == TYPE_DISK) ?
                                255 : 0xFFFF;
-               pRAID_Context->timeoutValue =
+               pRAID_Context->timeout_value =
                        cpu_to_le16((os_timeout_value > timeout_limit) ?
                        timeout_limit : os_timeout_value);
-               if (fusion->adapter_type == INVADER_SERIES)
+               if (fusion->adapter_type >= INVADER_SERIES)
                        io_request->IoFlags |=
                                cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH);
 
@@ -2066,9 +2674,11 @@ megasas_build_io_fusion(struct megasas_instance *instance,
                        struct scsi_cmnd *scp,
                        struct megasas_cmd_fusion *cmd)
 {
-       u16 sge_count;
+       int sge_count;
        u8  cmd_type;
        struct MPI2_RAID_SCSI_IO_REQUEST *io_request = cmd->io_request;
+       struct MR_PRIV_DEVICE *mr_device_priv_data;
+       mr_device_priv_data = scp->device->hostdata;
 
        /* Zero out some fields so they don't get reused */
        memset(io_request->LUN, 0x0, 8);
@@ -2078,9 +2688,9 @@ megasas_build_io_fusion(struct megasas_instance *instance,
        io_request->Control = 0;
        io_request->EEDPBlockSize = 0;
        io_request->ChainOffset = 0;
-       io_request->RaidContext.RAIDFlags = 0;
-       io_request->RaidContext.Type = 0;
-       io_request->RaidContext.nseg = 0;
+       io_request->RaidContext.raid_context.raid_flags = 0;
+       io_request->RaidContext.raid_context.type = 0;
+       io_request->RaidContext.raid_context.nseg = 0;
 
        memcpy(io_request->CDB.CDB32, scp->cmnd, scp->cmd_len);
        /*
@@ -2097,12 +2707,14 @@ megasas_build_io_fusion(struct megasas_instance *instance,
                megasas_build_ld_nonrw_fusion(instance, scp, cmd);
                break;
        case READ_WRITE_SYSPDIO:
+               megasas_build_syspd_fusion(instance, scp, cmd, true);
+               break;
        case NON_READ_WRITE_SYSPDIO:
-               if (instance->secure_jbod_support &&
-                       (cmd_type == NON_READ_WRITE_SYSPDIO))
-                       megasas_build_syspd_fusion(instance, scp, cmd, 0);
+               if (instance->secure_jbod_support ||
+                   mr_device_priv_data->is_tm_capable)
+                       megasas_build_syspd_fusion(instance, scp, cmd, false);
                else
-                       megasas_build_syspd_fusion(instance, scp, cmd, 1);
+                       megasas_build_syspd_fusion(instance, scp, cmd, true);
                break;
        default:
                break;
@@ -2112,23 +2724,27 @@ megasas_build_io_fusion(struct megasas_instance *instance,
         * Construct SGL
         */
 
-       sge_count =
-               megasas_make_sgl_fusion(instance, scp,
-                                       (struct MPI25_IEEE_SGE_CHAIN64 *)
-                                       &io_request->SGL, cmd);
+       sge_count = megasas_make_sgl(instance, scp, cmd);
 
-       if (sge_count > instance->max_num_sge) {
-               dev_err(&instance->pdev->dev, "Error. sge_count (0x%x) exceeds "
-                      "max (0x%x) allowed\n", sge_count,
-                      instance->max_num_sge);
+       if (sge_count > instance->max_num_sge || (sge_count < 0)) {
+               dev_err(&instance->pdev->dev,
+                       "%s %d sge_count (%d) is out of range. Range is:  0-%d\n",
+                       __func__, __LINE__, sge_count, instance->max_num_sge);
                return 1;
        }
 
-       /* numSGE store lower 8 bit of sge_count.
-        * numSGEExt store higher 8 bit of sge_count
-        */
-       io_request->RaidContext.numSGE = sge_count;
-       io_request->RaidContext.numSGEExt = (u8)(sge_count >> 8);
+       if (instance->is_ventura) {
+               set_num_sge(&io_request->RaidContext.raid_context_g35, sge_count);
+               cpu_to_le16s(&io_request->RaidContext.raid_context_g35.routing_flags);
+               cpu_to_le16s(&io_request->RaidContext.raid_context_g35.nseg_type);
+       } else {
+               /* numSGE store lower 8 bit of sge_count.
+                * numSGEExt store higher 8 bit of sge_count
+                */
+               io_request->RaidContext.raid_context.num_sge = sge_count;
+               io_request->RaidContext.raid_context.num_sge_ext =
+                       (u8)(sge_count >> 8);
+       }
 
        io_request->SGLFlags = cpu_to_le16(MPI2_SGE_FLAGS_64_BIT_ADDRESSING);
 
@@ -2149,25 +2765,61 @@ megasas_build_io_fusion(struct megasas_instance *instance,
        return 0;
 }
 
-union MEGASAS_REQUEST_DESCRIPTOR_UNION *
+static union MEGASAS_REQUEST_DESCRIPTOR_UNION *
 megasas_get_request_descriptor(struct megasas_instance *instance, u16 index)
 {
        u8 *p;
        struct fusion_context *fusion;
 
-       if (index >= instance->max_fw_cmds) {
-               dev_err(&instance->pdev->dev, "Invalid SMID (0x%x)request for "
-                      "descriptor for scsi%d\n", index,
-                       instance->host->host_no);
-               return NULL;
-       }
        fusion = instance->ctrl_context;
-       p = fusion->req_frames_desc
-               +sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) *index;
+       p = fusion->req_frames_desc +
+               sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) * index;
 
        return (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)p;
 }
 
+
+/* megasas_prepate_secondRaid1_IO
+ *  It prepares the raid 1 second IO
+ */
+void megasas_prepare_secondRaid1_IO(struct megasas_instance *instance,
+                           struct megasas_cmd_fusion *cmd,
+                           struct megasas_cmd_fusion *r1_cmd)
+{
+       union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc, *req_desc2 = NULL;
+       struct fusion_context *fusion;
+       fusion = instance->ctrl_context;
+       req_desc = cmd->request_desc;
+       /* copy the io request frame as well as 8 SGEs data for r1 command*/
+       memcpy(r1_cmd->io_request, cmd->io_request,
+              (sizeof(struct MPI2_RAID_SCSI_IO_REQUEST)));
+       memcpy(&r1_cmd->io_request->SGL, &cmd->io_request->SGL,
+              (fusion->max_sge_in_main_msg * sizeof(union MPI2_SGE_IO_UNION)));
+       /*sense buffer is different for r1 command*/
+       r1_cmd->io_request->SenseBufferLowAddress =
+                       cpu_to_le32(r1_cmd->sense_phys_addr);
+       r1_cmd->scmd = cmd->scmd;
+       req_desc2 = megasas_get_request_descriptor(instance,
+                                                  (r1_cmd->index - 1));
+       req_desc2->Words = 0;
+       r1_cmd->request_desc = req_desc2;
+       req_desc2->SCSIIO.SMID = cpu_to_le16(r1_cmd->index);
+       req_desc2->SCSIIO.RequestFlags = req_desc->SCSIIO.RequestFlags;
+       r1_cmd->request_desc->SCSIIO.DevHandle = cmd->r1_alt_dev_handle;
+       r1_cmd->io_request->DevHandle = cmd->r1_alt_dev_handle;
+       r1_cmd->r1_alt_dev_handle = cmd->io_request->DevHandle;
+       cmd->io_request->RaidContext.raid_context_g35.smid.peer_smid =
+                       cpu_to_le16(r1_cmd->index);
+       r1_cmd->io_request->RaidContext.raid_context_g35.smid.peer_smid =
+                       cpu_to_le16(cmd->index);
+       /*MSIxIndex of both commands request descriptors should be same*/
+       r1_cmd->request_desc->SCSIIO.MSIxIndex =
+                       cmd->request_desc->SCSIIO.MSIxIndex;
+       /*span arm is different for r1 cmd*/
+       r1_cmd->io_request->RaidContext.raid_context_g35.span_arm =
+                       cmd->io_request->RaidContext.raid_context_g35.span_arm + 1;
+}
+
 /**
  * megasas_build_and_issue_cmd_fusion -Main routine for building and
  *                                     issuing non IOCTL cmd
@@ -2178,7 +2830,7 @@ static u32
 megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance,
                                   struct scsi_cmnd *scmd)
 {
-       struct megasas_cmd_fusion *cmd;
+       struct megasas_cmd_fusion *cmd, *r1_cmd = NULL;
        union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
        u32 index;
        struct fusion_context *fusion;
@@ -2193,13 +2845,22 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance,
                return SCSI_MLQUEUE_DEVICE_BUSY;
        }
 
+       if (atomic_inc_return(&instance->fw_outstanding) >
+                       instance->host->can_queue) {
+               atomic_dec(&instance->fw_outstanding);
+               return SCSI_MLQUEUE_HOST_BUSY;
+       }
+
        cmd = megasas_get_cmd_fusion(instance, scmd->request->tag);
 
+       if (!cmd) {
+               atomic_dec(&instance->fw_outstanding);
+               return SCSI_MLQUEUE_HOST_BUSY;
+       }
+
        index = cmd->index;
 
        req_desc = megasas_get_request_descriptor(instance, index-1);
-       if (!req_desc)
-               return SCSI_MLQUEUE_HOST_BUSY;
 
        req_desc->Words = 0;
        cmd->request_desc = req_desc;
@@ -2208,6 +2869,7 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance,
                megasas_return_cmd_fusion(instance, cmd);
                dev_err(&instance->pdev->dev, "Error building command\n");
                cmd->request_desc = NULL;
+               atomic_dec(&instance->fw_outstanding);
                return SCSI_MLQUEUE_HOST_BUSY;
        }
 
@@ -2218,17 +2880,91 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance,
            cmd->io_request->ChainOffset != 0xF)
                dev_err(&instance->pdev->dev, "The chain offset value is not "
                       "correct : %x\n", cmd->io_request->ChainOffset);
+       /*
+        *      if it is raid 1/10 fp write capable.
+        *      try to get second command from pool and construct it.
+        *      From FW, it has confirmed that lba values of two PDs
+        *      corresponds to single R1/10 LD are always same
+        *
+        */
+       /*      driver side count always should be less than max_fw_cmds
+        *      to get new command
+        */
+       if (cmd->r1_alt_dev_handle != MR_DEVHANDLE_INVALID) {
+               r1_cmd = megasas_get_cmd_fusion(instance,
+                               (scmd->request->tag + instance->max_fw_cmds));
+               megasas_prepare_secondRaid1_IO(instance, cmd, r1_cmd);
+       }
+
 
        /*
         * Issue the command to the FW
         */
-       atomic_inc(&instance->fw_outstanding);
 
        megasas_fire_cmd_fusion(instance, req_desc);
 
+       if (r1_cmd)
+               megasas_fire_cmd_fusion(instance, r1_cmd->request_desc);
+
+
        return 0;
 }
 
+/**
+ * megasas_complete_r1_command -
+ * completes R1 FP write commands which has valid peer smid
+ * @instance:                  Adapter soft state
+ * @cmd_fusion:                        MPT command frame
+ *
+ */
+static inline void
+megasas_complete_r1_command(struct megasas_instance *instance,
+                           struct megasas_cmd_fusion *cmd)
+{
+       u8 *sense, status, ex_status;
+       u32 data_length;
+       u16 peer_smid;
+       struct fusion_context *fusion;
+       struct megasas_cmd_fusion *r1_cmd = NULL;
+       struct scsi_cmnd *scmd_local = NULL;
+       struct RAID_CONTEXT_G35 *rctx_g35;
+
+       rctx_g35 = &cmd->io_request->RaidContext.raid_context_g35;
+       fusion = instance->ctrl_context;
+       peer_smid = le16_to_cpu(rctx_g35->smid.peer_smid);
+
+       r1_cmd = fusion->cmd_list[peer_smid - 1];
+       scmd_local = cmd->scmd;
+       status = rctx_g35->status;
+       ex_status = rctx_g35->ex_status;
+       data_length = cmd->io_request->DataLength;
+       sense = cmd->sense;
+
+       cmd->cmd_completed = true;
+
+       /* Check if peer command is completed or not*/
+       if (r1_cmd->cmd_completed) {
+               rctx_g35 = &r1_cmd->io_request->RaidContext.raid_context_g35;
+               if (rctx_g35->status != MFI_STAT_OK) {
+                       status = rctx_g35->status;
+                       ex_status = rctx_g35->ex_status;
+                       data_length = r1_cmd->io_request->DataLength;
+                       sense = r1_cmd->sense;
+               }
+
+               megasas_return_cmd_fusion(instance, r1_cmd);
+               map_cmd_status(fusion, scmd_local, status, ex_status,
+                              le32_to_cpu(data_length), sense);
+               if (instance->ldio_threshold &&
+                   megasas_cmd_type(scmd_local) == READ_WRITE_LDIO)
+                       atomic_dec(&instance->ldio_outstanding);
+               scmd_local->SCp.ptr = NULL;
+               megasas_return_cmd_fusion(instance, cmd);
+               scsi_dma_unmap(scmd_local);
+               scmd_local->scsi_done(scmd_local);
+       }
+}
+
 /**
  * complete_cmd_fusion -       Completes command
  * @instance:                  Adapter soft state
@@ -2244,8 +2980,8 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
        struct megasas_cmd *cmd_mfi;
        struct megasas_cmd_fusion *cmd_fusion;
        u16 smid, num_completed;
-       u8 reply_descript_type;
-       u32 status, extStatus, device_id;
+       u8 reply_descript_type, *sense, status, extStatus;
+       u32 device_id, data_length;
        union desc_value d_val;
        struct LD_LOAD_BALANCE_INFO *lbinfo;
        int threshold_reply_count = 0;
@@ -2275,20 +3011,17 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
 
        while (d_val.u.low != cpu_to_le32(UINT_MAX) &&
               d_val.u.high != cpu_to_le32(UINT_MAX)) {
-               smid = le16_to_cpu(reply_desc->SMID);
 
+               smid = le16_to_cpu(reply_desc->SMID);
                cmd_fusion = fusion->cmd_list[smid - 1];
-
-               scsi_io_req =
-                       (struct MPI2_RAID_SCSI_IO_REQUEST *)
-                 cmd_fusion->io_request;
-
-               if (cmd_fusion->scmd)
-                       cmd_fusion->scmd->SCp.ptr = NULL;
+               scsi_io_req = (struct MPI2_RAID_SCSI_IO_REQUEST *)
+                                               cmd_fusion->io_request;
 
                scmd_local = cmd_fusion->scmd;
-               status = scsi_io_req->RaidContext.status;
-               extStatus = scsi_io_req->RaidContext.exStatus;
+               status = scsi_io_req->RaidContext.raid_context.status;
+               extStatus = scsi_io_req->RaidContext.raid_context.ex_status;
+               sense = cmd_fusion->sense;
+               data_length = scsi_io_req->DataLength;
 
                switch (scsi_io_req->Function) {
                case MPI2_FUNCTION_SCSI_TASK_MGMT:
@@ -2303,37 +3036,33 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
                        break;
                case MPI2_FUNCTION_SCSI_IO_REQUEST:  /*Fast Path IO.*/
                        /* Update load balancing info */
-                       device_id = MEGASAS_DEV_INDEX(scmd_local);
-                       lbinfo = &fusion->load_balance_info[device_id];
-                       if (cmd_fusion->scmd->SCp.Status &
-                           MEGASAS_LOAD_BALANCE_FLAG) {
+                       if (fusion->load_balance_info &&
+                           (cmd_fusion->scmd->SCp.Status &
+                           MEGASAS_LOAD_BALANCE_FLAG)) {
+                               device_id = MEGASAS_DEV_INDEX(scmd_local);
+                               lbinfo = &fusion->load_balance_info[device_id];
                                atomic_dec(&lbinfo->scsi_pending_cmds[cmd_fusion->pd_r1_lb]);
-                               cmd_fusion->scmd->SCp.Status &=
-                                       ~MEGASAS_LOAD_BALANCE_FLAG;
+                               cmd_fusion->scmd->SCp.Status &= ~MEGASAS_LOAD_BALANCE_FLAG;
                        }
-                       if (reply_descript_type ==
-                           MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS) {
-                               if (megasas_dbg_lvl == 5)
-                                       dev_err(&instance->pdev->dev, "\nFAST Path "
-                                              "IO Success\n");
-                       }
-                       /* Fall thru and complete IO */
+                       //Fall thru and complete IO
                case MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST: /* LD-IO Path */
-                       /* Map the FW Cmd Status */
-                       map_cmd_status(cmd_fusion, status, extStatus);
-                       scsi_io_req->RaidContext.status = 0;
-                       scsi_io_req->RaidContext.exStatus = 0;
-                       if (megasas_cmd_type(scmd_local) == READ_WRITE_LDIO)
-                               atomic_dec(&instance->ldio_outstanding);
-                       megasas_return_cmd_fusion(instance, cmd_fusion);
-                       scsi_dma_unmap(scmd_local);
-                       scmd_local->scsi_done(scmd_local);
                        atomic_dec(&instance->fw_outstanding);
-
+                       if (cmd_fusion->r1_alt_dev_handle == MR_DEVHANDLE_INVALID) {
+                               map_cmd_status(fusion, scmd_local, status,
+                                              extStatus, le32_to_cpu(data_length),
+                                              sense);
+                               if (instance->ldio_threshold &&
+                                   (megasas_cmd_type(scmd_local) == READ_WRITE_LDIO))
+                                       atomic_dec(&instance->ldio_outstanding);
+                               scmd_local->SCp.ptr = NULL;
+                               megasas_return_cmd_fusion(instance, cmd_fusion);
+                               scsi_dma_unmap(scmd_local);
+                               scmd_local->scsi_done(scmd_local);
+                       } else  /* Optimal VD - R1 FP command completion. */
+                               megasas_complete_r1_command(instance, cmd_fusion);
                        break;
                case MEGASAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST: /*MFI command */
                        cmd_mfi = instance->cmd_list[cmd_fusion->sync_cmd_idx];
-
                        /* Poll mode. Dummy free.
                         * In case of Interrupt mode, caller has reverse check.
                         */
@@ -2376,7 +3105,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
                 * pending to be completed
                 */
                if (threshold_reply_count >= THRESHOLD_REPLY_COUNT) {
-                       if (fusion->adapter_type == INVADER_SERIES)
+                       if (instance->msix_combined)
                                writel(((MSIxIndex & 0x7) << 24) |
                                        fusion->last_reply_idx[MSIxIndex],
                                        instance->reply_post_host_index_addr[MSIxIndex/8]);
@@ -2392,7 +3121,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
                return IRQ_NONE;
 
        wmb();
-       if (fusion->adapter_type == INVADER_SERIES)
+       if (instance->msix_combined)
                writel(((MSIxIndex & 0x7) << 24) |
                        fusion->last_reply_idx[MSIxIndex],
                        instance->reply_post_host_index_addr[MSIxIndex/8]);
@@ -2404,6 +3133,22 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
        return IRQ_HANDLED;
 }
 
+/**
+ * megasas_sync_irqs - Synchronizes all IRQs owned by adapter
+ * @instance:                  Adapter soft state
+ */
+void megasas_sync_irqs(unsigned long instance_addr)
+{
+       u32 count, i;
+       struct megasas_instance *instance =
+               (struct megasas_instance *)instance_addr;
+
+       count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
+
+       for (i = 0; i < count; i++)
+               synchronize_irq(pci_irq_vector(instance->pdev, i));
+}
+
 /**
  * megasas_complete_cmd_dpc_fusion -   Completes command
  * @instance:                  Adapter soft state
@@ -2489,7 +3234,7 @@ irqreturn_t megasas_isr_fusion(int irq, void *devp)
  * mfi_cmd:                    megasas_cmd pointer
  *
  */
-u8
+void
 build_mpt_mfi_pass_thru(struct megasas_instance *instance,
                        struct megasas_cmd *mfi_cmd)
 {
@@ -2518,7 +3263,7 @@ build_mpt_mfi_pass_thru(struct megasas_instance *instance,
 
        io_req = cmd->io_request;
 
-       if (fusion->adapter_type == INVADER_SERIES) {
+       if (fusion->adapter_type >= INVADER_SERIES) {
                struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr_end =
                        (struct MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL;
                sgl_ptr_end += fusion->max_sge_in_main_msg - 1;
@@ -2539,8 +3284,6 @@ build_mpt_mfi_pass_thru(struct megasas_instance *instance,
                MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR;
 
        mpi25_ieee_chain->Length = cpu_to_le32(instance->max_chain_frame_sz);
-
-       return 0;
 }
 
 /**
@@ -2552,21 +3295,14 @@ build_mpt_mfi_pass_thru(struct megasas_instance *instance,
 union MEGASAS_REQUEST_DESCRIPTOR_UNION *
 build_mpt_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
 {
-       union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
+       union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc = NULL;
        u16 index;
 
-       if (build_mpt_mfi_pass_thru(instance, cmd)) {
-               dev_err(&instance->pdev->dev, "Couldn't build MFI pass thru cmd\n");
-               return NULL;
-       }
-
+       build_mpt_mfi_pass_thru(instance, cmd);
        index = cmd->context.smid;
 
        req_desc = megasas_get_request_descriptor(instance, index - 1);
 
-       if (!req_desc)
-               return NULL;
-
        req_desc->Words = 0;
        req_desc->SCSIIO.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO <<
                                         MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
@@ -2582,21 +3318,16 @@ build_mpt_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
  * @cmd:                       mfi cmd pointer
  *
  */
-int
+void
 megasas_issue_dcmd_fusion(struct megasas_instance *instance,
                          struct megasas_cmd *cmd)
 {
        union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc;
 
        req_desc = build_mpt_cmd(instance, cmd);
-       if (!req_desc) {
-               dev_info(&instance->pdev->dev, "Failed from %s %d\n",
-                                       __func__, __LINE__);
-               return DCMD_NOT_FIRED;
-       }
 
        megasas_fire_cmd_fusion(instance, req_desc);
-       return DCMD_SUCCESS;
+       return;
 }
 
 /**
@@ -2771,6 +3502,14 @@ int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance,
                               " will reset adapter scsi%d.\n",
                                instance->host->host_no);
                        megasas_complete_cmd_dpc_fusion((unsigned long)instance);
+                       if (instance->requestorId && reason) {
+                               dev_warn(&instance->pdev->dev, "SR-IOV Found FW in FAULT"
+                               " state while polling during"
+                               " I/O timeout handling for %d\n",
+                               instance->host->host_no);
+                               *convert = 1;
+                       }
+
                        retval = 1;
                        goto out;
                }
@@ -2790,7 +3529,7 @@ int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance,
                }
 
                /* If SR-IOV VF mode & I/O timeout, check for HB timeout */
-               if (instance->requestorId && reason) {
+               if (instance->requestorId && (reason == SCSIIO_TIMEOUT_OCR)) {
                        if (instance->hb_host_mem->HB.fwCounter !=
                            instance->hb_host_mem->HB.driverCounter) {
                                instance->hb_host_mem->HB.driverCounter =
@@ -3030,12 +3769,6 @@ megasas_issue_tm(struct megasas_instance *instance, u16 device_handle,
 
        req_desc = megasas_get_request_descriptor(instance,
                        (cmd_fusion->index - 1));
-       if (!req_desc) {
-               dev_err(&instance->pdev->dev, "Failed from %s %d\n",
-                       __func__, __LINE__);
-               megasas_return_cmd(instance, cmd_mfi);
-               return -ENOMEM;
-       }
 
        cmd_fusion->request_desc = req_desc;
        req_desc->Words = 0;
@@ -3092,7 +3825,7 @@ megasas_issue_tm(struct megasas_instance *instance, u16 device_handle,
                        break;
                else {
                        instance->instancet->disable_intr(instance);
-                       msleep(1000);
+                       megasas_sync_irqs((unsigned long)instance);
                        megasas_complete_cmd_dpc_fusion
                                        ((unsigned long)instance);
                        instance->instancet->enable_intr(instance);
@@ -3173,13 +3906,13 @@ static u16 megasas_get_tm_devhandle(struct scsi_device *sdev)
        instance = (struct megasas_instance *)sdev->host->hostdata;
        fusion = instance->ctrl_context;
 
-       if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) {
+       if (!MEGASAS_IS_LOGICAL(sdev)) {
                if (instance->use_seqnum_jbod_fp) {
-                               pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
-                                               sdev->id;
-                               pd_sync = (void *)fusion->pd_seq_sync
-                                               [(instance->pd_seq_map_id - 1) & 1];
-                               devhandle = pd_sync->seq[pd_index].devHandle;
+                       pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL)
+                                   + sdev->id;
+                       pd_sync = (void *)fusion->pd_seq_sync
+                                       [(instance->pd_seq_map_id - 1) & 1];
+                       devhandle = pd_sync->seq[pd_index].devHandle;
                } else
                        sdev_printk(KERN_ERR, sdev, "Firmware expose tmCapable"
                                " without JBOD MAP support from %s %d\n", __func__, __LINE__);
@@ -3212,6 +3945,9 @@ int megasas_task_abort_fusion(struct scsi_cmnd *scmd)
        instance = (struct megasas_instance *)scmd->device->host->hostdata;
        fusion = instance->ctrl_context;
 
+       scmd_printk(KERN_INFO, scmd, "task abort called for scmd(%p)\n", scmd);
+       scsi_print_command(scmd);
+
        if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
                dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL,"
                "SCSI host:%d\n", instance->host->host_no);
@@ -3292,6 +4028,9 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd)
        instance = (struct megasas_instance *)scmd->device->host->hostdata;
        fusion = instance->ctrl_context;
 
+       sdev_printk(KERN_INFO, scmd->device,
+                   "target reset called for scmd(%p)\n", scmd);
+
        if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) {
                dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL,"
                "SCSI host:%d\n", instance->host->host_no);
@@ -3362,7 +4101,7 @@ int megasas_check_mpio_paths(struct megasas_instance *instance,
        struct scsi_cmnd *scmd)
 {
        struct megasas_instance *peer_instance = NULL;
-       int retval = (DID_RESET << 16);
+       int retval = (DID_REQUEUE << 16);
 
        if (instance->peerIsPresent) {
                peer_instance = megasas_get_peer_instance(instance);
@@ -3377,9 +4116,9 @@ int megasas_check_mpio_paths(struct megasas_instance *instance,
 /* Core fusion reset function */
 int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
 {
-       int retval = SUCCESS, i, convert = 0;
+       int retval = SUCCESS, i, j, convert = 0;
        struct megasas_instance *instance;
-       struct megasas_cmd_fusion *cmd_fusion;
+       struct megasas_cmd_fusion *cmd_fusion, *r1_cmd;
        struct fusion_context *fusion;
        u32 abs_state, status_reg, reset_adapter;
        u32 io_timeout_in_crash_mode = 0;
@@ -3440,7 +4179,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
        set_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags);
        atomic_set(&instance->adprecovery, MEGASAS_ADPRESET_SM_POLLING);
        instance->instancet->disable_intr(instance);
-       msleep(1000);
+       megasas_sync_irqs((unsigned long)instance);
 
        /* First try waiting for commands to complete */
        if (megasas_wait_for_outstanding_fusion(instance, reason,
@@ -3451,23 +4190,40 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
                if (convert)
                        reason = 0;
 
+               if (megasas_dbg_lvl & OCR_LOGS)
+                       dev_info(&instance->pdev->dev, "\nPending SCSI commands:\n");
+
                /* Now return commands back to the OS */
                for (i = 0 ; i < instance->max_scsi_cmds; i++) {
                        cmd_fusion = fusion->cmd_list[i];
+                       /*check for extra commands issued by driver*/
+                       if (instance->is_ventura) {
+                               r1_cmd = fusion->cmd_list[i + instance->max_fw_cmds];
+                               megasas_return_cmd_fusion(instance, r1_cmd);
+                       }
                        scmd_local = cmd_fusion->scmd;
                        if (cmd_fusion->scmd) {
+                               if (megasas_dbg_lvl & OCR_LOGS) {
+                                       sdev_printk(KERN_INFO,
+                                               cmd_fusion->scmd->device, "SMID: 0x%x\n",
+                                               cmd_fusion->index);
+                                       scsi_print_command(cmd_fusion->scmd);
+                               }
+
                                scmd_local->result =
                                        megasas_check_mpio_paths(instance,
                                                        scmd_local);
-                               if (megasas_cmd_type(scmd_local) == READ_WRITE_LDIO)
+                               if (instance->ldio_threshold &&
+                                       megasas_cmd_type(scmd_local) == READ_WRITE_LDIO)
                                        atomic_dec(&instance->ldio_outstanding);
                                megasas_return_cmd_fusion(instance, cmd_fusion);
                                scsi_dma_unmap(scmd_local);
                                scmd_local->scsi_done(scmd_local);
-                               atomic_dec(&instance->fw_outstanding);
                        }
                }
 
+               atomic_set(&instance->fw_outstanding, 0);
+
                status_reg = instance->instancet->read_fw_status_reg(
                        instance->reg_set);
                abs_state = status_reg & MFI_STATE_MASK;
@@ -3528,11 +4284,13 @@ transition_to_ready:
                                        __func__, __LINE__);
                                megaraid_sas_kill_hba(instance);
                                retval = FAILED;
+                               goto out;
                        }
                        /* Reset load balance info */
-                       memset(fusion->load_balance_info, 0,
-                              sizeof(struct LD_LOAD_BALANCE_INFO)
-                              *MAX_LOGICAL_DRIVES_EXT);
+                       if (fusion->load_balance_info)
+                               memset(fusion->load_balance_info, 0,
+                                      (sizeof(struct LD_LOAD_BALANCE_INFO) *
+                                      MAX_LOGICAL_DRIVES_EXT));
 
                        if (!megasas_get_map_info(instance))
                                megasas_sync_map_info(instance);
@@ -3540,7 +4298,17 @@ transition_to_ready:
                        megasas_setup_jbod_map(instance);
 
                        shost_for_each_device(sdev, shost)
-                               megasas_update_sdev_properties(sdev);
+                               megasas_set_dynamic_target_properties(sdev);
+
+                       /* reset stream detection array */
+                       if (instance->is_ventura) {
+                               for (j = 0; j < MAX_LOGICAL_DRIVES_EXT; ++j) {
+                                       memset(fusion->stream_detect_by_ld[j],
+                                       0, sizeof(struct LD_STREAM_DETECT));
+                                fusion->stream_detect_by_ld[j]->mru_bit_map
+                                               = MR_STREAM_BITMAP;
+                               }
+                       }
 
                        clear_bit(MEGASAS_FUSION_IN_RESET,
                                  &instance->reset_flags);
@@ -3676,6 +4444,64 @@ void megasas_fusion_ocr_wq(struct work_struct *work)
        megasas_reset_fusion(instance->host, 0);
 }
 
+/* Allocate fusion context */
+int
+megasas_alloc_fusion_context(struct megasas_instance *instance)
+{
+       struct fusion_context *fusion;
+
+       instance->ctrl_context_pages = get_order(sizeof(struct fusion_context));
+       instance->ctrl_context = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
+               instance->ctrl_context_pages);
+       if (!instance->ctrl_context) {
+               /* fall back to using vmalloc for fusion_context */
+               instance->ctrl_context = vzalloc(sizeof(struct fusion_context));
+               if (!instance->ctrl_context) {
+                       dev_err(&instance->pdev->dev, "Failed from %s %d\n", __func__, __LINE__);
+                       return -ENOMEM;
+               }
+       }
+
+       fusion = instance->ctrl_context;
+
+       fusion->load_balance_info_pages = get_order(MAX_LOGICAL_DRIVES_EXT *
+               sizeof(struct LD_LOAD_BALANCE_INFO));
+       fusion->load_balance_info =
+               (struct LD_LOAD_BALANCE_INFO *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
+               fusion->load_balance_info_pages);
+       if (!fusion->load_balance_info) {
+               fusion->load_balance_info = vzalloc(MAX_LOGICAL_DRIVES_EXT *
+                       sizeof(struct LD_LOAD_BALANCE_INFO));
+               if (!fusion->load_balance_info)
+                       dev_err(&instance->pdev->dev, "Failed to allocate load_balance_info, "
+                               "continuing without Load Balance support\n");
+       }
+
+       return 0;
+}
+
+void
+megasas_free_fusion_context(struct megasas_instance *instance)
+{
+       struct fusion_context *fusion = instance->ctrl_context;
+
+       if (fusion) {
+               if (fusion->load_balance_info) {
+                       if (is_vmalloc_addr(fusion->load_balance_info))
+                               vfree(fusion->load_balance_info);
+                       else
+                               free_pages((ulong)fusion->load_balance_info,
+                                       fusion->load_balance_info_pages);
+               }
+
+               if (is_vmalloc_addr(fusion))
+                       vfree(fusion);
+               else
+                       free_pages((ulong)fusion,
+                               instance->ctrl_context_pages);
+       }
+}
+
 struct megasas_instance_template megasas_instance_template_fusion = {
        .enable_intr = megasas_enable_intr_fusion,
        .disable_intr = megasas_disable_intr_fusion,
index e3bee04c1eb18a24f7e9b8a250042138e5660fb5..d78d76112501fd9108ef58636ffc6cb4b1e9cca4 100644 (file)
@@ -59,6 +59,8 @@
 #define        MR_RL_FLAGS_GRANT_DESTINATION_CPU1          0x10
 #define        MR_RL_FLAGS_GRANT_DESTINATION_CUDA          0x80
 #define MR_RL_FLAGS_SEQ_NUM_ENABLE                 0x8
+#define MR_RL_WRITE_THROUGH_MODE                   0x00
+#define MR_RL_WRITE_BACK_MODE                      0x01
 
 /* T10 PI defines */
 #define MR_PROT_INFO_TYPE_CONTROLLER                0x8
 enum MR_RAID_FLAGS_IO_SUB_TYPE {
        MR_RAID_FLAGS_IO_SUB_TYPE_NONE = 0,
        MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD = 1,
+       MR_RAID_FLAGS_IO_SUB_TYPE_RMW_DATA     = 2,
+       MR_RAID_FLAGS_IO_SUB_TYPE_RMW_P        = 3,
+       MR_RAID_FLAGS_IO_SUB_TYPE_RMW_Q        = 4,
+       MR_RAID_FLAGS_IO_SUB_TYPE_CACHE_BYPASS = 6,
+       MR_RAID_FLAGS_IO_SUB_TYPE_LDIO_BW_LIMIT = 7
 };
 
 /*
@@ -94,11 +101,13 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE {
 #define MEGASAS_FP_CMD_LEN     16
 #define MEGASAS_FUSION_IN_RESET 0
 #define THRESHOLD_REPLY_COUNT 50
+#define RAID_1_PEER_CMDS 2
 #define JBOD_MAPS_COUNT        2
 
 enum MR_FUSION_ADAPTER_TYPE {
        THUNDERBOLT_SERIES = 0,
        INVADER_SERIES = 1,
+       VENTURA_SERIES = 2,
 };
 
 /*
@@ -108,29 +117,133 @@ enum MR_FUSION_ADAPTER_TYPE {
 
 struct RAID_CONTEXT {
 #if   defined(__BIG_ENDIAN_BITFIELD)
-       u8      nseg:4;
-       u8      Type:4;
+       u8 nseg:4;
+       u8 type:4;
 #else
-       u8      Type:4;
-       u8      nseg:4;
+       u8 type:4;
+       u8 nseg:4;
 #endif
-       u8      resvd0;
-       __le16  timeoutValue;
-       u8      regLockFlags;
-       u8      resvd1;
-       __le16  VirtualDiskTgtId;
-       __le64  regLockRowLBA;
-       __le32  regLockLength;
-       __le16  nextLMId;
-       u8      exStatus;
-       u8      status;
-       u8      RAIDFlags;
-       u8      numSGE;
-       __le16  configSeqNum;
-       u8      spanArm;
-       u8      priority;
-       u8      numSGEExt;
-       u8      resvd2;
+       u8 resvd0;
+       __le16 timeout_value;
+       u8 reg_lock_flags;
+       u8 resvd1;
+       __le16 virtual_disk_tgt_id;
+       __le64 reg_lock_row_lba;
+       __le32 reg_lock_length;
+       __le16 next_lmid;
+       u8 ex_status;
+       u8 status;
+       u8 raid_flags;
+       u8 num_sge;
+       __le16 config_seq_num;
+       u8 span_arm;
+       u8 priority;
+       u8 num_sge_ext;
+       u8 resvd2;
+};
+
+/*
+ * Raid Context structure which describes ventura MegaRAID specific
+ * IO Paramenters ,This resides at offset 0x60 where the SGL normally
+ * starts in MPT IO Frames
+ */
+struct RAID_CONTEXT_G35 {
+       #define RAID_CONTEXT_NSEG_MASK  0x00F0
+       #define RAID_CONTEXT_NSEG_SHIFT 4
+       #define RAID_CONTEXT_TYPE_MASK  0x000F
+       #define RAID_CONTEXT_TYPE_SHIFT 0
+       u16             nseg_type;
+       u16 timeout_value; /* 0x02 -0x03 */
+       u16             routing_flags;  // 0x04 -0x05 routing flags
+       u16 virtual_disk_tgt_id;   /* 0x06 -0x07 */
+       u64 reg_lock_row_lba;      /* 0x08 - 0x0F */
+       u32 reg_lock_length;      /* 0x10 - 0x13 */
+       union {
+               u16 next_lmid; /* 0x14 - 0x15 */
+               u16     peer_smid;      /* used for the raid 1/10 fp writes */
+       } smid;
+       u8 ex_status;       /* 0x16 : OUT */
+       u8 status;          /* 0x17 status */
+       u8 raid_flags;          /* 0x18 resvd[7:6], ioSubType[5:4],
+                                * resvd[3:1], preferredCpu[0]
+                                */
+       u8 span_arm;            /* 0x1C span[7:5], arm[4:0] */
+       u16     config_seq_num;           /* 0x1A -0x1B */
+       union {
+               /*
+                * Bit format:
+                *       ---------------------------------
+                *       | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+                *       ---------------------------------
+                * Byte0 |    numSGE[7]- numSGE[0]       |
+                *       ---------------------------------
+                * Byte1 |SD | resvd     | numSGE 8-11   |
+                *        --------------------------------
+                */
+               #define NUM_SGE_MASK_LOWER      0xFF
+               #define NUM_SGE_MASK_UPPER      0x0F
+               #define NUM_SGE_SHIFT_UPPER     8
+               #define STREAM_DETECT_SHIFT     7
+               #define STREAM_DETECT_MASK      0x80
+               struct {
+#if   defined(__BIG_ENDIAN_BITFIELD) /* 0x1C - 0x1D */
+                       u16 stream_detected:1;
+                       u16 reserved:3;
+                       u16 num_sge:12;
+#else
+                       u16 num_sge:12;
+                       u16 reserved:3;
+                       u16 stream_detected:1;
+#endif
+               } bits;
+               u8 bytes[2];
+       } u;
+       u8 resvd2[2];          /* 0x1E-0x1F */
+};
+
+#define MR_RAID_CTX_ROUTINGFLAGS_SLD_SHIFT     1
+#define MR_RAID_CTX_ROUTINGFLAGS_C2D_SHIFT     2
+#define MR_RAID_CTX_ROUTINGFLAGS_FWD_SHIFT     3
+#define MR_RAID_CTX_ROUTINGFLAGS_SQN_SHIFT     4
+#define MR_RAID_CTX_ROUTINGFLAGS_SBS_SHIFT     5
+#define MR_RAID_CTX_ROUTINGFLAGS_RW_SHIFT      6
+#define MR_RAID_CTX_ROUTINGFLAGS_LOG_SHIFT     7
+#define MR_RAID_CTX_ROUTINGFLAGS_CPUSEL_SHIFT  8
+#define MR_RAID_CTX_ROUTINGFLAGS_CPUSEL_MASK   0x0F00
+#define MR_RAID_CTX_ROUTINGFLAGS_SETDIVERT_SHIFT       12
+#define MR_RAID_CTX_ROUTINGFLAGS_SETDIVERT_MASK        0xF000
+
+static inline void set_num_sge(struct RAID_CONTEXT_G35 *rctx_g35,
+                              u16 sge_count)
+{
+       rctx_g35->u.bytes[0] = (u8)(sge_count & NUM_SGE_MASK_LOWER);
+       rctx_g35->u.bytes[1] |= (u8)((sge_count >> NUM_SGE_SHIFT_UPPER)
+                                                       & NUM_SGE_MASK_UPPER);
+}
+
+static inline u16 get_num_sge(struct RAID_CONTEXT_G35 *rctx_g35)
+{
+       u16 sge_count;
+
+       sge_count = (u16)(((rctx_g35->u.bytes[1] & NUM_SGE_MASK_UPPER)
+                       << NUM_SGE_SHIFT_UPPER) | (rctx_g35->u.bytes[0]));
+       return sge_count;
+}
+
+#define SET_STREAM_DETECTED(rctx_g35) \
+       (rctx_g35.u.bytes[1] |= STREAM_DETECT_MASK)
+
+#define CLEAR_STREAM_DETECTED(rctx_g35) \
+       (rctx_g35.u.bytes[1] &= ~(STREAM_DETECT_MASK))
+
+static inline bool is_stream_detected(struct RAID_CONTEXT_G35 *rctx_g35)
+{
+       return ((rctx_g35->u.bytes[1] & STREAM_DETECT_MASK));
+}
+
+union RAID_CONTEXT_UNION {
+       struct RAID_CONTEXT raid_context;
+       struct RAID_CONTEXT_G35 raid_context_g35;
 };
 
 #define RAID_CTX_SPANARM_ARM_SHIFT     (0)
@@ -139,6 +252,14 @@ struct RAID_CONTEXT {
 #define RAID_CTX_SPANARM_SPAN_SHIFT    (5)
 #define RAID_CTX_SPANARM_SPAN_MASK     (0xE0)
 
+/* number of bits per index in U32 TrackStream */
+#define BITS_PER_INDEX_STREAM          4
+#define INVALID_STREAM_NUM              16
+#define MR_STREAM_BITMAP               0x76543210
+#define STREAM_MASK                    ((1 << BITS_PER_INDEX_STREAM) - 1)
+#define ZERO_LAST_STREAM               0x0fffffff
+#define MAX_STREAMS_TRACKED            8
+
 /*
  * define region lock types
  */
@@ -175,6 +296,8 @@ enum REGION_TYPE {
 #define MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG          (0x0200)
 #define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD           (0x0100)
 #define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP             (0x0004)
+/* EEDP escape mode */
+#define MPI25_SCSIIO_EEDPFLAGS_DO_NOT_DISABLE_MODE  (0x0040)
 #define MPI2_FUNCTION_SCSI_IO_REQUEST               (0x00) /* SCSI IO */
 #define MPI2_FUNCTION_SCSI_TASK_MGMT                (0x01)
 #define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY       (0x03)
@@ -407,7 +530,7 @@ struct MPI2_RAID_SCSI_IO_REQUEST {
        u8                      LUN[8];                         /* 0x34 */
        __le32                  Control;                        /* 0x3C */
        union MPI2_SCSI_IO_CDB_UNION  CDB;                      /* 0x40 */
-       struct RAID_CONTEXT     RaidContext;                    /* 0x60 */
+       union RAID_CONTEXT_UNION RaidContext;  /* 0x60 */
        union MPI2_SGE_IO_UNION       SGL;                      /* 0x80 */
 };
 
@@ -563,7 +686,7 @@ struct MPI2_IOC_INIT_REQUEST {
        __le16                  HeaderVersion;                  /* 0x0E */
        u32                     Reserved5;                      /* 0x10 */
        __le16                  Reserved6;                      /* 0x14 */
-       u8                      Reserved7;                      /* 0x16 */
+       u8                      HostPageSize;                   /* 0x16 */
        u8                      HostMSIxVectors;                /* 0x17 */
        __le16                  Reserved8;                      /* 0x18 */
        __le16                  SystemRequestFrameSize;         /* 0x1A */
@@ -579,6 +702,7 @@ struct MPI2_IOC_INIT_REQUEST {
 
 /* mrpriv defines */
 #define MR_PD_INVALID 0xFFFF
+#define MR_DEVHANDLE_INVALID 0xFFFF
 #define MAX_SPAN_DEPTH 8
 #define MAX_QUAD_DEPTH MAX_SPAN_DEPTH
 #define MAX_RAIDMAP_SPAN_DEPTH (MAX_SPAN_DEPTH)
@@ -586,16 +710,20 @@ struct MPI2_IOC_INIT_REQUEST {
 #define MAX_RAIDMAP_ROW_SIZE (MAX_ROW_SIZE)
 #define MAX_LOGICAL_DRIVES 64
 #define MAX_LOGICAL_DRIVES_EXT 256
+#define MAX_LOGICAL_DRIVES_DYN 512
 #define MAX_RAIDMAP_LOGICAL_DRIVES (MAX_LOGICAL_DRIVES)
 #define MAX_RAIDMAP_VIEWS (MAX_LOGICAL_DRIVES)
 #define MAX_ARRAYS 128
 #define MAX_RAIDMAP_ARRAYS (MAX_ARRAYS)
 #define MAX_ARRAYS_EXT 256
 #define MAX_API_ARRAYS_EXT (MAX_ARRAYS_EXT)
+#define MAX_API_ARRAYS_DYN 512
 #define MAX_PHYSICAL_DEVICES 256
 #define MAX_RAIDMAP_PHYSICAL_DEVICES (MAX_PHYSICAL_DEVICES)
+#define MAX_RAIDMAP_PHYSICAL_DEVICES_DYN 512
 #define MR_DCMD_LD_MAP_GET_INFO             0x0300e101
 #define MR_DCMD_SYSTEM_PD_MAP_GET_INFO      0x0200e102
+#define MR_DCMD_DRV_GET_TARGET_PROP         0x0200e103
 #define MR_DCMD_CTRL_SHARED_HOST_MEM_ALLOC  0x010e8485   /* SR-IOV HB alloc*/
 #define MR_DCMD_LD_VF_MAP_GET_ALL_LDS_111   0x03200200
 #define MR_DCMD_LD_VF_MAP_GET_ALL_LDS       0x03150200
@@ -603,7 +731,7 @@ struct MPI2_IOC_INIT_REQUEST {
 struct MR_DEV_HANDLE_INFO {
        __le16  curDevHdl;
        u8      validHandles;
-       u8      reserved;
+       u8      interfaceType;
        __le16  devHandle[2];
 };
 
@@ -640,10 +768,56 @@ struct MR_SPAN_BLOCK_INFO {
        struct MR_SPAN_INFO block_span_info;
 };
 
+#define MR_RAID_CTX_CPUSEL_0           0
+#define MR_RAID_CTX_CPUSEL_1           1
+#define MR_RAID_CTX_CPUSEL_2           2
+#define MR_RAID_CTX_CPUSEL_3           3
+#define MR_RAID_CTX_CPUSEL_FCFS                0xF
+
+struct MR_CPU_AFFINITY_MASK {
+       union {
+               struct {
+#ifndef MFI_BIG_ENDIAN
+               u8 hw_path:1;
+               u8 cpu0:1;
+               u8 cpu1:1;
+               u8 cpu2:1;
+               u8 cpu3:1;
+               u8 reserved:3;
+#else
+               u8 reserved:3;
+               u8 cpu3:1;
+               u8 cpu2:1;
+               u8 cpu1:1;
+               u8 cpu0:1;
+               u8 hw_path:1;
+#endif
+               };
+               u8 core_mask;
+       };
+};
+
+struct MR_IO_AFFINITY {
+       union {
+               struct {
+                       struct MR_CPU_AFFINITY_MASK pdRead;
+                       struct MR_CPU_AFFINITY_MASK pdWrite;
+                       struct MR_CPU_AFFINITY_MASK ldRead;
+                       struct MR_CPU_AFFINITY_MASK ldWrite;
+                       };
+               u32 word;
+               };
+       u8 maxCores;    /* Total cores + HW Path in ROC */
+       u8 reserved[3];
+};
+
 struct MR_LD_RAID {
        struct {
 #if   defined(__BIG_ENDIAN_BITFIELD)
-               u32     reserved4:5;
+               u32 reserved4:2;
+               u32 fp_cache_bypass_capable:1;
+               u32 fp_rmw_capable:1;
+               u32 disable_coalescing:1;
                u32     fpBypassRegionLock:1;
                u32     tmCapable:1;
                u32     fpNonRWCapable:1;
@@ -654,11 +828,13 @@ struct MR_LD_RAID {
                u32     encryptionType:8;
                u32     pdPiMode:4;
                u32     ldPiMode:4;
-               u32     reserved5:3;
+               u32 reserved5:2;
+               u32 ra_capable:1;
                u32     fpCapable:1;
 #else
                u32     fpCapable:1;
-               u32     reserved5:3;
+               u32 ra_capable:1;
+               u32 reserved5:2;
                u32     ldPiMode:4;
                u32     pdPiMode:4;
                u32     encryptionType:8;
@@ -669,7 +845,10 @@ struct MR_LD_RAID {
                u32     fpNonRWCapable:1;
                u32     tmCapable:1;
                u32     fpBypassRegionLock:1;
-               u32     reserved4:5;
+               u32 disable_coalescing:1;
+               u32 fp_rmw_capable:1;
+               u32 fp_cache_bypass_capable:1;
+               u32 reserved4:2;
 #endif
        } capability;
        __le32     reserved6;
@@ -696,7 +875,36 @@ struct MR_LD_RAID {
 
        u8      LUN[8]; /* 0x24 8 byte LUN field used for SCSI IO's */
        u8      fpIoTimeoutForLd;/*0x2C timeout value used by driver in FP IO*/
-       u8      reserved3[0x80-0x2D]; /* 0x2D */
+       /* Ox2D This LD accept priority boost of this type */
+       u8 ld_accept_priority_type;
+       u8 reserved2[2];                /* 0x2E - 0x2F */
+       /* 0x30 - 0x33, Logical block size for the LD */
+       u32 logical_block_length;
+       struct {
+#ifndef MFI_BIG_ENDIAN
+       /* 0x34, P_I_EXPONENT from READ CAPACITY 16 */
+       u32 ld_pi_exp:4;
+       /* 0x34, LOGICAL BLOCKS PER PHYSICAL
+        *  BLOCK EXPONENT from READ CAPACITY 16
+        */
+       u32 ld_logical_block_exp:4;
+       u32 reserved1:24;           /* 0x34 */
+#else
+       u32 reserved1:24;           /* 0x34 */
+       /* 0x34, LOGICAL BLOCKS PER PHYSICAL
+        *  BLOCK EXPONENT from READ CAPACITY 16
+        */
+       u32 ld_logical_block_exp:4;
+       /* 0x34, P_I_EXPONENT from READ CAPACITY 16 */
+       u32 ld_pi_exp:4;
+#endif
+       };                               /* 0x34 - 0x37 */
+        /* 0x38 - 0x3f, This will determine which
+         *  core will process LD IO and PD IO.
+         */
+       struct MR_IO_AFFINITY cpuAffinity;
+     /* Bit definiations are specified by MR_IO_AFFINITY */
+       u8 reserved3[0x80 - 0x40];    /* 0x40 - 0x7f */
 };
 
 struct MR_LD_SPAN_MAP {
@@ -735,6 +943,7 @@ struct IO_REQUEST_INFO {
        u16 ldTgtId;
        u8 isRead;
        __le16 devHandle;
+       u8 pd_interface;
        u64 pdBlock;
        u8 fpOkForIo;
        u8 IoforUnevenSpan;
@@ -743,6 +952,8 @@ struct IO_REQUEST_INFO {
        u64 start_row;
        u8  span_arm;   /* span[7:5], arm[4:0] */
        u8  pd_after_lb;
+       u16 r1_alt_dev_handle; /* raid 1/10 only */
+       bool ra_capable;
 };
 
 struct MR_LD_TARGET_SYNC {
@@ -751,6 +962,91 @@ struct MR_LD_TARGET_SYNC {
        __le16 seqNum;
 };
 
+/*
+ * RAID Map descriptor Types.
+ * Each element should uniquely idetify one data structure in the RAID map
+ */
+enum MR_RAID_MAP_DESC_TYPE {
+       /* MR_DEV_HANDLE_INFO data */
+       RAID_MAP_DESC_TYPE_DEVHDL_INFO    = 0x0,
+       /* target to Ld num Index map */
+       RAID_MAP_DESC_TYPE_TGTID_INFO     = 0x1,
+       /* MR_ARRAY_INFO data */
+       RAID_MAP_DESC_TYPE_ARRAY_INFO     = 0x2,
+       /* MR_LD_SPAN_MAP data */
+       RAID_MAP_DESC_TYPE_SPAN_INFO      = 0x3,
+       RAID_MAP_DESC_TYPE_COUNT,
+};
+
+/*
+ * This table defines the offset, size and num elements  of each descriptor
+ * type in the RAID Map buffer
+ */
+struct MR_RAID_MAP_DESC_TABLE {
+       /* Raid map descriptor type */
+       u32 raid_map_desc_type;
+       /* Offset into the RAID map buffer where
+        *  descriptor data is saved
+        */
+       u32 raid_map_desc_offset;
+       /* total size of the
+        * descriptor buffer
+        */
+       u32 raid_map_desc_buffer_size;
+       /* Number of elements contained in the
+        *  descriptor buffer
+        */
+       u32 raid_map_desc_elements;
+};
+
+/*
+ * Dynamic Raid Map Structure.
+ */
+struct MR_FW_RAID_MAP_DYNAMIC {
+       u32 raid_map_size;   /* total size of RAID Map structure */
+       u32 desc_table_offset;/* Offset of desc table into RAID map*/
+       u32 desc_table_size;  /* Total Size of desc table */
+       /* Total Number of elements in the desc table */
+       u32 desc_table_num_elements;
+       u64     reserved1;
+       u32     reserved2[3];   /*future use */
+       /* timeout value used by driver in FP IOs */
+       u8 fp_pd_io_timeout_sec;
+       u8 reserved3[3];
+       /* when this seqNum increments, driver needs to
+        *  release RMW buffers asap
+        */
+       u32 rmw_fp_seq_num;
+       u16 ld_count;   /* count of lds. */
+       u16 ar_count;   /* count of arrays */
+       u16 span_count; /* count of spans */
+       u16 reserved4[3];
+/*
+ * The below structure of pointers is only to be used by the driver.
+ * This is added in the ,API to reduce the amount of code changes
+ * needed in the driver to support dynamic RAID map Firmware should
+ * not update these pointers while preparing the raid map
+ */
+       union {
+               struct {
+                       struct MR_DEV_HANDLE_INFO  *dev_hndl_info;
+                       u16 *ld_tgt_id_to_ld;
+                       struct MR_ARRAY_INFO *ar_map_info;
+                       struct MR_LD_SPAN_MAP *ld_span_map;
+                       };
+               u64 ptr_structure_size[RAID_MAP_DESC_TYPE_COUNT];
+               };
+/*
+ * RAID Map descriptor table defines the layout of data in the RAID Map.
+ * The size of the descriptor table itself could change.
+ */
+       /* Variable Size descriptor Table. */
+       struct MR_RAID_MAP_DESC_TABLE
+                       raid_map_desc_table[RAID_MAP_DESC_TYPE_COUNT];
+       /* Variable Size buffer containing all data */
+       u32 raid_map_desc_data[1];
+}; /* Dynamicaly sized RAID MAp structure */
+
 #define IEEE_SGE_FLAGS_ADDR_MASK            (0x03)
 #define IEEE_SGE_FLAGS_SYSTEM_ADDR          (0x00)
 #define IEEE_SGE_FLAGS_IOCDDR_ADDR          (0x01)
@@ -759,6 +1055,16 @@ struct MR_LD_TARGET_SYNC {
 #define IEEE_SGE_FLAGS_CHAIN_ELEMENT        (0x80)
 #define IEEE_SGE_FLAGS_END_OF_LIST          (0x40)
 
+#define MPI2_SGE_FLAGS_SHIFT                (0x02)
+#define IEEE_SGE_FLAGS_FORMAT_MASK          (0xC0)
+#define IEEE_SGE_FLAGS_FORMAT_IEEE          (0x00)
+#define IEEE_SGE_FLAGS_FORMAT_NVME          (0x02)
+
+#define MPI26_IEEE_SGE_FLAGS_NSF_MASK           (0x1C)
+#define MPI26_IEEE_SGE_FLAGS_NSF_MPI_IEEE       (0x00)
+#define MPI26_IEEE_SGE_FLAGS_NSF_NVME_PRP       (0x08)
+#define MPI26_IEEE_SGE_FLAGS_NSF_NVME_SGL       (0x10)
+
 struct megasas_register_set;
 struct megasas_instance;
 
@@ -795,6 +1101,10 @@ struct megasas_cmd_fusion {
        u32 index;
        u8 pd_r1_lb;
        struct completion done;
+       u8 pd_interface;
+       u16 r1_alt_dev_handle; /* raid 1/10 only*/
+       bool cmd_completed;  /* raid 1/10 fp writes status holder */
+
 };
 
 struct LD_LOAD_BALANCE_INFO {
@@ -856,9 +1166,10 @@ struct MR_DRV_RAID_MAP {
        __le16                 spanCount;
        __le16                 reserve3;
 
-       struct MR_DEV_HANDLE_INFO  devHndlInfo[MAX_RAIDMAP_PHYSICAL_DEVICES];
-       u8                  ldTgtIdToLd[MAX_LOGICAL_DRIVES_EXT];
-       struct MR_ARRAY_INFO       arMapInfo[MAX_API_ARRAYS_EXT];
+       struct MR_DEV_HANDLE_INFO
+               devHndlInfo[MAX_RAIDMAP_PHYSICAL_DEVICES_DYN];
+       u16 ldTgtIdToLd[MAX_LOGICAL_DRIVES_DYN];
+       struct MR_ARRAY_INFO arMapInfo[MAX_API_ARRAYS_DYN];
        struct MR_LD_SPAN_MAP      ldSpanMap[1];
 
 };
@@ -870,7 +1181,7 @@ struct MR_DRV_RAID_MAP {
 struct MR_DRV_RAID_MAP_ALL {
 
        struct MR_DRV_RAID_MAP raidMap;
-       struct MR_LD_SPAN_MAP      ldSpanMap[MAX_LOGICAL_DRIVES_EXT - 1];
+       struct MR_LD_SPAN_MAP ldSpanMap[MAX_LOGICAL_DRIVES_DYN - 1];
 } __packed;
 
 
@@ -919,7 +1230,8 @@ struct MR_PD_CFG_SEQ {
                u8     reserved:7;
 #endif
        } capability;
-       u8  reserved[3];
+       u8  reserved;
+       u16 pd_target_id;
 } __packed;
 
 struct MR_PD_CFG_SEQ_NUM_SYNC {
@@ -928,6 +1240,30 @@ struct MR_PD_CFG_SEQ_NUM_SYNC {
        struct MR_PD_CFG_SEQ seq[1];
 } __packed;
 
+/* stream detection */
+struct STREAM_DETECT {
+       u64 next_seq_lba; /* next LBA to match sequential access */
+       struct megasas_cmd_fusion *first_cmd_fusion; /* first cmd in group */
+       struct megasas_cmd_fusion *last_cmd_fusion; /* last cmd in group */
+       u32 count_cmds_in_stream; /* count of host commands in this stream */
+       u16 num_sges_in_group; /* total number of SGEs in grouped IOs */
+       u8 is_read; /* SCSI OpCode for this stream */
+       u8 group_depth; /* total number of host commands in group */
+       /* TRUE if cannot add any more commands to this group */
+       bool group_flush;
+       u8 reserved[7]; /* pad to 64-bit alignment */
+};
+
+struct LD_STREAM_DETECT {
+       bool write_back; /* TRUE if WB, FALSE if WT */
+       bool fp_write_enabled;
+       bool members_ssds;
+       bool fp_cache_bypass_capable;
+       u32 mru_bit_map; /* bitmap used to track MRU and LRU stream indicies */
+       /* this is the array of stream detect structures (one per stream) */
+       struct STREAM_DETECT stream_track[MAX_STREAMS_TRACKED];
+};
+
 struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY {
        u64 RDPQBaseAddress;
        u32 Reserved1;
@@ -965,7 +1301,7 @@ struct fusion_context {
        u8      chain_offset_io_request;
        u8      chain_offset_mfi_pthru;
 
-       struct MR_FW_RAID_MAP_ALL *ld_map[2];
+       struct MR_FW_RAID_MAP_DYNAMIC *ld_map[2];
        dma_addr_t ld_map_phys[2];
 
        /*Non dma-able memory. Driver local copy.*/
@@ -973,14 +1309,18 @@ struct fusion_context {
 
        u32 max_map_sz;
        u32 current_map_sz;
+       u32 old_map_sz;
+       u32 new_map_sz;
        u32 drv_map_sz;
        u32 drv_map_pages;
        struct MR_PD_CFG_SEQ_NUM_SYNC   *pd_seq_sync[JBOD_MAPS_COUNT];
        dma_addr_t pd_seq_phys[JBOD_MAPS_COUNT];
        u8 fast_path_io;
-       struct LD_LOAD_BALANCE_INFO load_balance_info[MAX_LOGICAL_DRIVES_EXT];
+       struct LD_LOAD_BALANCE_INFO *load_balance_info;
+       u32 load_balance_info_pages;
        LD_SPAN_INFO log_to_span[MAX_LOGICAL_DRIVES_EXT];
        u8 adapter_type;
+       struct LD_STREAM_DETECT **stream_detect_by_ld;
 };
 
 union desc_value {
index 8bae305bc156d181b75d58496e799b930884dc88..af4be403582e8b1dcec58b6a1dd11540f479954a 100644 (file)
@@ -624,6 +624,8 @@ typedef struct _MPI26_EVENT_DATA_ACTIVE_CABLE_EXCEPT {
 
 /* defines for ReasonCode field */
 #define MPI26_EVENT_ACTIVE_CABLE_INSUFFICIENT_POWER     (0x00)
+#define MPI26_EVENT_ACTIVE_CABLE_PRESENT                (0x01)
+#define MPI26_EVENT_ACTIVE_CABLE_DEGRADED               (0x02)
 
 /*Hard Reset Received Event data */
 
index f00ef88a378af2f79f5ef9b38cc97b6cb9eeed19..a3fe1fb55c17c39c2e2c7293df32823aadaf5065 100644 (file)
@@ -1040,6 +1040,25 @@ _base_interrupt(int irq, void *bus_id)
                    reply_q->reply_post_free[reply_q->reply_post_host_index].
                    Default.ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
                completed_cmds++;
+               /* Update the reply post host index after continuously
+                * processing the threshold number of Reply Descriptors.
+                * So that FW can find enough entries to post the Reply
+                * Descriptors in the reply descriptor post queue.
+                */
+               if (completed_cmds > ioc->hba_queue_depth/3) {
+                       if (ioc->combined_reply_queue) {
+                               writel(reply_q->reply_post_host_index |
+                                               ((msix_index  & 7) <<
+                                                MPI2_RPHI_MSIX_INDEX_SHIFT),
+                                   ioc->replyPostRegisterIndex[msix_index/8]);
+                       } else {
+                               writel(reply_q->reply_post_host_index |
+                                               (msix_index <<
+                                                MPI2_RPHI_MSIX_INDEX_SHIFT),
+                                               &ioc->chip->ReplyPostHostIndex);
+                       }
+                       completed_cmds = 1;
+               }
                if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
                        goto out;
                if (!reply_q->reply_post_host_index)
@@ -5522,6 +5541,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
                goto out_free_resources;
 
        ioc->non_operational_loop = 0;
+       ioc->got_task_abort_from_ioctl = 0;
        return 0;
 
  out_free_resources:
index dcb33f4fa68720624945f4bdc3f5c932e530c86f..4ab634fc27df92d14b7dd2213b22f570ee4717fc 100644 (file)
@@ -73,9 +73,9 @@
 #define MPT3SAS_DRIVER_NAME            "mpt3sas"
 #define MPT3SAS_AUTHOR "Avago Technologies <MPT-FusionLinux.pdl@avagotech.com>"
 #define MPT3SAS_DESCRIPTION    "LSI MPT Fusion SAS 3.0 Device Driver"
-#define MPT3SAS_DRIVER_VERSION         "14.101.00.00"
-#define MPT3SAS_MAJOR_VERSION          14
-#define MPT3SAS_MINOR_VERSION          101
+#define MPT3SAS_DRIVER_VERSION         "15.100.00.00"
+#define MPT3SAS_MAJOR_VERSION          15
+#define MPT3SAS_MINOR_VERSION          100
 #define MPT3SAS_BUILD_VERSION          0
 #define MPT3SAS_RELEASE_VERSION        00
 
@@ -1000,6 +1000,7 @@ struct MPT3SAS_ADAPTER {
        u8              broadcast_aen_busy;
        u16             broadcast_aen_pending;
        u8              shost_recovery;
+       u8              got_task_abort_from_ioctl;
 
        struct mutex    reset_in_progress_mutex;
        spinlock_t      ioc_reset_in_progress_lock;
index 95f0f24bac05598e1c8246cb1078de9163a66e5d..02fe1c4aae2fdb1718f2e9ebf7a476d363159249 100644 (file)
@@ -826,16 +826,18 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
                        "TASK_MGMT: handle(0x%04x), task_type(0x%02x)\n",
                        ioc->name,
                    le16_to_cpu(tm_request->DevHandle), tm_request->TaskType));
-
+               ioc->got_task_abort_from_ioctl = 1;
                if (tm_request->TaskType ==
                    MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK ||
                    tm_request->TaskType ==
                    MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK) {
                        if (_ctl_set_task_mid(ioc, &karg, tm_request)) {
                                mpt3sas_base_free_smid(ioc, smid);
+                               ioc->got_task_abort_from_ioctl = 0;
                                goto out;
                        }
                }
+               ioc->got_task_abort_from_ioctl = 0;
 
                if (test_bit(device_handle, ioc->device_remove_in_progress)) {
                        dtmprintk(ioc, pr_info(MPT3SAS_FMT
index 0b5b423b1db0d19a1a1dfb6fc38e168af4559d71..46e866c36c8a884a98588a8d7a81272aed0ce400 100644 (file)
@@ -1074,6 +1074,26 @@ _scsih_scsi_lookup_get(struct MPT3SAS_ADAPTER *ioc, u16 smid)
        return ioc->scsi_lookup[smid - 1].scmd;
 }
 
+/**
+ * __scsih_scsi_lookup_get_clear - returns scmd entry without
+ *                                             holding any lock.
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * Returns the smid stored scmd pointer.
+ * Then will dereference the stored scmd pointer.
+ */
+static inline struct scsi_cmnd *
+__scsih_scsi_lookup_get_clear(struct MPT3SAS_ADAPTER *ioc,
+               u16 smid)
+{
+       struct scsi_cmnd *scmd = NULL;
+
+       swap(scmd, ioc->scsi_lookup[smid - 1].scmd);
+
+       return scmd;
+}
+
 /**
  * _scsih_scsi_lookup_get_clear - returns scmd entry
  * @ioc: per adapter object
@@ -1089,8 +1109,7 @@ _scsih_scsi_lookup_get_clear(struct MPT3SAS_ADAPTER *ioc, u16 smid)
        struct scsi_cmnd *scmd;
 
        spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
-       scmd = ioc->scsi_lookup[smid - 1].scmd;
-       ioc->scsi_lookup[smid - 1].scmd = NULL;
+       scmd = __scsih_scsi_lookup_get_clear(ioc, smid);
        spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
 
        return scmd;
@@ -4661,7 +4680,13 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
        unsigned int sector_sz;
 
        mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply);
-       scmd = _scsih_scsi_lookup_get_clear(ioc, smid);
+
+       if (ioc->broadcast_aen_busy || ioc->pci_error_recovery ||
+                       ioc->got_task_abort_from_ioctl)
+               scmd = _scsih_scsi_lookup_get_clear(ioc, smid);
+       else
+               scmd = __scsih_scsi_lookup_get_clear(ioc, smid);
+
        if (scmd == NULL)
                return 1;
 
@@ -4723,7 +4748,7 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
         * then scsi-ml does not need to handle this misbehavior.
         */
        sector_sz = scmd->device->sector_size;
-       if (unlikely(scmd->request->cmd_type == REQ_TYPE_FS && sector_sz &&
+       if (unlikely(!blk_rq_is_passthrough(scmd->request) && sector_sz &&
                     xfer_cnt % sector_sz)) {
                sdev_printk(KERN_INFO, scmd->device,
                    "unaligned partial completion avoided (xfer_cnt=%u, sector_sz=%u)\n",
@@ -8044,15 +8069,24 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index,
        case MPI2_EVENT_ACTIVE_CABLE_EXCEPTION:
                ActiveCableEventData =
                    (Mpi26EventDataActiveCableExcept_t *) mpi_reply->EventData;
-               if (ActiveCableEventData->ReasonCode ==
-                               MPI26_EVENT_ACTIVE_CABLE_INSUFFICIENT_POWER) {
-                       pr_info(MPT3SAS_FMT "Currently an active cable with ReceptacleID %d",
-                           ioc->name, ActiveCableEventData->ReceptacleID);
-                       pr_info("cannot be powered and devices connected to this active cable");
-                       pr_info("will not be seen. This active cable");
-                       pr_info("requires %d mW of power",
-                           ActiveCableEventData->ActiveCablePowerRequirement);
+               switch (ActiveCableEventData->ReasonCode) {
+               case MPI26_EVENT_ACTIVE_CABLE_INSUFFICIENT_POWER:
+                       pr_notice(MPT3SAS_FMT "Receptacle ID %d: This active cable"
+                                 " requires %d mW of power\n", ioc->name,
+                            ActiveCableEventData->ReceptacleID,
+                            ActiveCableEventData->ActiveCablePowerRequirement);
+                       pr_notice(MPT3SAS_FMT "Receptacle ID %d: Devices connected"
+                                 " to this active cable will not be seen\n",
+                            ioc->name, ActiveCableEventData->ReceptacleID);
+                       break;
+
+               case MPI26_EVENT_ACTIVE_CABLE_DEGRADED:
+                       pr_notice(MPT3SAS_FMT "ReceptacleID %d: This cable",
+                               ioc->name, ActiveCableEventData->ReceptacleID);
+                       pr_notice(" is not running at an optimal speed(12 Gb/s)\n");
+                       break;
                }
+
                break;
 
        default: /* ignore the rest */
index 7f1d5785bc30afc104c9c249f5cc9ec266e776d6..e7a7a704a315d4a63dda72f4a85d745c1caaf27a 100644 (file)
@@ -2057,10 +2057,10 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
                    ioc->name, __func__,
                    le16_to_cpu(mpi_reply->ResponseDataLength)));
 
-               memcpy(req->sense, mpi_reply, sizeof(*mpi_reply));
-               req->sense_len = sizeof(*mpi_reply);
-               req->resid_len = 0;
-               rsp->resid_len -=
+               memcpy(scsi_req(req)->sense, mpi_reply, sizeof(*mpi_reply));
+               scsi_req(req)->sense_len = sizeof(*mpi_reply);
+               scsi_req(req)->resid_len = 0;
+               scsi_req(rsp)->resid_len -=
                    le16_to_cpu(mpi_reply->ResponseDataLength);
 
                /* check if the resp needs to be copied from the allocated
index 39285070f3b5126e938fde8403eeabeca8395240..247df5e79b71b45b5bd9c4de8e056b9fd2171afb 100644 (file)
@@ -2225,15 +2225,12 @@ static struct scsi_host_template mvumi_template = {
        .name = "Marvell Storage Controller",
        .slave_configure = mvumi_slave_configure,
        .queuecommand = mvumi_queue_command,
+       .eh_timed_out = mvumi_timed_out,
        .eh_host_reset_handler = mvumi_host_reset,
        .bios_param = mvumi_bios_param,
        .this_id = -1,
 };
 
-static struct scsi_transport_template mvumi_transport_template = {
-       .eh_timed_out = mvumi_timed_out,
-};
-
 static int mvumi_cfg_hw_reg(struct mvumi_hba *mhba)
 {
        void *base = NULL;
@@ -2451,7 +2448,6 @@ static int mvumi_io_attach(struct mvumi_hba *mhba)
        host->cmd_per_lun = (mhba->max_io - 1) ? (mhba->max_io - 1) : 1;
        host->max_id = mhba->max_target_id;
        host->max_cmd_len = MAX_COMMAND_SIZE;
-       host->transportt = &mvumi_transport_template;
 
        ret = scsi_add_host(host, &mhba->pdev->dev);
        if (ret) {
index ef99f62831fb8586b42cb9a03ce02078d3aecd08..30b905080c61412a3e8e1234157e687594e0a041 100644 (file)
@@ -48,6 +48,7 @@
 #include <scsi/osd_sense.h>
 
 #include <scsi/scsi_device.h>
+#include <scsi/scsi_request.h>
 
 #include "osd_debug.h"
 
@@ -477,11 +478,13 @@ static void _set_error_resid(struct osd_request *or, struct request *req,
 {
        or->async_error = error;
        or->req_errors = req->errors ? : error;
-       or->sense_len = req->sense_len;
+       or->sense_len = scsi_req(req)->sense_len;
+       if (or->sense_len)
+               memcpy(or->sense, scsi_req(req)->sense, or->sense_len);
        if (or->out.req)
-               or->out.residual = or->out.req->resid_len;
+               or->out.residual = scsi_req(or->out.req)->resid_len;
        if (or->in.req)
-               or->in.residual = or->in.req->resid_len;
+               or->in.residual = scsi_req(or->in.req)->resid_len;
 }
 
 int osd_execute_request(struct osd_request *or)
@@ -1562,10 +1565,11 @@ static struct request *_make_request(struct request_queue *q, bool has_write,
        struct bio *bio = oii->bio;
        int ret;
 
-       req = blk_get_request(q, has_write ? WRITE : READ, flags);
+       req = blk_get_request(q, has_write ? REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN,
+                       flags);
        if (IS_ERR(req))
                return req;
-       blk_rq_set_block_pc(req);
+       scsi_req_init(req);
 
        for_each_bio(bio) {
                struct bio *bounce_bio = bio;
@@ -1599,8 +1603,6 @@ static int _init_blk_request(struct osd_request *or,
 
        req->timeout = or->timeout;
        req->retries = or->retries;
-       req->sense = or->sense;
-       req->sense_len = 0;
 
        if (has_out) {
                or->out.req = req;
@@ -1612,7 +1614,7 @@ static int _init_blk_request(struct osd_request *or,
                                ret = PTR_ERR(req);
                                goto out;
                        }
-                       blk_rq_set_block_pc(req);
+                       scsi_req_init(req);
                        or->in.req = or->request->next_rq = req;
                }
        } else if (has_in)
@@ -1699,8 +1701,8 @@ int osd_finalize_request(struct osd_request *or,
 
        osd_sec_sign_cdb(&or->cdb, cap_key);
 
-       or->request->cmd = or->cdb.buff;
-       or->request->cmd_len = _osd_req_cdb_len(or);
+       scsi_req(or->request)->cmd = or->cdb.buff;
+       scsi_req(or->request)->cmd_len = _osd_req_cdb_len(or);
 
        return 0;
 }
index e8196c55b633bcedb6cb6f52e2badf5e2867c164..451de6c5e3c9942b3a8094bd705fbd234b094f91 100644 (file)
@@ -322,6 +322,7 @@ static int osst_chk_result(struct osst_tape * STp, struct osst_request * SRpnt)
 /* Wakeup from interrupt */
 static void osst_end_async(struct request *req, int update)
 {
+       struct scsi_request *rq = scsi_req(req);
        struct osst_request *SRpnt = req->end_io_data;
        struct osst_tape *STp = SRpnt->stp;
        struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data;
@@ -330,6 +331,8 @@ static void osst_end_async(struct request *req, int update)
 #if DEBUG
        STp->write_pending = 0;
 #endif
+       if (rq->sense_len)
+               memcpy(SRpnt->sense, rq->sense, SCSI_SENSE_BUFFERSIZE);
        if (SRpnt->waiting)
                complete(SRpnt->waiting);
 
@@ -357,17 +360,20 @@ static int osst_execute(struct osst_request *SRpnt, const unsigned char *cmd,
                        int use_sg, int timeout, int retries)
 {
        struct request *req;
+       struct scsi_request *rq;
        struct page **pages = NULL;
        struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data;
 
        int err = 0;
        int write = (data_direction == DMA_TO_DEVICE);
 
-       req = blk_get_request(SRpnt->stp->device->request_queue, write, GFP_KERNEL);
+       req = blk_get_request(SRpnt->stp->device->request_queue,
+                       write ? REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, GFP_KERNEL);
        if (IS_ERR(req))
                return DRIVER_ERROR << 24;
 
-       blk_rq_set_block_pc(req);
+       rq = scsi_req(req);
+       scsi_req_init(req);
        req->rq_flags |= RQF_QUIET;
 
        SRpnt->bio = NULL;
@@ -404,11 +410,9 @@ static int osst_execute(struct osst_request *SRpnt, const unsigned char *cmd,
                        goto free_req;
        }
 
-       req->cmd_len = cmd_len;
-       memset(req->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */
-       memcpy(req->cmd, cmd, req->cmd_len);
-       req->sense = SRpnt->sense;
-       req->sense_len = 0;
+       rq->cmd_len = cmd_len;
+       memset(rq->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */
+       memcpy(rq->cmd, cmd, rq->cmd_len);
        req->timeout = timeout;
        req->retries = retries;
        req->end_io_data = SRpnt;
index 9fc675f57e3361a3dc371e973f1d0c2ceeff065e..417368ccb686883ee31d078def5f663d5deef114 100644 (file)
@@ -888,7 +888,6 @@ static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha)
        u32 i = 0, j = 0;
        u32 number_of_intr;
        int flag = 0;
-       u32 max_entry;
        int rc;
        static char intr_drvname[PM8001_MAX_MSIX_VEC][sizeof(DRV_NAME)+3];
 
@@ -900,18 +899,14 @@ static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha)
                flag &= ~IRQF_SHARED;
        }
 
-       max_entry = sizeof(pm8001_ha->msix_entries) /
-               sizeof(pm8001_ha->msix_entries[0]);
-       for (i = 0; i < max_entry ; i++)
-               pm8001_ha->msix_entries[i].entry = i;
-       rc = pci_enable_msix_exact(pm8001_ha->pdev, pm8001_ha->msix_entries,
-               number_of_intr);
-       pm8001_ha->number_of_intr = number_of_intr;
-       if (rc)
+       rc = pci_alloc_irq_vectors(pm8001_ha->pdev, number_of_intr,
+                       number_of_intr, PCI_IRQ_MSIX);
+       if (rc < 0)
                return rc;
+       pm8001_ha->number_of_intr = number_of_intr;
 
        PM8001_INIT_DBG(pm8001_ha, pm8001_printk(
-               "pci_enable_msix_exact request ret:%d no of intr %d\n",
+               "pci_alloc_irq_vectors request ret:%d no of intr %d\n",
                                rc, pm8001_ha->number_of_intr));
 
        for (i = 0; i < number_of_intr; i++) {
@@ -920,15 +915,15 @@ static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha)
                pm8001_ha->irq_vector[i].irq_id = i;
                pm8001_ha->irq_vector[i].drv_inst = pm8001_ha;
 
-               rc = request_irq(pm8001_ha->msix_entries[i].vector,
+               rc = request_irq(pci_irq_vector(pm8001_ha->pdev, i),
                        pm8001_interrupt_handler_msix, flag,
                        intr_drvname[i], &(pm8001_ha->irq_vector[i]));
                if (rc) {
                        for (j = 0; j < i; j++) {
-                               free_irq(pm8001_ha->msix_entries[j].vector,
+                               free_irq(pci_irq_vector(pm8001_ha->pdev, i),
                                        &(pm8001_ha->irq_vector[i]));
                        }
-                       pci_disable_msix(pm8001_ha->pdev);
+                       pci_free_irq_vectors(pm8001_ha->pdev);
                        break;
                }
        }
@@ -1102,11 +1097,10 @@ static void pm8001_pci_remove(struct pci_dev *pdev)
 
 #ifdef PM8001_USE_MSIX
        for (i = 0; i < pm8001_ha->number_of_intr; i++)
-               synchronize_irq(pm8001_ha->msix_entries[i].vector);
+               synchronize_irq(pci_irq_vector(pdev, i));
        for (i = 0; i < pm8001_ha->number_of_intr; i++)
-               free_irq(pm8001_ha->msix_entries[i].vector,
-                               &(pm8001_ha->irq_vector[i]));
-       pci_disable_msix(pdev);
+               free_irq(pci_irq_vector(pdev, i), &pm8001_ha->irq_vector[i]);
+       pci_free_irq_vectors(pdev);
 #else
        free_irq(pm8001_ha->irq, sha);
 #endif
@@ -1152,11 +1146,10 @@ static int pm8001_pci_suspend(struct pci_dev *pdev, pm_message_t state)
        PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha);
 #ifdef PM8001_USE_MSIX
        for (i = 0; i < pm8001_ha->number_of_intr; i++)
-               synchronize_irq(pm8001_ha->msix_entries[i].vector);
+               synchronize_irq(pci_irq_vector(pdev, i));
        for (i = 0; i < pm8001_ha->number_of_intr; i++)
-               free_irq(pm8001_ha->msix_entries[i].vector,
-                               &(pm8001_ha->irq_vector[i]));
-       pci_disable_msix(pdev);
+               free_irq(pci_irq_vector(pdev, i), &pm8001_ha->irq_vector[i]);
+       pci_free_irq_vectors(pdev);
 #else
        free_irq(pm8001_ha->irq, sha);
 #endif
index 6628cc38316c2ef5871ef81db4d9fe772e402fee..e81a8fa7ef1a85daae3e1474a1b541b1e494e290 100644 (file)
@@ -521,8 +521,6 @@ struct pm8001_hba_info {
        struct pm8001_device    *devices;
        struct pm8001_ccb_info  *ccb_info;
 #ifdef PM8001_USE_MSIX
-       struct msix_entry       msix_entries[PM8001_MAX_MSIX_VEC];
-                                       /*for msi-x interrupt*/
        int                     number_of_intr;/*will be used in remove()*/
 #endif
 #ifdef PM8001_USE_TASKLET
index 337982cf3d638198c1d674ab974d696b582ab160..49e70a383afaedf0c56024249b10bd67540169e7 100644 (file)
@@ -4587,16 +4587,14 @@ static void pmcraid_tasklet_function(unsigned long instance)
 static
 void pmcraid_unregister_interrupt_handler(struct pmcraid_instance *pinstance)
 {
+       struct pci_dev *pdev = pinstance->pdev;
        int i;
 
        for (i = 0; i < pinstance->num_hrrq; i++)
-               free_irq(pinstance->hrrq_vector[i].vector,
-                        &(pinstance->hrrq_vector[i]));
+               free_irq(pci_irq_vector(pdev, i), &pinstance->hrrq_vector[i]);
 
-       if (pinstance->interrupt_mode) {
-               pci_disable_msix(pinstance->pdev);
-               pinstance->interrupt_mode = 0;
-       }
+       pinstance->interrupt_mode = 0;
+       pci_free_irq_vectors(pdev);
 }
 
 /**
@@ -4609,60 +4607,52 @@ void pmcraid_unregister_interrupt_handler(struct pmcraid_instance *pinstance)
 static int
 pmcraid_register_interrupt_handler(struct pmcraid_instance *pinstance)
 {
-       int rc;
        struct pci_dev *pdev = pinstance->pdev;
+       unsigned int irq_flag = PCI_IRQ_LEGACY, flag;
+       int num_hrrq, rc, i;
+       irq_handler_t isr;
 
-       if ((pmcraid_enable_msix) &&
-               (pci_find_capability(pdev, PCI_CAP_ID_MSIX))) {
-               int num_hrrq = PMCRAID_NUM_MSIX_VECTORS;
-               struct msix_entry entries[PMCRAID_NUM_MSIX_VECTORS];
-               int i;
-               for (i = 0; i < PMCRAID_NUM_MSIX_VECTORS; i++)
-                       entries[i].entry = i;
-
-               num_hrrq = pci_enable_msix_range(pdev, entries, 1, num_hrrq);
-               if (num_hrrq < 0)
-                       goto pmcraid_isr_legacy;
-
-               for (i = 0; i < num_hrrq; i++) {
-                       pinstance->hrrq_vector[i].hrrq_id = i;
-                       pinstance->hrrq_vector[i].drv_inst = pinstance;
-                       pinstance->hrrq_vector[i].vector = entries[i].vector;
-                       rc = request_irq(pinstance->hrrq_vector[i].vector,
-                                       pmcraid_isr_msix, 0,
-                                       PMCRAID_DRIVER_NAME,
-                                       &(pinstance->hrrq_vector[i]));
-
-                       if (rc) {
-                               int j;
-                               for (j = 0; j < i; j++)
-                                       free_irq(entries[j].vector,
-                                                &(pinstance->hrrq_vector[j]));
-                               pci_disable_msix(pdev);
-                               goto pmcraid_isr_legacy;
-                       }
-               }
+       if (pmcraid_enable_msix)
+               irq_flag |= PCI_IRQ_MSIX;
 
-               pinstance->num_hrrq = num_hrrq;
+       num_hrrq = pci_alloc_irq_vectors(pdev, 1, PMCRAID_NUM_MSIX_VECTORS,
+                       irq_flag);
+       if (num_hrrq < 0)
+               return num_hrrq;
+
+       if (pdev->msix_enabled) {
+               flag = 0;
+               isr = pmcraid_isr_msix;
+       } else {
+               flag = IRQF_SHARED;
+               isr = pmcraid_isr;
+       }
+
+       for (i = 0; i < num_hrrq; i++) {
+               struct pmcraid_isr_param *vec = &pinstance->hrrq_vector[i];
+
+               vec->hrrq_id = i;
+               vec->drv_inst = pinstance;
+               rc = request_irq(pci_irq_vector(pdev, i), isr, flag,
+                               PMCRAID_DRIVER_NAME, vec);
+               if (rc)
+                       goto out_unwind;
+       }
+
+       pinstance->num_hrrq = num_hrrq;
+       if (pdev->msix_enabled) {
                pinstance->interrupt_mode = 1;
                iowrite32(DOORBELL_INTR_MODE_MSIX,
                          pinstance->int_regs.host_ioa_interrupt_reg);
                ioread32(pinstance->int_regs.host_ioa_interrupt_reg);
-               goto pmcraid_isr_out;
        }
 
-pmcraid_isr_legacy:
-       /* If MSI-X registration failed fallback to legacy mode, where
-        * only one hrrq entry will be used
-        */
-       pinstance->hrrq_vector[0].hrrq_id = 0;
-       pinstance->hrrq_vector[0].drv_inst = pinstance;
-       pinstance->hrrq_vector[0].vector = pdev->irq;
-       pinstance->num_hrrq = 1;
-
-       rc = request_irq(pdev->irq, pmcraid_isr, IRQF_SHARED,
-                        PMCRAID_DRIVER_NAME, &pinstance->hrrq_vector[0]);
-pmcraid_isr_out:
+       return 0;
+
+out_unwind:
+       while (--i > 0)
+               free_irq(pci_irq_vector(pdev, i), &pinstance->hrrq_vector[i]);
+       pci_free_irq_vectors(pdev);
        return rc;
 }
 
index e1d150f3fd4d4912c2cdc9f972550874f0fd63f7..568b18a2f47dd69d5347b103bd5ce27ef9af89c7 100644 (file)
@@ -628,7 +628,6 @@ struct pmcraid_interrupts {
 /* ISR parameters LLD allocates (one for each MSI-X if enabled) vectors */
 struct pmcraid_isr_param {
        struct pmcraid_instance *drv_inst;
-       u16 vector;                     /* allocated msi-x vector */
        u8 hrrq_id;                     /* hrrq entry index */
 };
 
index 2bdedb9c39bc4126ec6a1234e8db8e0884f33cf0..8fd28b056f73f389f6bb124c385f414cee28c21e 100644 (file)
@@ -52,7 +52,7 @@ qedi_dbg_warn(struct qedi_dbg_ctx *qedi, const char *func, u32 line,
        vaf.va = &va;
 
        if (!(qedi_dbg_log & QEDI_LOG_WARN))
-               return;
+               goto ret;
 
        if (likely(qedi) && likely(qedi->pdev))
                pr_warn("[%s]:[%s:%d]:%d: %pV", dev_name(&qedi->pdev->dev),
@@ -60,6 +60,7 @@ qedi_dbg_warn(struct qedi_dbg_ctx *qedi, const char *func, u32 line,
        else
                pr_warn("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf);
 
+ret:
        va_end(va);
 }
 
@@ -80,7 +81,7 @@ qedi_dbg_notice(struct qedi_dbg_ctx *qedi, const char *func, u32 line,
        vaf.va = &va;
 
        if (!(qedi_dbg_log & QEDI_LOG_NOTICE))
-               return;
+               goto ret;
 
        if (likely(qedi) && likely(qedi->pdev))
                pr_notice("[%s]:[%s:%d]:%d: %pV",
@@ -89,6 +90,7 @@ qedi_dbg_notice(struct qedi_dbg_ctx *qedi, const char *func, u32 line,
        else
                pr_notice("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf);
 
+ret:
        va_end(va);
 }
 
@@ -109,7 +111,7 @@ qedi_dbg_info(struct qedi_dbg_ctx *qedi, const char *func, u32 line,
        vaf.va = &va;
 
        if (!(qedi_dbg_log & level))
-               return;
+               goto ret;
 
        if (likely(qedi) && likely(qedi->pdev))
                pr_info("[%s]:[%s:%d]:%d: %pV", dev_name(&qedi->pdev->dev),
@@ -117,6 +119,7 @@ qedi_dbg_info(struct qedi_dbg_ctx *qedi, const char *func, u32 line,
        else
                pr_info("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf);
 
+ret:
        va_end(va);
 }
 
index d6a205433b66b6d2da39cbdbe99691d89afa2705..b9f79d36142d5e85182d39d16ba34a7a1a6f6521 100644 (file)
@@ -48,6 +48,7 @@ struct scsi_host_template qedi_host_template = {
        .name = "QLogic QEDI 25/40/100Gb iSCSI Initiator Driver",
        .proc_name = QEDI_MODULE_NAME,
        .queuecommand = iscsi_queuecommand,
+       .eh_timed_out = iscsi_eh_cmd_timed_out,
        .eh_abort_handler = iscsi_eh_abort,
        .eh_device_reset_handler = iscsi_eh_device_reset,
        .eh_target_reset_handler = iscsi_eh_recover_target,
@@ -453,13 +454,9 @@ static int qedi_iscsi_update_conn(struct qedi_ctx *qedi,
        if (rval) {
                rval = -ENXIO;
                QEDI_ERR(&qedi->dbg_ctx, "Could not update connection\n");
-               goto update_conn_err;
        }
 
        kfree(conn_info);
-       rval = 0;
-
-update_conn_err:
        return rval;
 }
 
index 1bf8061ff8032fae46854f84d85946ea55c6072a..40ca75bbcb9d3e3864df45ac5e69bb3df57f7ec7 100644 (file)
@@ -921,7 +921,7 @@ qla2x00_process_loopback(struct bsg_job *bsg_job)
 
        bsg_job->reply_len = sizeof(struct fc_bsg_reply) +
            sizeof(response) + sizeof(uint8_t);
-       fw_sts_ptr = ((uint8_t *)bsg_job->req->sense) +
+       fw_sts_ptr = ((uint8_t *)scsi_req(bsg_job->req)->sense) +
            sizeof(struct fc_bsg_reply);
        memcpy(fw_sts_ptr, response, sizeof(response));
        fw_sts_ptr += sizeof(response);
index 5b1287a63c494b6edf8fcf7e8ec75a17530032db..2f14adfab018d845505f8f67844ae2153769191b 100644 (file)
@@ -2248,7 +2248,7 @@ struct ct_fdmiv2_hba_attr {
                uint32_t num_ports;
                uint8_t fabric_name[WWN_SIZE];
                uint8_t bios_name[32];
-               uint8_t vendor_indentifer[8];
+               uint8_t vendor_identifier[8];
        } a;
 };
 
@@ -2423,7 +2423,7 @@ struct ct_sns_req {
                } rsnn_nn;
 
                struct {
-                       uint8_t hba_indentifier[8];
+                       uint8_t hba_identifier[8];
                } ghat;
 
                struct {
index 94e8a8592f6904be9b4bbe408f705b0e28a342f8..ee3df87948067ca090686af57dc900deb448eb02 100644 (file)
@@ -1939,15 +1939,15 @@ qla2x00_fdmiv2_rhba(scsi_qla_host_t *vha)
        /* Vendor Identifier */
        eiter = entries + size;
        eiter->type = cpu_to_be16(FDMI_HBA_TYPE_VENDOR_IDENTIFIER);
-       snprintf(eiter->a.vendor_indentifer, sizeof(eiter->a.vendor_indentifer),
+       snprintf(eiter->a.vendor_identifier, sizeof(eiter->a.vendor_identifier),
            "%s", "QLGC");
-       alen = strlen(eiter->a.vendor_indentifer);
+       alen = strlen(eiter->a.vendor_identifier);
        alen += 4 - (alen & 3);
        eiter->len = cpu_to_be16(4 + alen);
        size += 4 + alen;
 
        ql_dbg(ql_dbg_disc, vha, 0x20b1,
-           "Vendor Identifier = %s.\n", eiter->a.vendor_indentifer);
+           "Vendor Identifier = %s.\n", eiter->a.vendor_identifier);
 
        /* Update MS request size. */
        qla2x00_update_ms_fdmi_iocb(vha, size + 16);
index a94b0b6bd0306379b4707b29be1347d1ce89e6b8..edc2264db45becfc96d2666b13b604bcc2275ef7 100644 (file)
@@ -1468,7 +1468,8 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
                            type, sp->handle, comp_status, fw_status[1], fw_status[2],
                            le16_to_cpu(((struct els_sts_entry_24xx *)
                                pkt)->total_byte_count));
-                       fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply);
+                       fw_sts_ptr = ((uint8_t*)scsi_req(bsg_job->req)->sense) +
+                               sizeof(struct fc_bsg_reply);
                        memcpy( fw_sts_ptr, fw_status, sizeof(fw_status));
                }
                else {
@@ -1482,7 +1483,8 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
                                    pkt)->error_subcode_2));
                        res = DID_ERROR << 16;
                        bsg_reply->reply_payload_rcv_len = 0;
-                       fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply);
+                       fw_sts_ptr = ((uint8_t*)scsi_req(bsg_job->req)->sense) +
+                                       sizeof(struct fc_bsg_reply);
                        memcpy( fw_sts_ptr, fw_status, sizeof(fw_status));
                }
                ql_dump_buffer(ql_dbg_user + ql_dbg_buffer, vha, 0x5056,
@@ -2995,14 +2997,14 @@ struct qla_init_msix_entry {
        irq_handler_t handler;
 };
 
-static struct qla_init_msix_entry msix_entries[] = {
+static const struct qla_init_msix_entry msix_entries[] = {
        { "qla2xxx (default)", qla24xx_msix_default },
        { "qla2xxx (rsp_q)", qla24xx_msix_rsp_q },
        { "qla2xxx (atio_q)", qla83xx_msix_atio_q },
        { "qla2xxx (qpair_multiq)", qla2xxx_msix_rsp_q },
 };
 
-static struct qla_init_msix_entry qla82xx_msix_entries[] = {
+static const struct qla_init_msix_entry qla82xx_msix_entries[] = {
        { "qla2xxx (default)", qla82xx_msix_default },
        { "qla2xxx (rsp_q)", qla82xx_msix_rsp_q },
 };
@@ -3076,7 +3078,7 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
                qentry->handle = rsp;
                rsp->msix = qentry;
                scnprintf(qentry->name, sizeof(qentry->name),
-                   msix_entries[i].name);
+                   "%s", msix_entries[i].name);
                if (IS_P3P_TYPE(ha))
                        ret = request_irq(qentry->vector,
                                qla82xx_msix_entries[i].handler,
@@ -3100,7 +3102,7 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
                rsp->msix = qentry;
                qentry->handle = rsp;
                scnprintf(qentry->name, sizeof(qentry->name),
-                   msix_entries[QLA_ATIO_VECTOR].name);
+                   "%s", msix_entries[QLA_ATIO_VECTOR].name);
                qentry->in_use = 1;
                ret = request_irq(qentry->vector,
                        msix_entries[QLA_ATIO_VECTOR].handler,
@@ -3269,7 +3271,7 @@ free_irqs:
 int qla25xx_request_irq(struct qla_hw_data *ha, struct qla_qpair *qpair,
        struct qla_msix_entry *msix, int vector_type)
 {
-       struct qla_init_msix_entry *intr = &msix_entries[vector_type];
+       const struct qla_init_msix_entry *intr = &msix_entries[vector_type];
        scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
        int ret;
 
index 02f1de18bc2b61db57ad7021fea4e7272e7af437..96c33e292ebacc0572fb948ff5bdddaf529f969d 100644 (file)
@@ -2244,7 +2244,7 @@ qlafx00_ioctl_iosb_entry(scsi_qla_host_t *vha, struct req_que *req,
                memcpy(fstatus.reserved_3,
                    pkt->reserved_2, 20 * sizeof(uint8_t));
 
-               fw_sts_ptr = ((uint8_t *)bsg_job->req->sense) +
+               fw_sts_ptr = ((uint8_t *)scsi_req(bsg_job->req)->sense) +
                    sizeof(struct fc_bsg_reply);
 
                memcpy(fw_sts_ptr, (uint8_t *)&fstatus,
index 40660461a4b5c3e56e61b124385ee044547a4741..d01c90c7dd04f047e562a6e22178d936fa91b4b3 100644 (file)
@@ -262,6 +262,7 @@ struct scsi_host_template qla2xxx_driver_template = {
        .name                   = QLA2XXX_DRIVER_NAME,
        .queuecommand           = qla2xxx_queuecommand,
 
+       .eh_timed_out           = fc_eh_timed_out,
        .eh_abort_handler       = qla2xxx_eh_abort,
        .eh_device_reset_handler = qla2xxx_eh_device_reset,
        .eh_target_reset_handler = qla2xxx_eh_target_reset,
index aeebefb1e9f830c493e5a887d247b9ac602902cc..fc233717355fe22687678c805069478eddd99113 100644 (file)
@@ -408,9 +408,6 @@ struct qla4_8xxx_legacy_intr_set {
 };
 
 /* MSI-X Support */
-
-#define QLA_MSIX_DEFAULT       0
-#define QLA_MSIX_RSP_Q         1
 #define QLA_MSIX_ENTRIES       2
 
 /*
index 9fbb33fc90c7299376a9fa671a2f906714d5a613..ac52150d1569a830adfddeb8bbfa5e153feda9e9 100644 (file)
@@ -9539,15 +9539,15 @@ exit_host_reset:
  * driver calls the following device driver's callbacks
  *
  * - Fatal Errors - link_reset
- * - Non-Fatal Errors - driver's pci_error_detected() which
+ * - Non-Fatal Errors - driver's error_detected() which
  * returns CAN_RECOVER, NEED_RESET or DISCONNECT.
  *
  * PCI AER driver calls
- * CAN_RECOVER - driver's pci_mmio_enabled(), mmio_enabled
+ * CAN_RECOVER - driver's mmio_enabled(), mmio_enabled()
  *               returns RECOVERED or NEED_RESET if fw_hung
  * NEED_RESET - driver's slot_reset()
  * DISCONNECT - device is dead & cannot recover
- * RECOVERED - driver's pci_resume()
+ * RECOVERED - driver's resume()
  */
 static pci_ers_result_t
 qla4xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
index 75455d4dab68b5cd49378635d2848da8340b7ff3..7bfbcfa7af40b7df8bff2a0f38728621ee9f13e0 100644 (file)
@@ -98,176 +98,6 @@ EXPORT_SYMBOL(scsi_sd_probe_domain);
 ASYNC_DOMAIN_EXCLUSIVE(scsi_sd_pm_domain);
 EXPORT_SYMBOL(scsi_sd_pm_domain);
 
-struct scsi_host_cmd_pool {
-       struct kmem_cache       *cmd_slab;
-       struct kmem_cache       *sense_slab;
-       unsigned int            users;
-       char                    *cmd_name;
-       char                    *sense_name;
-       unsigned int            slab_flags;
-       gfp_t                   gfp_mask;
-};
-
-static struct scsi_host_cmd_pool scsi_cmd_pool = {
-       .cmd_name       = "scsi_cmd_cache",
-       .sense_name     = "scsi_sense_cache",
-       .slab_flags     = SLAB_HWCACHE_ALIGN,
-};
-
-static struct scsi_host_cmd_pool scsi_cmd_dma_pool = {
-       .cmd_name       = "scsi_cmd_cache(DMA)",
-       .sense_name     = "scsi_sense_cache(DMA)",
-       .slab_flags     = SLAB_HWCACHE_ALIGN|SLAB_CACHE_DMA,
-       .gfp_mask       = __GFP_DMA,
-};
-
-static DEFINE_MUTEX(host_cmd_pool_mutex);
-
-/**
- * scsi_host_free_command - internal function to release a command
- * @shost:     host to free the command for
- * @cmd:       command to release
- *
- * the command must previously have been allocated by
- * scsi_host_alloc_command.
- */
-static void
-scsi_host_free_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
-{
-       struct scsi_host_cmd_pool *pool = shost->cmd_pool;
-
-       if (cmd->prot_sdb)
-               kmem_cache_free(scsi_sdb_cache, cmd->prot_sdb);
-       kmem_cache_free(pool->sense_slab, cmd->sense_buffer);
-       kmem_cache_free(pool->cmd_slab, cmd);
-}
-
-/**
- * scsi_host_alloc_command - internal function to allocate command
- * @shost:     SCSI host whose pool to allocate from
- * @gfp_mask:  mask for the allocation
- *
- * Returns a fully allocated command with sense buffer and protection
- * data buffer (where applicable) or NULL on failure
- */
-static struct scsi_cmnd *
-scsi_host_alloc_command(struct Scsi_Host *shost, gfp_t gfp_mask)
-{
-       struct scsi_host_cmd_pool *pool = shost->cmd_pool;
-       struct scsi_cmnd *cmd;
-
-       cmd = kmem_cache_zalloc(pool->cmd_slab, gfp_mask | pool->gfp_mask);
-       if (!cmd)
-               goto fail;
-
-       cmd->sense_buffer = kmem_cache_alloc(pool->sense_slab,
-                                            gfp_mask | pool->gfp_mask);
-       if (!cmd->sense_buffer)
-               goto fail_free_cmd;
-
-       if (scsi_host_get_prot(shost) >= SHOST_DIX_TYPE0_PROTECTION) {
-               cmd->prot_sdb = kmem_cache_zalloc(scsi_sdb_cache, gfp_mask);
-               if (!cmd->prot_sdb)
-                       goto fail_free_sense;
-       }
-
-       return cmd;
-
-fail_free_sense:
-       kmem_cache_free(pool->sense_slab, cmd->sense_buffer);
-fail_free_cmd:
-       kmem_cache_free(pool->cmd_slab, cmd);
-fail:
-       return NULL;
-}
-
-/**
- * __scsi_get_command - Allocate a struct scsi_cmnd
- * @shost: host to transmit command
- * @gfp_mask: allocation mask
- *
- * Description: allocate a struct scsi_cmd from host's slab, recycling from the
- *              host's free_list if necessary.
- */
-static struct scsi_cmnd *
-__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask)
-{
-       struct scsi_cmnd *cmd = scsi_host_alloc_command(shost, gfp_mask);
-
-       if (unlikely(!cmd)) {
-               unsigned long flags;
-
-               spin_lock_irqsave(&shost->free_list_lock, flags);
-               if (likely(!list_empty(&shost->free_list))) {
-                       cmd = list_entry(shost->free_list.next,
-                                        struct scsi_cmnd, list);
-                       list_del_init(&cmd->list);
-               }
-               spin_unlock_irqrestore(&shost->free_list_lock, flags);
-
-               if (cmd) {
-                       void *buf, *prot;
-
-                       buf = cmd->sense_buffer;
-                       prot = cmd->prot_sdb;
-
-                       memset(cmd, 0, sizeof(*cmd));
-
-                       cmd->sense_buffer = buf;
-                       cmd->prot_sdb = prot;
-               }
-       }
-
-       return cmd;
-}
-
-/**
- * scsi_get_command - Allocate and setup a scsi command block
- * @dev: parent scsi device
- * @gfp_mask: allocator flags
- *
- * Returns:    The allocated scsi command structure.
- */
-struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask)
-{
-       struct scsi_cmnd *cmd = __scsi_get_command(dev->host, gfp_mask);
-       unsigned long flags;
-
-       if (unlikely(cmd == NULL))
-               return NULL;
-
-       cmd->device = dev;
-       INIT_LIST_HEAD(&cmd->list);
-       INIT_DELAYED_WORK(&cmd->abort_work, scmd_eh_abort_handler);
-       spin_lock_irqsave(&dev->list_lock, flags);
-       list_add_tail(&cmd->list, &dev->cmd_list);
-       spin_unlock_irqrestore(&dev->list_lock, flags);
-       cmd->jiffies_at_alloc = jiffies;
-       return cmd;
-}
-
-/**
- * __scsi_put_command - Free a struct scsi_cmnd
- * @shost: dev->host
- * @cmd: Command to free
- */
-static void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
-{
-       unsigned long flags;
-
-       if (unlikely(list_empty(&shost->free_list))) {
-               spin_lock_irqsave(&shost->free_list_lock, flags);
-               if (list_empty(&shost->free_list)) {
-                       list_add(&cmd->list, &shost->free_list);
-                       cmd = NULL;
-               }
-               spin_unlock_irqrestore(&shost->free_list_lock, flags);
-       }
-
-       if (likely(cmd != NULL))
-               scsi_host_free_command(shost, cmd);
-}
-
 /**
  * scsi_put_command - Free a scsi command block
  * @cmd: command block to free
@@ -287,188 +117,6 @@ void scsi_put_command(struct scsi_cmnd *cmd)
        spin_unlock_irqrestore(&cmd->device->list_lock, flags);
 
        BUG_ON(delayed_work_pending(&cmd->abort_work));
-
-       __scsi_put_command(cmd->device->host, cmd);
-}
-
-static struct scsi_host_cmd_pool *
-scsi_find_host_cmd_pool(struct Scsi_Host *shost)
-{
-       if (shost->hostt->cmd_size)
-               return shost->hostt->cmd_pool;
-       if (shost->unchecked_isa_dma)
-               return &scsi_cmd_dma_pool;
-       return &scsi_cmd_pool;
-}
-
-static void
-scsi_free_host_cmd_pool(struct scsi_host_cmd_pool *pool)
-{
-       kfree(pool->sense_name);
-       kfree(pool->cmd_name);
-       kfree(pool);
-}
-
-static struct scsi_host_cmd_pool *
-scsi_alloc_host_cmd_pool(struct Scsi_Host *shost)
-{
-       struct scsi_host_template *hostt = shost->hostt;
-       struct scsi_host_cmd_pool *pool;
-
-       pool = kzalloc(sizeof(*pool), GFP_KERNEL);
-       if (!pool)
-               return NULL;
-
-       pool->cmd_name = kasprintf(GFP_KERNEL, "%s_cmd", hostt->proc_name);
-       pool->sense_name = kasprintf(GFP_KERNEL, "%s_sense", hostt->proc_name);
-       if (!pool->cmd_name || !pool->sense_name) {
-               scsi_free_host_cmd_pool(pool);
-               return NULL;
-       }
-
-       pool->slab_flags = SLAB_HWCACHE_ALIGN;
-       if (shost->unchecked_isa_dma) {
-               pool->slab_flags |= SLAB_CACHE_DMA;
-               pool->gfp_mask = __GFP_DMA;
-       }
-
-       if (hostt->cmd_size)
-               hostt->cmd_pool = pool;
-
-       return pool;
-}
-
-static struct scsi_host_cmd_pool *
-scsi_get_host_cmd_pool(struct Scsi_Host *shost)
-{
-       struct scsi_host_template *hostt = shost->hostt;
-       struct scsi_host_cmd_pool *retval = NULL, *pool;
-       size_t cmd_size = sizeof(struct scsi_cmnd) + hostt->cmd_size;
-
-       /*
-        * Select a command slab for this host and create it if not
-        * yet existent.
-        */
-       mutex_lock(&host_cmd_pool_mutex);
-       pool = scsi_find_host_cmd_pool(shost);
-       if (!pool) {
-               pool = scsi_alloc_host_cmd_pool(shost);
-               if (!pool)
-                       goto out;
-       }
-
-       if (!pool->users) {
-               pool->cmd_slab = kmem_cache_create(pool->cmd_name, cmd_size, 0,
-                                                  pool->slab_flags, NULL);
-               if (!pool->cmd_slab)
-                       goto out_free_pool;
-
-               pool->sense_slab = kmem_cache_create(pool->sense_name,
-                                                    SCSI_SENSE_BUFFERSIZE, 0,
-                                                    pool->slab_flags, NULL);
-               if (!pool->sense_slab)
-                       goto out_free_slab;
-       }
-
-       pool->users++;
-       retval = pool;
-out:
-       mutex_unlock(&host_cmd_pool_mutex);
-       return retval;
-
-out_free_slab:
-       kmem_cache_destroy(pool->cmd_slab);
-out_free_pool:
-       if (hostt->cmd_size) {
-               scsi_free_host_cmd_pool(pool);
-               hostt->cmd_pool = NULL;
-       }
-       goto out;
-}
-
-static void scsi_put_host_cmd_pool(struct Scsi_Host *shost)
-{
-       struct scsi_host_template *hostt = shost->hostt;
-       struct scsi_host_cmd_pool *pool;
-
-       mutex_lock(&host_cmd_pool_mutex);
-       pool = scsi_find_host_cmd_pool(shost);
-
-       /*
-        * This may happen if a driver has a mismatched get and put
-        * of the command pool; the driver should be implicated in
-        * the stack trace
-        */
-       BUG_ON(pool->users == 0);
-
-       if (!--pool->users) {
-               kmem_cache_destroy(pool->cmd_slab);
-               kmem_cache_destroy(pool->sense_slab);
-               if (hostt->cmd_size) {
-                       scsi_free_host_cmd_pool(pool);
-                       hostt->cmd_pool = NULL;
-               }
-       }
-       mutex_unlock(&host_cmd_pool_mutex);
-}
-
-/**
- * scsi_setup_command_freelist - Setup the command freelist for a scsi host.
- * @shost: host to allocate the freelist for.
- *
- * Description: The command freelist protects against system-wide out of memory
- * deadlock by preallocating one SCSI command structure for each host, so the
- * system can always write to a swap file on a device associated with that host.
- *
- * Returns:    Nothing.
- */
-int scsi_setup_command_freelist(struct Scsi_Host *shost)
-{
-       const gfp_t gfp_mask = shost->unchecked_isa_dma ? GFP_DMA : GFP_KERNEL;
-       struct scsi_cmnd *cmd;
-
-       spin_lock_init(&shost->free_list_lock);
-       INIT_LIST_HEAD(&shost->free_list);
-
-       shost->cmd_pool = scsi_get_host_cmd_pool(shost);
-       if (!shost->cmd_pool)
-               return -ENOMEM;
-
-       /*
-        * Get one backup command for this host.
-        */
-       cmd = scsi_host_alloc_command(shost, gfp_mask);
-       if (!cmd) {
-               scsi_put_host_cmd_pool(shost);
-               shost->cmd_pool = NULL;
-               return -ENOMEM;
-       }
-       list_add(&cmd->list, &shost->free_list);
-       return 0;
-}
-
-/**
- * scsi_destroy_command_freelist - Release the command freelist for a scsi host.
- * @shost: host whose freelist is going to be destroyed
- */
-void scsi_destroy_command_freelist(struct Scsi_Host *shost)
-{
-       /*
-        * If cmd_pool is NULL the free list was not initialized, so
-        * do not attempt to release resources.
-        */
-       if (!shost->cmd_pool)
-               return;
-
-       while (!list_empty(&shost->free_list)) {
-               struct scsi_cmnd *cmd;
-
-               cmd = list_entry(shost->free_list.next, struct scsi_cmnd, list);
-               list_del_init(&cmd->list);
-               scsi_host_free_command(shost, cmd);
-       }
-       shost->cmd_pool = NULL;
-       scsi_put_host_cmd_pool(shost);
 }
 
 #ifdef CONFIG_SCSI_LOGGING
@@ -590,7 +238,7 @@ void scsi_finish_command(struct scsi_cmnd *cmd)
                                "(result %x)\n", cmd->result));
 
        good_bytes = scsi_bufflen(cmd);
-        if (cmd->request->cmd_type != REQ_TYPE_BLOCK_PC) {
+        if (!blk_rq_is_passthrough(cmd->request)) {
                int old_good_bytes = good_bytes;
                drv = scsi_cmd_to_driver(cmd);
                if (drv->done)
index 03051e12a0721ec0632ebca9f66538c295844479..17249c3650fef2c414a009013efa4582d7ab9b8d 100644 (file)
@@ -125,6 +125,7 @@ static const char *sdebug_version_date = "20160430";
 #define DEF_OPTS   0
 #define DEF_OPT_BLKS 1024
 #define DEF_PHYSBLK_EXP 0
+#define DEF_OPT_XFERLEN_EXP 0
 #define DEF_PTYPE   TYPE_DISK
 #define DEF_REMOVABLE false
 #define DEF_SCSI_LEVEL   7    /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
@@ -590,6 +591,7 @@ static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
 static int sdebug_opt_blks = DEF_OPT_BLKS;
 static int sdebug_opts = DEF_OPTS;
 static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
+static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
 static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
 static int sdebug_scsi_level = DEF_SCSI_LEVEL;
 static int sdebug_sector_size = DEF_SECTOR_SIZE;
@@ -1205,7 +1207,11 @@ static int inquiry_vpd_b0(unsigned char *arr)
        memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
 
        /* Optimal transfer length granularity */
-       gran = 1 << sdebug_physblk_exp;
+       if (sdebug_opt_xferlen_exp != 0 &&
+           sdebug_physblk_exp < sdebug_opt_xferlen_exp)
+               gran = 1 << sdebug_opt_xferlen_exp;
+       else
+               gran = 1 << sdebug_physblk_exp;
        put_unaligned_be16(gran, arr + 2);
 
        /* Maximum Transfer Length */
@@ -4161,6 +4167,7 @@ module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
 module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
 module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
 module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
+module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
 module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
 module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
 module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
@@ -4212,6 +4219,7 @@ MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
 MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
 MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
 MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
+MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
 MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
 MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
 MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
index 996e134d79faaf37674731e03a8de1360194d011..f2cafae150bcdb85292d86945cfb9d6e9fd7c340 100644 (file)
@@ -279,9 +279,7 @@ enum blk_eh_timer_return scsi_times_out(struct request *req)
        if (host->eh_deadline != -1 && !host->last_reset)
                host->last_reset = jiffies;
 
-       if (host->transportt->eh_timed_out)
-               rtn = host->transportt->eh_timed_out(scmd);
-       else if (host->hostt->eh_timed_out)
+       if (host->hostt->eh_timed_out)
                rtn = host->hostt->eh_timed_out(scmd);
 
        if (rtn == BLK_EH_NOT_HANDLED) {
@@ -1106,7 +1104,7 @@ static int scsi_request_sense(struct scsi_cmnd *scmd)
 
 static int scsi_eh_action(struct scsi_cmnd *scmd, int rtn)
 {
-       if (scmd->request->cmd_type != REQ_TYPE_BLOCK_PC) {
+       if (!blk_rq_is_passthrough(scmd->request)) {
                struct scsi_driver *sdrv = scsi_cmd_to_driver(scmd);
                if (sdrv->eh_action)
                        rtn = sdrv->eh_action(scmd, rtn);
@@ -1746,7 +1744,7 @@ check_type:
         * the check condition was retryable.
         */
        if (scmd->request->cmd_flags & REQ_FAILFAST_DEV ||
-           scmd->request->cmd_type == REQ_TYPE_BLOCK_PC)
+           blk_rq_is_passthrough(scmd->request))
                return 1;
        else
                return 0;
@@ -1968,25 +1966,25 @@ static void eh_lock_door_done(struct request *req, int uptodate)
 static void scsi_eh_lock_door(struct scsi_device *sdev)
 {
        struct request *req;
+       struct scsi_request *rq;
 
        /*
         * blk_get_request with GFP_KERNEL (__GFP_RECLAIM) sleeps until a
         * request becomes available
         */
-       req = blk_get_request(sdev->request_queue, READ, GFP_KERNEL);
+       req = blk_get_request(sdev->request_queue, REQ_OP_SCSI_IN, GFP_KERNEL);
        if (IS_ERR(req))
                return;
+       rq = scsi_req(req);
+       scsi_req_init(req);
 
-       blk_rq_set_block_pc(req);
-
-       req->cmd[0] = ALLOW_MEDIUM_REMOVAL;
-       req->cmd[1] = 0;
-       req->cmd[2] = 0;
-       req->cmd[3] = 0;
-       req->cmd[4] = SCSI_REMOVAL_PREVENT;
-       req->cmd[5] = 0;
-
-       req->cmd_len = COMMAND_SIZE(req->cmd[0]);
+       rq->cmd[0] = ALLOW_MEDIUM_REMOVAL;
+       rq->cmd[1] = 0;
+       rq->cmd[2] = 0;
+       rq->cmd[3] = 0;
+       rq->cmd[4] = SCSI_REMOVAL_PREVENT;
+       rq->cmd[5] = 0;
+       rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);
 
        req->rq_flags |= RQF_QUIET;
        req->timeout = 10 * HZ;
@@ -2331,7 +2329,7 @@ scsi_ioctl_reset(struct scsi_device *dev, int __user *arg)
 {
        struct scsi_cmnd *scmd;
        struct Scsi_Host *shost = dev->host;
-       struct request req;
+       struct request *rq;
        unsigned long flags;
        int error = 0, rtn, val;
 
@@ -2346,14 +2344,16 @@ scsi_ioctl_reset(struct scsi_device *dev, int __user *arg)
                return -EIO;
 
        error = -EIO;
-       scmd = scsi_get_command(dev, GFP_KERNEL);
-       if (!scmd)
+       rq = kzalloc(sizeof(struct request) + sizeof(struct scsi_cmnd) +
+                       shost->hostt->cmd_size, GFP_KERNEL);
+       if (!rq)
                goto out_put_autopm_host;
+       blk_rq_init(NULL, rq);
 
-       blk_rq_init(NULL, &req);
-       scmd->request = &req;
-
-       scmd->cmnd = req.cmd;
+       scmd = (struct scsi_cmnd *)(rq + 1);
+       scsi_init_command(dev, scmd);
+       scmd->request = rq;
+       scmd->cmnd = scsi_req(rq)->cmd;
 
        scmd->scsi_done         = scsi_reset_provider_done_command;
        memset(&scmd->sdb, 0, sizeof(scmd->sdb));
@@ -2413,6 +2413,7 @@ scsi_ioctl_reset(struct scsi_device *dev, int __user *arg)
        scsi_run_host_queues(shost);
 
        scsi_put_command(scmd);
+       kfree(rq);
 
 out_put_autopm_host:
        scsi_autopm_put_host(shost);
index 78db07fd8055df135dcc5488a06c443fc4b51ac8..912fbc3b4543dd5e87b04341862293d46fd57f30 100644 (file)
 #include "scsi_priv.h"
 #include "scsi_logging.h"
 
+static struct kmem_cache *scsi_sdb_cache;
+static struct kmem_cache *scsi_sense_cache;
+static struct kmem_cache *scsi_sense_isadma_cache;
+static DEFINE_MUTEX(scsi_sense_cache_mutex);
 
-struct kmem_cache *scsi_sdb_cache;
+static inline struct kmem_cache *
+scsi_select_sense_cache(struct Scsi_Host *shost)
+{
+       return shost->unchecked_isa_dma ?
+               scsi_sense_isadma_cache : scsi_sense_cache;
+}
+
+static void scsi_free_sense_buffer(struct Scsi_Host *shost,
+               unsigned char *sense_buffer)
+{
+       kmem_cache_free(scsi_select_sense_cache(shost), sense_buffer);
+}
+
+static unsigned char *scsi_alloc_sense_buffer(struct Scsi_Host *shost,
+       gfp_t gfp_mask, int numa_node)
+{
+       return kmem_cache_alloc_node(scsi_select_sense_cache(shost), gfp_mask,
+                       numa_node);
+}
+
+int scsi_init_sense_cache(struct Scsi_Host *shost)
+{
+       struct kmem_cache *cache;
+       int ret = 0;
+
+       cache = scsi_select_sense_cache(shost);
+       if (cache)
+               return 0;
+
+       mutex_lock(&scsi_sense_cache_mutex);
+       if (shost->unchecked_isa_dma) {
+               scsi_sense_isadma_cache =
+                       kmem_cache_create("scsi_sense_cache(DMA)",
+                       SCSI_SENSE_BUFFERSIZE, 0,
+                       SLAB_HWCACHE_ALIGN | SLAB_CACHE_DMA, NULL);
+               if (!scsi_sense_isadma_cache)
+                       ret = -ENOMEM;
+       } else {
+               scsi_sense_cache =
+                       kmem_cache_create("scsi_sense_cache",
+                       SCSI_SENSE_BUFFERSIZE, 0, SLAB_HWCACHE_ALIGN, NULL);
+               if (!scsi_sense_cache)
+                       ret = -ENOMEM;
+       }
+
+       mutex_unlock(&scsi_sense_cache_mutex);
+       return ret;
+}
 
 /*
  * When to reinvoke queueing after a resource shortage. It's 3 msecs to
@@ -168,22 +219,23 @@ static int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
                 req_flags_t rq_flags, int *resid)
 {
        struct request *req;
-       int write = (data_direction == DMA_TO_DEVICE);
+       struct scsi_request *rq;
        int ret = DRIVER_ERROR << 24;
 
-       req = blk_get_request(sdev->request_queue, write, __GFP_RECLAIM);
+       req = blk_get_request(sdev->request_queue,
+                       data_direction == DMA_TO_DEVICE ?
+                       REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, __GFP_RECLAIM);
        if (IS_ERR(req))
                return ret;
-       blk_rq_set_block_pc(req);
+       rq = scsi_req(req);
+       scsi_req_init(req);
 
        if (bufflen &&  blk_rq_map_kern(sdev->request_queue, req,
                                        buffer, bufflen, __GFP_RECLAIM))
                goto out;
 
-       req->cmd_len = COMMAND_SIZE(cmd[0]);
-       memcpy(req->cmd, cmd, req->cmd_len);
-       req->sense = sense;
-       req->sense_len = 0;
+       rq->cmd_len = COMMAND_SIZE(cmd[0]);
+       memcpy(rq->cmd, cmd, rq->cmd_len);
        req->retries = retries;
        req->timeout = timeout;
        req->cmd_flags |= flags;
@@ -200,11 +252,13 @@ static int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
         * is invalid.  Prevent the garbage from being misinterpreted
         * and prevent security leaks by zeroing out the excess data.
         */
-       if (unlikely(req->resid_len > 0 && req->resid_len <= bufflen))
-               memset(buffer + (bufflen - req->resid_len), 0, req->resid_len);
+       if (unlikely(rq->resid_len > 0 && rq->resid_len <= bufflen))
+               memset(buffer + (bufflen - rq->resid_len), 0, rq->resid_len);
 
        if (resid)
-               *resid = req->resid_len;
+               *resid = rq->resid_len;
+       if (sense && rq->sense_len)
+               memcpy(sense, rq->sense, SCSI_SENSE_BUFFERSIZE);
        ret = req->errors;
  out:
        blk_put_request(req);
@@ -529,7 +583,7 @@ void scsi_run_host_queues(struct Scsi_Host *shost)
 
 static void scsi_uninit_cmd(struct scsi_cmnd *cmd)
 {
-       if (cmd->request->cmd_type == REQ_TYPE_FS) {
+       if (!blk_rq_is_passthrough(cmd->request)) {
                struct scsi_driver *drv = scsi_cmd_to_driver(cmd);
 
                if (drv->uninit_command)
@@ -645,14 +699,13 @@ static bool scsi_end_request(struct request *req, int error,
 
                if (bidi_bytes)
                        scsi_release_bidi_buffers(cmd);
+               scsi_release_buffers(cmd);
+               scsi_put_command(cmd);
 
                spin_lock_irqsave(q->queue_lock, flags);
                blk_finish_request(req, error);
                spin_unlock_irqrestore(q->queue_lock, flags);
 
-               scsi_release_buffers(cmd);
-
-               scsi_put_command(cmd);
                scsi_run_queue(q);
        }
 
@@ -754,18 +807,15 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
                        sense_deferred = scsi_sense_is_deferred(&sshdr);
        }
 
-       if (req->cmd_type == REQ_TYPE_BLOCK_PC) { /* SG_IO ioctl from block level */
+       if (blk_rq_is_passthrough(req)) {
                if (result) {
-                       if (sense_valid && req->sense) {
+                       if (sense_valid) {
                                /*
                                 * SG_IO wants current and deferred errors
                                 */
-                               int len = 8 + cmd->sense_buffer[7];
-
-                               if (len > SCSI_SENSE_BUFFERSIZE)
-                                       len = SCSI_SENSE_BUFFERSIZE;
-                               memcpy(req->sense, cmd->sense_buffer,  len);
-                               req->sense_len = len;
+                               scsi_req(req)->sense_len =
+                                       min(8 + cmd->sense_buffer[7],
+                                           SCSI_SENSE_BUFFERSIZE);
                        }
                        if (!sense_deferred)
                                error = __scsi_error_from_host_byte(cmd, result);
@@ -775,14 +825,14 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
                 */
                req->errors = cmd->result;
 
-               req->resid_len = scsi_get_resid(cmd);
+               scsi_req(req)->resid_len = scsi_get_resid(cmd);
 
                if (scsi_bidi_cmnd(cmd)) {
                        /*
                         * Bidi commands Must be complete as a whole,
                         * both sides at once.
                         */
-                       req->next_rq->resid_len = scsi_in(cmd)->resid;
+                       scsi_req(req->next_rq)->resid_len = scsi_in(cmd)->resid;
                        if (scsi_end_request(req, 0, blk_rq_bytes(req),
                                        blk_rq_bytes(req->next_rq)))
                                BUG();
@@ -790,15 +840,14 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
                }
        } else if (blk_rq_bytes(req) == 0 && result && !sense_deferred) {
                /*
-                * Certain non BLOCK_PC requests are commands that don't
-                * actually transfer anything (FLUSH), so cannot use
+                * Flush commands do not transfers any data, and thus cannot use
                 * good_bytes != blk_rq_bytes(req) as the signal for an error.
                 * This sets the error explicitly for the problem case.
                 */
                error = __scsi_error_from_host_byte(cmd, result);
        }
 
-       /* no bidi support for !REQ_TYPE_BLOCK_PC yet */
+       /* no bidi support for !blk_rq_is_passthrough yet */
        BUG_ON(blk_bidi_rq(req));
 
        /*
@@ -810,8 +859,8 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
                blk_rq_sectors(req), good_bytes));
 
        /*
-        * Recovered errors need reporting, but they're always treated
-        * as success, so fiddle the result code here.  For BLOCK_PC
+        * Recovered errors need reporting, but they're always treated as
+        * success, so fiddle the result code here.  For passthrough requests
         * we already took a copy of the original into rq->errors which
         * is what gets returned to the user
         */
@@ -825,7 +874,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
                else if (!(req->rq_flags & RQF_QUIET))
                        scsi_print_sense(cmd);
                result = 0;
-               /* BLOCK_PC may have set error */
+               /* for passthrough error may be set */
                error = 0;
        }
 
@@ -1110,42 +1159,33 @@ err_exit:
 }
 EXPORT_SYMBOL(scsi_init_io);
 
-static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev,
-               struct request *req)
+void scsi_init_command(struct scsi_device *dev, struct scsi_cmnd *cmd)
 {
-       struct scsi_cmnd *cmd;
-
-       if (!req->special) {
-               /* Bail if we can't get a reference to the device */
-               if (!get_device(&sdev->sdev_gendev))
-                       return NULL;
-
-               cmd = scsi_get_command(sdev, GFP_ATOMIC);
-               if (unlikely(!cmd)) {
-                       put_device(&sdev->sdev_gendev);
-                       return NULL;
-               }
-               req->special = cmd;
-       } else {
-               cmd = req->special;
-       }
+       void *buf = cmd->sense_buffer;
+       void *prot = cmd->prot_sdb;
+       unsigned long flags;
 
-       /* pull a tag out of the request if we have one */
-       cmd->tag = req->tag;
-       cmd->request = req;
+       /* zero out the cmd, except for the embedded scsi_request */
+       memset((char *)cmd + sizeof(cmd->req), 0,
+               sizeof(*cmd) - sizeof(cmd->req));
 
-       cmd->cmnd = req->cmd;
-       cmd->prot_op = SCSI_PROT_NORMAL;
+       cmd->device = dev;
+       cmd->sense_buffer = buf;
+       cmd->prot_sdb = prot;
+       INIT_DELAYED_WORK(&cmd->abort_work, scmd_eh_abort_handler);
+       cmd->jiffies_at_alloc = jiffies;
 
-       return cmd;
+       spin_lock_irqsave(&dev->list_lock, flags);
+       list_add_tail(&cmd->list, &dev->cmd_list);
+       spin_unlock_irqrestore(&dev->list_lock, flags);
 }
 
-static int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
+static int scsi_setup_scsi_cmnd(struct scsi_device *sdev, struct request *req)
 {
        struct scsi_cmnd *cmd = req->special;
 
        /*
-        * BLOCK_PC requests may transfer data, in which case they must
+        * Passthrough requests may transfer data, in which case they must
         * a bio attached to them.  Or they might contain a SCSI command
         * that does not transfer data, in which case they may optionally
         * submit a request without an attached bio.
@@ -1160,14 +1200,15 @@ static int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
                memset(&cmd->sdb, 0, sizeof(cmd->sdb));
        }
 
-       cmd->cmd_len = req->cmd_len;
+       cmd->cmd_len = scsi_req(req)->cmd_len;
+       cmd->cmnd = scsi_req(req)->cmd;
        cmd->transfersize = blk_rq_bytes(req);
        cmd->allowed = req->retries;
        return BLKPREP_OK;
 }
 
 /*
- * Setup a REQ_TYPE_FS command.  These are simple request from filesystems
+ * Setup a normal block command.  These are simple request from filesystems
  * that still need to be translated to SCSI CDBs from the ULD.
  */
 static int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req)
@@ -1180,6 +1221,7 @@ static int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req)
                        return ret;
        }
 
+       cmd->cmnd = scsi_req(req)->cmd = scsi_req(req)->__cmd;
        memset(cmd->cmnd, 0, BLK_MAX_CDB);
        return scsi_cmd_to_driver(cmd)->init_command(cmd);
 }
@@ -1195,14 +1237,10 @@ static int scsi_setup_cmnd(struct scsi_device *sdev, struct request *req)
        else
                cmd->sc_data_direction = DMA_FROM_DEVICE;
 
-       switch (req->cmd_type) {
-       case REQ_TYPE_FS:
+       if (blk_rq_is_scsi(req))
+               return scsi_setup_scsi_cmnd(sdev, req);
+       else
                return scsi_setup_fs_cmnd(sdev, req);
-       case REQ_TYPE_BLOCK_PC:
-               return scsi_setup_blk_pc_cmnd(sdev, req);
-       default:
-               return BLKPREP_KILL;
-       }
 }
 
 static int
@@ -1298,19 +1336,28 @@ scsi_prep_return(struct request_queue *q, struct request *req, int ret)
 static int scsi_prep_fn(struct request_queue *q, struct request *req)
 {
        struct scsi_device *sdev = q->queuedata;
-       struct scsi_cmnd *cmd;
+       struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(req);
        int ret;
 
        ret = scsi_prep_state_check(sdev, req);
        if (ret != BLKPREP_OK)
                goto out;
 
-       cmd = scsi_get_cmd_from_req(sdev, req);
-       if (unlikely(!cmd)) {
-               ret = BLKPREP_DEFER;
-               goto out;
+       if (!req->special) {
+               /* Bail if we can't get a reference to the device */
+               if (unlikely(!get_device(&sdev->sdev_gendev))) {
+                       ret = BLKPREP_DEFER;
+                       goto out;
+               }
+
+               scsi_init_command(sdev, cmd);
+               req->special = cmd;
        }
 
+       cmd->tag = req->tag;
+       cmd->request = req;
+       cmd->prot_op = SCSI_PROT_NORMAL;
+
        ret = scsi_setup_cmnd(sdev, req);
 out:
        return scsi_prep_return(q, req, ret);
@@ -1827,7 +1874,9 @@ static int scsi_mq_prep_fn(struct request *req)
        unsigned char *sense_buf = cmd->sense_buffer;
        struct scatterlist *sg;
 
-       memset(cmd, 0, sizeof(struct scsi_cmnd));
+       /* zero out the cmd, except for the embedded scsi_request */
+       memset((char *)cmd + sizeof(cmd->req), 0,
+               sizeof(*cmd) - sizeof(cmd->req));
 
        req->special = cmd;
 
@@ -1837,7 +1886,6 @@ static int scsi_mq_prep_fn(struct request *req)
 
        cmd->tag = req->tag;
 
-       cmd->cmnd = req->cmd;
        cmd->prot_op = SCSI_PROT_NORMAL;
 
        INIT_LIST_HEAD(&cmd->list);
@@ -1912,7 +1960,6 @@ static int scsi_queue_rq(struct blk_mq_hw_ctx *hctx,
        if (!scsi_host_queue_ready(q, shost, sdev))
                goto out_dec_target_busy;
 
-
        if (!(req->rq_flags & RQF_DONTPREP)) {
                ret = prep_to_mq(scsi_mq_prep_fn(req));
                if (ret != BLK_MQ_RQ_QUEUE_OK)
@@ -1982,21 +2029,24 @@ static int scsi_init_request(void *data, struct request *rq,
                unsigned int hctx_idx, unsigned int request_idx,
                unsigned int numa_node)
 {
+       struct Scsi_Host *shost = data;
        struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq);
 
-       cmd->sense_buffer = kzalloc_node(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL,
-                       numa_node);
+       cmd->sense_buffer =
+               scsi_alloc_sense_buffer(shost, GFP_KERNEL, numa_node);
        if (!cmd->sense_buffer)
                return -ENOMEM;
+       cmd->req.sense = cmd->sense_buffer;
        return 0;
 }
 
 static void scsi_exit_request(void *data, struct request *rq,
                unsigned int hctx_idx, unsigned int request_idx)
 {
+       struct Scsi_Host *shost = data;
        struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq);
 
-       kfree(cmd->sense_buffer);
+       scsi_free_sense_buffer(shost, cmd->sense_buffer);
 }
 
 static int scsi_map_queues(struct blk_mq_tag_set *set)
@@ -2029,7 +2079,7 @@ static u64 scsi_calculate_bounce_limit(struct Scsi_Host *shost)
        return bounce_limit;
 }
 
-static void __scsi_init_queue(struct Scsi_Host *shost, struct request_queue *q)
+void __scsi_init_queue(struct Scsi_Host *shost, struct request_queue *q)
 {
        struct device *dev = shost->dma_dev;
 
@@ -2064,28 +2114,64 @@ static void __scsi_init_queue(struct Scsi_Host *shost, struct request_queue *q)
         */
        blk_queue_dma_alignment(q, 0x03);
 }
+EXPORT_SYMBOL_GPL(__scsi_init_queue);
 
-struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
-                                        request_fn_proc *request_fn)
+static int scsi_init_rq(struct request_queue *q, struct request *rq, gfp_t gfp)
 {
-       struct request_queue *q;
+       struct Scsi_Host *shost = q->rq_alloc_data;
+       struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq);
 
-       q = blk_init_queue(request_fn, NULL);
-       if (!q)
-               return NULL;
-       __scsi_init_queue(shost, q);
-       return q;
+       memset(cmd, 0, sizeof(*cmd));
+
+       cmd->sense_buffer = scsi_alloc_sense_buffer(shost, gfp, NUMA_NO_NODE);
+       if (!cmd->sense_buffer)
+               goto fail;
+       cmd->req.sense = cmd->sense_buffer;
+
+       if (scsi_host_get_prot(shost) >= SHOST_DIX_TYPE0_PROTECTION) {
+               cmd->prot_sdb = kmem_cache_zalloc(scsi_sdb_cache, gfp);
+               if (!cmd->prot_sdb)
+                       goto fail_free_sense;
+       }
+
+       return 0;
+
+fail_free_sense:
+       scsi_free_sense_buffer(shost, cmd->sense_buffer);
+fail:
+       return -ENOMEM;
+}
+
+static void scsi_exit_rq(struct request_queue *q, struct request *rq)
+{
+       struct Scsi_Host *shost = q->rq_alloc_data;
+       struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq);
+
+       if (cmd->prot_sdb)
+               kmem_cache_free(scsi_sdb_cache, cmd->prot_sdb);
+       scsi_free_sense_buffer(shost, cmd->sense_buffer);
 }
-EXPORT_SYMBOL(__scsi_alloc_queue);
 
 struct request_queue *scsi_alloc_queue(struct scsi_device *sdev)
 {
+       struct Scsi_Host *shost = sdev->host;
        struct request_queue *q;
 
-       q = __scsi_alloc_queue(sdev->host, scsi_request_fn);
+       q = blk_alloc_queue_node(GFP_KERNEL, NUMA_NO_NODE);
        if (!q)
                return NULL;
+       q->cmd_size = sizeof(struct scsi_cmnd) + shost->hostt->cmd_size;
+       q->rq_alloc_data = shost;
+       q->request_fn = scsi_request_fn;
+       q->init_rq_fn = scsi_init_rq;
+       q->exit_rq_fn = scsi_exit_rq;
+
+       if (blk_init_allocated_queue(q) < 0) {
+               blk_cleanup_queue(q);
+               return NULL;
+       }
 
+       __scsi_init_queue(shost, q);
        blk_queue_prep_rq(q, scsi_prep_fn);
        blk_queue_unprep_rq(q, scsi_unprep_fn);
        blk_queue_softirq_done(q, scsi_softirq_done);
@@ -2209,6 +2295,8 @@ int __init scsi_init_queue(void)
 
 void scsi_exit_queue(void)
 {
+       kmem_cache_destroy(scsi_sense_cache);
+       kmem_cache_destroy(scsi_sense_isadma_cache);
        kmem_cache_destroy(scsi_sdb_cache);
 }
 
index 193636a59adf1844316ee431b8de36cb3ecc01d0..99bfc985e1903bcffd10762d52f1a72448aaed96 100644 (file)
@@ -30,8 +30,8 @@ extern void scsi_exit_hosts(void);
 
 /* scsi.c */
 extern bool scsi_use_blk_mq;
-extern int scsi_setup_command_freelist(struct Scsi_Host *shost);
-extern void scsi_destroy_command_freelist(struct Scsi_Host *shost);
+int scsi_init_sense_cache(struct Scsi_Host *shost);
+void scsi_init_command(struct scsi_device *dev, struct scsi_cmnd *cmd);
 #ifdef CONFIG_SCSI_LOGGING
 void scsi_log_send(struct scsi_cmnd *cmd);
 void scsi_log_completion(struct scsi_cmnd *cmd, int disposition);
@@ -96,7 +96,6 @@ extern void scsi_exit_queue(void);
 extern void scsi_evt_thread(struct work_struct *work);
 struct request_queue;
 struct request;
-extern struct kmem_cache *scsi_sdb_cache;
 
 /* scsi_proc.c */
 #ifdef CONFIG_SCSI_PROC_FS
index 03577bde6ac56b91e92f8e631d98907a19dfb273..2d753c93e07a28e1f49d2e1144a8bb1af00d406b 100644 (file)
@@ -2055,7 +2055,7 @@ static int fc_vport_match(struct attribute_container *cont,
 
 
 /**
- * fc_timed_out - FC Transport I/O timeout intercept handler
+ * fc_eh_timed_out - FC Transport I/O timeout intercept handler
  * @scmd:      The SCSI command which timed out
  *
  * This routine protects against error handlers getting invoked while a
@@ -2076,8 +2076,8 @@ static int fc_vport_match(struct attribute_container *cont,
  * Notes:
  *     This routine assumes no locks are held on entry.
  */
-static enum blk_eh_timer_return
-fc_timed_out(struct scsi_cmnd *scmd)
+enum blk_eh_timer_return
+fc_eh_timed_out(struct scsi_cmnd *scmd)
 {
        struct fc_rport *rport = starget_to_rport(scsi_target(scmd->device));
 
@@ -2086,6 +2086,7 @@ fc_timed_out(struct scsi_cmnd *scmd)
 
        return BLK_EH_NOT_HANDLED;
 }
+EXPORT_SYMBOL(fc_eh_timed_out);
 
 /*
  * Called by fc_user_scan to locate an rport on the shost that
@@ -2159,19 +2160,6 @@ fc_user_scan(struct Scsi_Host *shost, uint channel, uint id, u64 lun)
        return 0;
 }
 
-static int fc_tsk_mgmt_response(struct Scsi_Host *shost, u64 nexus, u64 tm_id,
-                               int result)
-{
-       struct fc_internal *i = to_fc_internal(shost->transportt);
-       return i->f->tsk_mgmt_response(shost, nexus, tm_id, result);
-}
-
-static int fc_it_nexus_response(struct Scsi_Host *shost, u64 nexus, int result)
-{
-       struct fc_internal *i = to_fc_internal(shost->transportt);
-       return i->f->it_nexus_response(shost, nexus, result);
-}
-
 struct scsi_transport_template *
 fc_attach_transport(struct fc_function_template *ft)
 {
@@ -2211,14 +2199,8 @@ fc_attach_transport(struct fc_function_template *ft)
        /* Transport uses the shost workq for scsi scanning */
        i->t.create_work_queue = 1;
 
-       i->t.eh_timed_out = fc_timed_out;
-
        i->t.user_scan = fc_user_scan;
 
-       /* target-mode drivers' functions */
-       i->t.tsk_mgmt_response = fc_tsk_mgmt_response;
-       i->t.it_nexus_response = fc_it_nexus_response;
-
        /*
         * Setup SCSI Target Attributes.
         */
@@ -3765,7 +3747,6 @@ fc_bsg_hostadd(struct Scsi_Host *shost, struct fc_host_attrs *fc_host)
        struct device *dev = &shost->shost_gendev;
        struct fc_internal *i = to_fc_internal(shost->transportt);
        struct request_queue *q;
-       int err;
        char bsg_name[20];
 
        fc_host->rqst_q = NULL;
@@ -3776,23 +3757,14 @@ fc_bsg_hostadd(struct Scsi_Host *shost, struct fc_host_attrs *fc_host)
        snprintf(bsg_name, sizeof(bsg_name),
                 "fc_host%d", shost->host_no);
 
-       q = __scsi_alloc_queue(shost, bsg_request_fn);
-       if (!q) {
-               dev_err(dev,
-                       "fc_host%d: bsg interface failed to initialize - no request queue\n",
-                       shost->host_no);
-               return -ENOMEM;
-       }
-
-       err = bsg_setup_queue(dev, q, bsg_name, fc_bsg_dispatch,
-                                i->f->dd_bsg_size);
-       if (err) {
+       q = bsg_setup_queue(dev, bsg_name, fc_bsg_dispatch, i->f->dd_bsg_size);
+       if (IS_ERR(q)) {
                dev_err(dev,
                        "fc_host%d: bsg interface failed to initialize - setup queue\n",
                        shost->host_no);
-               blk_cleanup_queue(q);
-               return err;
+               return PTR_ERR(q);
        }
+       __scsi_init_queue(shost, q);
        blk_queue_rq_timed_out(q, fc_bsg_job_timeout);
        blk_queue_rq_timeout(q, FC_DEFAULT_BSG_TIMEOUT);
        fc_host->rqst_q = q;
@@ -3824,26 +3796,18 @@ fc_bsg_rportadd(struct Scsi_Host *shost, struct fc_rport *rport)
        struct device *dev = &rport->dev;
        struct fc_internal *i = to_fc_internal(shost->transportt);
        struct request_queue *q;
-       int err;
 
        rport->rqst_q = NULL;
 
        if (!i->f->bsg_request)
                return -ENOTSUPP;
 
-       q = __scsi_alloc_queue(shost, bsg_request_fn);
-       if (!q) {
-               dev_err(dev, "bsg interface failed to initialize - no request queue\n");
-               return -ENOMEM;
-       }
-
-       err = bsg_setup_queue(dev, q, NULL, fc_bsg_dispatch, i->f->dd_bsg_size);
-       if (err) {
+       q = bsg_setup_queue(dev, NULL, fc_bsg_dispatch, i->f->dd_bsg_size);
+       if (IS_ERR(q)) {
                dev_err(dev, "failed to setup bsg queue\n");
-               blk_cleanup_queue(q);
-               return err;
+               return PTR_ERR(q);
        }
-
+       __scsi_init_queue(shost, q);
        blk_queue_prep_rq(q, fc_bsg_rport_prep);
        blk_queue_rq_timed_out(q, fc_bsg_job_timeout);
        blk_queue_rq_timeout(q, BLK_DEFAULT_SG_TIMEOUT);
index 42bca619f8545746f60802ad0b33e15529e57f1c..568c9f26a561ebe6b580127598b926ec6d98bb2e 100644 (file)
@@ -1537,24 +1537,18 @@ iscsi_bsg_host_add(struct Scsi_Host *shost, struct iscsi_cls_host *ihost)
        struct iscsi_internal *i = to_iscsi_internal(shost->transportt);
        struct request_queue *q;
        char bsg_name[20];
-       int ret;
 
        if (!i->iscsi_transport->bsg_request)
                return -ENOTSUPP;
 
        snprintf(bsg_name, sizeof(bsg_name), "iscsi_host%d", shost->host_no);
-
-       q = __scsi_alloc_queue(shost, bsg_request_fn);
-       if (!q)
-               return -ENOMEM;
-
-       ret = bsg_setup_queue(dev, q, bsg_name, iscsi_bsg_host_dispatch, 0);
-       if (ret) {
+       q = bsg_setup_queue(dev, bsg_name, iscsi_bsg_host_dispatch, 0);
+       if (IS_ERR(q)) {
                shost_printk(KERN_ERR, shost, "bsg interface failed to "
                             "initialize - no request queue\n");
-               blk_cleanup_queue(q);
-               return ret;
+               return PTR_ERR(q);
        }
+       __scsi_init_queue(shost, q);
 
        ihost->bsg_q = q;
        return 0;
index 60b651bfaa01e91456a1c294704cb2193305aec8..126a5ee00987ee14e21553b035620bff88302252 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/bsg.h>
 
 #include <scsi/scsi.h>
+#include <scsi/scsi_request.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_transport.h>
@@ -177,6 +178,10 @@ static void sas_smp_request(struct request_queue *q, struct Scsi_Host *shost,
        while ((req = blk_fetch_request(q)) != NULL) {
                spin_unlock_irq(q->queue_lock);
 
+               scsi_req(req)->resid_len = blk_rq_bytes(req);
+               if (req->next_rq)
+                       scsi_req(req->next_rq)->resid_len =
+                               blk_rq_bytes(req->next_rq);
                handler = to_sas_internal(shost->transportt)->f->smp_handler;
                ret = handler(shost, rphy, req);
                req->errors = ret;
index b87a78673f6501be8e14f0dc28c97e244fa372ef..3c5d89852e9f0a8ed124444b25fc13f7f1fe937d 100644 (file)
@@ -591,7 +591,7 @@ EXPORT_SYMBOL(srp_reconnect_rport);
  * Note: This function is called from soft-IRQ context and with the request
  * queue lock held.
  */
-static enum blk_eh_timer_return srp_timed_out(struct scsi_cmnd *scmd)
+enum blk_eh_timer_return srp_timed_out(struct scsi_cmnd *scmd)
 {
        struct scsi_device *sdev = scmd->device;
        struct Scsi_Host *shost = sdev->host;
@@ -603,6 +603,7 @@ static enum blk_eh_timer_return srp_timed_out(struct scsi_cmnd *scmd)
                i->f->reset_timer_if_blocked && scsi_device_blocked(sdev) ?
                BLK_EH_RESET_TIMER : BLK_EH_NOT_HANDLED;
 }
+EXPORT_SYMBOL(srp_timed_out);
 
 static void srp_rport_release(struct device *dev)
 {
@@ -793,19 +794,6 @@ void srp_stop_rport_timers(struct srp_rport *rport)
 }
 EXPORT_SYMBOL_GPL(srp_stop_rport_timers);
 
-static int srp_tsk_mgmt_response(struct Scsi_Host *shost, u64 nexus, u64 tm_id,
-                                int result)
-{
-       struct srp_internal *i = to_srp_internal(shost->transportt);
-       return i->f->tsk_mgmt_response(shost, nexus, tm_id, result);
-}
-
-static int srp_it_nexus_response(struct Scsi_Host *shost, u64 nexus, int result)
-{
-       struct srp_internal *i = to_srp_internal(shost->transportt);
-       return i->f->it_nexus_response(shost, nexus, result);
-}
-
 /**
  * srp_attach_transport  -  instantiate SRP transport template
  * @ft:                SRP transport class function template
@@ -820,11 +808,6 @@ srp_attach_transport(struct srp_function_template *ft)
        if (!i)
                return NULL;
 
-       i->t.eh_timed_out = srp_timed_out;
-
-       i->t.tsk_mgmt_response = srp_tsk_mgmt_response;
-       i->t.it_nexus_response = srp_it_nexus_response;
-
        i->t.host_size = sizeof(struct srp_host_attrs);
        i->t.host_attrs.ac.attrs = &i->host_attrs[0];
        i->t.host_attrs.ac.class = &srp_host_class.class;
index 1f5d92a25a49dd0f928c194c5d64372fb2b071f6..cb6e68dd6df09d1576a353a60bce7e898a0382b5 100644 (file)
@@ -703,7 +703,7 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode)
 
 /**
  * sd_setup_discard_cmnd - unmap blocks on thinly provisioned device
- * @sdp: scsi device to operate one
+ * @sdp: scsi device to operate on
  * @rq: Request to prepare
  *
  * Will issue either UNMAP or WRITE SAME(16) depending on preference
@@ -781,7 +781,7 @@ static int sd_setup_discard_cmnd(struct scsi_cmnd *cmd)
        rq->special_vec.bv_len = len;
 
        rq->rq_flags |= RQF_SPECIAL_PAYLOAD;
-       rq->resid_len = len;
+       scsi_req(rq)->resid_len = len;
 
        ret = scsi_init_io(cmd);
 out:
@@ -1179,7 +1179,7 @@ static void sd_uninit_command(struct scsi_cmnd *SCpnt)
        if (rq->rq_flags & RQF_SPECIAL_PAYLOAD)
                __free_page(rq->special_vec.bv_page);
 
-       if (SCpnt->cmnd != rq->cmd) {
+       if (SCpnt->cmnd != scsi_req(rq)->cmd) {
                mempool_free(SCpnt->cmnd, sd_cdb_pool);
                SCpnt->cmnd = NULL;
                SCpnt->cmd_len = 0;
@@ -1750,9 +1750,6 @@ static unsigned int sd_completed_bytes(struct scsi_cmnd *scmd)
        unsigned int transferred = scsi_bufflen(scmd) - scsi_get_resid(scmd);
        unsigned int good_bytes;
 
-       if (scmd->request->cmd_type != REQ_TYPE_FS)
-               return 0;
-
        info_valid = scsi_get_sense_info_fld(scmd->sense_buffer,
                                             SCSI_SENSE_BUFFERSIZE,
                                             &bad_lba);
@@ -3082,6 +3079,23 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
        put_device(&sdkp->dev);
 }
 
+struct sd_devt {
+       int idx;
+       struct disk_devt disk_devt;
+};
+
+void sd_devt_release(struct disk_devt *disk_devt)
+{
+       struct sd_devt *sd_devt = container_of(disk_devt, struct sd_devt,
+                       disk_devt);
+
+       spin_lock(&sd_index_lock);
+       ida_remove(&sd_index_ida, sd_devt->idx);
+       spin_unlock(&sd_index_lock);
+
+       kfree(sd_devt);
+}
+
 /**
  *     sd_probe - called during driver initialization and whenever a
  *     new scsi device is attached to the system. It is called once
@@ -3103,6 +3117,7 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
 static int sd_probe(struct device *dev)
 {
        struct scsi_device *sdp = to_scsi_device(dev);
+       struct sd_devt *sd_devt;
        struct scsi_disk *sdkp;
        struct gendisk *gd;
        int index;
@@ -3128,9 +3143,13 @@ static int sd_probe(struct device *dev)
        if (!sdkp)
                goto out;
 
+       sd_devt = kzalloc(sizeof(*sd_devt), GFP_KERNEL);
+       if (!sd_devt)
+               goto out_free;
+
        gd = alloc_disk(SD_MINORS);
        if (!gd)
-               goto out_free;
+               goto out_free_devt;
 
        do {
                if (!ida_pre_get(&sd_index_ida, GFP_KERNEL))
@@ -3146,6 +3165,11 @@ static int sd_probe(struct device *dev)
                goto out_put;
        }
 
+       atomic_set(&sd_devt->disk_devt.count, 1);
+       sd_devt->disk_devt.release = sd_devt_release;
+       sd_devt->idx = index;
+       gd->disk_devt = &sd_devt->disk_devt;
+
        error = sd_format_disk_name("sd", index, gd->disk_name, DISK_NAME_LEN);
        if (error) {
                sdev_printk(KERN_WARNING, sdp, "SCSI disk (sd) name length exceeded.\n");
@@ -3185,13 +3209,14 @@ static int sd_probe(struct device *dev)
        return 0;
 
  out_free_index:
-       spin_lock(&sd_index_lock);
-       ida_remove(&sd_index_ida, index);
-       spin_unlock(&sd_index_lock);
+       put_disk_devt(&sd_devt->disk_devt);
+       sd_devt = NULL;
  out_put:
        put_disk(gd);
  out_free:
        kfree(sdkp);
+ out_free_devt:
+       kfree(sd_devt);
  out:
        scsi_autopm_put_device(sdp);
        return error;
@@ -3201,7 +3226,7 @@ static int sd_probe(struct device *dev)
  *     sd_remove - called whenever a scsi disk (previously recognized by
  *     sd_probe) is detached from the system. It is called (potentially
  *     multiple times) during sd module unload.
- *     @sdp: pointer to mid level scsi device object
+ *     @dev: pointer to device object
  *
  *     Note: this function is invoked from the scsi mid-level.
  *     This function potentially frees up a device name (e.g. /dev/sdc)
@@ -3250,10 +3275,7 @@ static void scsi_disk_release(struct device *dev)
        struct scsi_disk *sdkp = to_scsi_disk(dev);
        struct gendisk *disk = sdkp->disk;
        
-       spin_lock(&sd_index_lock);
-       ida_remove(&sd_index_ida, sdkp->index);
-       spin_unlock(&sd_index_lock);
-
+       put_disk_devt(disk->disk_devt);
        disk->private_data = NULL;
        put_disk(disk);
        put_device(&sdkp->device->sdev_gendev);
index 121de0aaa6adaa1e9a71376893072c1f69ddc228..e831e01f9fa68546083ae43c82d708980425d83c 100644 (file)
@@ -781,9 +781,7 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp,
        }
        if (atomic_read(&sdp->detaching)) {
                if (srp->bio) {
-                       if (srp->rq->cmd != srp->rq->__cmd)
-                               kfree(srp->rq->cmd);
-
+                       scsi_req_free_cmd(scsi_req(srp->rq));
                        blk_end_request_all(srp->rq, -EIO);
                        srp->rq = NULL;
                }
@@ -1279,6 +1277,7 @@ static void
 sg_rq_end_io(struct request *rq, int uptodate)
 {
        struct sg_request *srp = rq->end_io_data;
+       struct scsi_request *req = scsi_req(rq);
        Sg_device *sdp;
        Sg_fd *sfp;
        unsigned long iflags;
@@ -1297,9 +1296,9 @@ sg_rq_end_io(struct request *rq, int uptodate)
        if (unlikely(atomic_read(&sdp->detaching)))
                pr_info("%s: device detaching\n", __func__);
 
-       sense = rq->sense;
+       sense = req->sense;
        result = rq->errors;
-       resid = rq->resid_len;
+       resid = req->resid_len;
 
        SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sdp,
                                      "sg_cmd_done: pack_id=%d, res=0x%x\n",
@@ -1333,6 +1332,10 @@ sg_rq_end_io(struct request *rq, int uptodate)
                        sdp->device->changed = 1;
                }
        }
+
+       if (req->sense_len)
+               memcpy(srp->sense_b, req->sense, SCSI_SENSE_BUFFERSIZE);
+
        /* Rely on write phase to clean out srp status values, so no "else" */
 
        /*
@@ -1342,8 +1345,7 @@ sg_rq_end_io(struct request *rq, int uptodate)
         * blk_rq_unmap_user() can be called from user context.
         */
        srp->rq = NULL;
-       if (rq->cmd != rq->__cmd)
-               kfree(rq->cmd);
+       scsi_req_free_cmd(scsi_req(rq));
        __blk_put_request(rq->q, rq);
 
        write_lock_irqsave(&sfp->rq_list_lock, iflags);
@@ -1658,6 +1660,7 @@ sg_start_req(Sg_request *srp, unsigned char *cmd)
 {
        int res;
        struct request *rq;
+       struct scsi_request *req;
        Sg_fd *sfp = srp->parentfp;
        sg_io_hdr_t *hp = &srp->header;
        int dxfer_len = (int) hp->dxfer_len;
@@ -1695,22 +1698,23 @@ sg_start_req(Sg_request *srp, unsigned char *cmd)
         * With scsi-mq disabled, blk_get_request() with GFP_KERNEL usually
         * does not sleep except under memory pressure.
         */
-       rq = blk_get_request(q, rw, GFP_KERNEL);
+       rq = blk_get_request(q, hp->dxfer_direction == SG_DXFER_TO_DEV ?
+                       REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, GFP_KERNEL);
        if (IS_ERR(rq)) {
                kfree(long_cmdp);
                return PTR_ERR(rq);
        }
+       req = scsi_req(rq);
 
-       blk_rq_set_block_pc(rq);
+       scsi_req_init(rq);
 
        if (hp->cmd_len > BLK_MAX_CDB)
-               rq->cmd = long_cmdp;
-       memcpy(rq->cmd, cmd, hp->cmd_len);
-       rq->cmd_len = hp->cmd_len;
+               req->cmd = long_cmdp;
+       memcpy(req->cmd, cmd, hp->cmd_len);
+       req->cmd_len = hp->cmd_len;
 
        srp->rq = rq;
        rq->end_io_data = srp;
-       rq->sense = srp->sense_b;
        rq->retries = SG_DEFAULT_RETRIES;
 
        if ((dxfer_len <= 0) || (dxfer_dir == SG_DXFER_NONE))
@@ -1790,8 +1794,7 @@ sg_finish_rem_req(Sg_request *srp)
                ret = blk_rq_unmap_user(srp->bio);
 
        if (srp->rq) {
-               if (srp->rq->cmd != srp->rq->__cmd)
-                       kfree(srp->rq->cmd);
+               scsi_req_free_cmd(scsi_req(srp->rq));
                blk_put_request(srp->rq);
        }
 
index 8702d9cf80409ff00576fe1b92b013f30649e651..11c0dfb3dfa392a025c6ef29c1977247ee46cfc5 100644 (file)
@@ -4499,7 +4499,7 @@ static int pqi_scsi_queue_command(struct Scsi_Host *shost,
        if (pqi_is_logical_device(device)) {
                raid_bypassed = false;
                if (device->offload_enabled &&
-                       scmd->request->cmd_type == REQ_TYPE_FS) {
+                               !blk_rq_is_passthrough(scmd->request)) {
                        rc = pqi_raid_bypass_submit_scsi_cmd(ctrl_info, device,
                                scmd, queue_group);
                        if (rc == 0 ||
index 8ed778d4dbb9688864b20a34afaf9e724022d953..de0ab5fc84742fd685d18c41dfd05a9ac1588df2 100644 (file)
@@ -299,7 +299,6 @@ struct snic {
 
        /* pci related */
        struct pci_dev *pdev;
-       struct msix_entry msix_entry[SNIC_MSIX_INTR_MAX];
        struct snic_msix_entry msix[SNIC_MSIX_INTR_MAX];
 
        /* io related info */
index f552003128c6e7899362012766d0eea4f7f6f1cd..d859501e4ccd3785ff4344d10eed83d4bd5f0190 100644 (file)
@@ -93,7 +93,7 @@ snic_free_intr(struct snic *snic)
        /* ONLY interrupt mode MSIX is supported */
        for (i = 0; i < ARRAY_SIZE(snic->msix); i++) {
                if (snic->msix[i].requested) {
-                       free_irq(snic->msix_entry[i].vector,
+                       free_irq(pci_irq_vector(snic->pdev, i),
                                 snic->msix[i].devid);
                }
        }
@@ -134,7 +134,7 @@ snic_request_intr(struct snic *snic)
        snic->msix[SNIC_MSIX_ERR_NOTIFY].devid = snic;
 
        for (i = 0; i < ARRAY_SIZE(snic->msix); i++) {
-               ret = request_irq(snic->msix_entry[i].vector,
+               ret = request_irq(pci_irq_vector(snic->pdev, i),
                                  snic->msix[i].isr,
                                  0,
                                  snic->msix[i].devname,
@@ -158,47 +158,37 @@ snic_set_intr_mode(struct snic *snic)
 {
        unsigned int n = ARRAY_SIZE(snic->wq);
        unsigned int m = SNIC_CQ_IO_CMPL_MAX;
-       unsigned int i;
+       unsigned int vecs = n + m + 1;
 
        /*
         * We need n WQs, m CQs, and n+m+1 INTRs
         * (last INTR is used for WQ/CQ errors and notification area
         */
-
        BUILD_BUG_ON((ARRAY_SIZE(snic->wq) + SNIC_CQ_IO_CMPL_MAX) >
                        ARRAY_SIZE(snic->intr));
-       SNIC_BUG_ON(ARRAY_SIZE(snic->msix_entry) < (n + m + 1));
-
-       for (i = 0; i < (n + m + 1); i++)
-               snic->msix_entry[i].entry = i;
-
-       if (snic->wq_count >= n && snic->cq_count >= (n + m)) {
-               if (!pci_enable_msix(snic->pdev,
-                                    snic->msix_entry,
-                                    (n + m + 1))) {
-                       snic->wq_count = n;
-                       snic->cq_count = n + m;
-                       snic->intr_count = n + m + 1;
-                       snic->err_intr_offset = SNIC_MSIX_ERR_NOTIFY;
-
-                       SNIC_ISR_DBG(snic->shost,
-                                    "Using MSI-X Interrupts\n");
-                       svnic_dev_set_intr_mode(snic->vdev,
-                                               VNIC_DEV_INTR_MODE_MSIX);
-
-                       return 0;
-               }
-       }
 
-       svnic_dev_set_intr_mode(snic->vdev, VNIC_DEV_INTR_MODE_UNKNOWN);
+       if (snic->wq_count < n || snic->cq_count < n + m)
+               goto fail;
 
+       if (pci_alloc_irq_vectors(snic->pdev, vecs, vecs, PCI_IRQ_MSIX) < 0)
+               goto fail;
+
+       snic->wq_count = n;
+       snic->cq_count = n + m;
+       snic->intr_count = vecs;
+       snic->err_intr_offset = SNIC_MSIX_ERR_NOTIFY;
+
+       SNIC_ISR_DBG(snic->shost, "Using MSI-X Interrupts\n");
+       svnic_dev_set_intr_mode(snic->vdev, VNIC_DEV_INTR_MODE_MSIX);
+       return 0;
+fail:
+       svnic_dev_set_intr_mode(snic->vdev, VNIC_DEV_INTR_MODE_UNKNOWN);
        return -EINVAL;
 } /* end of snic_set_intr_mode */
 
 void
 snic_clear_intr_mode(struct snic *snic)
 {
-       pci_disable_msix(snic->pdev);
-
+       pci_free_irq_vectors(snic->pdev);
        svnic_dev_set_intr_mode(snic->vdev, VNIC_DEV_INTR_MODE_INTX);
 }
index 94352e4df831be803c3ef6a76cf7f6177750f29c..0b29b9329b1c2f5c8207188884498f314e0a414a 100644 (file)
@@ -117,7 +117,7 @@ static unsigned int sr_check_events(struct cdrom_device_info *cdi,
                                    unsigned int clearing, int slot);
 static int sr_packet(struct cdrom_device_info *, struct packet_command *);
 
-static struct cdrom_device_ops sr_dops = {
+static const struct cdrom_device_ops sr_dops = {
        .open                   = sr_open,
        .release                = sr_release,
        .drive_status           = sr_drive_status,
@@ -437,14 +437,17 @@ static int sr_init_command(struct scsi_cmnd *SCpnt)
                goto out;
        }
 
-       if (rq_data_dir(rq) == WRITE) {
+       switch (req_op(rq)) {
+       case REQ_OP_WRITE:
                if (!cd->writeable)
                        goto out;
                SCpnt->cmnd[0] = WRITE_10;
                cd->cdi.media_written = 1;
-       } else if (rq_data_dir(rq) == READ) {
+               break;
+       case REQ_OP_READ:
                SCpnt->cmnd[0] = READ_10;
-       } else {
+               break;
+       default:
                blk_dump_rq_flags(rq, "Unknown sr command");
                goto out;
        }
index 5f35b863e1a709fa3354ca3bae923fb9aee24fae..81212d4bd9bf2d5e5982ca2f4359ea12b712dced 100644 (file)
@@ -475,7 +475,7 @@ static void st_do_stats(struct scsi_tape *STp, struct request *req)
        ktime_t now;
 
        now = ktime_get();
-       if (req->cmd[0] == WRITE_6) {
+       if (scsi_req(req)->cmd[0] == WRITE_6) {
                now = ktime_sub(now, STp->stats->write_time);
                atomic64_add(ktime_to_ns(now), &STp->stats->tot_write_time);
                atomic64_add(ktime_to_ns(now), &STp->stats->tot_io_time);
@@ -489,7 +489,7 @@ static void st_do_stats(struct scsi_tape *STp, struct request *req)
                } else
                        atomic64_add(atomic_read(&STp->stats->last_write_size),
                                &STp->stats->write_byte_cnt);
-       } else if (req->cmd[0] == READ_6) {
+       } else if (scsi_req(req)->cmd[0] == READ_6) {
                now = ktime_sub(now, STp->stats->read_time);
                atomic64_add(ktime_to_ns(now), &STp->stats->tot_read_time);
                atomic64_add(ktime_to_ns(now), &STp->stats->tot_io_time);
@@ -514,15 +514,18 @@ static void st_do_stats(struct scsi_tape *STp, struct request *req)
 static void st_scsi_execute_end(struct request *req, int uptodate)
 {
        struct st_request *SRpnt = req->end_io_data;
+       struct scsi_request *rq = scsi_req(req);
        struct scsi_tape *STp = SRpnt->stp;
        struct bio *tmp;
 
        STp->buffer->cmdstat.midlevel_result = SRpnt->result = req->errors;
-       STp->buffer->cmdstat.residual = req->resid_len;
+       STp->buffer->cmdstat.residual = rq->resid_len;
 
        st_do_stats(STp, req);
 
        tmp = SRpnt->bio;
+       if (rq->sense_len)
+               memcpy(SRpnt->sense, rq->sense, SCSI_SENSE_BUFFERSIZE);
        if (SRpnt->waiting)
                complete(SRpnt->waiting);
 
@@ -535,17 +538,18 @@ static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd,
                           int timeout, int retries)
 {
        struct request *req;
+       struct scsi_request *rq;
        struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data;
        int err = 0;
-       int write = (data_direction == DMA_TO_DEVICE);
        struct scsi_tape *STp = SRpnt->stp;
 
-       req = blk_get_request(SRpnt->stp->device->request_queue, write,
-                             GFP_KERNEL);
+       req = blk_get_request(SRpnt->stp->device->request_queue,
+                       data_direction == DMA_TO_DEVICE ?
+                       REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, GFP_KERNEL);
        if (IS_ERR(req))
                return DRIVER_ERROR << 24;
-
-       blk_rq_set_block_pc(req);
+       rq = scsi_req(req);
+       scsi_req_init(req);
        req->rq_flags |= RQF_QUIET;
 
        mdata->null_mapped = 1;
@@ -571,11 +575,9 @@ static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd,
        }
 
        SRpnt->bio = req->bio;
-       req->cmd_len = COMMAND_SIZE(cmd[0]);
-       memset(req->cmd, 0, BLK_MAX_CDB);
-       memcpy(req->cmd, cmd, req->cmd_len);
-       req->sense = SRpnt->sense;
-       req->sense_len = 0;
+       rq->cmd_len = COMMAND_SIZE(cmd[0]);
+       memset(rq->cmd, 0, BLK_MAX_CDB);
+       memcpy(rq->cmd, cmd, rq->cmd_len);
        req->timeout = timeout;
        req->retries = retries;
        req->end_io_data = SRpnt;
index 05526b71541b0aed0a2b8d37c227fd0fcb3ae24d..585e54f6512cdd773342a7a040a203045ea65f26 100644 (file)
@@ -136,6 +136,8 @@ struct hv_fc_wwn_packet {
 #define SRB_FLAGS_PORT_DRIVER_RESERVED         0x0F000000
 #define SRB_FLAGS_CLASS_DRIVER_RESERVED                0xF0000000
 
+#define SP_UNTAGGED                    ((unsigned char) ~0)
+#define SRB_SIMPLE_TAG_REQUEST         0x20
 
 /*
  * Platform neutral description of a scsi request -
@@ -375,6 +377,7 @@ enum storvsc_request_type {
 #define SRB_STATUS_SUCCESS     0x01
 #define SRB_STATUS_ABORTED     0x02
 #define SRB_STATUS_ERROR       0x04
+#define SRB_STATUS_DATA_OVERRUN        0x12
 
 #define SRB_STATUS(status) \
        (status & ~(SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_QUEUE_FROZEN))
@@ -458,6 +461,15 @@ struct storvsc_device {
         * Max I/O, the device can support.
         */
        u32   max_transfer_bytes;
+       /*
+        * Number of sub-channels we will open.
+        */
+       u16 num_sc;
+       struct vmbus_channel **stor_chns;
+       /*
+        * Mask of CPUs bound to subchannels.
+        */
+       struct cpumask alloced_cpus;
        /* Used for vsc/vsp channel reset process */
        struct storvsc_cmd_request init_request;
        struct storvsc_cmd_request reset_request;
@@ -635,6 +647,11 @@ static void handle_sc_creation(struct vmbus_channel *new_sc)
                   (void *)&props,
                   sizeof(struct vmstorage_channel_properties),
                   storvsc_on_channel_callback, new_sc);
+
+       if (new_sc->state == CHANNEL_OPENED_STATE) {
+               stor_device->stor_chns[new_sc->target_cpu] = new_sc;
+               cpumask_set_cpu(new_sc->target_cpu, &stor_device->alloced_cpus);
+       }
 }
 
 static void  handle_multichannel_storage(struct hv_device *device, int max_chns)
@@ -651,6 +668,7 @@ static void  handle_multichannel_storage(struct hv_device *device, int max_chns)
        if (!stor_device)
                return;
 
+       stor_device->num_sc = num_sc;
        request = &stor_device->init_request;
        vstor_packet = &request->vstor_packet;
 
@@ -838,6 +856,25 @@ static int storvsc_channel_init(struct hv_device *device, bool is_fc)
         * support multi-channel.
         */
        max_chns = vstor_packet->storage_channel_properties.max_channel_cnt;
+
+       /*
+        * Allocate state to manage the sub-channels.
+        * We allocate an array based on the numbers of possible CPUs
+        * (Hyper-V does not support cpu online/offline).
+        * This Array will be sparseley populated with unique
+        * channels - primary + sub-channels.
+        * We will however populate all the slots to evenly distribute
+        * the load.
+        */
+       stor_device->stor_chns = kzalloc(sizeof(void *) * num_possible_cpus(),
+                                        GFP_KERNEL);
+       if (stor_device->stor_chns == NULL)
+               return -ENOMEM;
+
+       stor_device->stor_chns[device->channel->target_cpu] = device->channel;
+       cpumask_set_cpu(device->channel->target_cpu,
+                       &stor_device->alloced_cpus);
+
        if (vmstor_proto_version >= VMSTOR_PROTO_VERSION_WIN8) {
                if (vstor_packet->storage_channel_properties.flags &
                    STORAGE_CHANNEL_SUPPORTS_MULTI_CHANNEL)
@@ -888,6 +925,13 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb,
 
        switch (SRB_STATUS(vm_srb->srb_status)) {
        case SRB_STATUS_ERROR:
+               /*
+                * Let upper layer deal with error when
+                * sense message is present.
+                */
+
+               if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID)
+                       break;
                /*
                 * If there is an error; offline the device since all
                 * error recovery strategies would have already been
@@ -953,6 +997,7 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request,
        struct scsi_cmnd *scmnd = cmd_request->cmd;
        struct scsi_sense_hdr sense_hdr;
        struct vmscsi_request *vm_srb;
+       u32 data_transfer_length;
        struct Scsi_Host *host;
        u32 payload_sz = cmd_request->payload_sz;
        void *payload = cmd_request->payload;
@@ -960,6 +1005,7 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request,
        host = stor_dev->host;
 
        vm_srb = &cmd_request->vstor_packet.vm_srb;
+       data_transfer_length = vm_srb->data_transfer_length;
 
        scmnd->result = vm_srb->scsi_status;
 
@@ -973,13 +1019,20 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request,
                                             &sense_hdr);
        }
 
-       if (vm_srb->srb_status != SRB_STATUS_SUCCESS)
+       if (vm_srb->srb_status != SRB_STATUS_SUCCESS) {
                storvsc_handle_error(vm_srb, scmnd, host, sense_hdr.asc,
                                         sense_hdr.ascq);
+               /*
+                * The Windows driver set data_transfer_length on
+                * SRB_STATUS_DATA_OVERRUN. On other errors, this value
+                * is untouched.  In these cases we set it to 0.
+                */
+               if (vm_srb->srb_status != SRB_STATUS_DATA_OVERRUN)
+                       data_transfer_length = 0;
+       }
 
        scsi_set_resid(scmnd,
-               cmd_request->payload->range.len -
-               vm_srb->data_transfer_length);
+               cmd_request->payload->range.len - data_transfer_length);
 
        scmnd->scsi_done(scmnd);
 
@@ -1198,17 +1251,64 @@ static int storvsc_dev_remove(struct hv_device *device)
        /* Close the channel */
        vmbus_close(device->channel);
 
+       kfree(stor_device->stor_chns);
        kfree(stor_device);
        return 0;
 }
 
+static struct vmbus_channel *get_og_chn(struct storvsc_device *stor_device,
+                                       u16 q_num)
+{
+       u16 slot = 0;
+       u16 hash_qnum;
+       struct cpumask alloced_mask;
+       int num_channels, tgt_cpu;
+
+       if (stor_device->num_sc == 0)
+               return stor_device->device->channel;
+
+       /*
+        * Our channel array is sparsley populated and we
+        * initiated I/O on a processor/hw-q that does not
+        * currently have a designated channel. Fix this.
+        * The strategy is simple:
+        * I. Ensure NUMA locality
+        * II. Distribute evenly (best effort)
+        * III. Mapping is persistent.
+        */
+
+       cpumask_and(&alloced_mask, &stor_device->alloced_cpus,
+                   cpumask_of_node(cpu_to_node(q_num)));
+
+       num_channels = cpumask_weight(&alloced_mask);
+       if (num_channels == 0)
+               return stor_device->device->channel;
+
+       hash_qnum = q_num;
+       while (hash_qnum >= num_channels)
+               hash_qnum -= num_channels;
+
+       for_each_cpu(tgt_cpu, &alloced_mask) {
+               if (slot == hash_qnum)
+                       break;
+               slot++;
+       }
+
+       stor_device->stor_chns[q_num] = stor_device->stor_chns[tgt_cpu];
+
+       return stor_device->stor_chns[q_num];
+}
+
+
 static int storvsc_do_io(struct hv_device *device,
-                        struct storvsc_cmd_request *request)
+                        struct storvsc_cmd_request *request, u16 q_num)
 {
        struct storvsc_device *stor_device;
        struct vstor_packet *vstor_packet;
        struct vmbus_channel *outgoing_channel;
        int ret = 0;
+       struct cpumask alloced_mask;
+       int tgt_cpu;
 
        vstor_packet = &request->vstor_packet;
        stor_device = get_out_stor_device(device);
@@ -1222,7 +1322,26 @@ static int storvsc_do_io(struct hv_device *device,
         * Select an an appropriate channel to send the request out.
         */
 
-       outgoing_channel = vmbus_get_outgoing_channel(device->channel);
+       if (stor_device->stor_chns[q_num] != NULL) {
+               outgoing_channel = stor_device->stor_chns[q_num];
+               if (outgoing_channel->target_cpu == smp_processor_id()) {
+                       /*
+                        * Ideally, we want to pick a different channel if
+                        * available on the same NUMA node.
+                        */
+                       cpumask_and(&alloced_mask, &stor_device->alloced_cpus,
+                                   cpumask_of_node(cpu_to_node(q_num)));
+                       for_each_cpu(tgt_cpu, &alloced_mask) {
+                               if (tgt_cpu != outgoing_channel->target_cpu) {
+                                       outgoing_channel =
+                                       stor_device->stor_chns[tgt_cpu];
+                                       break;
+                               }
+                       }
+               }
+       } else {
+               outgoing_channel = get_og_chn(stor_device, q_num);
+       }
 
 
        vstor_packet->flags |= REQUEST_COMPLETION_FLAG;
@@ -1267,8 +1386,6 @@ static int storvsc_do_io(struct hv_device *device,
 static int storvsc_device_configure(struct scsi_device *sdevice)
 {
 
-       blk_queue_max_segment_size(sdevice->request_queue, PAGE_SIZE);
-
        blk_queue_bounce_limit(sdevice->request_queue, BLK_BOUNCE_ANY);
 
        blk_queue_rq_timeout(sdevice->request_queue, (storvsc_timeout * HZ));
@@ -1451,6 +1568,13 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
        vm_srb->win8_extension.srb_flags |=
                SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
 
+       if (scmnd->device->tagged_supported) {
+               vm_srb->win8_extension.srb_flags |=
+               (SRB_FLAGS_QUEUE_ACTION_ENABLE | SRB_FLAGS_NO_QUEUE_FREEZE);
+               vm_srb->win8_extension.queue_tag = SP_UNTAGGED;
+               vm_srb->win8_extension.queue_action = SRB_SIMPLE_TAG_REQUEST;
+       }
+
        /* Build the SRB */
        switch (scmnd->sc_data_direction) {
        case DMA_TO_DEVICE:
@@ -1511,20 +1635,14 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
                                page_to_pfn(sg_page((cur_sgl)));
                        cur_sgl = sg_next(cur_sgl);
                }
-
-       } else if (scsi_sglist(scmnd)) {
-               payload->range.len = length;
-               payload->range.offset =
-                       virt_to_phys(scsi_sglist(scmnd)) & (PAGE_SIZE-1);
-               payload->range.pfn_array[0] =
-                       virt_to_phys(scsi_sglist(scmnd)) >> PAGE_SHIFT;
        }
 
        cmd_request->payload = payload;
        cmd_request->payload_sz = payload_sz;
 
        /* Invokes the vsc to start an IO */
-       ret = storvsc_do_io(dev, cmd_request);
+       ret = storvsc_do_io(dev, cmd_request, get_cpu());
+       put_cpu();
 
        if (ret == -EAGAIN) {
                /* no more space */
@@ -1550,6 +1668,7 @@ static struct scsi_host_template scsi_driver = {
        /* Make sure we dont get a sg segment crosses a page boundary */
        .dma_boundary =         PAGE_SIZE-1,
        .no_write_same =        1,
+       .track_queue_depth =    1,
 };
 
 enum {
@@ -1680,6 +1799,11 @@ static int storvsc_probe(struct hv_device *device,
         * from the host.
         */
        host->sg_tablesize = (stor_device->max_transfer_bytes >> PAGE_SHIFT);
+       /*
+        * Set the number of HW queues we are supporting.
+        */
+       if (stor_device->num_sc != 0)
+               host->nr_hw_queues = stor_device->num_sc + 1;
 
        /* Register the HBA and start the scsi bus scan */
        ret = scsi_add_host(host, &device->device);
@@ -1716,6 +1840,7 @@ err_out2:
        goto err_out0;
 
 err_out1:
+       kfree(stor_device->stor_chns);
        kfree(stor_device);
 
 err_out0:
@@ -1774,11 +1899,6 @@ static int __init storvsc_drv_init(void)
        fc_transport_template = fc_attach_transport(&fc_transport_functions);
        if (!fc_transport_template)
                return -ENODEV;
-
-       /*
-        * Install Hyper-V specific timeout handler.
-        */
-       fc_transport_template->eh_timed_out = storvsc_eh_timed_out;
 #endif
 
        ret = vmbus_driver_register(&storvsc_drv);
index 88db6992420e47f023fdbba0a6c1d781e325408c..e64b0c542f950aae912a4615f8578a73df31ce6e 100644 (file)
@@ -34,7 +34,6 @@
 #include <asm/dvma.h>
 
 #include <scsi/scsi_host.h>
-#include "sun3_scsi.h"
 
 /* minimum number of bytes to do dma on */
 #define DMA_MIN_SIZE                    129
 #define NCR5380_dma_send_setup          sun3scsi_dma_count
 #define NCR5380_dma_residual            sun3scsi_dma_residual
 
-#define NCR5380_acquire_dma_irq(instance)    (1)
-#define NCR5380_release_dma_irq(instance)
-
 #include "NCR5380.h"
 
+/* dma regs start at regbase + 8, directly after the NCR regs */
+struct sun3_dma_regs {
+       unsigned short dma_addr_hi; /* vme only */
+       unsigned short dma_addr_lo; /* vme only */
+       unsigned short dma_count_hi; /* vme only */
+       unsigned short dma_count_lo; /* vme only */
+       unsigned short udc_data; /* udc dma data reg (obio only) */
+       unsigned short udc_addr; /* uda dma addr reg (obio only) */
+       unsigned short fifo_data; /* fifo data reg,
+                                  * holds extra byte on odd dma reads
+                                  */
+       unsigned short fifo_count;
+       unsigned short csr; /* control/status reg */
+       unsigned short bpack_hi; /* vme only */
+       unsigned short bpack_lo; /* vme only */
+       unsigned short ivect; /* vme only */
+       unsigned short fifo_count_hi; /* vme only */
+};
+
+/* ucd chip specific regs - live in dvma space */
+struct sun3_udc_regs {
+       unsigned short rsel; /* select regs to load */
+       unsigned short addr_hi; /* high word of addr */
+       unsigned short addr_lo; /* low word */
+       unsigned short count; /* words to be xfer'd */
+       unsigned short mode_hi; /* high word of channel mode */
+       unsigned short mode_lo; /* low word of channel mode */
+};
+
+/* addresses of the udc registers */
+#define UDC_MODE 0x38
+#define UDC_CSR 0x2e /* command/status */
+#define UDC_CHN_HI 0x26 /* chain high word */
+#define UDC_CHN_LO 0x22 /* chain lo word */
+#define UDC_CURA_HI 0x1a /* cur reg A high */
+#define UDC_CURA_LO 0x0a /* cur reg A low */
+#define UDC_CURB_HI 0x12 /* cur reg B high */
+#define UDC_CURB_LO 0x02 /* cur reg B low */
+#define UDC_MODE_HI 0x56 /* mode reg high */
+#define UDC_MODE_LO 0x52 /* mode reg low */
+#define UDC_COUNT 0x32 /* words to xfer */
+
+/* some udc commands */
+#define UDC_RESET 0
+#define UDC_CHN_START 0xa0 /* start chain */
+#define UDC_INT_ENABLE 0x32 /* channel 1 int on */
+
+/* udc mode words */
+#define UDC_MODE_HIWORD 0x40
+#define UDC_MODE_LSEND 0xc2
+#define UDC_MODE_LRECV 0xd2
+
+/* udc reg selections */
+#define UDC_RSEL_SEND 0x282
+#define UDC_RSEL_RECV 0x182
+
+/* bits in csr reg */
+#define CSR_DMA_ACTIVE 0x8000
+#define CSR_DMA_CONFLICT 0x4000
+#define CSR_DMA_BUSERR 0x2000
+
+#define CSR_FIFO_EMPTY 0x400 /* fifo flushed? */
+#define CSR_SDB_INT 0x200 /* sbc interrupt pending */
+#define CSR_DMA_INT 0x100 /* dma interrupt pending */
+
+#define CSR_LEFT 0xc0
+#define CSR_LEFT_3 0xc0
+#define CSR_LEFT_2 0x80
+#define CSR_LEFT_1 0x40
+#define CSR_PACK_ENABLE 0x20
+
+#define CSR_DMA_ENABLE 0x10
+
+#define CSR_SEND 0x8 /* 1 = send  0 = recv */
+#define CSR_FIFO 0x2 /* reset fifo */
+#define CSR_INTR 0x4 /* interrupt enable */
+#define CSR_SCSI 0x1
+
+#define VME_DATA24 0x3d00
 
 extern int sun3_map_test(unsigned long, char *);
 
@@ -260,7 +335,7 @@ static int sun3scsi_dma_xfer_len(struct NCR5380_hostdata *hostdata,
 {
        int wanted_len = cmd->SCp.this_residual;
 
-       if (wanted_len < DMA_MIN_SIZE || cmd->request->cmd_type != REQ_TYPE_FS)
+       if (wanted_len < DMA_MIN_SIZE || blk_rq_is_passthrough(cmd->request))
                return 0;
 
        return wanted_len;
diff --git a/drivers/scsi/sun3_scsi.h b/drivers/scsi/sun3_scsi.h
deleted file mode 100644 (file)
index d22745f..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl)
- *
- * Sun3 DMA additions by Sam Creasey (sammy@sammy.net)
- *
- * Adapted from mac_scsinew.h:
- */
-/*
- * Cumana Generic NCR5380 driver defines
- *
- * Copyright 1993, Drew Eckhardt
- *     Visionary Computing
- *     (Unix and Linux consulting and custom programming)
- *     drew@colorado.edu
- *      +1 (303) 440-4894
- */
-
-#ifndef SUN3_SCSI_H
-#define SUN3_SCSI_H
-
-/* additional registers - mainly DMA control regs */
-/* these start at regbase + 8 -- directly after the NCR regs */
-struct sun3_dma_regs {
-       unsigned short dma_addr_hi; /* vme only */
-       unsigned short dma_addr_lo; /* vme only */
-       unsigned short dma_count_hi; /* vme only */
-       unsigned short dma_count_lo; /* vme only */
-       unsigned short udc_data; /* udc dma data reg (obio only) */
-       unsigned short udc_addr; /* uda dma addr reg (obio only) */
-       unsigned short fifo_data; /* fifo data reg, holds extra byte on
-                                    odd dma reads */
-       unsigned short fifo_count; 
-       unsigned short csr; /* control/status reg */
-       unsigned short bpack_hi; /* vme only */
-       unsigned short bpack_lo; /* vme only */
-       unsigned short ivect; /* vme only */
-       unsigned short fifo_count_hi; /* vme only */
-};
-
-/* ucd chip specific regs - live in dvma space */
-struct sun3_udc_regs {
-     unsigned short rsel; /* select regs to load */
-     unsigned short addr_hi; /* high word of addr */
-     unsigned short addr_lo; /* low word */
-     unsigned short count; /* words to be xfer'd */
-     unsigned short mode_hi; /* high word of channel mode */
-     unsigned short mode_lo; /* low word of channel mode */
-};
-
-/* addresses of the udc registers */
-#define UDC_MODE 0x38 
-#define UDC_CSR 0x2e /* command/status */
-#define UDC_CHN_HI 0x26 /* chain high word */
-#define UDC_CHN_LO 0x22 /* chain lo word */
-#define UDC_CURA_HI 0x1a /* cur reg A high */
-#define UDC_CURA_LO 0x0a /* cur reg A low */
-#define UDC_CURB_HI 0x12 /* cur reg B high */
-#define UDC_CURB_LO 0x02 /* cur reg B low */
-#define UDC_MODE_HI 0x56 /* mode reg high */
-#define UDC_MODE_LO 0x52 /* mode reg low */
-#define UDC_COUNT 0x32 /* words to xfer */
-
-/* some udc commands */
-#define UDC_RESET 0
-#define UDC_CHN_START 0xa0 /* start chain */
-#define UDC_INT_ENABLE 0x32 /* channel 1 int on */
-
-/* udc mode words */
-#define UDC_MODE_HIWORD 0x40
-#define UDC_MODE_LSEND 0xc2
-#define UDC_MODE_LRECV 0xd2
-
-/* udc reg selections */
-#define UDC_RSEL_SEND 0x282
-#define UDC_RSEL_RECV 0x182
-
-/* bits in csr reg */
-#define CSR_DMA_ACTIVE 0x8000
-#define CSR_DMA_CONFLICT 0x4000
-#define CSR_DMA_BUSERR 0x2000
-
-#define CSR_FIFO_EMPTY 0x400 /* fifo flushed? */
-#define CSR_SDB_INT 0x200 /* sbc interrupt pending */
-#define CSR_DMA_INT 0x100 /* dma interrupt pending */
-
-#define CSR_LEFT 0xc0
-#define CSR_LEFT_3 0xc0
-#define CSR_LEFT_2 0x80
-#define CSR_LEFT_1 0x40
-#define CSR_PACK_ENABLE 0x20
-
-#define CSR_DMA_ENABLE 0x10
-
-#define CSR_SEND 0x8 /* 1 = send  0 = recv */
-#define CSR_FIFO 0x2 /* reset fifo */
-#define CSR_INTR 0x4 /* interrupt enable */
-#define CSR_SCSI 0x1 
-
-#define VME_DATA24 0x3d00
-
-#endif /* SUN3_SCSI_H */
-
index abe6173726614f627c085129f4e8aa9dc6ba1eda..ce5d023c1c915cca3e11cb751d9beb462ddda63f 100644 (file)
@@ -1497,17 +1497,21 @@ static void ufs_qcom_print_hw_debug_reg_all(struct ufs_hba *hba,
 
 static void ufs_qcom_enable_test_bus(struct ufs_qcom_host *host)
 {
-       if (host->dbg_print_en & UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
+       if (host->dbg_print_en & UFS_QCOM_DBG_PRINT_TEST_BUS_EN) {
+               ufshcd_rmwl(host->hba, UFS_REG_TEST_BUS_EN,
+                               UFS_REG_TEST_BUS_EN, REG_UFS_CFG1);
                ufshcd_rmwl(host->hba, TEST_BUS_EN, TEST_BUS_EN, REG_UFS_CFG1);
-       else
+       } else {
+               ufshcd_rmwl(host->hba, UFS_REG_TEST_BUS_EN, 0, REG_UFS_CFG1);
                ufshcd_rmwl(host->hba, TEST_BUS_EN, 0, REG_UFS_CFG1);
+       }
 }
 
 static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host)
 {
        /* provide a legal default configuration */
-       host->testbus.select_major = TSTBUS_UAWM;
-       host->testbus.select_minor = 1;
+       host->testbus.select_major = TSTBUS_UNIPRO;
+       host->testbus.select_minor = 37;
 }
 
 static bool ufs_qcom_testbus_cfg_is_ok(struct ufs_qcom_host *host)
@@ -1524,7 +1528,7 @@ static bool ufs_qcom_testbus_cfg_is_ok(struct ufs_qcom_host *host)
         * mappings of select_minor, since there is no harm in
         * configuring a non-existent select_minor
         */
-       if (host->testbus.select_minor > 0x1F) {
+       if (host->testbus.select_minor > 0xFF) {
                dev_err(host->hba->dev,
                        "%s: 0x%05X is not a legal testbus option\n",
                        __func__, host->testbus.select_minor);
@@ -1593,7 +1597,8 @@ int ufs_qcom_testbus_config(struct ufs_qcom_host *host)
                break;
        case TSTBUS_UNIPRO:
                reg = UFS_UNIPRO_CFG;
-               offset = 1;
+               offset = 20;
+               mask = 0xFFF;
                break;
        /*
         * No need for a default case, since
@@ -1612,6 +1617,11 @@ int ufs_qcom_testbus_config(struct ufs_qcom_host *host)
                    (u32)host->testbus.select_minor << offset,
                    reg);
        ufs_qcom_enable_test_bus(host);
+       /*
+        * Make sure the test bus configuration is
+        * committed before returning.
+        */
+       mb();
        ufshcd_release(host->hba);
        pm_runtime_put_sync(host->hba->dev);
 
@@ -1623,13 +1633,39 @@ static void ufs_qcom_testbus_read(struct ufs_hba *hba)
        ufs_qcom_dump_regs(hba, UFS_TEST_BUS, 1, "UFS_TEST_BUS ");
 }
 
+static void ufs_qcom_print_unipro_testbus(struct ufs_hba *hba)
+{
+       struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+       u32 *testbus = NULL;
+       int i, nminor = 256, testbus_len = nminor * sizeof(u32);
+
+       testbus = kmalloc(testbus_len, GFP_KERNEL);
+       if (!testbus)
+               return;
+
+       host->testbus.select_major = TSTBUS_UNIPRO;
+       for (i = 0; i < nminor; i++) {
+               host->testbus.select_minor = i;
+               ufs_qcom_testbus_config(host);
+               testbus[i] = ufshcd_readl(hba, UFS_TEST_BUS);
+       }
+       print_hex_dump(KERN_ERR, "UNIPRO_TEST_BUS ", DUMP_PREFIX_OFFSET,
+                       16, 4, testbus, testbus_len, false);
+       kfree(testbus);
+}
+
 static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)
 {
        ufs_qcom_dump_regs(hba, REG_UFS_SYS1CLK_1US, 16,
                        "HCI Vendor Specific Registers ");
 
+       /* sleep a bit intermittently as we are dumping too much data */
        ufs_qcom_print_hw_debug_reg_all(hba, NULL, ufs_qcom_dump_regs_wrapper);
+       usleep_range(1000, 1100);
        ufs_qcom_testbus_read(hba);
+       usleep_range(1000, 1100);
+       ufs_qcom_print_unipro_testbus(hba);
+       usleep_range(1000, 1100);
 }
 
 /**
@@ -1692,6 +1728,7 @@ static const struct of_device_id ufs_qcom_of_match[] = {
        { .compatible = "qcom,ufshc"},
        {},
 };
+MODULE_DEVICE_TABLE(of, ufs_qcom_of_match);
 
 static const struct dev_pm_ops ufs_qcom_pm_ops = {
        .suspend        = ufshcd_pltfrm_suspend,
index fe517cd7dac348b40b97c322e49e26976b7256cc..076f52813a4cb238dc06bddc5c3533c9433c81c2 100644 (file)
@@ -95,6 +95,7 @@ enum {
 #define QUNIPRO_SEL    UFS_BIT(0)
 #define TEST_BUS_EN            BIT(18)
 #define TEST_BUS_SEL           GENMASK(22, 19)
+#define UFS_REG_TEST_BUS_EN    BIT(30)
 
 /* bit definitions for REG_UFS_CFG2 register */
 #define UAWM_HW_CGC_EN         (1 << 0)
index 8e6709a3fb6b1be98c48aab9914c59a1e4c4dbd3..318e4a1f76c92bab27954b5cc29a3d374c8eb6e7 100644 (file)
@@ -523,4 +523,16 @@ struct ufs_dev_info {
        bool is_lu_power_on_wp;
 };
 
+#define MAX_MODEL_LEN 16
+/**
+ * ufs_dev_desc - ufs device details from the device descriptor
+ *
+ * @wmanufacturerid: card details
+ * @model: card model
+ */
+struct ufs_dev_desc {
+       u16 wmanufacturerid;
+       char model[MAX_MODEL_LEN + 1];
+};
+
 #endif /* End of Header */
index 08b799d4efcc68b99b7c43fa7af968dd3b543a2c..71f73d1d1ad1fb9b7c357c65baf0f49ec9dfa780 100644 (file)
 #define UFS_ANY_VENDOR 0xFFFF
 #define UFS_ANY_MODEL  "ANY_MODEL"
 
-#define MAX_MODEL_LEN 16
-
 #define UFS_VENDOR_TOSHIBA     0x198
 #define UFS_VENDOR_SAMSUNG     0x1CE
 #define UFS_VENDOR_SKHYNIX     0x1AD
 
-/**
- * ufs_device_info - ufs device details
- * @wmanufacturerid: card details
- * @model: card model
- */
-struct ufs_device_info {
-       u16 wmanufacturerid;
-       char model[MAX_MODEL_LEN + 1];
-};
-
 /**
  * ufs_dev_fix - ufs device quirk info
  * @card: ufs card details
  * @quirk: device quirk
  */
 struct ufs_dev_fix {
-       struct ufs_device_info card;
+       struct ufs_dev_desc card;
        unsigned int quirk;
 };
 
 #define END_FIX { { 0 }, 0 }
 
 /* add specific device quirk */
-#define UFS_FIX(_vendor, _model, _quirk) \
-               {                                         \
-                       .card.wmanufacturerid = (_vendor),\
-                       .card.model = (_model),           \
-                       .quirk = (_quirk),                \
-               }
+#define UFS_FIX(_vendor, _model, _quirk) { \
+       .card.wmanufacturerid = (_vendor),\
+       .card.model = (_model),            \
+       .quirk = (_quirk),                 \
+}
 
 /*
  * If UFS device is having issue in processing LCC (Line Control
@@ -144,7 +131,4 @@ struct ufs_dev_fix {
  */
 #define UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME        (1 << 8)
 
-struct ufs_hba;
-void ufs_advertise_fixup_device(struct ufs_hba *hba);
-
 #endif /* UFS_QUIRKS_H_ */
index 20e5e5fb048cddbb3df34e06723adfa083083835..8b721f431dd0df2cbeee9cac486667bd09def2a4 100644 (file)
@@ -45,6 +45,9 @@
 #include "ufs_quirks.h"
 #include "unipro.h"
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/ufs.h>
+
 #define UFSHCD_REQ_SENSE_SIZE  18
 
 #define UFSHCD_ENABLE_INTRS    (UTP_TRANSFER_REQ_COMPL |\
@@ -94,6 +97,9 @@
                _ret;                                                   \
        })
 
+#define ufshcd_hex_dump(prefix_str, buf, len) \
+print_hex_dump(KERN_ERR, prefix_str, DUMP_PREFIX_OFFSET, 16, 4, buf, len, false)
+
 static u32 ufs_query_desc_max_size[] = {
        QUERY_DESC_DEVICE_MAX_SIZE,
        QUERY_DESC_CONFIGURAION_MAX_SIZE,
@@ -185,6 +191,22 @@ ufs_get_pm_lvl_to_link_pwr_state(enum ufs_pm_level lvl)
        return ufs_pm_lvl_states[lvl].link_state;
 }
 
+static inline enum ufs_pm_level
+ufs_get_desired_pm_lvl_for_dev_link_state(enum ufs_dev_pwr_mode dev_state,
+                                       enum uic_link_state link_state)
+{
+       enum ufs_pm_level lvl;
+
+       for (lvl = UFS_PM_LVL_0; lvl < UFS_PM_LVL_MAX; lvl++) {
+               if ((ufs_pm_lvl_states[lvl].dev_state == dev_state) &&
+                       (ufs_pm_lvl_states[lvl].link_state == link_state))
+                       return lvl;
+       }
+
+       /* if no match found, return the level 0 */
+       return UFS_PM_LVL_0;
+}
+
 static struct ufs_dev_fix ufs_fixups[] = {
        /* UFS cards deviations table */
        UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL,
@@ -212,6 +234,7 @@ static struct ufs_dev_fix ufs_fixups[] = {
 static void ufshcd_tmc_handler(struct ufs_hba *hba);
 static void ufshcd_async_scan(void *data, async_cookie_t cookie);
 static int ufshcd_reset_and_restore(struct ufs_hba *hba);
+static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd);
 static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag);
 static void ufshcd_hba_exit(struct ufs_hba *hba);
 static int ufshcd_probe_hba(struct ufs_hba *hba);
@@ -223,6 +246,10 @@ static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba);
 static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba);
 static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba);
 static int ufshcd_host_reset_and_restore(struct ufs_hba *hba);
+static void ufshcd_resume_clkscaling(struct ufs_hba *hba);
+static void ufshcd_suspend_clkscaling(struct ufs_hba *hba);
+static void __ufshcd_suspend_clkscaling(struct ufs_hba *hba);
+static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up);
 static irqreturn_t ufshcd_intr(int irq, void *__hba);
 static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
                struct ufs_pa_layer_attr *desired_pwr_mode);
@@ -267,6 +294,214 @@ static inline void ufshcd_remove_non_printable(char *val)
                *val = ' ';
 }
 
+static void ufshcd_add_command_trace(struct ufs_hba *hba,
+               unsigned int tag, const char *str)
+{
+       sector_t lba = -1;
+       u8 opcode = 0;
+       u32 intr, doorbell;
+       struct ufshcd_lrb *lrbp;
+       int transfer_len = -1;
+
+       if (!trace_ufshcd_command_enabled())
+               return;
+
+       lrbp = &hba->lrb[tag];
+
+       if (lrbp->cmd) { /* data phase exists */
+               opcode = (u8)(*lrbp->cmd->cmnd);
+               if ((opcode == READ_10) || (opcode == WRITE_10)) {
+                       /*
+                        * Currently we only fully trace read(10) and write(10)
+                        * commands
+                        */
+                       if (lrbp->cmd->request && lrbp->cmd->request->bio)
+                               lba =
+                                 lrbp->cmd->request->bio->bi_iter.bi_sector;
+                       transfer_len = be32_to_cpu(
+                               lrbp->ucd_req_ptr->sc.exp_data_transfer_len);
+               }
+       }
+
+       intr = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
+       doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
+       trace_ufshcd_command(dev_name(hba->dev), str, tag,
+                               doorbell, transfer_len, intr, lba, opcode);
+}
+
+static void ufshcd_print_clk_freqs(struct ufs_hba *hba)
+{
+       struct ufs_clk_info *clki;
+       struct list_head *head = &hba->clk_list_head;
+
+       if (!head || list_empty(head))
+               return;
+
+       list_for_each_entry(clki, head, list) {
+               if (!IS_ERR_OR_NULL(clki->clk) && clki->min_freq &&
+                               clki->max_freq)
+                       dev_err(hba->dev, "clk: %s, rate: %u\n",
+                                       clki->name, clki->curr_freq);
+       }
+}
+
+static void ufshcd_print_uic_err_hist(struct ufs_hba *hba,
+               struct ufs_uic_err_reg_hist *err_hist, char *err_name)
+{
+       int i;
+
+       for (i = 0; i < UIC_ERR_REG_HIST_LENGTH; i++) {
+               int p = (i + err_hist->pos - 1) % UIC_ERR_REG_HIST_LENGTH;
+
+               if (err_hist->reg[p] == 0)
+                       continue;
+               dev_err(hba->dev, "%s[%d] = 0x%x at %lld us\n", err_name, i,
+                       err_hist->reg[p], ktime_to_us(err_hist->tstamp[p]));
+       }
+}
+
+static void ufshcd_print_host_regs(struct ufs_hba *hba)
+{
+       /*
+        * hex_dump reads its data without the readl macro. This might
+        * cause inconsistency issues on some platform, as the printed
+        * values may be from cache and not the most recent value.
+        * To know whether you are looking at an un-cached version verify
+        * that IORESOURCE_MEM flag is on when xxx_get_resource() is invoked
+        * during platform/pci probe function.
+        */
+       ufshcd_hex_dump("host regs: ", hba->mmio_base, UFSHCI_REG_SPACE_SIZE);
+       dev_err(hba->dev, "hba->ufs_version = 0x%x, hba->capabilities = 0x%x\n",
+               hba->ufs_version, hba->capabilities);
+       dev_err(hba->dev,
+               "hba->outstanding_reqs = 0x%x, hba->outstanding_tasks = 0x%x\n",
+               (u32)hba->outstanding_reqs, (u32)hba->outstanding_tasks);
+       dev_err(hba->dev,
+               "last_hibern8_exit_tstamp at %lld us, hibern8_exit_cnt = %d\n",
+               ktime_to_us(hba->ufs_stats.last_hibern8_exit_tstamp),
+               hba->ufs_stats.hibern8_exit_cnt);
+
+       ufshcd_print_uic_err_hist(hba, &hba->ufs_stats.pa_err, "pa_err");
+       ufshcd_print_uic_err_hist(hba, &hba->ufs_stats.dl_err, "dl_err");
+       ufshcd_print_uic_err_hist(hba, &hba->ufs_stats.nl_err, "nl_err");
+       ufshcd_print_uic_err_hist(hba, &hba->ufs_stats.tl_err, "tl_err");
+       ufshcd_print_uic_err_hist(hba, &hba->ufs_stats.dme_err, "dme_err");
+
+       ufshcd_print_clk_freqs(hba);
+
+       if (hba->vops && hba->vops->dbg_register_dump)
+               hba->vops->dbg_register_dump(hba);
+}
+
+static
+void ufshcd_print_trs(struct ufs_hba *hba, unsigned long bitmap, bool pr_prdt)
+{
+       struct ufshcd_lrb *lrbp;
+       int prdt_length;
+       int tag;
+
+       for_each_set_bit(tag, &bitmap, hba->nutrs) {
+               lrbp = &hba->lrb[tag];
+
+               dev_err(hba->dev, "UPIU[%d] - issue time %lld us\n",
+                               tag, ktime_to_us(lrbp->issue_time_stamp));
+               dev_err(hba->dev,
+                       "UPIU[%d] - Transfer Request Descriptor phys@0x%llx\n",
+                       tag, (u64)lrbp->utrd_dma_addr);
+
+               ufshcd_hex_dump("UPIU TRD: ", lrbp->utr_descriptor_ptr,
+                               sizeof(struct utp_transfer_req_desc));
+               dev_err(hba->dev, "UPIU[%d] - Request UPIU phys@0x%llx\n", tag,
+                       (u64)lrbp->ucd_req_dma_addr);
+               ufshcd_hex_dump("UPIU REQ: ", lrbp->ucd_req_ptr,
+                               sizeof(struct utp_upiu_req));
+               dev_err(hba->dev, "UPIU[%d] - Response UPIU phys@0x%llx\n", tag,
+                       (u64)lrbp->ucd_rsp_dma_addr);
+               ufshcd_hex_dump("UPIU RSP: ", lrbp->ucd_rsp_ptr,
+                               sizeof(struct utp_upiu_rsp));
+
+               prdt_length = le16_to_cpu(
+                       lrbp->utr_descriptor_ptr->prd_table_length);
+               dev_err(hba->dev,
+                       "UPIU[%d] - PRDT - %d entries  phys@0x%llx\n",
+                       tag, prdt_length,
+                       (u64)lrbp->ucd_prdt_dma_addr);
+
+               if (pr_prdt)
+                       ufshcd_hex_dump("UPIU PRDT: ", lrbp->ucd_prdt_ptr,
+                               sizeof(struct ufshcd_sg_entry) * prdt_length);
+       }
+}
+
+static void ufshcd_print_tmrs(struct ufs_hba *hba, unsigned long bitmap)
+{
+       struct utp_task_req_desc *tmrdp;
+       int tag;
+
+       for_each_set_bit(tag, &bitmap, hba->nutmrs) {
+               tmrdp = &hba->utmrdl_base_addr[tag];
+               dev_err(hba->dev, "TM[%d] - Task Management Header\n", tag);
+               ufshcd_hex_dump("TM TRD: ", &tmrdp->header,
+                               sizeof(struct request_desc_header));
+               dev_err(hba->dev, "TM[%d] - Task Management Request UPIU\n",
+                               tag);
+               ufshcd_hex_dump("TM REQ: ", tmrdp->task_req_upiu,
+                               sizeof(struct utp_upiu_req));
+               dev_err(hba->dev, "TM[%d] - Task Management Response UPIU\n",
+                               tag);
+               ufshcd_hex_dump("TM RSP: ", tmrdp->task_rsp_upiu,
+                               sizeof(struct utp_task_req_desc));
+       }
+}
+
+static void ufshcd_print_host_state(struct ufs_hba *hba)
+{
+       dev_err(hba->dev, "UFS Host state=%d\n", hba->ufshcd_state);
+       dev_err(hba->dev, "lrb in use=0x%lx, outstanding reqs=0x%lx tasks=0x%lx\n",
+               hba->lrb_in_use, hba->outstanding_tasks, hba->outstanding_reqs);
+       dev_err(hba->dev, "saved_err=0x%x, saved_uic_err=0x%x\n",
+               hba->saved_err, hba->saved_uic_err);
+       dev_err(hba->dev, "Device power mode=%d, UIC link state=%d\n",
+               hba->curr_dev_pwr_mode, hba->uic_link_state);
+       dev_err(hba->dev, "PM in progress=%d, sys. suspended=%d\n",
+               hba->pm_op_in_progress, hba->is_sys_suspended);
+       dev_err(hba->dev, "Auto BKOPS=%d, Host self-block=%d\n",
+               hba->auto_bkops_enabled, hba->host->host_self_blocked);
+       dev_err(hba->dev, "Clk gate=%d\n", hba->clk_gating.state);
+       dev_err(hba->dev, "error handling flags=0x%x, req. abort count=%d\n",
+               hba->eh_flags, hba->req_abort_count);
+       dev_err(hba->dev, "Host capabilities=0x%x, caps=0x%x\n",
+               hba->capabilities, hba->caps);
+       dev_err(hba->dev, "quirks=0x%x, dev. quirks=0x%x\n", hba->quirks,
+               hba->dev_quirks);
+}
+
+/**
+ * ufshcd_print_pwr_info - print power params as saved in hba
+ * power info
+ * @hba: per-adapter instance
+ */
+static void ufshcd_print_pwr_info(struct ufs_hba *hba)
+{
+       static const char * const names[] = {
+               "INVALID MODE",
+               "FAST MODE",
+               "SLOW_MODE",
+               "INVALID MODE",
+               "FASTAUTO_MODE",
+               "SLOWAUTO_MODE",
+               "INVALID MODE",
+       };
+
+       dev_err(hba->dev, "%s:[RX, TX]: gear=[%d, %d], lane[%d, %d], pwr[%s, %s], rate = %d\n",
+                __func__,
+                hba->pwr_info.gear_rx, hba->pwr_info.gear_tx,
+                hba->pwr_info.lane_rx, hba->pwr_info.lane_tx,
+                names[hba->pwr_info.pwr_rx],
+                names[hba->pwr_info.pwr_tx],
+                hba->pwr_info.hs_rate);
+}
+
 /*
  * ufshcd_wait_for_register - wait for register value to change
  * @hba - per-adapter interface
@@ -605,6 +840,28 @@ static inline int ufshcd_is_hba_active(struct ufs_hba *hba)
        return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1;
 }
 
+static const char *ufschd_uic_link_state_to_string(
+                       enum uic_link_state state)
+{
+       switch (state) {
+       case UIC_LINK_OFF_STATE:        return "OFF";
+       case UIC_LINK_ACTIVE_STATE:     return "ACTIVE";
+       case UIC_LINK_HIBERN8_STATE:    return "HIBERN8";
+       default:                        return "UNKNOWN";
+       }
+}
+
+static const char *ufschd_ufs_dev_pwr_mode_to_string(
+                       enum ufs_dev_pwr_mode state)
+{
+       switch (state) {
+       case UFS_ACTIVE_PWR_MODE:       return "ACTIVE";
+       case UFS_SLEEP_PWR_MODE:        return "SLEEP";
+       case UFS_POWERDOWN_PWR_MODE:    return "POWERDOWN";
+       default:                        return "UNKNOWN";
+       }
+}
+
 u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba)
 {
        /* HCI version 1.0 and 1.1 supports UniPro 1.41 */
@@ -633,20 +890,523 @@ static bool ufshcd_is_unipro_pa_params_tuning_req(struct ufs_hba *hba)
                return false;
 }
 
+static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up)
+{
+       int ret = 0;
+       struct ufs_clk_info *clki;
+       struct list_head *head = &hba->clk_list_head;
+       ktime_t start = ktime_get();
+       bool clk_state_changed = false;
+
+       if (!head || list_empty(head))
+               goto out;
+
+       ret = ufshcd_vops_clk_scale_notify(hba, scale_up, PRE_CHANGE);
+       if (ret)
+               return ret;
+
+       list_for_each_entry(clki, head, list) {
+               if (!IS_ERR_OR_NULL(clki->clk)) {
+                       if (scale_up && clki->max_freq) {
+                               if (clki->curr_freq == clki->max_freq)
+                                       continue;
+
+                               clk_state_changed = true;
+                               ret = clk_set_rate(clki->clk, clki->max_freq);
+                               if (ret) {
+                                       dev_err(hba->dev, "%s: %s clk set rate(%dHz) failed, %d\n",
+                                               __func__, clki->name,
+                                               clki->max_freq, ret);
+                                       break;
+                               }
+                               trace_ufshcd_clk_scaling(dev_name(hba->dev),
+                                               "scaled up", clki->name,
+                                               clki->curr_freq,
+                                               clki->max_freq);
+
+                               clki->curr_freq = clki->max_freq;
+
+                       } else if (!scale_up && clki->min_freq) {
+                               if (clki->curr_freq == clki->min_freq)
+                                       continue;
+
+                               clk_state_changed = true;
+                               ret = clk_set_rate(clki->clk, clki->min_freq);
+                               if (ret) {
+                                       dev_err(hba->dev, "%s: %s clk set rate(%dHz) failed, %d\n",
+                                               __func__, clki->name,
+                                               clki->min_freq, ret);
+                                       break;
+                               }
+                               trace_ufshcd_clk_scaling(dev_name(hba->dev),
+                                               "scaled down", clki->name,
+                                               clki->curr_freq,
+                                               clki->min_freq);
+                               clki->curr_freq = clki->min_freq;
+                       }
+               }
+               dev_dbg(hba->dev, "%s: clk: %s, rate: %lu\n", __func__,
+                               clki->name, clk_get_rate(clki->clk));
+       }
+
+       ret = ufshcd_vops_clk_scale_notify(hba, scale_up, POST_CHANGE);
+
+out:
+       if (clk_state_changed)
+               trace_ufshcd_profile_clk_scaling(dev_name(hba->dev),
+                       (scale_up ? "up" : "down"),
+                       ktime_to_us(ktime_sub(ktime_get(), start)), ret);
+       return ret;
+}
+
+/**
+ * ufshcd_is_devfreq_scaling_required - check if scaling is required or not
+ * @hba: per adapter instance
+ * @scale_up: True if scaling up and false if scaling down
+ *
+ * Returns true if scaling is required, false otherwise.
+ */
+static bool ufshcd_is_devfreq_scaling_required(struct ufs_hba *hba,
+                                              bool scale_up)
+{
+       struct ufs_clk_info *clki;
+       struct list_head *head = &hba->clk_list_head;
+
+       if (!head || list_empty(head))
+               return false;
+
+       list_for_each_entry(clki, head, list) {
+               if (!IS_ERR_OR_NULL(clki->clk)) {
+                       if (scale_up && clki->max_freq) {
+                               if (clki->curr_freq == clki->max_freq)
+                                       continue;
+                               return true;
+                       } else if (!scale_up && clki->min_freq) {
+                               if (clki->curr_freq == clki->min_freq)
+                                       continue;
+                               return true;
+                       }
+               }
+       }
+
+       return false;
+}
+
+static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba,
+                                       u64 wait_timeout_us)
+{
+       unsigned long flags;
+       int ret = 0;
+       u32 tm_doorbell;
+       u32 tr_doorbell;
+       bool timeout = false, do_last_check = false;
+       ktime_t start;
+
+       ufshcd_hold(hba, false);
+       spin_lock_irqsave(hba->host->host_lock, flags);
+       /*
+        * Wait for all the outstanding tasks/transfer requests.
+        * Verify by checking the doorbell registers are clear.
+        */
+       start = ktime_get();
+       do {
+               if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL) {
+                       ret = -EBUSY;
+                       goto out;
+               }
+
+               tm_doorbell = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL);
+               tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
+               if (!tm_doorbell && !tr_doorbell) {
+                       timeout = false;
+                       break;
+               } else if (do_last_check) {
+                       break;
+               }
+
+               spin_unlock_irqrestore(hba->host->host_lock, flags);
+               schedule();
+               if (ktime_to_us(ktime_sub(ktime_get(), start)) >
+                   wait_timeout_us) {
+                       timeout = true;
+                       /*
+                        * We might have scheduled out for long time so make
+                        * sure to check if doorbells are cleared by this time
+                        * or not.
+                        */
+                       do_last_check = true;
+               }
+               spin_lock_irqsave(hba->host->host_lock, flags);
+       } while (tm_doorbell || tr_doorbell);
+
+       if (timeout) {
+               dev_err(hba->dev,
+                       "%s: timedout waiting for doorbell to clear (tm=0x%x, tr=0x%x)\n",
+                       __func__, tm_doorbell, tr_doorbell);
+               ret = -EBUSY;
+       }
+out:
+       spin_unlock_irqrestore(hba->host->host_lock, flags);
+       ufshcd_release(hba);
+       return ret;
+}
+
+/**
+ * ufshcd_scale_gear - scale up/down UFS gear
+ * @hba: per adapter instance
+ * @scale_up: True for scaling up gear and false for scaling down
+ *
+ * Returns 0 for success,
+ * Returns -EBUSY if scaling can't happen at this time
+ * Returns non-zero for any other errors
+ */
+static int ufshcd_scale_gear(struct ufs_hba *hba, bool scale_up)
+{
+       #define UFS_MIN_GEAR_TO_SCALE_DOWN      UFS_HS_G1
+       int ret = 0;
+       struct ufs_pa_layer_attr new_pwr_info;
+
+       if (scale_up) {
+               memcpy(&new_pwr_info, &hba->clk_scaling.saved_pwr_info.info,
+                      sizeof(struct ufs_pa_layer_attr));
+       } else {
+               memcpy(&new_pwr_info, &hba->pwr_info,
+                      sizeof(struct ufs_pa_layer_attr));
+
+               if (hba->pwr_info.gear_tx > UFS_MIN_GEAR_TO_SCALE_DOWN
+                   || hba->pwr_info.gear_rx > UFS_MIN_GEAR_TO_SCALE_DOWN) {
+                       /* save the current power mode */
+                       memcpy(&hba->clk_scaling.saved_pwr_info.info,
+                               &hba->pwr_info,
+                               sizeof(struct ufs_pa_layer_attr));
+
+                       /* scale down gear */
+                       new_pwr_info.gear_tx = UFS_MIN_GEAR_TO_SCALE_DOWN;
+                       new_pwr_info.gear_rx = UFS_MIN_GEAR_TO_SCALE_DOWN;
+               }
+       }
+
+       /* check if the power mode needs to be changed or not? */
+       ret = ufshcd_change_power_mode(hba, &new_pwr_info);
+
+       if (ret)
+               dev_err(hba->dev, "%s: failed err %d, old gear: (tx %d rx %d), new gear: (tx %d rx %d)",
+                       __func__, ret,
+                       hba->pwr_info.gear_tx, hba->pwr_info.gear_rx,
+                       new_pwr_info.gear_tx, new_pwr_info.gear_rx);
+
+       return ret;
+}
+
+static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba)
+{
+       #define DOORBELL_CLR_TOUT_US            (1000 * 1000) /* 1 sec */
+       int ret = 0;
+       /*
+        * make sure that there are no outstanding requests when
+        * clock scaling is in progress
+        */
+       scsi_block_requests(hba->host);
+       down_write(&hba->clk_scaling_lock);
+       if (ufshcd_wait_for_doorbell_clr(hba, DOORBELL_CLR_TOUT_US)) {
+               ret = -EBUSY;
+               up_write(&hba->clk_scaling_lock);
+               scsi_unblock_requests(hba->host);
+       }
+
+       return ret;
+}
+
+static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba)
+{
+       up_write(&hba->clk_scaling_lock);
+       scsi_unblock_requests(hba->host);
+}
+
+/**
+ * ufshcd_devfreq_scale - scale up/down UFS clocks and gear
+ * @hba: per adapter instance
+ * @scale_up: True for scaling up and false for scalin down
+ *
+ * Returns 0 for success,
+ * Returns -EBUSY if scaling can't happen at this time
+ * Returns non-zero for any other errors
+ */
+static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up)
+{
+       int ret = 0;
+
+       /* let's not get into low power until clock scaling is completed */
+       ufshcd_hold(hba, false);
+
+       ret = ufshcd_clock_scaling_prepare(hba);
+       if (ret)
+               return ret;
+
+       /* scale down the gear before scaling down clocks */
+       if (!scale_up) {
+               ret = ufshcd_scale_gear(hba, false);
+               if (ret)
+                       goto out;
+       }
+
+       ret = ufshcd_scale_clks(hba, scale_up);
+       if (ret) {
+               if (!scale_up)
+                       ufshcd_scale_gear(hba, true);
+               goto out;
+       }
+
+       /* scale up the gear after scaling up clocks */
+       if (scale_up) {
+               ret = ufshcd_scale_gear(hba, true);
+               if (ret) {
+                       ufshcd_scale_clks(hba, false);
+                       goto out;
+               }
+       }
+
+       ret = ufshcd_vops_clk_scale_notify(hba, scale_up, POST_CHANGE);
+
+out:
+       ufshcd_clock_scaling_unprepare(hba);
+       ufshcd_release(hba);
+       return ret;
+}
+
+static void ufshcd_clk_scaling_suspend_work(struct work_struct *work)
+{
+       struct ufs_hba *hba = container_of(work, struct ufs_hba,
+                                          clk_scaling.suspend_work);
+       unsigned long irq_flags;
+
+       spin_lock_irqsave(hba->host->host_lock, irq_flags);
+       if (hba->clk_scaling.active_reqs || hba->clk_scaling.is_suspended) {
+               spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+               return;
+       }
+       hba->clk_scaling.is_suspended = true;
+       spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+
+       __ufshcd_suspend_clkscaling(hba);
+}
+
+static void ufshcd_clk_scaling_resume_work(struct work_struct *work)
+{
+       struct ufs_hba *hba = container_of(work, struct ufs_hba,
+                                          clk_scaling.resume_work);
+       unsigned long irq_flags;
+
+       spin_lock_irqsave(hba->host->host_lock, irq_flags);
+       if (!hba->clk_scaling.is_suspended) {
+               spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+               return;
+       }
+       hba->clk_scaling.is_suspended = false;
+       spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+
+       devfreq_resume_device(hba->devfreq);
+}
+
+static int ufshcd_devfreq_target(struct device *dev,
+                               unsigned long *freq, u32 flags)
+{
+       int ret = 0;
+       struct ufs_hba *hba = dev_get_drvdata(dev);
+       ktime_t start;
+       bool scale_up, sched_clk_scaling_suspend_work = false;
+       unsigned long irq_flags;
+
+       if (!ufshcd_is_clkscaling_supported(hba))
+               return -EINVAL;
+
+       if ((*freq > 0) && (*freq < UINT_MAX)) {
+               dev_err(hba->dev, "%s: invalid freq = %lu\n", __func__, *freq);
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(hba->host->host_lock, irq_flags);
+       if (ufshcd_eh_in_progress(hba)) {
+               spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+               return 0;
+       }
+
+       if (!hba->clk_scaling.active_reqs)
+               sched_clk_scaling_suspend_work = true;
+
+       scale_up = (*freq == UINT_MAX) ? true : false;
+       if (!ufshcd_is_devfreq_scaling_required(hba, scale_up)) {
+               spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+               ret = 0;
+               goto out; /* no state change required */
+       }
+       spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+
+       start = ktime_get();
+       ret = ufshcd_devfreq_scale(hba, scale_up);
+
+       trace_ufshcd_profile_clk_scaling(dev_name(hba->dev),
+               (scale_up ? "up" : "down"),
+               ktime_to_us(ktime_sub(ktime_get(), start)), ret);
+
+out:
+       if (sched_clk_scaling_suspend_work)
+               queue_work(hba->clk_scaling.workq,
+                          &hba->clk_scaling.suspend_work);
+
+       return ret;
+}
+
+
+static int ufshcd_devfreq_get_dev_status(struct device *dev,
+               struct devfreq_dev_status *stat)
+{
+       struct ufs_hba *hba = dev_get_drvdata(dev);
+       struct ufs_clk_scaling *scaling = &hba->clk_scaling;
+       unsigned long flags;
+
+       if (!ufshcd_is_clkscaling_supported(hba))
+               return -EINVAL;
+
+       memset(stat, 0, sizeof(*stat));
+
+       spin_lock_irqsave(hba->host->host_lock, flags);
+       if (!scaling->window_start_t)
+               goto start_window;
+
+       if (scaling->is_busy_started)
+               scaling->tot_busy_t += ktime_to_us(ktime_sub(ktime_get(),
+                                       scaling->busy_start_t));
+
+       stat->total_time = jiffies_to_usecs((long)jiffies -
+                               (long)scaling->window_start_t);
+       stat->busy_time = scaling->tot_busy_t;
+start_window:
+       scaling->window_start_t = jiffies;
+       scaling->tot_busy_t = 0;
+
+       if (hba->outstanding_reqs) {
+               scaling->busy_start_t = ktime_get();
+               scaling->is_busy_started = true;
+       } else {
+               scaling->busy_start_t = 0;
+               scaling->is_busy_started = false;
+       }
+       spin_unlock_irqrestore(hba->host->host_lock, flags);
+       return 0;
+}
+
+static struct devfreq_dev_profile ufs_devfreq_profile = {
+       .polling_ms     = 100,
+       .target         = ufshcd_devfreq_target,
+       .get_dev_status = ufshcd_devfreq_get_dev_status,
+};
+
+static void __ufshcd_suspend_clkscaling(struct ufs_hba *hba)
+{
+       unsigned long flags;
+
+       devfreq_suspend_device(hba->devfreq);
+       spin_lock_irqsave(hba->host->host_lock, flags);
+       hba->clk_scaling.window_start_t = 0;
+       spin_unlock_irqrestore(hba->host->host_lock, flags);
+}
+
 static void ufshcd_suspend_clkscaling(struct ufs_hba *hba)
 {
-       if (ufshcd_is_clkscaling_enabled(hba)) {
-               devfreq_suspend_device(hba->devfreq);
-               hba->clk_scaling.window_start_t = 0;
+       unsigned long flags;
+       bool suspend = false;
+
+       if (!ufshcd_is_clkscaling_supported(hba))
+               return;
+
+       spin_lock_irqsave(hba->host->host_lock, flags);
+       if (!hba->clk_scaling.is_suspended) {
+               suspend = true;
+               hba->clk_scaling.is_suspended = true;
        }
+       spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+       if (suspend)
+               __ufshcd_suspend_clkscaling(hba);
 }
 
 static void ufshcd_resume_clkscaling(struct ufs_hba *hba)
 {
-       if (ufshcd_is_clkscaling_enabled(hba))
+       unsigned long flags;
+       bool resume = false;
+
+       if (!ufshcd_is_clkscaling_supported(hba))
+               return;
+
+       spin_lock_irqsave(hba->host->host_lock, flags);
+       if (hba->clk_scaling.is_suspended) {
+               resume = true;
+               hba->clk_scaling.is_suspended = false;
+       }
+       spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+       if (resume)
                devfreq_resume_device(hba->devfreq);
 }
 
+static ssize_t ufshcd_clkscale_enable_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct ufs_hba *hba = dev_get_drvdata(dev);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", hba->clk_scaling.is_allowed);
+}
+
+static ssize_t ufshcd_clkscale_enable_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct ufs_hba *hba = dev_get_drvdata(dev);
+       u32 value;
+       int err;
+
+       if (kstrtou32(buf, 0, &value))
+               return -EINVAL;
+
+       value = !!value;
+       if (value == hba->clk_scaling.is_allowed)
+               goto out;
+
+       pm_runtime_get_sync(hba->dev);
+       ufshcd_hold(hba, false);
+
+       cancel_work_sync(&hba->clk_scaling.suspend_work);
+       cancel_work_sync(&hba->clk_scaling.resume_work);
+
+       hba->clk_scaling.is_allowed = value;
+
+       if (value) {
+               ufshcd_resume_clkscaling(hba);
+       } else {
+               ufshcd_suspend_clkscaling(hba);
+               err = ufshcd_devfreq_scale(hba, true);
+               if (err)
+                       dev_err(hba->dev, "%s: failed to scale clocks up %d\n",
+                                       __func__, err);
+       }
+
+       ufshcd_release(hba);
+       pm_runtime_put_sync(hba->dev);
+out:
+       return count;
+}
+
+static void ufshcd_clkscaling_init_sysfs(struct ufs_hba *hba)
+{
+       hba->clk_scaling.enable_attr.show = ufshcd_clkscale_enable_show;
+       hba->clk_scaling.enable_attr.store = ufshcd_clkscale_enable_store;
+       sysfs_attr_init(&hba->clk_scaling.enable_attr.attr);
+       hba->clk_scaling.enable_attr.attr.name = "clkscale_enable";
+       hba->clk_scaling.enable_attr.attr.mode = 0644;
+       if (device_create_file(hba->dev, &hba->clk_scaling.enable_attr))
+               dev_err(hba->dev, "Failed to create sysfs for clkscale_enable\n");
+}
+
 static void ufshcd_ungate_work(struct work_struct *work)
 {
        int ret;
@@ -680,7 +1440,6 @@ static void ufshcd_ungate_work(struct work_struct *work)
                hba->clk_gating.is_suspended = false;
        }
 unblock_reqs:
-       ufshcd_resume_clkscaling(hba);
        scsi_unblock_requests(hba->host);
 }
 
@@ -727,6 +1486,8 @@ start:
        case REQ_CLKS_OFF:
                if (cancel_delayed_work(&hba->clk_gating.gate_work)) {
                        hba->clk_gating.state = CLKS_ON;
+                       trace_ufshcd_clk_gating(dev_name(hba->dev),
+                                               hba->clk_gating.state);
                        break;
                }
                /*
@@ -737,6 +1498,8 @@ start:
        case CLKS_OFF:
                scsi_block_requests(hba->host);
                hba->clk_gating.state = REQ_CLKS_ON;
+               trace_ufshcd_clk_gating(dev_name(hba->dev),
+                                       hba->clk_gating.state);
                schedule_work(&hba->clk_gating.ungate_work);
                /*
                 * fall through to check if we should wait for this
@@ -781,6 +1544,8 @@ static void ufshcd_gate_work(struct work_struct *work)
        if (hba->clk_gating.is_suspended ||
                (hba->clk_gating.state == REQ_CLKS_ON)) {
                hba->clk_gating.state = CLKS_ON;
+               trace_ufshcd_clk_gating(dev_name(hba->dev),
+                                       hba->clk_gating.state);
                goto rel_lock;
        }
 
@@ -796,13 +1561,13 @@ static void ufshcd_gate_work(struct work_struct *work)
        if (ufshcd_can_hibern8_during_gating(hba)) {
                if (ufshcd_uic_hibern8_enter(hba)) {
                        hba->clk_gating.state = CLKS_ON;
+                       trace_ufshcd_clk_gating(dev_name(hba->dev),
+                                               hba->clk_gating.state);
                        goto out;
                }
                ufshcd_set_link_hibern8(hba);
        }
 
-       ufshcd_suspend_clkscaling(hba);
-
        if (!ufshcd_is_link_active(hba))
                ufshcd_setup_clocks(hba, false);
        else
@@ -819,9 +1584,11 @@ static void ufshcd_gate_work(struct work_struct *work)
         * new requests arriving before the current cancel work is done.
         */
        spin_lock_irqsave(hba->host->host_lock, flags);
-       if (hba->clk_gating.state == REQ_CLKS_OFF)
+       if (hba->clk_gating.state == REQ_CLKS_OFF) {
                hba->clk_gating.state = CLKS_OFF;
-
+               trace_ufshcd_clk_gating(dev_name(hba->dev),
+                                       hba->clk_gating.state);
+       }
 rel_lock:
        spin_unlock_irqrestore(hba->host->host_lock, flags);
 out:
@@ -844,6 +1611,7 @@ static void __ufshcd_release(struct ufs_hba *hba)
                return;
 
        hba->clk_gating.state = REQ_CLKS_OFF;
+       trace_ufshcd_clk_gating(dev_name(hba->dev), hba->clk_gating.state);
        schedule_delayed_work(&hba->clk_gating.gate_work,
                        msecs_to_jiffies(hba->clk_gating.delay_ms));
 }
@@ -881,6 +1649,41 @@ static ssize_t ufshcd_clkgate_delay_store(struct device *dev,
        return count;
 }
 
+static ssize_t ufshcd_clkgate_enable_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct ufs_hba *hba = dev_get_drvdata(dev);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", hba->clk_gating.is_enabled);
+}
+
+static ssize_t ufshcd_clkgate_enable_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct ufs_hba *hba = dev_get_drvdata(dev);
+       unsigned long flags;
+       u32 value;
+
+       if (kstrtou32(buf, 0, &value))
+               return -EINVAL;
+
+       value = !!value;
+       if (value == hba->clk_gating.is_enabled)
+               goto out;
+
+       if (value) {
+               ufshcd_release(hba);
+       } else {
+               spin_lock_irqsave(hba->host->host_lock, flags);
+               hba->clk_gating.active_reqs++;
+               spin_unlock_irqrestore(hba->host->host_lock, flags);
+       }
+
+       hba->clk_gating.is_enabled = value;
+out:
+       return count;
+}
+
 static void ufshcd_init_clk_gating(struct ufs_hba *hba)
 {
        if (!ufshcd_is_clkgating_allowed(hba))
@@ -890,13 +1693,23 @@ static void ufshcd_init_clk_gating(struct ufs_hba *hba)
        INIT_DELAYED_WORK(&hba->clk_gating.gate_work, ufshcd_gate_work);
        INIT_WORK(&hba->clk_gating.ungate_work, ufshcd_ungate_work);
 
+       hba->clk_gating.is_enabled = true;
+
        hba->clk_gating.delay_attr.show = ufshcd_clkgate_delay_show;
        hba->clk_gating.delay_attr.store = ufshcd_clkgate_delay_store;
        sysfs_attr_init(&hba->clk_gating.delay_attr.attr);
        hba->clk_gating.delay_attr.attr.name = "clkgate_delay_ms";
-       hba->clk_gating.delay_attr.attr.mode = S_IRUGO | S_IWUSR;
+       hba->clk_gating.delay_attr.attr.mode = 0644;
        if (device_create_file(hba->dev, &hba->clk_gating.delay_attr))
                dev_err(hba->dev, "Failed to create sysfs for clkgate_delay\n");
+
+       hba->clk_gating.enable_attr.show = ufshcd_clkgate_enable_show;
+       hba->clk_gating.enable_attr.store = ufshcd_clkgate_enable_store;
+       sysfs_attr_init(&hba->clk_gating.enable_attr.attr);
+       hba->clk_gating.enable_attr.attr.name = "clkgate_enable";
+       hba->clk_gating.enable_attr.attr.mode = 0644;
+       if (device_create_file(hba->dev, &hba->clk_gating.enable_attr))
+               dev_err(hba->dev, "Failed to create sysfs for clkgate_enable\n");
 }
 
 static void ufshcd_exit_clk_gating(struct ufs_hba *hba)
@@ -904,6 +1717,7 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba)
        if (!ufshcd_is_clkgating_allowed(hba))
                return;
        device_remove_file(hba->dev, &hba->clk_gating.delay_attr);
+       device_remove_file(hba->dev, &hba->clk_gating.enable_attr);
        cancel_work_sync(&hba->clk_gating.ungate_work);
        cancel_delayed_work_sync(&hba->clk_gating.gate_work);
 }
@@ -911,9 +1725,27 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba)
 /* Must be called with host lock acquired */
 static void ufshcd_clk_scaling_start_busy(struct ufs_hba *hba)
 {
-       if (!ufshcd_is_clkscaling_enabled(hba))
+       bool queue_resume_work = false;
+
+       if (!ufshcd_is_clkscaling_supported(hba))
                return;
 
+       if (!hba->clk_scaling.active_reqs++)
+               queue_resume_work = true;
+
+       if (!hba->clk_scaling.is_allowed || hba->pm_op_in_progress)
+               return;
+
+       if (queue_resume_work)
+               queue_work(hba->clk_scaling.workq,
+                          &hba->clk_scaling.resume_work);
+
+       if (!hba->clk_scaling.window_start_t) {
+               hba->clk_scaling.window_start_t = jiffies;
+               hba->clk_scaling.tot_busy_t = 0;
+               hba->clk_scaling.is_busy_started = false;
+       }
+
        if (!hba->clk_scaling.is_busy_started) {
                hba->clk_scaling.busy_start_t = ktime_get();
                hba->clk_scaling.is_busy_started = true;
@@ -924,7 +1756,7 @@ static void ufshcd_clk_scaling_update_busy(struct ufs_hba *hba)
 {
        struct ufs_clk_scaling *scaling = &hba->clk_scaling;
 
-       if (!ufshcd_is_clkscaling_enabled(hba))
+       if (!ufshcd_is_clkscaling_supported(hba))
                return;
 
        if (!hba->outstanding_reqs && scaling->is_busy_started) {
@@ -942,11 +1774,13 @@ static void ufshcd_clk_scaling_update_busy(struct ufs_hba *hba)
 static inline
 void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
 {
+       hba->lrb[task_tag].issue_time_stamp = ktime_get();
        ufshcd_clk_scaling_start_busy(hba);
        __set_bit(task_tag, &hba->outstanding_reqs);
        ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL);
        /* Make sure that doorbell is committed immediately */
        wmb();
+       ufshcd_add_command_trace(hba, task_tag, "send");
 }
 
 /**
@@ -1484,6 +2318,9 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
                BUG();
        }
 
+       if (!down_read_trylock(&hba->clk_scaling_lock))
+               return SCSI_MLQUEUE_HOST_BUSY;
+
        spin_lock_irqsave(hba->host->host_lock, flags);
        switch (hba->ufshcd_state) {
        case UFSHCD_STATE_OPERATIONAL:
@@ -1512,6 +2349,8 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
        }
        spin_unlock_irqrestore(hba->host->host_lock, flags);
 
+       hba->req_abort_count = 0;
+
        /* acquire the tag to make sure device cmds don't use it */
        if (test_and_set_bit_lock(tag, &hba->lrb_in_use)) {
                /*
@@ -1541,6 +2380,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
        lrbp->task_tag = tag;
        lrbp->lun = ufshcd_scsi_to_upiu_lun(cmd->device->lun);
        lrbp->intr_cmd = !ufshcd_is_intr_aggr_allowed(hba) ? true : false;
+       lrbp->req_abort_skip = false;
 
        ufshcd_comp_scsi_upiu(hba, lrbp);
 
@@ -1560,6 +2400,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
 out_unlock:
        spin_unlock_irqrestore(hba->host->host_lock, flags);
 out:
+       up_read(&hba->clk_scaling_lock);
        return err;
 }
 
@@ -1622,6 +2463,7 @@ ufshcd_dev_cmd_completion(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
        int resp;
        int err = 0;
 
+       hba->ufs_stats.last_hibern8_exit_tstamp = ktime_set(0, 0);
        resp = ufshcd_get_req_rsp(lrbp->ucd_rsp_ptr);
 
        switch (resp) {
@@ -1748,6 +2590,8 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba,
        struct completion wait;
        unsigned long flags;
 
+       down_read(&hba->clk_scaling_lock);
+
        /*
         * Get free slot, sleep if slots are unavailable.
         * Even though we use wait_event() which sleeps indefinitely,
@@ -1776,6 +2620,7 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba,
 out_put_tag:
        ufshcd_put_dev_cmd_tag(hba, tag);
        wake_up(&hba->dev_cmd.tag_wq);
+       up_read(&hba->clk_scaling_lock);
        return err;
 }
 
@@ -2073,9 +2918,11 @@ out:
  * The buf_len parameter will contain, on return, the length parameter
  * received on the response.
  */
-int ufshcd_query_descriptor_retry(struct ufs_hba *hba,
-                       enum query_opcode opcode, enum desc_idn idn, u8 index,
-                       u8 selector, u8 *desc_buf, int *buf_len)
+static int ufshcd_query_descriptor_retry(struct ufs_hba *hba,
+                                        enum query_opcode opcode,
+                                        enum desc_idn idn, u8 index,
+                                        u8 selector,
+                                        u8 *desc_buf, int *buf_len)
 {
        int err;
        int retries;
@@ -2089,7 +2936,6 @@ int ufshcd_query_descriptor_retry(struct ufs_hba *hba,
 
        return err;
 }
-EXPORT_SYMBOL(ufshcd_query_descriptor_retry);
 
 /**
  * ufshcd_read_desc_param - read the specified descriptor parameter
@@ -2207,11 +3053,10 @@ static inline int ufshcd_read_power_desc(struct ufs_hba *hba,
        return err;
 }
 
-int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size)
+static int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size)
 {
        return ufshcd_read_desc(hba, QUERY_DESC_IDN_DEVICE, 0, buf, size);
 }
-EXPORT_SYMBOL(ufshcd_read_device_desc);
 
 /**
  * ufshcd_read_string_desc - read string descriptor
@@ -2223,8 +3068,9 @@ EXPORT_SYMBOL(ufshcd_read_device_desc);
  *
  * Return 0 in case of success, non-zero otherwise
  */
-int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, u8 *buf,
-                               u32 size, bool ascii)
+#define ASCII_STD true
+static int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index,
+                                  u8 *buf, u32 size, bool ascii)
 {
        int err = 0;
 
@@ -2280,7 +3126,6 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, u8 *buf,
 out:
        return err;
 }
-EXPORT_SYMBOL(ufshcd_read_string_desc);
 
 /**
  * ufshcd_read_unit_desc_param - read the specified unit descriptor parameter
@@ -2453,12 +3298,19 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba)
                }
 
                hba->lrb[i].utr_descriptor_ptr = (utrdlp + i);
+               hba->lrb[i].utrd_dma_addr = hba->utrdl_dma_addr +
+                               (i * sizeof(struct utp_transfer_req_desc));
                hba->lrb[i].ucd_req_ptr =
                        (struct utp_upiu_req *)(cmd_descp + i);
+               hba->lrb[i].ucd_req_dma_addr = cmd_desc_element_addr;
                hba->lrb[i].ucd_rsp_ptr =
                        (struct utp_upiu_rsp *)cmd_descp[i].response_upiu;
+               hba->lrb[i].ucd_rsp_dma_addr = cmd_desc_element_addr +
+                               response_offset;
                hba->lrb[i].ucd_prdt_ptr =
                        (struct ufshcd_sg_entry *)cmd_descp[i].prd_table;
+               hba->lrb[i].ucd_prdt_dma_addr = cmd_desc_element_addr +
+                               prdt_offset;
        }
 }
 
@@ -2482,7 +3334,7 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
 
        ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
        if (ret)
-               dev_err(hba->dev,
+               dev_dbg(hba->dev,
                        "dme-link-startup: error code %d\n", ret);
        return ret;
 }
@@ -2702,6 +3554,12 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd)
                ret = (status != PWR_OK) ? status : -1;
        }
 out:
+       if (ret) {
+               ufshcd_print_host_state(hba);
+               ufshcd_print_pwr_info(hba);
+               ufshcd_print_host_regs(hba);
+       }
+
        spin_lock_irqsave(hba->host->host_lock, flags);
        hba->active_uic_cmd = NULL;
        hba->uic_async_done = NULL;
@@ -2776,11 +3634,14 @@ static int __ufshcd_uic_hibern8_enter(struct ufs_hba *hba)
 {
        int ret;
        struct uic_command uic_cmd = {0};
+       ktime_t start = ktime_get();
 
        ufshcd_vops_hibern8_notify(hba, UIC_CMD_DME_HIBER_ENTER, PRE_CHANGE);
 
        uic_cmd.command = UIC_CMD_DME_HIBER_ENTER;
        ret = ufshcd_uic_pwr_ctrl(hba, &uic_cmd);
+       trace_ufshcd_profile_hibern8(dev_name(hba->dev), "enter",
+                            ktime_to_us(ktime_sub(ktime_get(), start)), ret);
 
        if (ret) {
                dev_err(hba->dev, "%s: hibern8 enter failed. ret = %d\n",
@@ -2816,18 +3677,25 @@ static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba)
 {
        struct uic_command uic_cmd = {0};
        int ret;
+       ktime_t start = ktime_get();
 
        ufshcd_vops_hibern8_notify(hba, UIC_CMD_DME_HIBER_EXIT, PRE_CHANGE);
 
        uic_cmd.command = UIC_CMD_DME_HIBER_EXIT;
        ret = ufshcd_uic_pwr_ctrl(hba, &uic_cmd);
+       trace_ufshcd_profile_hibern8(dev_name(hba->dev), "exit",
+                            ktime_to_us(ktime_sub(ktime_get(), start)), ret);
+
        if (ret) {
                dev_err(hba->dev, "%s: hibern8 exit failed. ret = %d\n",
                        __func__, ret);
                ret = ufshcd_link_recovery(hba);
-       } else
+       } else {
                ufshcd_vops_hibern8_notify(hba, UIC_CMD_DME_HIBER_EXIT,
                                                                POST_CHANGE);
+               hba->ufs_stats.last_hibern8_exit_tstamp = ktime_get();
+               hba->ufs_stats.hibern8_exit_cnt++;
+       }
 
        return ret;
 }
@@ -2994,6 +3862,8 @@ static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
                memcpy(&final_params, desired_pwr_mode, sizeof(final_params));
 
        ret = ufshcd_change_power_mode(hba, &final_params);
+       if (!ret)
+               ufshcd_print_pwr_info(hba);
 
        return ret;
 }
@@ -3265,6 +4135,10 @@ link_startup:
                goto link_startup;
        }
 
+       /* Mark that link is up in PWM-G1, 1-lane, SLOW-AUTO mode */
+       ufshcd_init_pwr_info(hba);
+       ufshcd_print_pwr_info(hba);
+
        if (hba->quirks & UFSHCD_QUIRK_BROKEN_LCC) {
                ret = ufshcd_disable_device_tx_lcc(hba);
                if (ret)
@@ -3278,8 +4152,12 @@ link_startup:
 
        ret = ufshcd_make_hba_operational(hba);
 out:
-       if (ret)
+       if (ret) {
                dev_err(hba->dev, "link startup failed %d\n", ret);
+               ufshcd_print_host_state(hba);
+               ufshcd_print_pwr_info(hba);
+               ufshcd_print_host_regs(hba);
+       }
        return ret;
 }
 
@@ -3591,7 +4469,7 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
        switch (ocs) {
        case OCS_SUCCESS:
                result = ufshcd_get_req_rsp(lrbp->ucd_rsp_ptr);
-
+               hba->ufs_stats.last_hibern8_exit_tstamp = ktime_set(0, 0);
                switch (result) {
                case UPIU_TRANSACTION_RESPONSE:
                        /*
@@ -3652,10 +4530,15 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
        default:
                result |= DID_ERROR << 16;
                dev_err(hba->dev,
-               "OCS error from controller = %x\n", ocs);
+                               "OCS error from controller = %x for tag %d\n",
+                               ocs, lrbp->task_tag);
+               ufshcd_print_host_regs(hba);
+               ufshcd_print_host_state(hba);
                break;
        } /* end of switch */
 
+       if (host_byte(result) != DID_OK)
+               ufshcd_print_trs(hba, 1 << lrbp->task_tag, true);
        return result;
 }
 
@@ -3695,6 +4578,7 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba,
                lrbp = &hba->lrb[index];
                cmd = lrbp->cmd;
                if (cmd) {
+                       ufshcd_add_command_trace(hba, index, "complete");
                        result = ufshcd_transfer_rsp_status(hba, lrbp);
                        scsi_dma_unmap(cmd);
                        cmd->result = result;
@@ -3706,9 +4590,16 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba,
                        __ufshcd_release(hba);
                } else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE ||
                        lrbp->command_type == UTP_CMD_TYPE_UFS_STORAGE) {
-                       if (hba->dev_cmd.complete)
+                       if (hba->dev_cmd.complete) {
+                               ufshcd_add_command_trace(hba, index,
+                                               "dev_complete");
                                complete(hba->dev_cmd.complete);
+                       }
                }
+               if (ufshcd_is_clkscaling_supported(hba))
+                       hba->clk_scaling.active_reqs--;
+               if (ufshcd_is_clkscaling_supported(hba))
+                       hba->clk_scaling.active_reqs--;
        }
 
        /* clear corresponding bits of completed commands */
@@ -3828,6 +4719,7 @@ static int ufshcd_enable_auto_bkops(struct ufs_hba *hba)
        }
 
        hba->auto_bkops_enabled = true;
+       trace_ufshcd_auto_bkops_state(dev_name(hba->dev), "Enabled");
 
        /* No need of URGENT_BKOPS exception from the device */
        err = ufshcd_disable_ee(hba, MASK_EE_URGENT_BKOPS);
@@ -3878,23 +4770,31 @@ static int ufshcd_disable_auto_bkops(struct ufs_hba *hba)
        }
 
        hba->auto_bkops_enabled = false;
+       trace_ufshcd_auto_bkops_state(dev_name(hba->dev), "Disabled");
 out:
        return err;
 }
 
 /**
- * ufshcd_force_reset_auto_bkops - force enable of auto bkops
+ * ufshcd_force_reset_auto_bkops - force reset auto bkops state
  * @hba: per adapter instance
  *
  * After a device reset the device may toggle the BKOPS_EN flag
  * to default value. The s/w tracking variables should be updated
- * as well. Do this by forcing enable of auto bkops.
+ * as well. This function would change the auto-bkops state based on
+ * UFSHCD_CAP_KEEP_AUTO_BKOPS_ENABLED_EXCEPT_SUSPEND.
  */
-static void  ufshcd_force_reset_auto_bkops(struct ufs_hba *hba)
+static void ufshcd_force_reset_auto_bkops(struct ufs_hba *hba)
 {
-       hba->auto_bkops_enabled = false;
-       hba->ee_ctrl_mask |= MASK_EE_URGENT_BKOPS;
-       ufshcd_enable_auto_bkops(hba);
+       if (ufshcd_keep_autobkops_enabled_except_suspend(hba)) {
+               hba->auto_bkops_enabled = false;
+               hba->ee_ctrl_mask |= MASK_EE_URGENT_BKOPS;
+               ufshcd_enable_auto_bkops(hba);
+       } else {
+               hba->auto_bkops_enabled = true;
+               hba->ee_ctrl_mask &= ~MASK_EE_URGENT_BKOPS;
+               ufshcd_disable_auto_bkops(hba);
+       }
 }
 
 static inline int ufshcd_get_bkops_status(struct ufs_hba *hba, u32 *status)
@@ -4246,6 +5146,14 @@ out:
        pm_runtime_put_sync(hba->dev);
 }
 
+static void ufshcd_update_uic_reg_hist(struct ufs_uic_err_reg_hist *reg_hist,
+               u32 reg)
+{
+       reg_hist->reg[reg_hist->pos] = reg;
+       reg_hist->tstamp[reg_hist->pos] = ktime_get();
+       reg_hist->pos = (reg_hist->pos + 1) % UIC_ERR_REG_HIST_LENGTH;
+}
+
 /**
  * ufshcd_update_uic_error - check and set fatal UIC error flags.
  * @hba: per-adapter instance
@@ -4258,15 +5166,20 @@ static void ufshcd_update_uic_error(struct ufs_hba *hba)
        reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
        /* Ignore LINERESET indication, as this is not an error */
        if ((reg & UIC_PHY_ADAPTER_LAYER_ERROR) &&
-                       (reg & UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK))
+                       (reg & UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK)) {
                /*
                 * To know whether this error is fatal or not, DB timeout
                 * must be checked but this error is handled separately.
                 */
                dev_dbg(hba->dev, "%s: UIC Lane error reported\n", __func__);
+               ufshcd_update_uic_reg_hist(&hba->ufs_stats.pa_err, reg);
+       }
 
        /* PA_INIT_ERROR is fatal and needs UIC reset */
        reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DATA_LINK_LAYER);
+       if (reg)
+               ufshcd_update_uic_reg_hist(&hba->ufs_stats.dl_err, reg);
+
        if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT)
                hba->uic_error |= UFSHCD_UIC_DL_PA_INIT_ERROR;
        else if (hba->dev_quirks &
@@ -4280,16 +5193,22 @@ static void ufshcd_update_uic_error(struct ufs_hba *hba)
 
        /* UIC NL/TL/DME errors needs software retry */
        reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_NETWORK_LAYER);
-       if (reg)
+       if (reg) {
+               ufshcd_update_uic_reg_hist(&hba->ufs_stats.nl_err, reg);
                hba->uic_error |= UFSHCD_UIC_NL_ERROR;
+       }
 
        reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_TRANSPORT_LAYER);
-       if (reg)
+       if (reg) {
+               ufshcd_update_uic_reg_hist(&hba->ufs_stats.tl_err, reg);
                hba->uic_error |= UFSHCD_UIC_TL_ERROR;
+       }
 
        reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DME);
-       if (reg)
+       if (reg) {
+               ufshcd_update_uic_reg_hist(&hba->ufs_stats.dme_err, reg);
                hba->uic_error |= UFSHCD_UIC_DME_ERROR;
+       }
 
        dev_dbg(hba->dev, "%s: UIC error flags = 0x%08x\n",
                        __func__, hba->uic_error);
@@ -4327,6 +5246,22 @@ static void ufshcd_check_errors(struct ufs_hba *hba)
                        scsi_block_requests(hba->host);
 
                        hba->ufshcd_state = UFSHCD_STATE_EH_SCHEDULED;
+
+                       /* dump controller state before resetting */
+                       if (hba->saved_err & (INT_FATAL_ERRORS | UIC_ERROR)) {
+                               bool pr_prdt = !!(hba->saved_err &
+                                               SYSTEM_BUS_FATAL_ERROR);
+
+                               dev_err(hba->dev, "%s: saved_err 0x%x saved_uic_err 0x%x\n",
+                                       __func__, hba->saved_err,
+                                       hba->saved_uic_err);
+
+                               ufshcd_print_host_regs(hba);
+                               ufshcd_print_pwr_info(hba);
+                               ufshcd_print_tmrs(hba, hba->outstanding_tasks);
+                               ufshcd_print_trs(hba, hba->outstanding_reqs,
+                                                       pr_prdt);
+                       }
                        schedule_work(&hba->eh_work);
                }
        }
@@ -4557,7 +5492,9 @@ static int ufshcd_eh_device_reset_handler(struct scsi_cmnd *cmd)
        spin_lock_irqsave(host->host_lock, flags);
        ufshcd_transfer_req_compl(hba);
        spin_unlock_irqrestore(host->host_lock, flags);
+
 out:
+       hba->req_abort_count = 0;
        if (!err) {
                err = SUCCESS;
        } else {
@@ -4567,6 +5504,17 @@ out:
        return err;
 }
 
+static void ufshcd_set_req_abort_skip(struct ufs_hba *hba, unsigned long bitmap)
+{
+       struct ufshcd_lrb *lrbp;
+       int tag;
+
+       for_each_set_bit(tag, &bitmap, hba->nutrs) {
+               lrbp = &hba->lrb[tag];
+               lrbp->req_abort_skip = true;
+       }
+}
+
 /**
  * ufshcd_abort - abort a specific command
  * @cmd: SCSI command pointer
@@ -4594,6 +5542,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
        host = cmd->device->host;
        hba = shost_priv(host);
        tag = cmd->request->tag;
+       lrbp = &hba->lrb[tag];
        if (!ufshcd_valid_tag(hba, tag)) {
                dev_err(hba->dev,
                        "%s: invalid command tag %d: cmd=0x%p, cmd->request=0x%p",
@@ -4601,6 +5550,16 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
                BUG();
        }
 
+       /*
+        * Task abort to the device W-LUN is illegal. When this command
+        * will fail, due to spec violation, scsi err handling next step
+        * will be to send LU reset which, again, is a spec violation.
+        * To avoid these unnecessary/illegal step we skip to the last error
+        * handling stage: reset and restore.
+        */
+       if (lrbp->lun == UFS_UPIU_UFS_DEVICE_WLUN)
+               return ufshcd_eh_host_reset_handler(cmd);
+
        ufshcd_hold(hba, false);
        reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
        /* If command is already aborted/completed, return SUCCESS */
@@ -4617,18 +5576,48 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
                __func__, tag);
        }
 
-       lrbp = &hba->lrb[tag];
+       /* Print Transfer Request of aborted task */
+       dev_err(hba->dev, "%s: Device abort task at tag %d\n", __func__, tag);
+
+       /*
+        * Print detailed info about aborted request.
+        * As more than one request might get aborted at the same time,
+        * print full information only for the first aborted request in order
+        * to reduce repeated printouts. For other aborted requests only print
+        * basic details.
+        */
+       scsi_print_command(hba->lrb[tag].cmd);
+       if (!hba->req_abort_count) {
+               ufshcd_print_host_regs(hba);
+               ufshcd_print_host_state(hba);
+               ufshcd_print_pwr_info(hba);
+               ufshcd_print_trs(hba, 1 << tag, true);
+       } else {
+               ufshcd_print_trs(hba, 1 << tag, false);
+       }
+       hba->req_abort_count++;
+
+       /* Skip task abort in case previous aborts failed and report failure */
+       if (lrbp->req_abort_skip) {
+               err = -EIO;
+               goto out;
+       }
+
        for (poll_cnt = 100; poll_cnt; poll_cnt--) {
                err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag,
                                UFS_QUERY_TASK, &resp);
                if (!err && resp == UPIU_TASK_MANAGEMENT_FUNC_SUCCEEDED) {
                        /* cmd pending in the device */
+                       dev_err(hba->dev, "%s: cmd pending in the device. tag = %d\n",
+                               __func__, tag);
                        break;
                } else if (!err && resp == UPIU_TASK_MANAGEMENT_FUNC_COMPL) {
                        /*
                         * cmd not pending in the device, check if it is
                         * in transition.
                         */
+                       dev_err(hba->dev, "%s: cmd at tag %d not pending in the device.\n",
+                               __func__, tag);
                        reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
                        if (reg & (1 << tag)) {
                                /* sleep for max. 200us to stabilize */
@@ -4636,8 +5625,13 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
                                continue;
                        }
                        /* command completed already */
+                       dev_err(hba->dev, "%s: cmd at tag %d successfully cleared from DB.\n",
+                               __func__, tag);
                        goto out;
                } else {
+                       dev_err(hba->dev,
+                               "%s: no response from device. tag = %d, err %d\n",
+                               __func__, tag, err);
                        if (!err)
                                err = resp; /* service response error */
                        goto out;
@@ -4652,14 +5646,20 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
        err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag,
                        UFS_ABORT_TASK, &resp);
        if (err || resp != UPIU_TASK_MANAGEMENT_FUNC_COMPL) {
-               if (!err)
+               if (!err) {
                        err = resp; /* service response error */
+                       dev_err(hba->dev, "%s: issued. tag = %d, err %d\n",
+                               __func__, tag, err);
+               }
                goto out;
        }
 
        err = ufshcd_clear_cmd(hba, tag);
-       if (err)
+       if (err) {
+               dev_err(hba->dev, "%s: Failed clearing cmd at tag %d, err %d\n",
+                       __func__, tag, err);
                goto out;
+       }
 
        scsi_dma_unmap(cmd);
 
@@ -4676,6 +5676,7 @@ out:
                err = SUCCESS;
        } else {
                dev_err(hba->dev, "%s: failed with err %d\n", __func__, err);
+               ufshcd_set_req_abort_skip(hba, hba->outstanding_reqs);
                err = FAILED;
        }
 
@@ -4707,6 +5708,9 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba)
        ufshcd_hba_stop(hba, false);
        spin_unlock_irqrestore(hba->host->host_lock, flags);
 
+       /* scale up clocks to max frequency before full reinitialization */
+       ufshcd_scale_clks(hba, true);
+
        err = ufshcd_hba_enable(hba);
        if (err)
                goto out;
@@ -4822,7 +5826,7 @@ static u32 ufshcd_get_max_icc_level(int sup_curr_uA, u32 start_scan, char *buff)
        u16 unit;
 
        for (i = start_scan; i >= 0; i--) {
-               data = be16_to_cpu(*((u16 *)(buff + 2*i)));
+               data = be16_to_cpup((__be16 *)&buff[2 * i]);
                unit = (data & ATTR_ICC_LVL_UNIT_MASK) >>
                                                ATTR_ICC_LVL_UNIT_OFFSET;
                curr_uA = data & ATTR_ICC_LVL_VALUE_MASK;
@@ -5008,8 +6012,8 @@ out:
        return ret;
 }
 
-static int ufs_get_device_info(struct ufs_hba *hba,
-                               struct ufs_device_info *card_data)
+static int ufs_get_device_desc(struct ufs_hba *hba,
+                              struct ufs_dev_desc *dev_desc)
 {
        int err;
        u8 model_index;
@@ -5028,7 +6032,7 @@ static int ufs_get_device_info(struct ufs_hba *hba,
         * getting vendor (manufacturerID) and Bank Index in big endian
         * format
         */
-       card_data->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 |
+       dev_desc->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 |
                                     desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1];
 
        model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME];
@@ -5042,36 +6046,26 @@ static int ufs_get_device_info(struct ufs_hba *hba,
        }
 
        str_desc_buf[QUERY_DESC_STRING_MAX_SIZE] = '\0';
-       strlcpy(card_data->model, (str_desc_buf + QUERY_DESC_HDR_SIZE),
+       strlcpy(dev_desc->model, (str_desc_buf + QUERY_DESC_HDR_SIZE),
                min_t(u8, str_desc_buf[QUERY_DESC_LENGTH_OFFSET],
                      MAX_MODEL_LEN));
 
        /* Null terminate the model string */
-       card_data->model[MAX_MODEL_LEN] = '\0';
+       dev_desc->model[MAX_MODEL_LEN] = '\0';
 
 out:
        return err;
 }
 
-void ufs_advertise_fixup_device(struct ufs_hba *hba)
+static void ufs_fixup_device_setup(struct ufs_hba *hba,
+                                  struct ufs_dev_desc *dev_desc)
 {
-       int err;
        struct ufs_dev_fix *f;
-       struct ufs_device_info card_data;
-
-       card_data.wmanufacturerid = 0;
-
-       err = ufs_get_device_info(hba, &card_data);
-       if (err) {
-               dev_err(hba->dev, "%s: Failed getting device info. err = %d\n",
-                       __func__, err);
-               return;
-       }
 
        for (f = ufs_fixups; f->quirk; f++) {
-               if (((f->card.wmanufacturerid == card_data.wmanufacturerid) ||
-                   (f->card.wmanufacturerid == UFS_ANY_VENDOR)) &&
-                   (STR_PRFX_EQUAL(f->card.model, card_data.model) ||
+               if ((f->card.wmanufacturerid == dev_desc->wmanufacturerid ||
+                    f->card.wmanufacturerid == UFS_ANY_VENDOR) &&
+                   (STR_PRFX_EQUAL(f->card.model, dev_desc->model) ||
                     !strcmp(f->card.model, UFS_ANY_MODEL)))
                        hba->dev_quirks |= f->quirk;
        }
@@ -5241,6 +6235,22 @@ static void ufshcd_tune_unipro_params(struct ufs_hba *hba)
        ufshcd_vops_apply_dev_quirks(hba);
 }
 
+static void ufshcd_clear_dbg_ufs_stats(struct ufs_hba *hba)
+{
+       int err_reg_hist_size = sizeof(struct ufs_uic_err_reg_hist);
+
+       hba->ufs_stats.hibern8_exit_cnt = 0;
+       hba->ufs_stats.last_hibern8_exit_tstamp = ktime_set(0, 0);
+
+       memset(&hba->ufs_stats.pa_err, 0, err_reg_hist_size);
+       memset(&hba->ufs_stats.dl_err, 0, err_reg_hist_size);
+       memset(&hba->ufs_stats.nl_err, 0, err_reg_hist_size);
+       memset(&hba->ufs_stats.tl_err, 0, err_reg_hist_size);
+       memset(&hba->ufs_stats.dme_err, 0, err_reg_hist_size);
+
+       hba->req_abort_count = 0;
+}
+
 /**
  * ufshcd_probe_hba - probe hba to detect device and initialize
  * @hba: per-adapter instance
@@ -5249,18 +6259,21 @@ static void ufshcd_tune_unipro_params(struct ufs_hba *hba)
  */
 static int ufshcd_probe_hba(struct ufs_hba *hba)
 {
+       struct ufs_dev_desc card = {0};
        int ret;
+       ktime_t start = ktime_get();
 
        ret = ufshcd_link_startup(hba);
        if (ret)
                goto out;
 
-       ufshcd_init_pwr_info(hba);
-
        /* set the default level for urgent bkops */
        hba->urgent_bkops_lvl = BKOPS_STATUS_PERF_IMPACT;
        hba->is_urgent_bkops_lvl_checked = false;
 
+       /* Debug counters initialization */
+       ufshcd_clear_dbg_ufs_stats(hba);
+
        /* UniPro link is active now */
        ufshcd_set_link_active(hba);
 
@@ -5272,7 +6285,14 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
        if (ret)
                goto out;
 
-       ufs_advertise_fixup_device(hba);
+       ret = ufs_get_device_desc(hba, &card);
+       if (ret) {
+               dev_err(hba->dev, "%s: Failed getting device info. err = %d\n",
+                       __func__, ret);
+               goto out;
+       }
+
+       ufs_fixup_device_setup(hba, &card);
        ufshcd_tune_unipro_params(hba);
 
        ret = ufshcd_set_vccq_rail_unused(hba,
@@ -5320,6 +6340,27 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
                if (ufshcd_scsi_add_wlus(hba))
                        goto out;
 
+               /* Initialize devfreq after UFS device is detected */
+               if (ufshcd_is_clkscaling_supported(hba)) {
+                       memcpy(&hba->clk_scaling.saved_pwr_info.info,
+                               &hba->pwr_info,
+                               sizeof(struct ufs_pa_layer_attr));
+                       hba->clk_scaling.saved_pwr_info.is_valid = true;
+                       if (!hba->devfreq) {
+                               hba->devfreq = devm_devfreq_add_device(hba->dev,
+                                                       &ufs_devfreq_profile,
+                                                       "simple_ondemand",
+                                                       NULL);
+                               if (IS_ERR(hba->devfreq)) {
+                                       ret = PTR_ERR(hba->devfreq);
+                                       dev_err(hba->dev, "Unable to register with devfreq %d\n",
+                                                       ret);
+                                       goto out;
+                               }
+                       }
+                       hba->clk_scaling.is_allowed = true;
+               }
+
                scsi_scan_host(hba->host);
                pm_runtime_put_sync(hba->dev);
        }
@@ -5327,9 +6368,6 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
        if (!hba->is_init_prefetch)
                hba->is_init_prefetch = true;
 
-       /* Resume devfreq after UFS device is detected */
-       ufshcd_resume_clkscaling(hba);
-
 out:
        /*
         * If we failed to initialize the device or the device is not
@@ -5340,6 +6378,9 @@ out:
                ufshcd_hba_exit(hba);
        }
 
+       trace_ufshcd_init(dev_name(hba->dev), ret,
+               ktime_to_us(ktime_sub(ktime_get(), start)),
+               hba->curr_dev_pwr_mode, hba->uic_link_state);
        return ret;
 }
 
@@ -5650,6 +6691,8 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
        struct ufs_clk_info *clki;
        struct list_head *head = &hba->clk_list_head;
        unsigned long flags;
+       ktime_t start = ktime_get();
+       bool clk_state_changed = false;
 
        if (!head || list_empty(head))
                goto out;
@@ -5663,6 +6706,7 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
                        if (skip_ref_clk && !strcmp(clki->name, "ref_clk"))
                                continue;
 
+                       clk_state_changed = on ^ clki->enabled;
                        if (on && !clki->enabled) {
                                ret = clk_prepare_enable(clki->clk);
                                if (ret) {
@@ -5689,11 +6733,18 @@ out:
                        if (!IS_ERR_OR_NULL(clki->clk) && clki->enabled)
                                clk_disable_unprepare(clki->clk);
                }
-       } else if (on) {
+       } else if (!ret && on) {
                spin_lock_irqsave(hba->host->host_lock, flags);
                hba->clk_gating.state = CLKS_ON;
+               trace_ufshcd_clk_gating(dev_name(hba->dev),
+                                       hba->clk_gating.state);
                spin_unlock_irqrestore(hba->host->host_lock, flags);
        }
+
+       if (clk_state_changed)
+               trace_ufshcd_profile_clk_gating(dev_name(hba->dev),
+                       (on ? "on" : "off"),
+                       ktime_to_us(ktime_sub(ktime_get(), start)), ret);
        return ret;
 }
 
@@ -5835,6 +6886,11 @@ static void ufshcd_hba_exit(struct ufs_hba *hba)
                ufshcd_variant_hba_exit(hba);
                ufshcd_setup_vreg(hba, false);
                ufshcd_suspend_clkscaling(hba);
+               if (ufshcd_is_clkscaling_supported(hba)) {
+                       if (hba->devfreq)
+                               ufshcd_suspend_clkscaling(hba);
+                       destroy_workqueue(hba->clk_scaling.workq);
+               }
                ufshcd_setup_clocks(hba, false);
                ufshcd_setup_hba_vreg(hba, false);
                hba->is_powered = false;
@@ -6110,7 +7166,11 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
        ufshcd_hold(hba, false);
        hba->clk_gating.is_suspended = true;
 
-       ufshcd_suspend_clkscaling(hba);
+       if (hba->clk_scaling.is_allowed) {
+               cancel_work_sync(&hba->clk_scaling.suspend_work);
+               cancel_work_sync(&hba->clk_scaling.resume_work);
+               ufshcd_suspend_clkscaling(hba);
+       }
 
        if (req_dev_pwr_mode == UFS_ACTIVE_PWR_MODE &&
                        req_link_state == UIC_LINK_ACTIVE_STATE) {
@@ -6176,6 +7236,7 @@ disable_clks:
                __ufshcd_setup_clocks(hba, false, true);
 
        hba->clk_gating.state = CLKS_OFF;
+       trace_ufshcd_clk_gating(dev_name(hba->dev), hba->clk_gating.state);
        /*
         * Disable the host irq as host controller as there won't be any
         * host controller transaction expected till resume.
@@ -6186,7 +7247,8 @@ disable_clks:
        goto out;
 
 set_link_active:
-       ufshcd_resume_clkscaling(hba);
+       if (hba->clk_scaling.is_allowed)
+               ufshcd_resume_clkscaling(hba);
        ufshcd_vreg_set_hpm(hba);
        if (ufshcd_is_link_hibern8(hba) && !ufshcd_uic_hibern8_exit(hba))
                ufshcd_set_link_active(hba);
@@ -6196,7 +7258,8 @@ set_dev_active:
        if (!ufshcd_set_dev_pwr_mode(hba, UFS_ACTIVE_PWR_MODE))
                ufshcd_disable_auto_bkops(hba);
 enable_gating:
-       ufshcd_resume_clkscaling(hba);
+       if (hba->clk_scaling.is_allowed)
+               ufshcd_resume_clkscaling(hba);
        hba->clk_gating.is_suspended = false;
        ufshcd_release(hba);
 out:
@@ -6268,14 +7331,19 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
                        goto set_old_link_state;
        }
 
-       /*
-        * If BKOPs operations are urgently needed at this moment then
-        * keep auto-bkops enabled or else disable it.
-        */
-       ufshcd_urgent_bkops(hba);
+       if (ufshcd_keep_autobkops_enabled_except_suspend(hba))
+               ufshcd_enable_auto_bkops(hba);
+       else
+               /*
+                * If BKOPs operations are urgently needed at this moment then
+                * keep auto-bkops enabled or else disable it.
+                */
+               ufshcd_urgent_bkops(hba);
+
        hba->clk_gating.is_suspended = false;
 
-       ufshcd_resume_clkscaling(hba);
+       if (hba->clk_scaling.is_allowed)
+               ufshcd_resume_clkscaling(hba);
 
        /* Schedule clock gating in case of no access to UFS device yet */
        ufshcd_release(hba);
@@ -6289,7 +7357,8 @@ disable_vreg:
        ufshcd_vreg_set_lpm(hba);
 disable_irq_and_vops_clks:
        ufshcd_disable_irq(hba);
-       ufshcd_suspend_clkscaling(hba);
+       if (hba->clk_scaling.is_allowed)
+               ufshcd_suspend_clkscaling(hba);
        ufshcd_setup_clocks(hba, false);
 out:
        hba->pm_op_in_progress = 0;
@@ -6308,6 +7377,7 @@ out:
 int ufshcd_system_suspend(struct ufs_hba *hba)
 {
        int ret = 0;
+       ktime_t start = ktime_get();
 
        if (!hba || !hba->is_powered)
                return 0;
@@ -6334,6 +7404,9 @@ int ufshcd_system_suspend(struct ufs_hba *hba)
 
        ret = ufshcd_suspend(hba, UFS_SYSTEM_PM);
 out:
+       trace_ufshcd_system_suspend(dev_name(hba->dev), ret,
+               ktime_to_us(ktime_sub(ktime_get(), start)),
+               hba->curr_dev_pwr_mode, hba->uic_link_state);
        if (!ret)
                hba->is_sys_suspended = true;
        return ret;
@@ -6349,6 +7422,9 @@ EXPORT_SYMBOL(ufshcd_system_suspend);
 
 int ufshcd_system_resume(struct ufs_hba *hba)
 {
+       int ret = 0;
+       ktime_t start = ktime_get();
+
        if (!hba)
                return -EINVAL;
 
@@ -6357,9 +7433,14 @@ int ufshcd_system_resume(struct ufs_hba *hba)
                 * Let the runtime resume take care of resuming
                 * if runtime suspended.
                 */
-               return 0;
-
-       return ufshcd_resume(hba, UFS_SYSTEM_PM);
+               goto out;
+       else
+               ret = ufshcd_resume(hba, UFS_SYSTEM_PM);
+out:
+       trace_ufshcd_system_resume(dev_name(hba->dev), ret,
+               ktime_to_us(ktime_sub(ktime_get(), start)),
+               hba->curr_dev_pwr_mode, hba->uic_link_state);
+       return ret;
 }
 EXPORT_SYMBOL(ufshcd_system_resume);
 
@@ -6373,13 +7454,21 @@ EXPORT_SYMBOL(ufshcd_system_resume);
  */
 int ufshcd_runtime_suspend(struct ufs_hba *hba)
 {
+       int ret = 0;
+       ktime_t start = ktime_get();
+
        if (!hba)
                return -EINVAL;
 
        if (!hba->is_powered)
-               return 0;
-
-       return ufshcd_suspend(hba, UFS_RUNTIME_PM);
+               goto out;
+       else
+               ret = ufshcd_suspend(hba, UFS_RUNTIME_PM);
+out:
+       trace_ufshcd_runtime_suspend(dev_name(hba->dev), ret,
+               ktime_to_us(ktime_sub(ktime_get(), start)),
+               hba->curr_dev_pwr_mode, hba->uic_link_state);
+       return ret;
 }
 EXPORT_SYMBOL(ufshcd_runtime_suspend);
 
@@ -6406,13 +7495,21 @@ EXPORT_SYMBOL(ufshcd_runtime_suspend);
  */
 int ufshcd_runtime_resume(struct ufs_hba *hba)
 {
+       int ret = 0;
+       ktime_t start = ktime_get();
+
        if (!hba)
                return -EINVAL;
 
        if (!hba->is_powered)
-               return 0;
-
-       return ufshcd_resume(hba, UFS_RUNTIME_PM);
+               goto out;
+       else
+               ret = ufshcd_resume(hba, UFS_RUNTIME_PM);
+out:
+       trace_ufshcd_runtime_resume(dev_name(hba->dev), ret,
+               ktime_to_us(ktime_sub(ktime_get(), start)),
+               hba->curr_dev_pwr_mode, hba->uic_link_state);
+       return ret;
 }
 EXPORT_SYMBOL(ufshcd_runtime_resume);
 
@@ -6422,6 +7519,127 @@ int ufshcd_runtime_idle(struct ufs_hba *hba)
 }
 EXPORT_SYMBOL(ufshcd_runtime_idle);
 
+static inline ssize_t ufshcd_pm_lvl_store(struct device *dev,
+                                          struct device_attribute *attr,
+                                          const char *buf, size_t count,
+                                          bool rpm)
+{
+       struct ufs_hba *hba = dev_get_drvdata(dev);
+       unsigned long flags, value;
+
+       if (kstrtoul(buf, 0, &value))
+               return -EINVAL;
+
+       if ((value < UFS_PM_LVL_0) || (value >= UFS_PM_LVL_MAX))
+               return -EINVAL;
+
+       spin_lock_irqsave(hba->host->host_lock, flags);
+       if (rpm)
+               hba->rpm_lvl = value;
+       else
+               hba->spm_lvl = value;
+       spin_unlock_irqrestore(hba->host->host_lock, flags);
+       return count;
+}
+
+static ssize_t ufshcd_rpm_lvl_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct ufs_hba *hba = dev_get_drvdata(dev);
+       int curr_len;
+       u8 lvl;
+
+       curr_len = snprintf(buf, PAGE_SIZE,
+                           "\nCurrent Runtime PM level [%d] => dev_state [%s] link_state [%s]\n",
+                           hba->rpm_lvl,
+                           ufschd_ufs_dev_pwr_mode_to_string(
+                               ufs_pm_lvl_states[hba->rpm_lvl].dev_state),
+                           ufschd_uic_link_state_to_string(
+                               ufs_pm_lvl_states[hba->rpm_lvl].link_state));
+
+       curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len),
+                            "\nAll available Runtime PM levels info:\n");
+       for (lvl = UFS_PM_LVL_0; lvl < UFS_PM_LVL_MAX; lvl++)
+               curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len),
+                                    "\tRuntime PM level [%d] => dev_state [%s] link_state [%s]\n",
+                                   lvl,
+                                   ufschd_ufs_dev_pwr_mode_to_string(
+                                       ufs_pm_lvl_states[lvl].dev_state),
+                                   ufschd_uic_link_state_to_string(
+                                       ufs_pm_lvl_states[lvl].link_state));
+
+       return curr_len;
+}
+
+static ssize_t ufshcd_rpm_lvl_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       return ufshcd_pm_lvl_store(dev, attr, buf, count, true);
+}
+
+static void ufshcd_add_rpm_lvl_sysfs_nodes(struct ufs_hba *hba)
+{
+       hba->rpm_lvl_attr.show = ufshcd_rpm_lvl_show;
+       hba->rpm_lvl_attr.store = ufshcd_rpm_lvl_store;
+       sysfs_attr_init(&hba->rpm_lvl_attr.attr);
+       hba->rpm_lvl_attr.attr.name = "rpm_lvl";
+       hba->rpm_lvl_attr.attr.mode = 0644;
+       if (device_create_file(hba->dev, &hba->rpm_lvl_attr))
+               dev_err(hba->dev, "Failed to create sysfs for rpm_lvl\n");
+}
+
+static ssize_t ufshcd_spm_lvl_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct ufs_hba *hba = dev_get_drvdata(dev);
+       int curr_len;
+       u8 lvl;
+
+       curr_len = snprintf(buf, PAGE_SIZE,
+                           "\nCurrent System PM level [%d] => dev_state [%s] link_state [%s]\n",
+                           hba->spm_lvl,
+                           ufschd_ufs_dev_pwr_mode_to_string(
+                               ufs_pm_lvl_states[hba->spm_lvl].dev_state),
+                           ufschd_uic_link_state_to_string(
+                               ufs_pm_lvl_states[hba->spm_lvl].link_state));
+
+       curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len),
+                            "\nAll available System PM levels info:\n");
+       for (lvl = UFS_PM_LVL_0; lvl < UFS_PM_LVL_MAX; lvl++)
+               curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len),
+                                    "\tSystem PM level [%d] => dev_state [%s] link_state [%s]\n",
+                                   lvl,
+                                   ufschd_ufs_dev_pwr_mode_to_string(
+                                       ufs_pm_lvl_states[lvl].dev_state),
+                                   ufschd_uic_link_state_to_string(
+                                       ufs_pm_lvl_states[lvl].link_state));
+
+       return curr_len;
+}
+
+static ssize_t ufshcd_spm_lvl_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       return ufshcd_pm_lvl_store(dev, attr, buf, count, false);
+}
+
+static void ufshcd_add_spm_lvl_sysfs_nodes(struct ufs_hba *hba)
+{
+       hba->spm_lvl_attr.show = ufshcd_spm_lvl_show;
+       hba->spm_lvl_attr.store = ufshcd_spm_lvl_store;
+       sysfs_attr_init(&hba->spm_lvl_attr.attr);
+       hba->spm_lvl_attr.attr.name = "spm_lvl";
+       hba->spm_lvl_attr.attr.mode = 0644;
+       if (device_create_file(hba->dev, &hba->spm_lvl_attr))
+               dev_err(hba->dev, "Failed to create sysfs for spm_lvl\n");
+}
+
+static inline void ufshcd_add_sysfs_nodes(struct ufs_hba *hba)
+{
+       ufshcd_add_rpm_lvl_sysfs_nodes(hba);
+       ufshcd_add_spm_lvl_sysfs_nodes(hba);
+}
+
 /**
  * ufshcd_shutdown - shutdown routine
  * @hba: per adapter instance
@@ -6465,6 +7683,8 @@ void ufshcd_remove(struct ufs_hba *hba)
        ufshcd_hba_stop(hba, true);
 
        ufshcd_exit_clk_gating(hba);
+       if (ufshcd_is_clkscaling_supported(hba))
+               device_remove_file(hba->dev, &hba->clk_scaling.enable_attr);
        ufshcd_hba_exit(hba);
 }
 EXPORT_SYMBOL_GPL(ufshcd_remove);
@@ -6531,149 +7751,6 @@ out_error:
 }
 EXPORT_SYMBOL(ufshcd_alloc_host);
 
-static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up)
-{
-       int ret = 0;
-       struct ufs_clk_info *clki;
-       struct list_head *head = &hba->clk_list_head;
-
-       if (!head || list_empty(head))
-               goto out;
-
-       ret = ufshcd_vops_clk_scale_notify(hba, scale_up, PRE_CHANGE);
-       if (ret)
-               return ret;
-
-       list_for_each_entry(clki, head, list) {
-               if (!IS_ERR_OR_NULL(clki->clk)) {
-                       if (scale_up && clki->max_freq) {
-                               if (clki->curr_freq == clki->max_freq)
-                                       continue;
-                               ret = clk_set_rate(clki->clk, clki->max_freq);
-                               if (ret) {
-                                       dev_err(hba->dev, "%s: %s clk set rate(%dHz) failed, %d\n",
-                                               __func__, clki->name,
-                                               clki->max_freq, ret);
-                                       break;
-                               }
-                               clki->curr_freq = clki->max_freq;
-
-                       } else if (!scale_up && clki->min_freq) {
-                               if (clki->curr_freq == clki->min_freq)
-                                       continue;
-                               ret = clk_set_rate(clki->clk, clki->min_freq);
-                               if (ret) {
-                                       dev_err(hba->dev, "%s: %s clk set rate(%dHz) failed, %d\n",
-                                               __func__, clki->name,
-                                               clki->min_freq, ret);
-                                       break;
-                               }
-                               clki->curr_freq = clki->min_freq;
-                       }
-               }
-               dev_dbg(hba->dev, "%s: clk: %s, rate: %lu\n", __func__,
-                               clki->name, clk_get_rate(clki->clk));
-       }
-
-       ret = ufshcd_vops_clk_scale_notify(hba, scale_up, POST_CHANGE);
-
-out:
-       return ret;
-}
-
-static int ufshcd_devfreq_target(struct device *dev,
-                               unsigned long *freq, u32 flags)
-{
-       int err = 0;
-       struct ufs_hba *hba = dev_get_drvdata(dev);
-       bool release_clk_hold = false;
-       unsigned long irq_flags;
-
-       if (!ufshcd_is_clkscaling_enabled(hba))
-               return -EINVAL;
-
-       spin_lock_irqsave(hba->host->host_lock, irq_flags);
-       if (ufshcd_eh_in_progress(hba)) {
-               spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
-               return 0;
-       }
-
-       if (ufshcd_is_clkgating_allowed(hba) &&
-           (hba->clk_gating.state != CLKS_ON)) {
-               if (cancel_delayed_work(&hba->clk_gating.gate_work)) {
-                       /* hold the vote until the scaling work is completed */
-                       hba->clk_gating.active_reqs++;
-                       release_clk_hold = true;
-                       hba->clk_gating.state = CLKS_ON;
-               } else {
-                       /*
-                        * Clock gating work seems to be running in parallel
-                        * hence skip scaling work to avoid deadlock between
-                        * current scaling work and gating work.
-                        */
-                       spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
-                       return 0;
-               }
-       }
-       spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
-
-       if (*freq == UINT_MAX)
-               err = ufshcd_scale_clks(hba, true);
-       else if (*freq == 0)
-               err = ufshcd_scale_clks(hba, false);
-
-       spin_lock_irqsave(hba->host->host_lock, irq_flags);
-       if (release_clk_hold)
-               __ufshcd_release(hba);
-       spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
-
-       return err;
-}
-
-static int ufshcd_devfreq_get_dev_status(struct device *dev,
-               struct devfreq_dev_status *stat)
-{
-       struct ufs_hba *hba = dev_get_drvdata(dev);
-       struct ufs_clk_scaling *scaling = &hba->clk_scaling;
-       unsigned long flags;
-
-       if (!ufshcd_is_clkscaling_enabled(hba))
-               return -EINVAL;
-
-       memset(stat, 0, sizeof(*stat));
-
-       spin_lock_irqsave(hba->host->host_lock, flags);
-       if (!scaling->window_start_t)
-               goto start_window;
-
-       if (scaling->is_busy_started)
-               scaling->tot_busy_t += ktime_to_us(ktime_sub(ktime_get(),
-                                       scaling->busy_start_t));
-
-       stat->total_time = jiffies_to_usecs((long)jiffies -
-                               (long)scaling->window_start_t);
-       stat->busy_time = scaling->tot_busy_t;
-start_window:
-       scaling->window_start_t = jiffies;
-       scaling->tot_busy_t = 0;
-
-       if (hba->outstanding_reqs) {
-               scaling->busy_start_t = ktime_get();
-               scaling->is_busy_started = true;
-       } else {
-               scaling->busy_start_t = 0;
-               scaling->is_busy_started = false;
-       }
-       spin_unlock_irqrestore(hba->host->host_lock, flags);
-       return 0;
-}
-
-static struct devfreq_dev_profile ufs_devfreq_profile = {
-       .polling_ms     = 100,
-       .target         = ufshcd_devfreq_target,
-       .get_dev_status = ufshcd_devfreq_get_dev_status,
-};
-
 /**
  * ufshcd_init - Driver initialization routine
  * @hba: per-adapter instance
@@ -6757,6 +7834,8 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
        /* Initialize mutex for device management commands */
        mutex_init(&hba->dev_cmd.lock);
 
+       init_rwsem(&hba->clk_scaling_lock);
+
        /* Initialize device management tag acquire wait queue */
        init_waitqueue_head(&hba->dev_cmd.tag_wq);
 
@@ -6795,22 +7874,38 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
        err = ufshcd_hba_enable(hba);
        if (err) {
                dev_err(hba->dev, "Host controller enable failed\n");
+               ufshcd_print_host_regs(hba);
+               ufshcd_print_host_state(hba);
                goto out_remove_scsi_host;
        }
 
-       if (ufshcd_is_clkscaling_enabled(hba)) {
-               hba->devfreq = devm_devfreq_add_device(dev, &ufs_devfreq_profile,
-                                                  "simple_ondemand", NULL);
-               if (IS_ERR(hba->devfreq)) {
-                       dev_err(hba->dev, "Unable to register with devfreq %ld\n",
-                                       PTR_ERR(hba->devfreq));
-                       err = PTR_ERR(hba->devfreq);
-                       goto out_remove_scsi_host;
-               }
-               /* Suspend devfreq until the UFS device is detected */
-               ufshcd_suspend_clkscaling(hba);
+       if (ufshcd_is_clkscaling_supported(hba)) {
+               char wq_name[sizeof("ufs_clkscaling_00")];
+
+               INIT_WORK(&hba->clk_scaling.suspend_work,
+                         ufshcd_clk_scaling_suspend_work);
+               INIT_WORK(&hba->clk_scaling.resume_work,
+                         ufshcd_clk_scaling_resume_work);
+
+               snprintf(wq_name, ARRAY_SIZE(wq_name), "ufs_clkscaling_%d",
+                        host->host_no);
+               hba->clk_scaling.workq = create_singlethread_workqueue(wq_name);
+
+               ufshcd_clkscaling_init_sysfs(hba);
        }
 
+       /*
+        * Set the default power management level for runtime and system PM.
+        * Default power saving mode is to keep UFS link in Hibern8 state
+        * and UFS device in sleep state.
+        */
+       hba->rpm_lvl = ufs_get_desired_pm_lvl_for_dev_link_state(
+                                               UFS_SLEEP_PWR_MODE,
+                                               UIC_LINK_HIBERN8_STATE);
+       hba->spm_lvl = ufs_get_desired_pm_lvl_for_dev_link_state(
+                                               UFS_SLEEP_PWR_MODE,
+                                               UIC_LINK_HIBERN8_STATE);
+
        /* Hold auto suspend until async scan completes */
        pm_runtime_get_sync(dev);
 
@@ -6823,6 +7918,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
        ufshcd_set_ufs_dev_active(hba);
 
        async_schedule(ufshcd_async_scan, hba);
+       ufshcd_add_sysfs_nodes(hba);
 
        return 0;
 
index 08cd26ed238270a3f6bfb797137f4962bfe04312..7630600217a2ef91e7d3629e5a4d2a0716c24c2a 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/rwsem.h>
 #include <linux/workqueue.h>
 #include <linux/errno.h>
 #include <linux/types.h>
@@ -152,6 +153,10 @@ struct ufs_pm_lvl_states {
  * @ucd_req_ptr: UCD address of the command
  * @ucd_rsp_ptr: Response UPIU address for this command
  * @ucd_prdt_ptr: PRDT address of the command
+ * @utrd_dma_addr: UTRD dma address for debug
+ * @ucd_prdt_dma_addr: PRDT dma address for debug
+ * @ucd_rsp_dma_addr: UPIU response dma address for debug
+ * @ucd_req_dma_addr: UPIU request dma address for debug
  * @cmd: pointer to SCSI command
  * @sense_buffer: pointer to sense buffer address of the SCSI command
  * @sense_bufflen: Length of the sense buffer
@@ -160,6 +165,8 @@ struct ufs_pm_lvl_states {
  * @task_tag: Task tag of the command
  * @lun: LUN of the command
  * @intr_cmd: Interrupt command (doesn't participate in interrupt aggregation)
+ * @issue_time_stamp: time stamp for debug purposes
+ * @req_abort_skip: skip request abort task flag
  */
 struct ufshcd_lrb {
        struct utp_transfer_req_desc *utr_descriptor_ptr;
@@ -167,6 +174,11 @@ struct ufshcd_lrb {
        struct utp_upiu_rsp *ucd_rsp_ptr;
        struct ufshcd_sg_entry *ucd_prdt_ptr;
 
+       dma_addr_t utrd_dma_addr;
+       dma_addr_t ucd_req_dma_addr;
+       dma_addr_t ucd_rsp_dma_addr;
+       dma_addr_t ucd_prdt_dma_addr;
+
        struct scsi_cmnd *cmd;
        u8 *sense_buffer;
        unsigned int sense_bufflen;
@@ -176,6 +188,9 @@ struct ufshcd_lrb {
        int task_tag;
        u8 lun; /* UPIU LUN id field is only 8-bit wide */
        bool intr_cmd;
+       ktime_t issue_time_stamp;
+
+       bool req_abort_skip;
 };
 
 /**
@@ -320,6 +335,8 @@ enum clk_gating_state {
  * @is_suspended: clk gating is suspended when set to 1 which can be used
  * during suspend/resume
  * @delay_attr: sysfs attribute to control delay_attr
+ * @enable_attr: sysfs attribute to enable/disable clock gating
+ * @is_enabled: Indicates the current status of clock gating
  * @active_reqs: number of requests that are pending and should be waited for
  * completion before gating clocks.
  */
@@ -330,14 +347,47 @@ struct ufs_clk_gating {
        unsigned long delay_ms;
        bool is_suspended;
        struct device_attribute delay_attr;
+       struct device_attribute enable_attr;
+       bool is_enabled;
        int active_reqs;
 };
 
+struct ufs_saved_pwr_info {
+       struct ufs_pa_layer_attr info;
+       bool is_valid;
+};
+
+/**
+ * struct ufs_clk_scaling - UFS clock scaling related data
+ * @active_reqs: number of requests that are pending. If this is zero when
+ * devfreq ->target() function is called then schedule "suspend_work" to
+ * suspend devfreq.
+ * @tot_busy_t: Total busy time in current polling window
+ * @window_start_t: Start time (in jiffies) of the current polling window
+ * @busy_start_t: Start time of current busy period
+ * @enable_attr: sysfs attribute to enable/disable clock scaling
+ * @saved_pwr_info: UFS power mode may also be changed during scaling and this
+ * one keeps track of previous power mode.
+ * @workq: workqueue to schedule devfreq suspend/resume work
+ * @suspend_work: worker to suspend devfreq
+ * @resume_work: worker to resume devfreq
+ * @is_allowed: tracks if scaling is currently allowed or not
+ * @is_busy_started: tracks if busy period has started or not
+ * @is_suspended: tracks if devfreq is suspended or not
+ */
 struct ufs_clk_scaling {
-       ktime_t  busy_start_t;
-       bool is_busy_started;
-       unsigned long  tot_busy_t;
+       int active_reqs;
+       unsigned long tot_busy_t;
        unsigned long window_start_t;
+       ktime_t busy_start_t;
+       struct device_attribute enable_attr;
+       struct ufs_saved_pwr_info saved_pwr_info;
+       struct workqueue_struct *workq;
+       struct work_struct suspend_work;
+       struct work_struct resume_work;
+       bool is_allowed;
+       bool is_busy_started;
+       bool is_suspended;
 };
 
 /**
@@ -349,6 +399,41 @@ struct ufs_init_prefetch {
        u32 icc_level;
 };
 
+#define UIC_ERR_REG_HIST_LENGTH 8
+/**
+ * struct ufs_uic_err_reg_hist - keeps history of uic errors
+ * @pos: index to indicate cyclic buffer position
+ * @reg: cyclic buffer for registers value
+ * @tstamp: cyclic buffer for time stamp
+ */
+struct ufs_uic_err_reg_hist {
+       int pos;
+       u32 reg[UIC_ERR_REG_HIST_LENGTH];
+       ktime_t tstamp[UIC_ERR_REG_HIST_LENGTH];
+};
+
+/**
+ * struct ufs_stats - keeps usage/err statistics
+ * @hibern8_exit_cnt: Counter to keep track of number of exits,
+ *             reset this after link-startup.
+ * @last_hibern8_exit_tstamp: Set time after the hibern8 exit.
+ *             Clear after the first successful command completion.
+ * @pa_err: tracks pa-uic errors
+ * @dl_err: tracks dl-uic errors
+ * @nl_err: tracks nl-uic errors
+ * @tl_err: tracks tl-uic errors
+ * @dme_err: tracks dme errors
+ */
+struct ufs_stats {
+       u32 hibern8_exit_cnt;
+       ktime_t last_hibern8_exit_tstamp;
+       struct ufs_uic_err_reg_hist pa_err;
+       struct ufs_uic_err_reg_hist dl_err;
+       struct ufs_uic_err_reg_hist nl_err;
+       struct ufs_uic_err_reg_hist tl_err;
+       struct ufs_uic_err_reg_hist dme_err;
+};
+
 /**
  * struct ufs_hba - per adapter private structure
  * @mmio_base: UFSHCI base register address
@@ -429,6 +514,8 @@ struct ufs_hba {
        enum ufs_pm_level rpm_lvl;
        /* Desired UFS power management level during system PM */
        enum ufs_pm_level spm_lvl;
+       struct device_attribute rpm_lvl_attr;
+       struct device_attribute spm_lvl_attr;
        int pm_op_in_progress;
 
        struct ufshcd_lrb *lrb;
@@ -523,6 +610,7 @@ struct ufs_hba {
        u32 uic_error;
        u32 saved_err;
        u32 saved_uic_err;
+       struct ufs_stats ufs_stats;
 
        /* Device management request data */
        struct ufs_dev_cmd dev_cmd;
@@ -536,6 +624,9 @@ struct ufs_hba {
 
        bool wlun_dev_clr_ua;
 
+       /* Number of requests aborts */
+       int req_abort_count;
+
        /* Number of lanes available (1 or 2) for Rx/Tx */
        u32 lanes_per_direction;
        struct ufs_pa_layer_attr pwr_info;
@@ -558,6 +649,14 @@ struct ufs_hba {
         * CAUTION: Enabling this might reduce overall UFS throughput.
         */
 #define UFSHCD_CAP_INTR_AGGR (1 << 4)
+       /*
+        * This capability allows the device auto-bkops to be always enabled
+        * except during suspend (both runtime and suspend).
+        * Enabling this capability means that device will always be allowed
+        * to do background operation when it's active but it might degrade
+        * the performance of ongoing read/write operations.
+        */
+#define UFSHCD_CAP_KEEP_AUTO_BKOPS_ENABLED_EXCEPT_SUSPEND (1 << 5)
 
        struct devfreq *devfreq;
        struct ufs_clk_scaling clk_scaling;
@@ -565,6 +664,8 @@ struct ufs_hba {
 
        enum bkops_status urgent_bkops_lvl;
        bool is_urgent_bkops_lvl_checked;
+
+       struct rw_semaphore clk_scaling_lock;
 };
 
 /* Returns true if clocks can be gated. Otherwise false */
@@ -576,7 +677,7 @@ static inline bool ufshcd_can_hibern8_during_gating(struct ufs_hba *hba)
 {
        return hba->caps & UFSHCD_CAP_HIBERN8_WITH_CLK_GATING;
 }
-static inline int ufshcd_is_clkscaling_enabled(struct ufs_hba *hba)
+static inline int ufshcd_is_clkscaling_supported(struct ufs_hba *hba)
 {
        return hba->caps & UFSHCD_CAP_CLK_SCALING;
 }
@@ -655,6 +756,11 @@ static inline void *ufshcd_get_variant(struct ufs_hba *hba)
        BUG_ON(!hba);
        return hba->priv;
 }
+static inline bool ufshcd_keep_autobkops_enabled_except_suspend(
+                                                       struct ufs_hba *hba)
+{
+       return hba->caps & UFSHCD_CAP_KEEP_AUTO_BKOPS_ENABLED_EXCEPT_SUSPEND;
+}
 
 extern int ufshcd_runtime_suspend(struct ufs_hba *hba);
 extern int ufshcd_runtime_resume(struct ufs_hba *hba);
@@ -713,8 +819,6 @@ static inline int ufshcd_dme_peer_get(struct ufs_hba *hba,
        return ufshcd_dme_get_attr(hba, attr_sel, mib_val, DME_PEER);
 }
 
-int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size);
-
 static inline bool ufshcd_is_hs_mode(struct ufs_pa_layer_attr *pwr_info)
 {
        return (pwr_info->pwr_rx == FAST_MODE ||
@@ -723,11 +827,6 @@ static inline bool ufshcd_is_hs_mode(struct ufs_pa_layer_attr *pwr_info)
                pwr_info->pwr_tx == FASTAUTO_MODE);
 }
 
-#define ASCII_STD true
-
-int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, u8 *buf,
-                               u32 size, bool ascii);
-
 /* Expose Query-Request API */
 int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
        enum flag_idn idn, bool *flag_res);
index 8c5190e2e1c928407e8aac111b67758fff9bc191..d14e9b965d1e3566b25c41f91b794b7f19f05ff1 100644 (file)
@@ -72,6 +72,9 @@ enum {
        REG_UIC_COMMAND_ARG_1                   = 0x94,
        REG_UIC_COMMAND_ARG_2                   = 0x98,
        REG_UIC_COMMAND_ARG_3                   = 0x9C,
+
+       UFSHCI_REG_SPACE_SIZE                   = 0xA0,
+
        REG_UFS_CCAP                            = 0x100,
        REG_UFS_CRYPTOCAP                       = 0x104,
 
index 15ca09cd16f34ad6f7a8ece088e1dababef3a1b5..ef474a7487449b4c1d51f82643988eb08fc1ed86 100644 (file)
@@ -68,10 +68,7 @@ struct pvscsi_ctx {
 
 struct pvscsi_adapter {
        char                            *mmioBase;
-       unsigned int                    irq;
        u8                              rev;
-       bool                            use_msi;
-       bool                            use_msix;
        bool                            use_msg;
        bool                            use_req_threshold;
 
@@ -1161,30 +1158,26 @@ static bool pvscsi_setup_req_threshold(struct pvscsi_adapter *adapter,
 static irqreturn_t pvscsi_isr(int irq, void *devp)
 {
        struct pvscsi_adapter *adapter = devp;
-       int handled;
-
-       if (adapter->use_msi || adapter->use_msix)
-               handled = true;
-       else {
-               u32 val = pvscsi_read_intr_status(adapter);
-               handled = (val & PVSCSI_INTR_ALL_SUPPORTED) != 0;
-               if (handled)
-                       pvscsi_write_intr_status(devp, val);
-       }
-
-       if (handled) {
-               unsigned long flags;
+       unsigned long flags;
 
-               spin_lock_irqsave(&adapter->hw_lock, flags);
+       spin_lock_irqsave(&adapter->hw_lock, flags);
+       pvscsi_process_completion_ring(adapter);
+       if (adapter->use_msg && pvscsi_msg_pending(adapter))
+               queue_work(adapter->workqueue, &adapter->work);
+       spin_unlock_irqrestore(&adapter->hw_lock, flags);
 
-               pvscsi_process_completion_ring(adapter);
-               if (adapter->use_msg && pvscsi_msg_pending(adapter))
-                       queue_work(adapter->workqueue, &adapter->work);
+       return IRQ_HANDLED;
+}
 
-               spin_unlock_irqrestore(&adapter->hw_lock, flags);
-       }
+static irqreturn_t pvscsi_shared_isr(int irq, void *devp)
+{
+       struct pvscsi_adapter *adapter = devp;
+       u32 val = pvscsi_read_intr_status(adapter);
 
-       return IRQ_RETVAL(handled);
+       if (!(val & PVSCSI_INTR_ALL_SUPPORTED))
+               return IRQ_NONE;
+       pvscsi_write_intr_status(devp, val);
+       return pvscsi_isr(irq, devp);
 }
 
 static void pvscsi_free_sgls(const struct pvscsi_adapter *adapter)
@@ -1196,34 +1189,10 @@ static void pvscsi_free_sgls(const struct pvscsi_adapter *adapter)
                free_pages((unsigned long)ctx->sgl, get_order(SGL_SIZE));
 }
 
-static int pvscsi_setup_msix(const struct pvscsi_adapter *adapter,
-                            unsigned int *irq)
-{
-       struct msix_entry entry = { 0, PVSCSI_VECTOR_COMPLETION };
-       int ret;
-
-       ret = pci_enable_msix_exact(adapter->dev, &entry, 1);
-       if (ret)
-               return ret;
-
-       *irq = entry.vector;
-
-       return 0;
-}
-
 static void pvscsi_shutdown_intr(struct pvscsi_adapter *adapter)
 {
-       if (adapter->irq) {
-               free_irq(adapter->irq, adapter);
-               adapter->irq = 0;
-       }
-       if (adapter->use_msi) {
-               pci_disable_msi(adapter->dev);
-               adapter->use_msi = 0;
-       } else if (adapter->use_msix) {
-               pci_disable_msix(adapter->dev);
-               adapter->use_msix = 0;
-       }
+       free_irq(pci_irq_vector(adapter->dev, 0), adapter);
+       pci_free_irq_vectors(adapter->dev);
 }
 
 static void pvscsi_release_resources(struct pvscsi_adapter *adapter)
@@ -1359,11 +1328,11 @@ exit:
 
 static int pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
+       unsigned int irq_flag = PCI_IRQ_MSIX | PCI_IRQ_MSI | PCI_IRQ_LEGACY;
        struct pvscsi_adapter *adapter;
        struct pvscsi_adapter adapter_temp;
        struct Scsi_Host *host = NULL;
        unsigned int i;
-       unsigned long flags = 0;
        int error;
        u32 max_id;
 
@@ -1512,30 +1481,33 @@ static int pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                goto out_reset_adapter;
        }
 
-       if (!pvscsi_disable_msix &&
-           pvscsi_setup_msix(adapter, &adapter->irq) == 0) {
-               printk(KERN_INFO "vmw_pvscsi: using MSI-X\n");
-               adapter->use_msix = 1;
-       } else if (!pvscsi_disable_msi && pci_enable_msi(pdev) == 0) {
-               printk(KERN_INFO "vmw_pvscsi: using MSI\n");
-               adapter->use_msi = 1;
-               adapter->irq = pdev->irq;
-       } else {
-               printk(KERN_INFO "vmw_pvscsi: using INTx\n");
-               adapter->irq = pdev->irq;
-               flags = IRQF_SHARED;
-       }
+       if (pvscsi_disable_msix)
+               irq_flag &= ~PCI_IRQ_MSIX;
+       if (pvscsi_disable_msi)
+               irq_flag &= ~PCI_IRQ_MSI;
+
+       error = pci_alloc_irq_vectors(adapter->dev, 1, 1, irq_flag);
+       if (error)
+               goto out_reset_adapter;
 
        adapter->use_req_threshold = pvscsi_setup_req_threshold(adapter, true);
        printk(KERN_DEBUG "vmw_pvscsi: driver-based request coalescing %sabled\n",
               adapter->use_req_threshold ? "en" : "dis");
 
-       error = request_irq(adapter->irq, pvscsi_isr, flags,
-                           "vmw_pvscsi", adapter);
+       if (adapter->dev->msix_enabled || adapter->dev->msi_enabled) {
+               printk(KERN_INFO "vmw_pvscsi: using MSI%s\n",
+                       adapter->dev->msix_enabled ? "-X" : "");
+               error = request_irq(pci_irq_vector(pdev, 0), pvscsi_isr,
+                               0, "vmw_pvscsi", adapter);
+       } else {
+               printk(KERN_INFO "vmw_pvscsi: using INTx\n");
+               error = request_irq(pci_irq_vector(pdev, 0), pvscsi_shared_isr,
+                               IRQF_SHARED, "vmw_pvscsi", adapter);
+       }
+
        if (error) {
                printk(KERN_ERR
                       "vmw_pvscsi: unable to request IRQ: %d\n", error);
-               adapter->irq = 0;
                goto out_reset_adapter;
        }
 
index d41292ef85f2ff93b879237a8da7f2357c489b24..75966d3f326e0b20ee49b78cdea0b0d6bd635470 100644 (file)
@@ -422,11 +422,6 @@ struct PVSCSIConfigPageController {
  */
 #define PVSCSI_MAX_INTRS        24
 
-/*
- * Enumeration of supported MSI-X vectors
- */
-#define PVSCSI_VECTOR_COMPLETION   0
-
 /*
  * Misc constants for the rings.
  */
index 0acdfd82e7510189bc8bb4a254c653667d012e89..813df6e7292d7ac4cbf25d33d0e5e166dce6e14b 100644 (file)
@@ -11,6 +11,8 @@
 
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/mfd/syscon.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 
@@ -92,9 +94,18 @@ static const struct of_device_id exynos_pmu_of_device_ids[] = {
        { /*sentinel*/ },
 };
 
+struct regmap *exynos_get_pmu_regmap(void)
+{
+       struct device_node *np = of_find_matching_node(NULL,
+                                                     exynos_pmu_of_device_ids);
+       if (np)
+               return syscon_node_to_regmap(np);
+       return ERR_PTR(-ENODEV);
+}
+EXPORT_SYMBOL_GPL(exynos_get_pmu_regmap);
+
 static int exynos_pmu_probe(struct platform_device *pdev)
 {
-       const struct of_device_id *match;
        struct device *dev = &pdev->dev;
        struct resource *res;
 
@@ -106,15 +117,10 @@ static int exynos_pmu_probe(struct platform_device *pdev)
        pmu_context = devm_kzalloc(&pdev->dev,
                        sizeof(struct exynos_pmu_context),
                        GFP_KERNEL);
-       if (!pmu_context) {
-               dev_err(dev, "Cannot allocate memory.\n");
+       if (!pmu_context)
                return -ENOMEM;
-       }
        pmu_context->dev = dev;
-
-       match = of_match_node(exynos_pmu_of_device_ids, dev->of_node);
-
-       pmu_context->pmu_data = match->data;
+       pmu_context->pmu_data = of_device_get_match_data(dev);
 
        if (pmu_context->pmu_data->pmu_init)
                pmu_context->pmu_data->pmu_init();
index 2922a9908302d84781f63d1b091ca6e4ddb2eba8..25ae7f2e44b51717251c068e3a9f85288c614093 100644 (file)
@@ -162,7 +162,8 @@ config SPI_BCM63XX_HSSPI
 
 config SPI_BCM_QSPI
        tristate "Broadcom BSPI and MSPI controller support"
-       depends on ARCH_BRCMSTB || ARCH_BCM || ARCH_BCM_IPROC || COMPILE_TEST
+       depends on ARCH_BRCMSTB || ARCH_BCM || ARCH_BCM_IPROC || \
+                       BMIPS_GENERIC || COMPILE_TEST
        default ARCH_BCM_IPROC
        help
          Enables support for the Broadcom SPI flash and MSPI controller.
@@ -263,7 +264,7 @@ config SPI_EP93XX
          mode.
 
 config SPI_FALCON
-       tristate "Falcon SPI controller support"
+       bool "Falcon SPI controller support"
        depends on SOC_FALCON
        help
          The external bus unit (EBU) found on the FALC-ON SoC has SPI
@@ -416,6 +417,14 @@ config SPI_NUC900
        help
          SPI driver for Nuvoton NUC900 series ARM SoCs
 
+config SPI_LANTIQ_SSC
+       tristate "Lantiq SSC SPI controller"
+       depends on LANTIQ || COMPILE_TEST
+       help
+         This driver supports the Lantiq SSC SPI controller in master
+         mode. This controller is found on Intel (former Lantiq) SoCs like
+         the Danube, Falcon, xRX200, xRX300.
+
 config SPI_OC_TINY
        tristate "OpenCores tiny SPI"
        depends on GPIOLIB || COMPILE_TEST
index 7a6b64662c82c71106f3af94a61190ba1f98a218..b375a7a892160b76b5bf62a7f66f86484f300ed1 100644 (file)
@@ -49,6 +49,7 @@ obj-$(CONFIG_SPI_FSL_SPI)             += spi-fsl-spi.o
 obj-$(CONFIG_SPI_GPIO)                 += spi-gpio.o
 obj-$(CONFIG_SPI_IMG_SPFI)             += spi-img-spfi.o
 obj-$(CONFIG_SPI_IMX)                  += spi-imx.o
+obj-$(CONFIG_SPI_LANTIQ_SSC)           += spi-lantiq-ssc.o
 obj-$(CONFIG_SPI_JCORE)                        += spi-jcore.o
 obj-$(CONFIG_SPI_LM70_LLP)             += spi-lm70llp.o
 obj-$(CONFIG_SPI_LP8841_RTC)           += spi-lp8841-rtc.o
index 0314c6b9e04415b0cb792d8e9a4048a6311fd97d..6c7d7a460689917d577973f7bb47a1e408470210 100644 (file)
@@ -170,12 +170,12 @@ static int a3700_spi_pin_mode_set(struct a3700_spi *a3700_spi,
        val &= ~(A3700_SPI_DATA_PIN0 | A3700_SPI_DATA_PIN1);
 
        switch (pin_mode) {
-       case 1:
+       case SPI_NBITS_SINGLE:
                break;
-       case 2:
+       case SPI_NBITS_DUAL:
                val |= A3700_SPI_DATA_PIN0;
                break;
-       case 4:
+       case SPI_NBITS_QUAD:
                val |= A3700_SPI_DATA_PIN1;
                break;
        default:
@@ -340,8 +340,7 @@ static irqreturn_t a3700_spi_interrupt(int irq, void *dev_id)
        spireg_write(a3700_spi, A3700_SPI_INT_STAT_REG, cause);
 
        /* Wake up the transfer */
-       if (a3700_spi->wait_mask & cause)
-               complete(&a3700_spi->done);
+       complete(&a3700_spi->done);
 
        return IRQ_HANDLED;
 }
@@ -421,7 +420,7 @@ static void a3700_spi_fifo_thres_set(struct a3700_spi *a3700_spi,
 }
 
 static void a3700_spi_transfer_setup(struct spi_device *spi,
-                                   struct spi_transfer *xfer)
+                                    struct spi_transfer *xfer)
 {
        struct a3700_spi *a3700_spi;
        unsigned int byte_len;
@@ -562,6 +561,7 @@ static int a3700_spi_fifo_read(struct a3700_spi *a3700_spi)
                val = spireg_read(a3700_spi, A3700_SPI_DATA_IN_REG);
                if (a3700_spi->buf_len >= 4) {
                        u32 data = le32_to_cpu(val);
+
                        memcpy(a3700_spi->rx_buf, &data, 4);
 
                        a3700_spi->buf_len -= 4;
@@ -901,7 +901,6 @@ static int a3700_spi_remove(struct platform_device *pdev)
        struct a3700_spi *spi = spi_master_get_devdata(master);
 
        clk_unprepare(spi->clk);
-       spi_master_put(master);
 
        return 0;
 }
@@ -909,7 +908,6 @@ static int a3700_spi_remove(struct platform_device *pdev)
 static struct platform_driver a3700_spi_driver = {
        .driver = {
                .name   = DRIVER_NAME,
-               .owner  = THIS_MODULE,
                .of_match_table = of_match_ptr(a3700_spi_dt_ids),
        },
        .probe          = a3700_spi_probe,
index f369174fbd886fbbc09a13af5f9dbce66d498635..b89cee11f41815be61876bb9206e59cb4d6714b1 100644 (file)
@@ -78,14 +78,16 @@ static void ath79_spi_chipselect(struct spi_device *spi, int is_active)
                ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base);
        }
 
-       if (spi->chip_select) {
+       if (gpio_is_valid(spi->cs_gpio)) {
                /* SPI is normally active-low */
-               gpio_set_value(spi->cs_gpio, cs_high);
+               gpio_set_value_cansleep(spi->cs_gpio, cs_high);
        } else {
+               u32 cs_bit = AR71XX_SPI_IOC_CS(spi->chip_select);
+
                if (cs_high)
-                       sp->ioc_base |= AR71XX_SPI_IOC_CS0;
+                       sp->ioc_base |= cs_bit;
                else
-                       sp->ioc_base &= ~AR71XX_SPI_IOC_CS0;
+                       sp->ioc_base &= ~cs_bit;
 
                ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base);
        }
@@ -118,11 +120,8 @@ static int ath79_spi_setup_cs(struct spi_device *spi)
        struct ath79_spi *sp = ath79_spidev_to_sp(spi);
        int status;
 
-       if (spi->chip_select && !gpio_is_valid(spi->cs_gpio))
-               return -EINVAL;
-
        status = 0;
-       if (spi->chip_select) {
+       if (gpio_is_valid(spi->cs_gpio)) {
                unsigned long flags;
 
                flags = GPIOF_DIR_OUT;
@@ -134,10 +133,12 @@ static int ath79_spi_setup_cs(struct spi_device *spi)
                status = gpio_request_one(spi->cs_gpio, flags,
                                          dev_name(&spi->dev));
        } else {
+               u32 cs_bit = AR71XX_SPI_IOC_CS(spi->chip_select);
+
                if (spi->mode & SPI_CS_HIGH)
-                       sp->ioc_base &= ~AR71XX_SPI_IOC_CS0;
+                       sp->ioc_base &= ~cs_bit;
                else
-                       sp->ioc_base |= AR71XX_SPI_IOC_CS0;
+                       sp->ioc_base |= cs_bit;
 
                ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base);
        }
@@ -147,7 +148,7 @@ static int ath79_spi_setup_cs(struct spi_device *spi)
 
 static void ath79_spi_cleanup_cs(struct spi_device *spi)
 {
-       if (spi->chip_select) {
+       if (gpio_is_valid(spi->cs_gpio)) {
                gpio_free(spi->cs_gpio);
        }
 }
index d7843fd8c610427d1da58a689c115025084eced2..b19722ba908c1be3855e42d21b25f2e6fb38eae8 100644 (file)
@@ -89,7 +89,7 @@
 #define BSPI_BPP_MODE_SELECT_MASK              BIT(8)
 #define BSPI_BPP_ADDR_SELECT_MASK              BIT(16)
 
-#define BSPI_READ_LENGTH                       256
+#define BSPI_READ_LENGTH                       512
 
 /* MSPI register offsets */
 #define MSPI_SPCR0_LSB                         0x000
@@ -192,9 +192,11 @@ struct bcm_qspi_dev_id {
        void *dev;
 };
 
+
 struct qspi_trans {
        struct spi_transfer *trans;
        int byte;
+       bool mspi_last_trans;
 };
 
 struct bcm_qspi {
@@ -616,6 +618,16 @@ static int bcm_qspi_setup(struct spi_device *spi)
        return 0;
 }
 
+static bool bcm_qspi_mspi_transfer_is_last(struct bcm_qspi *qspi,
+                                          struct qspi_trans *qt)
+{
+       if (qt->mspi_last_trans &&
+           spi_transfer_is_last(qspi->master, qt->trans))
+               return true;
+       else
+               return false;
+}
+
 static int update_qspi_trans_byte_count(struct bcm_qspi *qspi,
                                        struct qspi_trans *qt, int flags)
 {
@@ -629,7 +641,6 @@ static int update_qspi_trans_byte_count(struct bcm_qspi *qspi,
 
        if (qt->byte >= qt->trans->len) {
                /* we're at the end of the spi_transfer */
-
                /* in TX mode, need to pause for a delay or CS change */
                if (qt->trans->delay_usecs &&
                    (flags & TRANS_STATUS_BREAK_DELAY))
@@ -641,7 +652,7 @@ static int update_qspi_trans_byte_count(struct bcm_qspi *qspi,
                        goto done;
 
                dev_dbg(&qspi->pdev->dev, "advance msg exit\n");
-               if (spi_transfer_is_last(qspi->master, qt->trans))
+               if (bcm_qspi_mspi_transfer_is_last(qspi, qt))
                        ret = TRANS_STATUS_BREAK_EOM;
                else
                        ret = TRANS_STATUS_BREAK_NO_BYTES;
@@ -813,7 +824,7 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi,
                                    struct spi_flash_read_message *msg)
 {
        struct bcm_qspi *qspi = spi_master_get_devdata(spi->master);
-       u32 addr = 0, len, len_words;
+       u32 addr = 0, len, rdlen, len_words;
        int ret = 0;
        unsigned long timeo = msecs_to_jiffies(100);
        struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;
@@ -826,7 +837,7 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi,
        bcm_qspi_write(qspi, MSPI, MSPI_WRITE_LOCK, 0);
 
        /*
-        * when using flex mode mode we need to send
+        * when using flex mode we need to send
         * the upper address byte to bspi
         */
        if (bcm_qspi_bspi_ver_three(qspi) == false) {
@@ -840,48 +851,127 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi,
        else
                addr = msg->from & 0x00ffffff;
 
-       /* set BSPI RAF buffer max read length */
-       len = msg->len;
-       if (len > BSPI_READ_LENGTH)
-               len = BSPI_READ_LENGTH;
-
        if (bcm_qspi_bspi_ver_three(qspi) == true)
                addr = (addr + 0xc00000) & 0xffffff;
 
-       reinit_completion(&qspi->bspi_done);
-       bcm_qspi_enable_bspi(qspi);
-       len_words = (len + 3) >> 2;
-       qspi->bspi_rf_msg = msg;
-       qspi->bspi_rf_msg_status = 0;
+       /*
+        * read into the entire buffer by breaking the reads
+        * into RAF buffer read lengths
+        */
+       len = msg->len;
        qspi->bspi_rf_msg_idx = 0;
-       qspi->bspi_rf_msg_len = len;
-       dev_dbg(&qspi->pdev->dev, "bspi xfr addr 0x%x len 0x%x", addr, len);
 
-       bcm_qspi_write(qspi, BSPI, BSPI_RAF_START_ADDR, addr);
-       bcm_qspi_write(qspi, BSPI, BSPI_RAF_NUM_WORDS, len_words);
-       bcm_qspi_write(qspi, BSPI, BSPI_RAF_WATERMARK, 0);
+       do {
+               if (len > BSPI_READ_LENGTH)
+                       rdlen = BSPI_READ_LENGTH;
+               else
+                       rdlen = len;
+
+               reinit_completion(&qspi->bspi_done);
+               bcm_qspi_enable_bspi(qspi);
+               len_words = (rdlen + 3) >> 2;
+               qspi->bspi_rf_msg = msg;
+               qspi->bspi_rf_msg_status = 0;
+               qspi->bspi_rf_msg_len = rdlen;
+               dev_dbg(&qspi->pdev->dev,
+                       "bspi xfr addr 0x%x len 0x%x", addr, rdlen);
+               bcm_qspi_write(qspi, BSPI, BSPI_RAF_START_ADDR, addr);
+               bcm_qspi_write(qspi, BSPI, BSPI_RAF_NUM_WORDS, len_words);
+               bcm_qspi_write(qspi, BSPI, BSPI_RAF_WATERMARK, 0);
+               if (qspi->soc_intc) {
+                       /*
+                        * clear soc MSPI and BSPI interrupts and enable
+                        * BSPI interrupts.
+                        */
+                       soc_intc->bcm_qspi_int_ack(soc_intc, MSPI_BSPI_DONE);
+                       soc_intc->bcm_qspi_int_set(soc_intc, BSPI_DONE, true);
+               }
 
-       if (qspi->soc_intc) {
-               /*
-                * clear soc MSPI and BSPI interrupts and enable
-                * BSPI interrupts.
-                */
-               soc_intc->bcm_qspi_int_ack(soc_intc, MSPI_BSPI_DONE);
-               soc_intc->bcm_qspi_int_set(soc_intc, BSPI_DONE, true);
+               /* Must flush previous writes before starting BSPI operation */
+               mb();
+               bcm_qspi_bspi_lr_start(qspi);
+               if (!wait_for_completion_timeout(&qspi->bspi_done, timeo)) {
+                       dev_err(&qspi->pdev->dev, "timeout waiting for BSPI\n");
+                       ret = -ETIMEDOUT;
+                       break;
+               }
+
+               /* set msg return length */
+               msg->retlen += rdlen;
+               addr += rdlen;
+               len -= rdlen;
+       } while (len);
+
+       return ret;
+}
+
+static int bcm_qspi_transfer_one(struct spi_master *master,
+                                struct spi_device *spi,
+                                struct spi_transfer *trans)
+{
+       struct bcm_qspi *qspi = spi_master_get_devdata(master);
+       int slots;
+       unsigned long timeo = msecs_to_jiffies(100);
+
+       bcm_qspi_chip_select(qspi, spi->chip_select);
+       qspi->trans_pos.trans = trans;
+       qspi->trans_pos.byte = 0;
+
+       while (qspi->trans_pos.byte < trans->len) {
+               reinit_completion(&qspi->mspi_done);
+
+               slots = write_to_hw(qspi, spi);
+               if (!wait_for_completion_timeout(&qspi->mspi_done, timeo)) {
+                       dev_err(&qspi->pdev->dev, "timeout waiting for MSPI\n");
+                       return -ETIMEDOUT;
+               }
+
+               read_from_hw(qspi, slots);
        }
 
-       /* Must flush previous writes before starting BSPI operation */
-       mb();
+       return 0;
+}
 
-       bcm_qspi_bspi_lr_start(qspi);
-       if (!wait_for_completion_timeout(&qspi->bspi_done, timeo)) {
-               dev_err(&qspi->pdev->dev, "timeout waiting for BSPI\n");
-               ret = -ETIMEDOUT;
-       } else {
-               /* set the return length for the caller */
-               msg->retlen = len;
+static int bcm_qspi_mspi_flash_read(struct spi_device *spi,
+                                   struct spi_flash_read_message *msg)
+{
+       struct bcm_qspi *qspi = spi_master_get_devdata(spi->master);
+       struct spi_transfer t[2];
+       u8 cmd[6];
+       int ret;
+
+       memset(cmd, 0, sizeof(cmd));
+       memset(t, 0, sizeof(t));
+
+       /* tx */
+       /* opcode is in cmd[0] */
+       cmd[0] = msg->read_opcode;
+       cmd[1] = msg->from >> (msg->addr_width * 8 -  8);
+       cmd[2] = msg->from >> (msg->addr_width * 8 - 16);
+       cmd[3] = msg->from >> (msg->addr_width * 8 - 24);
+       cmd[4] = msg->from >> (msg->addr_width * 8 - 32);
+       t[0].tx_buf = cmd;
+       t[0].len = msg->addr_width + msg->dummy_bytes + 1;
+       t[0].bits_per_word = spi->bits_per_word;
+       t[0].tx_nbits = msg->opcode_nbits;
+       /* lets mspi know that this is not last transfer */
+       qspi->trans_pos.mspi_last_trans = false;
+       ret = bcm_qspi_transfer_one(spi->master, spi, &t[0]);
+
+       /* rx */
+       qspi->trans_pos.mspi_last_trans = true;
+       if (!ret) {
+               /* rx */
+               t[1].rx_buf = msg->buf;
+               t[1].len = msg->len;
+               t[1].rx_nbits =  msg->data_nbits;
+               t[1].bits_per_word = spi->bits_per_word;
+               ret = bcm_qspi_transfer_one(spi->master, spi, &t[1]);
        }
 
+       if (!ret)
+               msg->retlen = msg->len;
+
        return ret;
 }
 
@@ -918,8 +1008,7 @@ static int bcm_qspi_flash_read(struct spi_device *spi,
                mspi_read = true;
 
        if (mspi_read)
-               /* this will make the m25p80 read to fallback to mspi read */
-               return -EAGAIN;
+               return bcm_qspi_mspi_flash_read(spi, msg);
 
        io_width = msg->data_nbits ? msg->data_nbits : SPI_NBITS_SINGLE;
        addrlen = msg->addr_width;
@@ -931,33 +1020,6 @@ static int bcm_qspi_flash_read(struct spi_device *spi,
        return ret;
 }
 
-static int bcm_qspi_transfer_one(struct spi_master *master,
-                                struct spi_device *spi,
-                                struct spi_transfer *trans)
-{
-       struct bcm_qspi *qspi = spi_master_get_devdata(master);
-       int slots;
-       unsigned long timeo = msecs_to_jiffies(100);
-
-       bcm_qspi_chip_select(qspi, spi->chip_select);
-       qspi->trans_pos.trans = trans;
-       qspi->trans_pos.byte = 0;
-
-       while (qspi->trans_pos.byte < trans->len) {
-               reinit_completion(&qspi->mspi_done);
-
-               slots = write_to_hw(qspi, spi);
-               if (!wait_for_completion_timeout(&qspi->mspi_done, timeo)) {
-                       dev_err(&qspi->pdev->dev, "timeout waiting for MSPI\n");
-                       return -ETIMEDOUT;
-               }
-
-               read_from_hw(qspi, slots);
-       }
-
-       return 0;
-}
-
 static void bcm_qspi_cleanup(struct spi_device *spi)
 {
        struct bcm_qspi_parms *xp = spi_get_ctldata(spi);
@@ -1187,6 +1249,7 @@ int bcm_qspi_probe(struct platform_device *pdev,
        qspi->pdev = pdev;
        qspi->trans_pos.trans = NULL;
        qspi->trans_pos.byte = 0;
+       qspi->trans_pos.mspi_last_trans = true;
        qspi->master = master;
 
        master->bus_num = -1;
@@ -1345,7 +1408,6 @@ int bcm_qspi_remove(struct platform_device *pdev)
 {
        struct bcm_qspi *qspi = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
        bcm_qspi_hw_uninit(qspi);
        clk_disable_unprepare(qspi->clk);
        kfree(qspi->dev_ids);
index afb51699dbb5a6953821189ed03a9bfbfa8d9b7a..6e409eabe1c938224b9907f0fbe3fe86679eeb98 100644 (file)
@@ -1,3 +1,11 @@
+/*
+ * Copyright (C) 2014-2016 RafaÅ‚ MiÅ‚ecki <rafal@milecki.pl>
+ *
+ * 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.
+ */
+
 #define pr_fmt(fmt)            KBUILD_MODNAME ": " fmt
 
 #include <linux/kernel.h>
@@ -275,10 +283,6 @@ static int bcm53xxspi_flash_read(struct spi_device *spi,
  * BCMA
  **************************************************/
 
-static struct spi_board_info bcm53xx_info = {
-       .modalias       = "bcm53xxspiflash",
-};
-
 static const struct bcma_device_id bcm53xxspi_bcma_tbl[] = {
        BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_QSPI, BCMA_ANY_REV, BCMA_ANY_CLASS),
        {},
@@ -311,6 +315,7 @@ static int bcm53xxspi_bcma_probe(struct bcma_device *core)
        b53spi->bspi = true;
        bcm53xxspi_disable_bspi(b53spi);
 
+       master->dev.of_node = dev->of_node;
        master->transfer_one = bcm53xxspi_transfer_one;
        if (b53spi->mmio_base)
                master->spi_flash_read = bcm53xxspi_flash_read;
@@ -324,9 +329,6 @@ static int bcm53xxspi_bcma_probe(struct bcma_device *core)
                return err;
        }
 
-       /* Broadcom SoCs (at least with the CC rev 42) use SPI for flash only */
-       spi_new_device(master, &bcm53xx_info);
-
        return 0;
 }
 
@@ -361,4 +363,4 @@ module_exit(bcm53xxspi_module_exit);
 
 MODULE_DESCRIPTION("Broadcom BCM53xx SPI Controller driver");
 MODULE_AUTHOR("RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com>");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
index 054012f875671b995141f8c549021389f21f454f..b217c22ff72fe9a2284f59f8c1cd62aca58680aa 100644 (file)
@@ -107,9 +107,9 @@ static const struct file_operations dw_spi_regs_ops = {
 
 static int dw_spi_debugfs_init(struct dw_spi *dws)
 {
-       char name[128];
+       char name[32];
 
-       snprintf(name, 128, "dw_spi-%s", dev_name(&dws->master->dev));
+       snprintf(name, 32, "dw_spi%d", dws->master->bus_num);
        dws->debugfs = debugfs_create_dir(name, NULL);
        if (!dws->debugfs)
                return -ENOMEM;
@@ -486,9 +486,9 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
        dws->type = SSI_MOTO_SPI;
        dws->dma_inited = 0;
        dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR);
-       snprintf(dws->name, sizeof(dws->name), "dw_spi%d", dws->bus_num);
 
-       ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dws->name, master);
+       ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dev_name(dev),
+                         master);
        if (ret < 0) {
                dev_err(dev, "can not get IRQ\n");
                goto err_free_master;
index c21ca02f8ec5fcb1d6ca74ee15f43028d03044c7..da5eab62df3477dc4ceb66bed98457373bef3fe8 100644 (file)
@@ -101,7 +101,6 @@ struct dw_spi_dma_ops {
 struct dw_spi {
        struct spi_master       *master;
        enum dw_ssi_type        type;
-       char                    name[16];
 
        void __iomem            *regs;
        unsigned long           paddr;
index 17a6387e20b5fb0f9cf673cfb4cc8e4322ea9fed..b5d766064b7b59390d50e888ad0832605f47699f 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/platform_device.h>
 #include <linux/sched.h>
 #include <linux/scatterlist.h>
+#include <linux/gpio.h>
 #include <linux/spi/spi.h>
 
 #include <linux/platform_data/dma-ep93xx.h>
@@ -107,16 +108,6 @@ struct ep93xx_spi {
        void                            *zeropage;
 };
 
-/**
- * struct ep93xx_spi_chip - SPI device hardware settings
- * @spi: back pointer to the SPI device
- * @ops: private chip operations
- */
-struct ep93xx_spi_chip {
-       const struct spi_device         *spi;
-       struct ep93xx_spi_chip_ops      *ops;
-};
-
 /* converts bits per word to CR0.DSS value */
 #define bits_per_word_to_dss(bpw)      ((bpw) - 1)
 
@@ -229,104 +220,36 @@ static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi,
        return -EINVAL;
 }
 
-static void ep93xx_spi_cs_control(struct spi_device *spi, bool control)
-{
-       struct ep93xx_spi_chip *chip = spi_get_ctldata(spi);
-       int value = (spi->mode & SPI_CS_HIGH) ? control : !control;
-
-       if (chip->ops && chip->ops->cs_control)
-               chip->ops->cs_control(spi, value);
-}
-
-/**
- * ep93xx_spi_setup() - setup an SPI device
- * @spi: SPI device to setup
- *
- * This function sets up SPI device mode, speed etc. Can be called multiple
- * times for a single device. Returns %0 in case of success, negative error in
- * case of failure. When this function returns success, the device is
- * deselected.
- */
-static int ep93xx_spi_setup(struct spi_device *spi)
+static void ep93xx_spi_cs_control(struct spi_device *spi, bool enable)
 {
-       struct ep93xx_spi *espi = spi_master_get_devdata(spi->master);
-       struct ep93xx_spi_chip *chip;
+       if (spi->mode & SPI_CS_HIGH)
+               enable = !enable;
 
-       chip = spi_get_ctldata(spi);
-       if (!chip) {
-               dev_dbg(&espi->pdev->dev, "initial setup for %s\n",
-                       spi->modalias);
-
-               chip = kzalloc(sizeof(*chip), GFP_KERNEL);
-               if (!chip)
-                       return -ENOMEM;
-
-               chip->spi = spi;
-               chip->ops = spi->controller_data;
-
-               if (chip->ops && chip->ops->setup) {
-                       int ret = chip->ops->setup(spi);
-
-                       if (ret) {
-                               kfree(chip);
-                               return ret;
-                       }
-               }
-
-               spi_set_ctldata(spi, chip);
-       }
-
-       ep93xx_spi_cs_control(spi, false);
-       return 0;
+       if (gpio_is_valid(spi->cs_gpio))
+               gpio_set_value(spi->cs_gpio, !enable);
 }
 
-/**
- * ep93xx_spi_cleanup() - cleans up master controller specific state
- * @spi: SPI device to cleanup
- *
- * This function releases master controller specific state for given @spi
- * device.
- */
-static void ep93xx_spi_cleanup(struct spi_device *spi)
-{
-       struct ep93xx_spi_chip *chip;
-
-       chip = spi_get_ctldata(spi);
-       if (chip) {
-               if (chip->ops && chip->ops->cleanup)
-                       chip->ops->cleanup(spi);
-               spi_set_ctldata(spi, NULL);
-               kfree(chip);
-       }
-}
-
-/**
- * ep93xx_spi_chip_setup() - configures hardware according to given @chip
- * @espi: ep93xx SPI controller struct
- * @chip: chip specific settings
- * @speed_hz: transfer speed
- * @bits_per_word: transfer bits_per_word
- */
 static int ep93xx_spi_chip_setup(const struct ep93xx_spi *espi,
-                                const struct ep93xx_spi_chip *chip,
-                                u32 speed_hz, u8 bits_per_word)
+                                struct spi_device *spi,
+                                struct spi_transfer *xfer)
 {
-       u8 dss = bits_per_word_to_dss(bits_per_word);
+       u8 dss = bits_per_word_to_dss(xfer->bits_per_word);
        u8 div_cpsr = 0;
        u8 div_scr = 0;
        u16 cr0;
        int err;
 
-       err = ep93xx_spi_calc_divisors(espi, speed_hz, &div_cpsr, &div_scr);
+       err = ep93xx_spi_calc_divisors(espi, xfer->speed_hz,
+                                      &div_cpsr, &div_scr);
        if (err)
                return err;
 
        cr0 = div_scr << SSPCR0_SCR_SHIFT;
-       cr0 |= (chip->spi->mode & (SPI_CPHA|SPI_CPOL)) << SSPCR0_MODE_SHIFT;
+       cr0 |= (spi->mode & (SPI_CPHA | SPI_CPOL)) << SSPCR0_MODE_SHIFT;
        cr0 |= dss;
 
        dev_dbg(&espi->pdev->dev, "setup: mode %d, cpsr %d, scr %d, dss %d\n",
-               chip->spi->mode, div_cpsr, div_scr, dss);
+               spi->mode, div_cpsr, div_scr, dss);
        dev_dbg(&espi->pdev->dev, "setup: cr0 %#x\n", cr0);
 
        ep93xx_spi_write_u8(espi, SSPCPSR, div_cpsr);
@@ -603,12 +526,11 @@ static void ep93xx_spi_process_transfer(struct ep93xx_spi *espi,
                                        struct spi_message *msg,
                                        struct spi_transfer *t)
 {
-       struct ep93xx_spi_chip *chip = spi_get_ctldata(msg->spi);
        int err;
 
        msg->state = t;
 
-       err = ep93xx_spi_chip_setup(espi, chip, t->speed_hz, t->bits_per_word);
+       err = ep93xx_spi_chip_setup(espi, msg->spi, t);
        if (err) {
                dev_err(&espi->pdev->dev,
                        "failed to setup chip for transfer\n");
@@ -863,8 +785,13 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
        struct resource *res;
        int irq;
        int error;
+       int i;
 
        info = dev_get_platdata(&pdev->dev);
+       if (!info) {
+               dev_err(&pdev->dev, "missing platform data\n");
+               return -EINVAL;
+       }
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
@@ -882,14 +809,36 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
        if (!master)
                return -ENOMEM;
 
-       master->setup = ep93xx_spi_setup;
        master->transfer_one_message = ep93xx_spi_transfer_one_message;
-       master->cleanup = ep93xx_spi_cleanup;
        master->bus_num = pdev->id;
-       master->num_chipselect = info->num_chipselect;
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
        master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
 
+       master->num_chipselect = info->num_chipselect;
+       master->cs_gpios = devm_kzalloc(&master->dev,
+                                       sizeof(int) * master->num_chipselect,
+                                       GFP_KERNEL);
+       if (!master->cs_gpios) {
+               error = -ENOMEM;
+               goto fail_release_master;
+       }
+
+       for (i = 0; i < master->num_chipselect; i++) {
+               master->cs_gpios[i] = info->chipselect[i];
+
+               if (!gpio_is_valid(master->cs_gpios[i]))
+                       continue;
+
+               error = devm_gpio_request_one(&pdev->dev, master->cs_gpios[i],
+                                             GPIOF_OUT_INIT_HIGH,
+                                             "ep93xx-spi");
+               if (error) {
+                       dev_err(&pdev->dev, "could not request cs gpio %d\n",
+                               master->cs_gpios[i]);
+                       goto fail_release_master;
+               }
+       }
+
        platform_set_drvdata(pdev, master);
 
        espi = spi_master_get_devdata(master);
index 52551f6d0c7ddf71aaf03ecc18c5caf2f804108b..cb3c73007ca15a79dc4283c8a07d065118cbca24 100644 (file)
@@ -366,7 +366,7 @@ static int fsl_lpspi_transfer_one_msg(struct spi_master *master,
        struct spi_transfer *xfer;
        bool is_first_xfer = true;
        u32 temp;
-       int ret;
+       int ret = 0;
 
        msg->status = 0;
        msg->actual_length = 0;
@@ -512,9 +512,9 @@ static int fsl_lpspi_remove(struct platform_device *pdev)
 
 static struct platform_driver fsl_lpspi_driver = {
        .driver = {
-                  .name = DRIVER_NAME,
-                  .of_match_table = fsl_lpspi_dt_ids,
-                  },
+               .name = DRIVER_NAME,
+               .of_match_table = fsl_lpspi_dt_ids,
+       },
        .probe = fsl_lpspi_probe,
        .remove = fsl_lpspi_remove,
 };
index 8b290d9d7935044640da36688e82fd01e90bf114..0fc3452652aee4fad412d74398ff6dd13f1ceb96 100644 (file)
@@ -267,10 +267,9 @@ static int fsl_spi_setup_transfer(struct spi_device *spi,
        if ((mpc8xxx_spi->spibrg / hz) > 64) {
                cs->hw_mode |= SPMODE_DIV16;
                pm = (mpc8xxx_spi->spibrg - 1) / (hz * 64) + 1;
-
-               WARN_ONCE(pm > 16, "%s: Requested speed is too low: %d Hz. "
-                         "Will use %d Hz instead.\n", dev_name(&spi->dev),
-                         hz, mpc8xxx_spi->spibrg / 1024);
+               WARN_ONCE(pm > 16,
+                         "%s: Requested speed is too low: %d Hz. Will use %d Hz instead.\n",
+                         dev_name(&spi->dev), hz, mpc8xxx_spi->spibrg / 1024);
                if (pm > 16)
                        pm = 16;
        } else {
@@ -727,12 +726,13 @@ static int of_fsl_spi_get_chipselects(struct device *dev)
                return 0;
        }
 
-       pinfo->gpios = kmalloc(ngpios * sizeof(*pinfo->gpios), GFP_KERNEL);
+       pinfo->gpios = kmalloc_array(ngpios, sizeof(*pinfo->gpios),
+                                    GFP_KERNEL);
        if (!pinfo->gpios)
                return -ENOMEM;
        memset(pinfo->gpios, -1, ngpios * sizeof(*pinfo->gpios));
 
-       pinfo->alow_flags = kzalloc(ngpios * sizeof(*pinfo->alow_flags),
+       pinfo->alow_flags = kcalloc(ngpios, sizeof(*pinfo->alow_flags),
                                    GFP_KERNEL);
        if (!pinfo->alow_flags) {
                ret = -ENOMEM;
@@ -762,8 +762,9 @@ static int of_fsl_spi_get_chipselects(struct device *dev)
                ret = gpio_direction_output(pinfo->gpios[i],
                                            pinfo->alow_flags[i]);
                if (ret) {
-                       dev_err(dev, "can't set output direction for gpio "
-                               "#%d: %d\n", i, ret);
+                       dev_err(dev,
+                               "can't set output direction for gpio #%d: %d\n",
+                               i, ret);
                        goto err_loop;
                }
        }
index 32ced64a5bb9a012e2edd0d415d8c477ebc0522a..9a7c62f471dc8cb2e62638d2846989da076442ae 100644 (file)
@@ -211,7 +211,7 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
                         struct spi_transfer *transfer)
 {
        struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
-       unsigned int bpw;
+       unsigned int bpw, i;
 
        if (!master->dma_rx)
                return false;
@@ -228,12 +228,16 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
        if (bpw != 1 && bpw != 2 && bpw != 4)
                return false;
 
-       if (transfer->len < spi_imx->wml * bpw)
-               return false;
+       for (i = spi_imx_get_fifosize(spi_imx) / 2; i > 0; i--) {
+               if (!(transfer->len % (i * bpw)))
+                       break;
+       }
 
-       if (transfer->len % (spi_imx->wml * bpw))
+       if (i == 0)
                return false;
 
+       spi_imx->wml = i;
+
        return true;
 }
 
@@ -837,10 +841,6 @@ static int spi_imx_dma_configure(struct spi_master *master,
        struct dma_slave_config rx = {}, tx = {};
        struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
 
-       if (bytes_per_word == spi_imx->bytes_per_word)
-               /* Same as last time */
-               return 0;
-
        switch (bytes_per_word) {
        case 4:
                buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
diff --git a/drivers/spi/spi-lantiq-ssc.c b/drivers/spi/spi-lantiq-ssc.c
new file mode 100644 (file)
index 0000000..8a626f7
--- /dev/null
@@ -0,0 +1,983 @@
+/*
+ * Copyright (C) 2011-2015 Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+ * Copyright (C) 2016 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/completion.h>
+#include <linux/spinlock.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/pm_runtime.h>
+#include <linux/spi/spi.h>
+
+#ifdef CONFIG_LANTIQ
+#include <lantiq_soc.h>
+#endif
+
+#define SPI_RX_IRQ_NAME                "spi_rx"
+#define SPI_TX_IRQ_NAME                "spi_tx"
+#define SPI_ERR_IRQ_NAME       "spi_err"
+#define SPI_FRM_IRQ_NAME       "spi_frm"
+
+#define SPI_CLC                        0x00
+#define SPI_PISEL              0x04
+#define SPI_ID                 0x08
+#define SPI_CON                        0x10
+#define SPI_STAT               0x14
+#define SPI_WHBSTATE           0x18
+#define SPI_TB                 0x20
+#define SPI_RB                 0x24
+#define SPI_RXFCON             0x30
+#define SPI_TXFCON             0x34
+#define SPI_FSTAT              0x38
+#define SPI_BRT                        0x40
+#define SPI_BRSTAT             0x44
+#define SPI_SFCON              0x60
+#define SPI_SFSTAT             0x64
+#define SPI_GPOCON             0x70
+#define SPI_GPOSTAT            0x74
+#define SPI_FPGO               0x78
+#define SPI_RXREQ              0x80
+#define SPI_RXCNT              0x84
+#define SPI_DMACON             0xec
+#define SPI_IRNEN              0xf4
+#define SPI_IRNICR             0xf8
+#define SPI_IRNCR              0xfc
+
+#define SPI_CLC_SMC_S          16      /* Clock divider for sleep mode */
+#define SPI_CLC_SMC_M          (0xFF << SPI_CLC_SMC_S)
+#define SPI_CLC_RMC_S          8       /* Clock divider for normal run mode */
+#define SPI_CLC_RMC_M          (0xFF << SPI_CLC_RMC_S)
+#define SPI_CLC_DISS           BIT(1)  /* Disable status bit */
+#define SPI_CLC_DISR           BIT(0)  /* Disable request bit */
+
+#define SPI_ID_TXFS_S          24      /* Implemented TX FIFO size */
+#define SPI_ID_TXFS_M          (0x3F << SPI_ID_TXFS_S)
+#define SPI_ID_RXFS_S          16      /* Implemented RX FIFO size */
+#define SPI_ID_RXFS_M          (0x3F << SPI_ID_RXFS_S)
+#define SPI_ID_MOD_S           8       /* Module ID */
+#define SPI_ID_MOD_M           (0xff << SPI_ID_MOD_S)
+#define SPI_ID_CFG_S           5       /* DMA interface support */
+#define SPI_ID_CFG_M           (1 << SPI_ID_CFG_S)
+#define SPI_ID_REV_M           0x1F    /* Hardware revision number */
+
+#define SPI_CON_BM_S           16      /* Data width selection */
+#define SPI_CON_BM_M           (0x1F << SPI_CON_BM_S)
+#define SPI_CON_EM             BIT(24) /* Echo mode */
+#define SPI_CON_IDLE           BIT(23) /* Idle bit value */
+#define SPI_CON_ENBV           BIT(22) /* Enable byte valid control */
+#define SPI_CON_RUEN           BIT(12) /* Receive underflow error enable */
+#define SPI_CON_TUEN           BIT(11) /* Transmit underflow error enable */
+#define SPI_CON_AEN            BIT(10) /* Abort error enable */
+#define SPI_CON_REN            BIT(9)  /* Receive overflow error enable */
+#define SPI_CON_TEN            BIT(8)  /* Transmit overflow error enable */
+#define SPI_CON_LB             BIT(7)  /* Loopback control */
+#define SPI_CON_PO             BIT(6)  /* Clock polarity control */
+#define SPI_CON_PH             BIT(5)  /* Clock phase control */
+#define SPI_CON_HB             BIT(4)  /* Heading control */
+#define SPI_CON_RXOFF          BIT(1)  /* Switch receiver off */
+#define SPI_CON_TXOFF          BIT(0)  /* Switch transmitter off */
+
+#define SPI_STAT_RXBV_S                28
+#define SPI_STAT_RXBV_M                (0x7 << SPI_STAT_RXBV_S)
+#define SPI_STAT_BSY           BIT(13) /* Busy flag */
+#define SPI_STAT_RUE           BIT(12) /* Receive underflow error flag */
+#define SPI_STAT_TUE           BIT(11) /* Transmit underflow error flag */
+#define SPI_STAT_AE            BIT(10) /* Abort error flag */
+#define SPI_STAT_RE            BIT(9)  /* Receive error flag */
+#define SPI_STAT_TE            BIT(8)  /* Transmit error flag */
+#define SPI_STAT_ME            BIT(7)  /* Mode error flag */
+#define SPI_STAT_MS            BIT(1)  /* Master/slave select bit */
+#define SPI_STAT_EN            BIT(0)  /* Enable bit */
+#define SPI_STAT_ERRORS                (SPI_STAT_ME | SPI_STAT_TE | SPI_STAT_RE | \
+                                SPI_STAT_AE | SPI_STAT_TUE | SPI_STAT_RUE)
+
+#define SPI_WHBSTATE_SETTUE    BIT(15) /* Set transmit underflow error flag */
+#define SPI_WHBSTATE_SETAE     BIT(14) /* Set abort error flag */
+#define SPI_WHBSTATE_SETRE     BIT(13) /* Set receive error flag */
+#define SPI_WHBSTATE_SETTE     BIT(12) /* Set transmit error flag */
+#define SPI_WHBSTATE_CLRTUE    BIT(11) /* Clear transmit underflow error flag */
+#define SPI_WHBSTATE_CLRAE     BIT(10) /* Clear abort error flag */
+#define SPI_WHBSTATE_CLRRE     BIT(9)  /* Clear receive error flag */
+#define SPI_WHBSTATE_CLRTE     BIT(8)  /* Clear transmit error flag */
+#define SPI_WHBSTATE_SETME     BIT(7)  /* Set mode error flag */
+#define SPI_WHBSTATE_CLRME     BIT(6)  /* Clear mode error flag */
+#define SPI_WHBSTATE_SETRUE    BIT(5)  /* Set receive underflow error flag */
+#define SPI_WHBSTATE_CLRRUE    BIT(4)  /* Clear receive underflow error flag */
+#define SPI_WHBSTATE_SETMS     BIT(3)  /* Set master select bit */
+#define SPI_WHBSTATE_CLRMS     BIT(2)  /* Clear master select bit */
+#define SPI_WHBSTATE_SETEN     BIT(1)  /* Set enable bit (operational mode) */
+#define SPI_WHBSTATE_CLREN     BIT(0)  /* Clear enable bit (config mode */
+#define SPI_WHBSTATE_CLR_ERRORS        (SPI_WHBSTATE_CLRRUE | SPI_WHBSTATE_CLRME | \
+                                SPI_WHBSTATE_CLRTE | SPI_WHBSTATE_CLRRE | \
+                                SPI_WHBSTATE_CLRAE | SPI_WHBSTATE_CLRTUE)
+
+#define SPI_RXFCON_RXFITL_S    8       /* FIFO interrupt trigger level */
+#define SPI_RXFCON_RXFITL_M    (0x3F << SPI_RXFCON_RXFITL_S)
+#define SPI_RXFCON_RXFLU       BIT(1)  /* FIFO flush */
+#define SPI_RXFCON_RXFEN       BIT(0)  /* FIFO enable */
+
+#define SPI_TXFCON_TXFITL_S    8       /* FIFO interrupt trigger level */
+#define SPI_TXFCON_TXFITL_M    (0x3F << SPI_TXFCON_TXFITL_S)
+#define SPI_TXFCON_TXFLU       BIT(1)  /* FIFO flush */
+#define SPI_TXFCON_TXFEN       BIT(0)  /* FIFO enable */
+
+#define SPI_FSTAT_RXFFL_S      0
+#define SPI_FSTAT_RXFFL_M      (0x3f << SPI_FSTAT_RXFFL_S)
+#define SPI_FSTAT_TXFFL_S      8
+#define SPI_FSTAT_TXFFL_M      (0x3f << SPI_FSTAT_TXFFL_S)
+
+#define SPI_GPOCON_ISCSBN_S    8
+#define SPI_GPOCON_INVOUTN_S   0
+
+#define SPI_FGPO_SETOUTN_S     8
+#define SPI_FGPO_CLROUTN_S     0
+
+#define SPI_RXREQ_RXCNT_M      0xFFFF  /* Receive count value */
+#define SPI_RXCNT_TODO_M       0xFFFF  /* Recevie to-do value */
+
+#define SPI_IRNEN_TFI          BIT(4)  /* TX finished interrupt */
+#define SPI_IRNEN_F            BIT(3)  /* Frame end interrupt request */
+#define SPI_IRNEN_E            BIT(2)  /* Error end interrupt request */
+#define SPI_IRNEN_T_XWAY       BIT(1)  /* Transmit end interrupt request */
+#define SPI_IRNEN_R_XWAY       BIT(0)  /* Receive end interrupt request */
+#define SPI_IRNEN_R_XRX                BIT(1)  /* Transmit end interrupt request */
+#define SPI_IRNEN_T_XRX                BIT(0)  /* Receive end interrupt request */
+#define SPI_IRNEN_ALL          0x1F
+
+struct lantiq_ssc_hwcfg {
+       unsigned int irnen_r;
+       unsigned int irnen_t;
+};
+
+struct lantiq_ssc_spi {
+       struct spi_master               *master;
+       struct device                   *dev;
+       void __iomem                    *regbase;
+       struct clk                      *spi_clk;
+       struct clk                      *fpi_clk;
+       const struct lantiq_ssc_hwcfg   *hwcfg;
+
+       spinlock_t                      lock;
+       struct workqueue_struct         *wq;
+       struct work_struct              work;
+
+       const u8                        *tx;
+       u8                              *rx;
+       unsigned int                    tx_todo;
+       unsigned int                    rx_todo;
+       unsigned int                    bits_per_word;
+       unsigned int                    speed_hz;
+       unsigned int                    tx_fifo_size;
+       unsigned int                    rx_fifo_size;
+       unsigned int                    base_cs;
+};
+
+static u32 lantiq_ssc_readl(const struct lantiq_ssc_spi *spi, u32 reg)
+{
+       return __raw_readl(spi->regbase + reg);
+}
+
+static void lantiq_ssc_writel(const struct lantiq_ssc_spi *spi, u32 val,
+                             u32 reg)
+{
+       __raw_writel(val, spi->regbase + reg);
+}
+
+static void lantiq_ssc_maskl(const struct lantiq_ssc_spi *spi, u32 clr,
+                            u32 set, u32 reg)
+{
+       u32 val = __raw_readl(spi->regbase + reg);
+
+       val &= ~clr;
+       val |= set;
+       __raw_writel(val, spi->regbase + reg);
+}
+
+static unsigned int tx_fifo_level(const struct lantiq_ssc_spi *spi)
+{
+       u32 fstat = lantiq_ssc_readl(spi, SPI_FSTAT);
+
+       return (fstat & SPI_FSTAT_TXFFL_M) >> SPI_FSTAT_TXFFL_S;
+}
+
+static unsigned int rx_fifo_level(const struct lantiq_ssc_spi *spi)
+{
+       u32 fstat = lantiq_ssc_readl(spi, SPI_FSTAT);
+
+       return fstat & SPI_FSTAT_RXFFL_M;
+}
+
+static unsigned int tx_fifo_free(const struct lantiq_ssc_spi *spi)
+{
+       return spi->tx_fifo_size - tx_fifo_level(spi);
+}
+
+static void rx_fifo_reset(const struct lantiq_ssc_spi *spi)
+{
+       u32 val = spi->rx_fifo_size << SPI_RXFCON_RXFITL_S;
+
+       val |= SPI_RXFCON_RXFEN | SPI_RXFCON_RXFLU;
+       lantiq_ssc_writel(spi, val, SPI_RXFCON);
+}
+
+static void tx_fifo_reset(const struct lantiq_ssc_spi *spi)
+{
+       u32 val = 1 << SPI_TXFCON_TXFITL_S;
+
+       val |= SPI_TXFCON_TXFEN | SPI_TXFCON_TXFLU;
+       lantiq_ssc_writel(spi, val, SPI_TXFCON);
+}
+
+static void rx_fifo_flush(const struct lantiq_ssc_spi *spi)
+{
+       lantiq_ssc_maskl(spi, 0, SPI_RXFCON_RXFLU, SPI_RXFCON);
+}
+
+static void tx_fifo_flush(const struct lantiq_ssc_spi *spi)
+{
+       lantiq_ssc_maskl(spi, 0, SPI_TXFCON_TXFLU, SPI_TXFCON);
+}
+
+static void hw_enter_config_mode(const struct lantiq_ssc_spi *spi)
+{
+       lantiq_ssc_writel(spi, SPI_WHBSTATE_CLREN, SPI_WHBSTATE);
+}
+
+static void hw_enter_active_mode(const struct lantiq_ssc_spi *spi)
+{
+       lantiq_ssc_writel(spi, SPI_WHBSTATE_SETEN, SPI_WHBSTATE);
+}
+
+static void hw_setup_speed_hz(const struct lantiq_ssc_spi *spi,
+                             unsigned int max_speed_hz)
+{
+       u32 spi_clk, brt;
+
+       /*
+        * SPI module clock is derived from FPI bus clock dependent on
+        * divider value in CLC.RMS which is always set to 1.
+        *
+        *                 f_SPI
+        * baudrate = --------------
+        *             2 * (BR + 1)
+        */
+       spi_clk = clk_get_rate(spi->fpi_clk) / 2;
+
+       if (max_speed_hz > spi_clk)
+               brt = 0;
+       else
+               brt = spi_clk / max_speed_hz - 1;
+
+       if (brt > 0xFFFF)
+               brt = 0xFFFF;
+
+       dev_dbg(spi->dev, "spi_clk %u, max_speed_hz %u, brt %u\n",
+               spi_clk, max_speed_hz, brt);
+
+       lantiq_ssc_writel(spi, brt, SPI_BRT);
+}
+
+static void hw_setup_bits_per_word(const struct lantiq_ssc_spi *spi,
+                                  unsigned int bits_per_word)
+{
+       u32 bm;
+
+       /* CON.BM value = bits_per_word - 1 */
+       bm = (bits_per_word - 1) << SPI_CON_BM_S;
+
+       lantiq_ssc_maskl(spi, SPI_CON_BM_M, bm, SPI_CON);
+}
+
+static void hw_setup_clock_mode(const struct lantiq_ssc_spi *spi,
+                               unsigned int mode)
+{
+       u32 con_set = 0, con_clr = 0;
+
+       /*
+        * SPI mode mapping in CON register:
+        * Mode CPOL CPHA CON.PO CON.PH
+        *  0    0    0      0      1
+        *  1    0    1      0      0
+        *  2    1    0      1      1
+        *  3    1    1      1      0
+        */
+       if (mode & SPI_CPHA)
+               con_clr |= SPI_CON_PH;
+       else
+               con_set |= SPI_CON_PH;
+
+       if (mode & SPI_CPOL)
+               con_set |= SPI_CON_PO | SPI_CON_IDLE;
+       else
+               con_clr |= SPI_CON_PO | SPI_CON_IDLE;
+
+       /* Set heading control */
+       if (mode & SPI_LSB_FIRST)
+               con_clr |= SPI_CON_HB;
+       else
+               con_set |= SPI_CON_HB;
+
+       /* Set loopback mode */
+       if (mode & SPI_LOOP)
+               con_set |= SPI_CON_LB;
+       else
+               con_clr |= SPI_CON_LB;
+
+       lantiq_ssc_maskl(spi, con_clr, con_set, SPI_CON);
+}
+
+static void lantiq_ssc_hw_init(const struct lantiq_ssc_spi *spi)
+{
+       const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg;
+
+       /*
+        * Set clock divider for run mode to 1 to
+        * run at same frequency as FPI bus
+        */
+       lantiq_ssc_writel(spi, 1 << SPI_CLC_RMC_S, SPI_CLC);
+
+       /* Put controller into config mode */
+       hw_enter_config_mode(spi);
+
+       /* Clear error flags */
+       lantiq_ssc_maskl(spi, 0, SPI_WHBSTATE_CLR_ERRORS, SPI_WHBSTATE);
+
+       /* Enable error checking, disable TX/RX */
+       lantiq_ssc_writel(spi, SPI_CON_RUEN | SPI_CON_AEN | SPI_CON_TEN |
+               SPI_CON_REN | SPI_CON_TXOFF | SPI_CON_RXOFF, SPI_CON);
+
+       /* Setup default SPI mode */
+       hw_setup_bits_per_word(spi, spi->bits_per_word);
+       hw_setup_clock_mode(spi, SPI_MODE_0);
+
+       /* Enable master mode and clear error flags */
+       lantiq_ssc_writel(spi, SPI_WHBSTATE_SETMS | SPI_WHBSTATE_CLR_ERRORS,
+                              SPI_WHBSTATE);
+
+       /* Reset GPIO/CS registers */
+       lantiq_ssc_writel(spi, 0, SPI_GPOCON);
+       lantiq_ssc_writel(spi, 0xFF00, SPI_FPGO);
+
+       /* Enable and flush FIFOs */
+       rx_fifo_reset(spi);
+       tx_fifo_reset(spi);
+
+       /* Enable interrupts */
+       lantiq_ssc_writel(spi, hwcfg->irnen_t | hwcfg->irnen_r | SPI_IRNEN_E,
+                         SPI_IRNEN);
+}
+
+static int lantiq_ssc_setup(struct spi_device *spidev)
+{
+       struct spi_master *master = spidev->master;
+       struct lantiq_ssc_spi *spi = spi_master_get_devdata(master);
+       unsigned int cs = spidev->chip_select;
+       u32 gpocon;
+
+       /* GPIOs are used for CS */
+       if (gpio_is_valid(spidev->cs_gpio))
+               return 0;
+
+       dev_dbg(spi->dev, "using internal chipselect %u\n", cs);
+
+       if (cs < spi->base_cs) {
+               dev_err(spi->dev,
+                       "chipselect %i too small (min %i)\n", cs, spi->base_cs);
+               return -EINVAL;
+       }
+
+       /* set GPO pin to CS mode */
+       gpocon = 1 << ((cs - spi->base_cs) + SPI_GPOCON_ISCSBN_S);
+
+       /* invert GPO pin */
+       if (spidev->mode & SPI_CS_HIGH)
+               gpocon |= 1 << (cs - spi->base_cs);
+
+       lantiq_ssc_maskl(spi, 0, gpocon, SPI_GPOCON);
+
+       return 0;
+}
+
+static int lantiq_ssc_prepare_message(struct spi_master *master,
+                                     struct spi_message *message)
+{
+       struct lantiq_ssc_spi *spi = spi_master_get_devdata(master);
+
+       hw_enter_config_mode(spi);
+       hw_setup_clock_mode(spi, message->spi->mode);
+       hw_enter_active_mode(spi);
+
+       return 0;
+}
+
+static void hw_setup_transfer(struct lantiq_ssc_spi *spi,
+                             struct spi_device *spidev, struct spi_transfer *t)
+{
+       unsigned int speed_hz = t->speed_hz;
+       unsigned int bits_per_word = t->bits_per_word;
+       u32 con;
+
+       if (bits_per_word != spi->bits_per_word ||
+               speed_hz != spi->speed_hz) {
+               hw_enter_config_mode(spi);
+               hw_setup_speed_hz(spi, speed_hz);
+               hw_setup_bits_per_word(spi, bits_per_word);
+               hw_enter_active_mode(spi);
+
+               spi->speed_hz = speed_hz;
+               spi->bits_per_word = bits_per_word;
+       }
+
+       /* Configure transmitter and receiver */
+       con = lantiq_ssc_readl(spi, SPI_CON);
+       if (t->tx_buf)
+               con &= ~SPI_CON_TXOFF;
+       else
+               con |= SPI_CON_TXOFF;
+
+       if (t->rx_buf)
+               con &= ~SPI_CON_RXOFF;
+       else
+               con |= SPI_CON_RXOFF;
+
+       lantiq_ssc_writel(spi, con, SPI_CON);
+}
+
+static int lantiq_ssc_unprepare_message(struct spi_master *master,
+                                       struct spi_message *message)
+{
+       struct lantiq_ssc_spi *spi = spi_master_get_devdata(master);
+
+       flush_workqueue(spi->wq);
+
+       /* Disable transmitter and receiver while idle */
+       lantiq_ssc_maskl(spi, 0, SPI_CON_TXOFF | SPI_CON_RXOFF, SPI_CON);
+
+       return 0;
+}
+
+static void tx_fifo_write(struct lantiq_ssc_spi *spi)
+{
+       const u8 *tx8;
+       const u16 *tx16;
+       const u32 *tx32;
+       u32 data;
+       unsigned int tx_free = tx_fifo_free(spi);
+
+       while (spi->tx_todo && tx_free) {
+               switch (spi->bits_per_word) {
+               case 2 ... 8:
+                       tx8 = spi->tx;
+                       data = *tx8;
+                       spi->tx_todo--;
+                       spi->tx++;
+                       break;
+               case 16:
+                       tx16 = (u16 *) spi->tx;
+                       data = *tx16;
+                       spi->tx_todo -= 2;
+                       spi->tx += 2;
+                       break;
+               case 32:
+                       tx32 = (u32 *) spi->tx;
+                       data = *tx32;
+                       spi->tx_todo -= 4;
+                       spi->tx += 4;
+                       break;
+               default:
+                       WARN_ON(1);
+                       data = 0;
+                       break;
+               }
+
+               lantiq_ssc_writel(spi, data, SPI_TB);
+               tx_free--;
+       }
+}
+
+static void rx_fifo_read_full_duplex(struct lantiq_ssc_spi *spi)
+{
+       u8 *rx8;
+       u16 *rx16;
+       u32 *rx32;
+       u32 data;
+       unsigned int rx_fill = rx_fifo_level(spi);
+
+       while (rx_fill) {
+               data = lantiq_ssc_readl(spi, SPI_RB);
+
+               switch (spi->bits_per_word) {
+               case 2 ... 8:
+                       rx8 = spi->rx;
+                       *rx8 = data;
+                       spi->rx_todo--;
+                       spi->rx++;
+                       break;
+               case 16:
+                       rx16 = (u16 *) spi->rx;
+                       *rx16 = data;
+                       spi->rx_todo -= 2;
+                       spi->rx += 2;
+                       break;
+               case 32:
+                       rx32 = (u32 *) spi->rx;
+                       *rx32 = data;
+                       spi->rx_todo -= 4;
+                       spi->rx += 4;
+                       break;
+               default:
+                       WARN_ON(1);
+                       break;
+               }
+
+               rx_fill--;
+       }
+}
+
+static void rx_fifo_read_half_duplex(struct lantiq_ssc_spi *spi)
+{
+       u32 data, *rx32;
+       u8 *rx8;
+       unsigned int rxbv, shift;
+       unsigned int rx_fill = rx_fifo_level(spi);
+
+       /*
+        * In RX-only mode the bits per word value is ignored by HW. A value
+        * of 32 is used instead. Thus all 4 bytes per FIFO must be read.
+        * If remaining RX bytes are less than 4, the FIFO must be read
+        * differently. The amount of received and valid bytes is indicated
+        * by STAT.RXBV register value.
+        */
+       while (rx_fill) {
+               if (spi->rx_todo < 4)  {
+                       rxbv = (lantiq_ssc_readl(spi, SPI_STAT) &
+                               SPI_STAT_RXBV_M) >> SPI_STAT_RXBV_S;
+                       data = lantiq_ssc_readl(spi, SPI_RB);
+
+                       shift = (rxbv - 1) * 8;
+                       rx8 = spi->rx;
+
+                       while (rxbv) {
+                               *rx8++ = (data >> shift) & 0xFF;
+                               rxbv--;
+                               shift -= 8;
+                               spi->rx_todo--;
+                               spi->rx++;
+                       }
+               } else {
+                       data = lantiq_ssc_readl(spi, SPI_RB);
+                       rx32 = (u32 *) spi->rx;
+
+                       *rx32++ = data;
+                       spi->rx_todo -= 4;
+                       spi->rx += 4;
+               }
+               rx_fill--;
+       }
+}
+
+static void rx_request(struct lantiq_ssc_spi *spi)
+{
+       unsigned int rxreq, rxreq_max;
+
+       /*
+        * To avoid receive overflows at high clocks it is better to request
+        * only the amount of bytes that fits into all FIFOs. This value
+        * depends on the FIFO size implemented in hardware.
+        */
+       rxreq = spi->rx_todo;
+       rxreq_max = spi->rx_fifo_size * 4;
+       if (rxreq > rxreq_max)
+               rxreq = rxreq_max;
+
+       lantiq_ssc_writel(spi, rxreq, SPI_RXREQ);
+}
+
+static irqreturn_t lantiq_ssc_xmit_interrupt(int irq, void *data)
+{
+       struct lantiq_ssc_spi *spi = data;
+
+       if (spi->tx) {
+               if (spi->rx && spi->rx_todo)
+                       rx_fifo_read_full_duplex(spi);
+
+               if (spi->tx_todo)
+                       tx_fifo_write(spi);
+               else if (!tx_fifo_level(spi))
+                       goto completed;
+       } else if (spi->rx) {
+               if (spi->rx_todo) {
+                       rx_fifo_read_half_duplex(spi);
+
+                       if (spi->rx_todo)
+                               rx_request(spi);
+                       else
+                               goto completed;
+               } else {
+                       goto completed;
+               }
+       }
+
+       return IRQ_HANDLED;
+
+completed:
+       queue_work(spi->wq, &spi->work);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t lantiq_ssc_err_interrupt(int irq, void *data)
+{
+       struct lantiq_ssc_spi *spi = data;
+       u32 stat = lantiq_ssc_readl(spi, SPI_STAT);
+
+       if (!(stat & SPI_STAT_ERRORS))
+               return IRQ_NONE;
+
+       if (stat & SPI_STAT_RUE)
+               dev_err(spi->dev, "receive underflow error\n");
+       if (stat & SPI_STAT_TUE)
+               dev_err(spi->dev, "transmit underflow error\n");
+       if (stat & SPI_STAT_AE)
+               dev_err(spi->dev, "abort error\n");
+       if (stat & SPI_STAT_RE)
+               dev_err(spi->dev, "receive overflow error\n");
+       if (stat & SPI_STAT_TE)
+               dev_err(spi->dev, "transmit overflow error\n");
+       if (stat & SPI_STAT_ME)
+               dev_err(spi->dev, "mode error\n");
+
+       /* Clear error flags */
+       lantiq_ssc_maskl(spi, 0, SPI_WHBSTATE_CLR_ERRORS, SPI_WHBSTATE);
+
+       /* set bad status so it can be retried */
+       if (spi->master->cur_msg)
+               spi->master->cur_msg->status = -EIO;
+       queue_work(spi->wq, &spi->work);
+
+       return IRQ_HANDLED;
+}
+
+static int transfer_start(struct lantiq_ssc_spi *spi, struct spi_device *spidev,
+                         struct spi_transfer *t)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&spi->lock, flags);
+
+       spi->tx = t->tx_buf;
+       spi->rx = t->rx_buf;
+
+       if (t->tx_buf) {
+               spi->tx_todo = t->len;
+
+               /* initially fill TX FIFO */
+               tx_fifo_write(spi);
+       }
+
+       if (spi->rx) {
+               spi->rx_todo = t->len;
+
+               /* start shift clock in RX-only mode */
+               if (!spi->tx)
+                       rx_request(spi);
+       }
+
+       spin_unlock_irqrestore(&spi->lock, flags);
+
+       return t->len;
+}
+
+/*
+ * The driver only gets an interrupt when the FIFO is empty, but there
+ * is an additional shift register from which the data is written to
+ * the wire. We get the last interrupt when the controller starts to
+ * write the last word to the wire, not when it is finished. Do busy
+ * waiting till it finishes.
+ */
+static void lantiq_ssc_bussy_work(struct work_struct *work)
+{
+       struct lantiq_ssc_spi *spi;
+       unsigned long long timeout = 8LL * 1000LL;
+       unsigned long end;
+
+       spi = container_of(work, typeof(*spi), work);
+
+       do_div(timeout, spi->speed_hz);
+       timeout += timeout + 100; /* some tolerance */
+
+       end = jiffies + msecs_to_jiffies(timeout);
+       do {
+               u32 stat = lantiq_ssc_readl(spi, SPI_STAT);
+
+               if (!(stat & SPI_STAT_BSY)) {
+                       spi_finalize_current_transfer(spi->master);
+                       return;
+               }
+
+               cond_resched();
+       } while (!time_after_eq(jiffies, end));
+
+       if (spi->master->cur_msg)
+               spi->master->cur_msg->status = -EIO;
+       spi_finalize_current_transfer(spi->master);
+}
+
+static void lantiq_ssc_handle_err(struct spi_master *master,
+                                 struct spi_message *message)
+{
+       struct lantiq_ssc_spi *spi = spi_master_get_devdata(master);
+
+       /* flush FIFOs on timeout */
+       rx_fifo_flush(spi);
+       tx_fifo_flush(spi);
+}
+
+static void lantiq_ssc_set_cs(struct spi_device *spidev, bool enable)
+{
+       struct lantiq_ssc_spi *spi = spi_master_get_devdata(spidev->master);
+       unsigned int cs = spidev->chip_select;
+       u32 fgpo;
+
+       if (!!(spidev->mode & SPI_CS_HIGH) == enable)
+               fgpo = (1 << (cs - spi->base_cs));
+       else
+               fgpo = (1 << (cs - spi->base_cs + SPI_FGPO_SETOUTN_S));
+
+       lantiq_ssc_writel(spi, fgpo, SPI_FPGO);
+}
+
+static int lantiq_ssc_transfer_one(struct spi_master *master,
+                                  struct spi_device *spidev,
+                                  struct spi_transfer *t)
+{
+       struct lantiq_ssc_spi *spi = spi_master_get_devdata(master);
+
+       hw_setup_transfer(spi, spidev, t);
+
+       return transfer_start(spi, spidev, t);
+}
+
+static const struct lantiq_ssc_hwcfg lantiq_ssc_xway = {
+       .irnen_r = SPI_IRNEN_R_XWAY,
+       .irnen_t = SPI_IRNEN_T_XWAY,
+};
+
+static const struct lantiq_ssc_hwcfg lantiq_ssc_xrx = {
+       .irnen_r = SPI_IRNEN_R_XRX,
+       .irnen_t = SPI_IRNEN_T_XRX,
+};
+
+static const struct of_device_id lantiq_ssc_match[] = {
+       { .compatible = "lantiq,ase-spi", .data = &lantiq_ssc_xway, },
+       { .compatible = "lantiq,falcon-spi", .data = &lantiq_ssc_xrx, },
+       { .compatible = "lantiq,xrx100-spi", .data = &lantiq_ssc_xrx, },
+       {},
+};
+MODULE_DEVICE_TABLE(of, lantiq_ssc_match);
+
+static int lantiq_ssc_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct spi_master *master;
+       struct resource *res;
+       struct lantiq_ssc_spi *spi;
+       const struct lantiq_ssc_hwcfg *hwcfg;
+       const struct of_device_id *match;
+       int err, rx_irq, tx_irq, err_irq;
+       u32 id, supports_dma, revision;
+       unsigned int num_cs;
+
+       match = of_match_device(lantiq_ssc_match, dev);
+       if (!match) {
+               dev_err(dev, "no device match\n");
+               return -EINVAL;
+       }
+       hwcfg = match->data;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(dev, "failed to get resources\n");
+               return -ENXIO;
+       }
+
+       rx_irq = platform_get_irq_byname(pdev, SPI_RX_IRQ_NAME);
+       if (rx_irq < 0) {
+               dev_err(dev, "failed to get %s\n", SPI_RX_IRQ_NAME);
+               return -ENXIO;
+       }
+
+       tx_irq = platform_get_irq_byname(pdev, SPI_TX_IRQ_NAME);
+       if (tx_irq < 0) {
+               dev_err(dev, "failed to get %s\n", SPI_TX_IRQ_NAME);
+               return -ENXIO;
+       }
+
+       err_irq = platform_get_irq_byname(pdev, SPI_ERR_IRQ_NAME);
+       if (err_irq < 0) {
+               dev_err(dev, "failed to get %s\n", SPI_ERR_IRQ_NAME);
+               return -ENXIO;
+       }
+
+       master = spi_alloc_master(dev, sizeof(struct lantiq_ssc_spi));
+       if (!master)
+               return -ENOMEM;
+
+       spi = spi_master_get_devdata(master);
+       spi->master = master;
+       spi->dev = dev;
+       spi->hwcfg = hwcfg;
+       platform_set_drvdata(pdev, spi);
+
+       spi->regbase = devm_ioremap_resource(dev, res);
+       if (IS_ERR(spi->regbase)) {
+               err = PTR_ERR(spi->regbase);
+               goto err_master_put;
+       }
+
+       err = devm_request_irq(dev, rx_irq, lantiq_ssc_xmit_interrupt,
+                              0, SPI_RX_IRQ_NAME, spi);
+       if (err)
+               goto err_master_put;
+
+       err = devm_request_irq(dev, tx_irq, lantiq_ssc_xmit_interrupt,
+                              0, SPI_TX_IRQ_NAME, spi);
+       if (err)
+               goto err_master_put;
+
+       err = devm_request_irq(dev, err_irq, lantiq_ssc_err_interrupt,
+                              0, SPI_ERR_IRQ_NAME, spi);
+       if (err)
+               goto err_master_put;
+
+       spi->spi_clk = devm_clk_get(dev, "gate");
+       if (IS_ERR(spi->spi_clk)) {
+               err = PTR_ERR(spi->spi_clk);
+               goto err_master_put;
+       }
+       err = clk_prepare_enable(spi->spi_clk);
+       if (err)
+               goto err_master_put;
+
+       /*
+        * Use the old clk_get_fpi() function on Lantiq platform, till it
+        * supports common clk.
+        */
+#if defined(CONFIG_LANTIQ) && !defined(CONFIG_COMMON_CLK)
+       spi->fpi_clk = clk_get_fpi();
+#else
+       spi->fpi_clk = clk_get(dev, "freq");
+#endif
+       if (IS_ERR(spi->fpi_clk)) {
+               err = PTR_ERR(spi->fpi_clk);
+               goto err_clk_disable;
+       }
+
+       num_cs = 8;
+       of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs);
+
+       spi->base_cs = 1;
+       of_property_read_u32(pdev->dev.of_node, "base-cs", &spi->base_cs);
+
+       spin_lock_init(&spi->lock);
+       spi->bits_per_word = 8;
+       spi->speed_hz = 0;
+
+       master->dev.of_node = pdev->dev.of_node;
+       master->num_chipselect = num_cs;
+       master->setup = lantiq_ssc_setup;
+       master->set_cs = lantiq_ssc_set_cs;
+       master->handle_err = lantiq_ssc_handle_err;
+       master->prepare_message = lantiq_ssc_prepare_message;
+       master->unprepare_message = lantiq_ssc_unprepare_message;
+       master->transfer_one = lantiq_ssc_transfer_one;
+       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_CS_HIGH |
+                               SPI_LOOP;
+       master->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 8) |
+                                    SPI_BPW_MASK(16) | SPI_BPW_MASK(32);
+
+       spi->wq = alloc_ordered_workqueue(dev_name(dev), 0);
+       if (!spi->wq) {
+               err = -ENOMEM;
+               goto err_clk_put;
+       }
+       INIT_WORK(&spi->work, lantiq_ssc_bussy_work);
+
+       id = lantiq_ssc_readl(spi, SPI_ID);
+       spi->tx_fifo_size = (id & SPI_ID_TXFS_M) >> SPI_ID_TXFS_S;
+       spi->rx_fifo_size = (id & SPI_ID_RXFS_M) >> SPI_ID_RXFS_S;
+       supports_dma = (id & SPI_ID_CFG_M) >> SPI_ID_CFG_S;
+       revision = id & SPI_ID_REV_M;
+
+       lantiq_ssc_hw_init(spi);
+
+       dev_info(dev,
+               "Lantiq SSC SPI controller (Rev %i, TXFS %u, RXFS %u, DMA %u)\n",
+               revision, spi->tx_fifo_size, spi->rx_fifo_size, supports_dma);
+
+       err = devm_spi_register_master(dev, master);
+       if (err) {
+               dev_err(dev, "failed to register spi_master\n");
+               goto err_wq_destroy;
+       }
+
+       return 0;
+
+err_wq_destroy:
+       destroy_workqueue(spi->wq);
+err_clk_put:
+       clk_put(spi->fpi_clk);
+err_clk_disable:
+       clk_disable_unprepare(spi->spi_clk);
+err_master_put:
+       spi_master_put(master);
+
+       return err;
+}
+
+static int lantiq_ssc_remove(struct platform_device *pdev)
+{
+       struct lantiq_ssc_spi *spi = platform_get_drvdata(pdev);
+
+       lantiq_ssc_writel(spi, 0, SPI_IRNEN);
+       lantiq_ssc_writel(spi, 0, SPI_CLC);
+       rx_fifo_flush(spi);
+       tx_fifo_flush(spi);
+       hw_enter_config_mode(spi);
+
+       destroy_workqueue(spi->wq);
+       clk_disable_unprepare(spi->spi_clk);
+       clk_put(spi->fpi_clk);
+
+       return 0;
+}
+
+static struct platform_driver lantiq_ssc_driver = {
+       .probe = lantiq_ssc_probe,
+       .remove = lantiq_ssc_remove,
+       .driver = {
+               .name = "spi-lantiq-ssc",
+               .owner = THIS_MODULE,
+               .of_match_table = lantiq_ssc_match,
+       },
+};
+module_platform_driver(lantiq_ssc_driver);
+
+MODULE_DESCRIPTION("Lantiq SSC SPI controller driver");
+MODULE_AUTHOR("Daniel Schwierzeck <daniel.schwierzeck@gmail.com>");
+MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:spi-lantiq-ssc");
index c36002110c30a58e158043d5820fc671fb9b5c64..e8b59ce4dc3a74153cb15ef9f128b44070a573da 100644 (file)
@@ -437,8 +437,9 @@ static int mpc52xx_spi_probe(struct platform_device *op)
        ms->gpio_cs_count = of_gpio_count(op->dev.of_node);
        if (ms->gpio_cs_count > 0) {
                master->num_chipselect = ms->gpio_cs_count;
-               ms->gpio_cs = kmalloc(ms->gpio_cs_count * sizeof(unsigned int),
-                               GFP_KERNEL);
+               ms->gpio_cs = kmalloc_array(ms->gpio_cs_count,
+                                           sizeof(*ms->gpio_cs),
+                                           GFP_KERNEL);
                if (!ms->gpio_cs) {
                        rc = -ENOMEM;
                        goto err_alloc_gpio;
@@ -448,8 +449,7 @@ static int mpc52xx_spi_probe(struct platform_device *op)
                        gpio_cs = of_get_gpio(op->dev.of_node, i);
                        if (gpio_cs < 0) {
                                dev_err(&op->dev,
-                                       "could not parse the gpio field "
-                                       "in oftree\n");
+                                       "could not parse the gpio field in oftree\n");
                                rc = -ENODEV;
                                goto err_gpio;
                        }
@@ -457,8 +457,8 @@ static int mpc52xx_spi_probe(struct platform_device *op)
                        rc = gpio_request(gpio_cs, dev_name(&op->dev));
                        if (rc) {
                                dev_err(&op->dev,
-                                       "can't request spi cs gpio #%d "
-                                       "on gpio line %d\n", i, gpio_cs);
+                                       "can't request spi cs gpio #%d on gpio line %d\n",
+                                       i, gpio_cs);
                                goto err_gpio;
                        }
 
index 899d7a8f0889eaf39388ad458b28a1abbeeba671..278867a319506ff830c634cc24b2a2d819021a6b 100644 (file)
@@ -73,7 +73,7 @@
 #define MTK_SPI_IDLE 0
 #define MTK_SPI_PAUSED 1
 
-#define MTK_SPI_MAX_FIFO_SIZE 32
+#define MTK_SPI_MAX_FIFO_SIZE 32U
 #define MTK_SPI_PACKET_SIZE 1024
 
 struct mtk_spi_compatible {
@@ -333,7 +333,7 @@ static int mtk_spi_fifo_transfer(struct spi_master *master,
        struct mtk_spi *mdata = spi_master_get_devdata(master);
 
        mdata->cur_transfer = xfer;
-       mdata->xfer_len = xfer->len;
+       mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, xfer->len);
        mtk_spi_prepare_transfer(master, xfer);
        mtk_spi_setup_packet(master);
 
@@ -410,7 +410,10 @@ static bool mtk_spi_can_dma(struct spi_master *master,
                            struct spi_device *spi,
                            struct spi_transfer *xfer)
 {
-       return xfer->len > MTK_SPI_MAX_FIFO_SIZE;
+       /* Buffers for DMA transactions must be 4-byte aligned */
+       return (xfer->len > MTK_SPI_MAX_FIFO_SIZE &&
+               (unsigned long)xfer->tx_buf % 4 == 0 &&
+               (unsigned long)xfer->rx_buf % 4 == 0);
 }
 
 static int mtk_spi_setup(struct spi_device *spi)
@@ -451,7 +454,33 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)
                                        &reg_val, remainder);
                        }
                }
-               spi_finalize_current_transfer(master);
+
+               trans->len -= mdata->xfer_len;
+               if (!trans->len) {
+                       spi_finalize_current_transfer(master);
+                       return IRQ_HANDLED;
+               }
+
+               if (trans->tx_buf)
+                       trans->tx_buf += mdata->xfer_len;
+               if (trans->rx_buf)
+                       trans->rx_buf += mdata->xfer_len;
+
+               mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, trans->len);
+               mtk_spi_setup_packet(master);
+
+               cnt = trans->len / 4;
+               iowrite32_rep(mdata->base + SPI_TX_DATA_REG, trans->tx_buf, cnt);
+
+               remainder = trans->len % 4;
+               if (remainder > 0) {
+                       reg_val = 0;
+                       memcpy(&reg_val, trans->tx_buf + (cnt * 4), remainder);
+                       writel(reg_val, mdata->base + SPI_TX_DATA_REG);
+               }
+
+               mtk_spi_enable_transfer(master);
+
                return IRQ_HANDLED;
        }
 
index dd3d0a218d8b1ffc2299595fc55adadaaa3bdeeb..967d94844b30d162b353da096e1d2f865f7128e8 100644 (file)
@@ -411,7 +411,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
        if (num_gpios > 0) {
                int i;
 
-               hw->gpios = kzalloc(sizeof(int) * num_gpios, GFP_KERNEL);
+               hw->gpios = kcalloc(num_gpios, sizeof(*hw->gpios), GFP_KERNEL);
                if (!hw->gpios) {
                        ret = -ENOMEM;
                        goto free_master;
@@ -428,8 +428,9 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
                                /* Real CS - set the initial state. */
                                ret = gpio_request(gpio, np->name);
                                if (ret < 0) {
-                                       dev_err(dev, "can't request gpio "
-                                                       "#%d: %d\n", i, ret);
+                                       dev_err(dev,
+                                               "can't request gpio #%d: %d\n",
+                                               i, ret);
                                        goto free_gpios;
                                }
 
index 58d2d48e16a530869528288d50f3a6581c3ea311..869f188b02eb3b92e994400c886ba631c95f2805 100644 (file)
@@ -41,6 +41,13 @@ struct pxa_spi_info {
 static struct dw_dma_slave byt_tx_param = { .dst_id = 0 };
 static struct dw_dma_slave byt_rx_param = { .src_id = 1 };
 
+static struct dw_dma_slave mrfld3_tx_param = { .dst_id = 15 };
+static struct dw_dma_slave mrfld3_rx_param = { .src_id = 14 };
+static struct dw_dma_slave mrfld5_tx_param = { .dst_id = 13 };
+static struct dw_dma_slave mrfld5_rx_param = { .src_id = 12 };
+static struct dw_dma_slave mrfld6_tx_param = { .dst_id = 11 };
+static struct dw_dma_slave mrfld6_rx_param = { .src_id = 10 };
+
 static struct dw_dma_slave bsw0_tx_param = { .dst_id = 0 };
 static struct dw_dma_slave bsw0_rx_param = { .src_id = 1 };
 static struct dw_dma_slave bsw1_tx_param = { .dst_id = 6 };
@@ -93,22 +100,39 @@ static int lpss_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c)
 
 static int mrfld_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c)
 {
+       struct pci_dev *dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(21, 0));
+       struct dw_dma_slave *tx, *rx;
+
        switch (PCI_FUNC(dev->devfn)) {
        case 0:
                c->port_id = 3;
                c->num_chipselect = 1;
+               c->tx_param = &mrfld3_tx_param;
+               c->rx_param = &mrfld3_rx_param;
                break;
        case 1:
                c->port_id = 5;
                c->num_chipselect = 4;
+               c->tx_param = &mrfld5_tx_param;
+               c->rx_param = &mrfld5_rx_param;
                break;
        case 2:
                c->port_id = 6;
                c->num_chipselect = 1;
+               c->tx_param = &mrfld6_tx_param;
+               c->rx_param = &mrfld6_rx_param;
                break;
        default:
                return -ENODEV;
        }
+
+       tx = c->tx_param;
+       tx->dma_dev = &dma_dev->dev;
+
+       rx = c->rx_param;
+       rx->dma_dev = &dma_dev->dev;
+
+       c->dma_filter = lpss_dma_filter;
        return 0;
 }
 
@@ -203,10 +227,16 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
        ssp = &spi_pdata.ssp;
        ssp->phys_base = pci_resource_start(dev, 0);
        ssp->mmio_base = pcim_iomap_table(dev)[0];
-       ssp->irq = dev->irq;
        ssp->port_id = (c->port_id >= 0) ? c->port_id : dev->devfn;
        ssp->type = c->type;
 
+       pci_set_master(dev);
+
+       ret = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_ALL_TYPES);
+       if (ret < 0)
+               return ret;
+       ssp->irq = pci_irq_vector(dev, 0);
+
        snprintf(buf, sizeof(buf), "pxa2xx-spi.%d", ssp->port_id);
        ssp->clk = clk_register_fixed_rate(&dev->dev, buf , NULL, 0,
                                           c->max_clk_rate);
index d6239fa718be9e251f577b9d9dd792a0e5c5ead5..47b65d7c40721eaf39fc0ba0e9dfa016a5407cfa 100644 (file)
@@ -732,6 +732,20 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
        return IRQ_HANDLED;
 }
 
+static void handle_bad_msg(struct driver_data *drv_data)
+{
+       pxa2xx_spi_write(drv_data, SSCR0,
+                        pxa2xx_spi_read(drv_data, SSCR0) & ~SSCR0_SSE);
+       pxa2xx_spi_write(drv_data, SSCR1,
+                        pxa2xx_spi_read(drv_data, SSCR1) & ~drv_data->int_cr1);
+       if (!pxa25x_ssp_comp(drv_data))
+               pxa2xx_spi_write(drv_data, SSTO, 0);
+       write_SSSR_CS(drv_data, drv_data->clear_sr);
+
+       dev_err(&drv_data->pdev->dev,
+               "bad message state in interrupt handler\n");
+}
+
 static irqreturn_t ssp_int(int irq, void *dev_id)
 {
        struct driver_data *drv_data = dev_id;
@@ -771,21 +785,11 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
        if (!(status & mask))
                return IRQ_NONE;
 
-       if (!drv_data->master->cur_msg) {
-
-               pxa2xx_spi_write(drv_data, SSCR0,
-                                pxa2xx_spi_read(drv_data, SSCR0)
-                                & ~SSCR0_SSE);
-               pxa2xx_spi_write(drv_data, SSCR1,
-                                pxa2xx_spi_read(drv_data, SSCR1)
-                                & ~drv_data->int_cr1);
-               if (!pxa25x_ssp_comp(drv_data))
-                       pxa2xx_spi_write(drv_data, SSTO, 0);
-               write_SSSR_CS(drv_data, drv_data->clear_sr);
-
-               dev_err(&drv_data->pdev->dev,
-                       "bad message state in interrupt handler\n");
+       pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg & ~drv_data->int_cr1);
+       pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg);
 
+       if (!drv_data->master->cur_msg) {
+               handle_bad_msg(drv_data);
                /* Never fail */
                return IRQ_HANDLED;
        }
@@ -1458,6 +1462,10 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = {
        { PCI_VDEVICE(INTEL, 0x1ac2), LPSS_BXT_SSP },
        { PCI_VDEVICE(INTEL, 0x1ac4), LPSS_BXT_SSP },
        { PCI_VDEVICE(INTEL, 0x1ac6), LPSS_BXT_SSP },
+       /* GLK */
+       { PCI_VDEVICE(INTEL, 0x31c2), LPSS_BXT_SSP },
+       { PCI_VDEVICE(INTEL, 0x31c4), LPSS_BXT_SSP },
+       { PCI_VDEVICE(INTEL, 0x31c6), LPSS_BXT_SSP },
        /* APL */
        { PCI_VDEVICE(INTEL, 0x5ac2), LPSS_BXT_SSP },
        { PCI_VDEVICE(INTEL, 0x5ac4), LPSS_BXT_SSP },
index 0f89c2169c244e433a36e7cc7e672d385d3c6560..acf31f36b89856bcf0a3b9c7d0ae113d6e5589cb 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/dmaengine.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/pm_runtime.h>
@@ -843,6 +844,8 @@ static int rockchip_spi_suspend(struct device *dev)
                clk_disable_unprepare(rs->apb_pclk);
        }
 
+       pinctrl_pm_select_sleep_state(dev);
+
        return ret;
 }
 
@@ -852,6 +855,8 @@ static int rockchip_spi_resume(struct device *dev)
        struct spi_master *master = dev_get_drvdata(dev);
        struct rockchip_spi *rs = spi_master_get_devdata(master);
 
+       pinctrl_pm_select_default_state(dev);
+
        if (!pm_runtime_suspended(dev)) {
                ret = clk_prepare_enable(rs->apb_pclk);
                if (ret < 0)
index 9daf500317376bd143cb56eb4b14738d11adbdca..2a10b3f94ff72a4ea3d6924a082ef6d2db174528 100644 (file)
@@ -808,7 +808,7 @@ static int qspi_transfer_out(struct rspi_data *rspi, struct spi_transfer *xfer)
                        for (i = 0; i < len; i++)
                                rspi_write_data(rspi, *tx++);
                } else {
-                       ret = rspi_pio_transfer(rspi, tx, NULL, n);
+                       ret = rspi_pio_transfer(rspi, tx, NULL, len);
                        if (ret < 0)
                                return ret;
                }
@@ -845,10 +845,9 @@ static int qspi_transfer_in(struct rspi_data *rspi, struct spi_transfer *xfer)
                        for (i = 0; i < len; i++)
                                *rx++ = rspi_read_data(rspi);
                } else {
-                       ret = rspi_pio_transfer(rspi, NULL, rx, n);
+                       ret = rspi_pio_transfer(rspi, NULL, rx, len);
                        if (ret < 0)
                                return ret;
-                       *rx++ = ret;
                }
                n -= len;
        }
@@ -1227,10 +1226,8 @@ static int rspi_probe(struct platform_device *pdev)
        const struct spi_ops *ops;
 
        master = spi_alloc_master(&pdev->dev, sizeof(struct rspi_data));
-       if (master == NULL) {
-               dev_err(&pdev->dev, "spi_alloc_master error.\n");
+       if (master == NULL)
                return -ENOMEM;
-       }
 
        of_id = of_match_device(rspi_of_match, &pdev->dev);
        if (of_id) {
index 28dfdce4beae4d5fe3d983eb11a78a4c9a70a840..b392cca8fa4f5ba3c1c499ea8b1bc228fcabdbee 100644 (file)
@@ -341,43 +341,16 @@ static void s3c64xx_spi_set_cs(struct spi_device *spi, bool enable)
 static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
 {
        struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
-       struct device *dev = &sdd->pdev->dev;
 
        if (is_polling(sdd))
                return 0;
 
-       /* Acquire DMA channels */
-       sdd->rx_dma.ch = dma_request_slave_channel(dev, "rx");
-       if (!sdd->rx_dma.ch) {
-               dev_err(dev, "Failed to get RX DMA channel\n");
-               return -EBUSY;
-       }
        spi->dma_rx = sdd->rx_dma.ch;
-
-       sdd->tx_dma.ch = dma_request_slave_channel(dev, "tx");
-       if (!sdd->tx_dma.ch) {
-               dev_err(dev, "Failed to get TX DMA channel\n");
-               dma_release_channel(sdd->rx_dma.ch);
-               return -EBUSY;
-       }
        spi->dma_tx = sdd->tx_dma.ch;
 
        return 0;
 }
 
-static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
-{
-       struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
-
-       /* Free DMA channels */
-       if (!is_polling(sdd)) {
-               dma_release_channel(sdd->rx_dma.ch);
-               dma_release_channel(sdd->tx_dma.ch);
-       }
-
-       return 0;
-}
-
 static bool s3c64xx_spi_can_dma(struct spi_master *master,
                                struct spi_device *spi,
                                struct spi_transfer *xfer)
@@ -996,7 +969,7 @@ static struct s3c64xx_spi_info *s3c64xx_spi_parse_dt(struct device *dev)
                sci->num_cs = temp;
        }
 
-       sci->no_cs = of_property_read_bool(dev->of_node, "broken-cs");
+       sci->no_cs = of_property_read_bool(dev->of_node, "no-cs-readback");
 
        return sci;
 }
@@ -1094,7 +1067,6 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
        master->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer;
        master->prepare_message = s3c64xx_spi_prepare_message;
        master->transfer_one = s3c64xx_spi_transfer_one;
-       master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer;
        master->num_chipselect = sci->num_cs;
        master->dma_alignment = 8;
        master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) |
@@ -1161,6 +1133,24 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
                }
        }
 
+       if (!is_polling(sdd)) {
+               /* Acquire DMA channels */
+               sdd->rx_dma.ch = dma_request_slave_channel_reason(&pdev->dev,
+                                                                 "rx");
+               if (IS_ERR(sdd->rx_dma.ch)) {
+                       dev_err(&pdev->dev, "Failed to get RX DMA channel\n");
+                       ret = PTR_ERR(sdd->rx_dma.ch);
+                       goto err_disable_io_clk;
+               }
+               sdd->tx_dma.ch = dma_request_slave_channel_reason(&pdev->dev,
+                                                                 "tx");
+               if (IS_ERR(sdd->tx_dma.ch)) {
+                       dev_err(&pdev->dev, "Failed to get TX DMA channel\n");
+                       ret = PTR_ERR(sdd->tx_dma.ch);
+                       goto err_release_rx_dma;
+               }
+       }
+
        pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_TIMEOUT);
        pm_runtime_use_autosuspend(&pdev->dev);
        pm_runtime_set_active(&pdev->dev);
@@ -1206,6 +1196,12 @@ err_pm_put:
        pm_runtime_disable(&pdev->dev);
        pm_runtime_set_suspended(&pdev->dev);
 
+       if (!is_polling(sdd))
+               dma_release_channel(sdd->tx_dma.ch);
+err_release_rx_dma:
+       if (!is_polling(sdd))
+               dma_release_channel(sdd->rx_dma.ch);
+err_disable_io_clk:
        clk_disable_unprepare(sdd->ioclk);
 err_disable_src_clk:
        clk_disable_unprepare(sdd->src_clk);
@@ -1226,6 +1222,11 @@ static int s3c64xx_spi_remove(struct platform_device *pdev)
 
        writel(0, sdd->regs + S3C64XX_SPI_INT_EN);
 
+       if (!is_polling(sdd)) {
+               dma_release_channel(sdd->rx_dma.ch);
+               dma_release_channel(sdd->tx_dma.ch);
+       }
+
        clk_disable_unprepare(sdd->ioclk);
 
        clk_disable_unprepare(sdd->src_clk);
index 1f00eeb0b5a3fb93ae838978dbf7815d94897378..2ce15ca977828668e0fa8e186b6b9a8393cdc70d 100644 (file)
@@ -1164,10 +1164,8 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
        int ret;
 
        master = spi_alloc_master(&pdev->dev, sizeof(struct sh_msiof_spi_priv));
-       if (master == NULL) {
-               dev_err(&pdev->dev, "failed to allocate spi master\n");
+       if (master == NULL)
                return -ENOMEM;
-       }
 
        p = spi_master_get_devdata(master);
 
index ec6fb09e2e1711f7adfbe079559a89f1a9cd343d..ad76a44fee6f4e9df0e2bb6e46354599e907192a 100644 (file)
@@ -652,7 +652,8 @@ static int ti_qspi_probe(struct platform_device *pdev)
                r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
                if (r == NULL) {
                        dev_err(&pdev->dev, "missing platform data\n");
-                       return -ENODEV;
+                       ret = -ENODEV;
+                       goto free_master;
                }
        }
 
@@ -669,7 +670,8 @@ static int ti_qspi_probe(struct platform_device *pdev)
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
                dev_err(&pdev->dev, "no irq resource?\n");
-               return irq;
+               ret = irq;
+               goto free_master;
        }
 
        mutex_init(&qspi->list_lock);
@@ -685,15 +687,17 @@ static int ti_qspi_probe(struct platform_device *pdev)
                qspi->ctrl_base =
                syscon_regmap_lookup_by_phandle(np,
                                                "syscon-chipselects");
-               if (IS_ERR(qspi->ctrl_base))
-                       return PTR_ERR(qspi->ctrl_base);
+               if (IS_ERR(qspi->ctrl_base)) {
+                       ret = PTR_ERR(qspi->ctrl_base);
+                       goto free_master;
+               }
                ret = of_property_read_u32_index(np,
                                                 "syscon-chipselects",
                                                 1, &qspi->ctrl_reg);
                if (ret) {
                        dev_err(&pdev->dev,
                                "couldn't get ctrl_mod reg index\n");
-                       return ret;
+                       goto free_master;
                }
        }
 
@@ -714,9 +718,10 @@ static int ti_qspi_probe(struct platform_device *pdev)
        dma_cap_set(DMA_MEMCPY, mask);
 
        qspi->rx_chan = dma_request_chan_by_mask(&mask);
-       if (!qspi->rx_chan) {
+       if (IS_ERR(qspi->rx_chan)) {
                dev_err(qspi->dev,
                        "No Rx DMA available, trying mmap mode\n");
+               qspi->rx_chan = NULL;
                ret = 0;
                goto no_dma;
        }
@@ -742,6 +747,7 @@ no_dma:
        if (!ret)
                return 0;
 
+       pm_runtime_disable(&pdev->dev);
 free_master:
        spi_master_put(master);
        return ret;
index fcb991034c3d076bc032545addca93517017b126..97d137591b18d5fe12359e5a8865fd00b93a9118 100644 (file)
@@ -591,7 +591,6 @@ static void pch_spi_set_tx(struct pch_spi_data *data, int *bpw)
 
        if (!data->pkt_rx_buff) {
                /* flush queue and set status of all transfers to -ENOMEM */
-               dev_err(&data->master->dev, "%s :kzalloc failed\n", __func__);
                list_for_each_entry_safe(pmsg, tmp, data->queue.next, queue) {
                        pmsg->status = -ENOMEM;
 
@@ -622,8 +621,9 @@ static void pch_spi_set_tx(struct pch_spi_data *data, int *bpw)
        if (n_writes > PCH_MAX_FIFO_DEPTH)
                n_writes = PCH_MAX_FIFO_DEPTH;
 
-       dev_dbg(&data->master->dev, "\n%s:Pulling down SSN low - writing "
-               "0x2 to SSNXCR\n", __func__);
+       dev_dbg(&data->master->dev,
+               "\n%s:Pulling down SSN low - writing 0x2 to SSNXCR\n",
+               __func__);
        pch_spi_writereg(data->master, PCH_SSNXCR, SSN_LOW);
 
        for (j = 0; j < n_writes; j++)
@@ -915,7 +915,6 @@ static void pch_spi_release_dma(struct pch_spi_data *data)
                dma_release_channel(dma->chan_rx);
                dma->chan_rx = NULL;
        }
-       return;
 }
 
 static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
@@ -1008,7 +1007,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
        spin_unlock_irqrestore(&data->lock, flags);
 
        /* RX */
-       dma->sg_rx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC);
+       dma->sg_rx_p = kcalloc(num, sizeof(*dma->sg_rx_p), GFP_ATOMIC);
        sg_init_table(dma->sg_rx_p, num); /* Initialize SG table */
        /* offset, length setting */
        sg = dma->sg_rx_p;
@@ -1068,7 +1067,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
                head = 0;
        }
 
-       dma->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC);
+       dma->sg_tx_p = kcalloc(num, sizeof(*dma->sg_tx_p), GFP_ATOMIC);
        sg_init_table(dma->sg_tx_p, num); /* Initialize SG table */
        /* offset, length setting */
        sg = dma->sg_tx_p;
@@ -1181,14 +1180,16 @@ static void pch_spi_process_messages(struct work_struct *pwork)
                        data->cur_trans =
                                list_entry(data->current_msg->transfers.next,
                                           struct spi_transfer, transfer_list);
-                       dev_dbg(&data->master->dev, "%s "
-                               ":Getting 1st transfer message\n", __func__);
+                       dev_dbg(&data->master->dev,
+                               "%s :Getting 1st transfer message\n",
+                               __func__);
                } else {
                        data->cur_trans =
                                list_entry(data->cur_trans->transfer_list.next,
                                           struct spi_transfer, transfer_list);
-                       dev_dbg(&data->master->dev, "%s "
-                               ":Getting next transfer message\n", __func__);
+                       dev_dbg(&data->master->dev,
+                               "%s :Getting next transfer message\n",
+                               __func__);
                }
                spin_unlock(&data->lock);
 
@@ -1233,9 +1234,8 @@ static void pch_spi_process_messages(struct work_struct *pwork)
 
                /* check for delay */
                if (data->cur_trans->delay_usecs) {
-                       dev_dbg(&data->master->dev, "%s:"
-                               "delay in usec=%d\n", __func__,
-                               data->cur_trans->delay_usecs);
+                       dev_dbg(&data->master->dev, "%s:delay in usec=%d\n",
+                               __func__, data->cur_trans->delay_usecs);
                        udelay(data->cur_trans->delay_usecs);
                }
 
@@ -1292,7 +1292,6 @@ static void pch_free_dma_buf(struct pch_spi_board_data *board_dat,
        if (dma->rx_buf_dma)
                dma_free_coherent(&board_dat->pdev->dev, PCH_BUF_SIZE,
                                  dma->rx_buf_virt, dma->rx_buf_dma);
-       return;
 }
 
 static void pch_alloc_dma_buf(struct pch_spi_board_data *board_dat,
@@ -1541,11 +1540,11 @@ static int pch_spi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        int i;
        struct pch_pd_dev_save *pd_dev_save;
 
-       pd_dev_save = kzalloc(sizeof(struct pch_pd_dev_save), GFP_KERNEL);
+       pd_dev_save = kzalloc(sizeof(*pd_dev_save), GFP_KERNEL);
        if (!pd_dev_save)
                return -ENOMEM;
 
-       board_dat = kzalloc(sizeof(struct pch_spi_board_data), GFP_KERNEL);
+       board_dat = kzalloc(sizeof(*board_dat), GFP_KERNEL);
        if (!board_dat) {
                retval = -ENOMEM;
                goto err_no_mem;
index 656dd3e3220c5062b43b5a162a078f245f90630c..44222ef9471e589b3b78bc44ad978c33808320e9 100644 (file)
@@ -621,8 +621,10 @@ void spi_unregister_device(struct spi_device *spi)
        if (!spi)
                return;
 
-       if (spi->dev.of_node)
+       if (spi->dev.of_node) {
                of_node_clear_flag(spi->dev.of_node, OF_POPULATED);
+               of_node_put(spi->dev.of_node);
+       }
        if (ACPI_COMPANION(&spi->dev))
                acpi_device_clear_enumerated(ACPI_COMPANION(&spi->dev));
        device_unregister(&spi->dev);
@@ -672,7 +674,7 @@ int spi_register_board_info(struct spi_board_info const *info, unsigned n)
        if (!n)
                return -EINVAL;
 
-       bi = kzalloc(n * sizeof(*bi), GFP_KERNEL);
+       bi = kcalloc(n, sizeof(*bi), GFP_KERNEL);
        if (!bi)
                return -ENOMEM;
 
@@ -805,12 +807,12 @@ static int __spi_map_msg(struct spi_master *master, struct spi_message *msg)
        if (master->dma_tx)
                tx_dev = master->dma_tx->device->dev;
        else
-               tx_dev = &master->dev;
+               tx_dev = master->dev.parent;
 
        if (master->dma_rx)
                rx_dev = master->dma_rx->device->dev;
        else
-               rx_dev = &master->dev;
+               rx_dev = master->dev.parent;
 
        list_for_each_entry(xfer, &msg->transfers, transfer_list) {
                if (!master->can_dma(master, msg->spi, xfer))
@@ -852,12 +854,12 @@ static int __spi_unmap_msg(struct spi_master *master, struct spi_message *msg)
        if (master->dma_tx)
                tx_dev = master->dma_tx->device->dev;
        else
-               tx_dev = &master->dev;
+               tx_dev = master->dev.parent;
 
        if (master->dma_rx)
                rx_dev = master->dma_rx->device->dev;
        else
-               rx_dev = &master->dev;
+               rx_dev = master->dev.parent;
 
        list_for_each_entry(xfer, &msg->transfers, transfer_list) {
                if (!master->can_dma(master, msg->spi, xfer))
@@ -1502,37 +1504,18 @@ err_init_queue:
 /*-------------------------------------------------------------------------*/
 
 #if defined(CONFIG_OF)
-static struct spi_device *
-of_register_spi_device(struct spi_master *master, struct device_node *nc)
+static int of_spi_parse_dt(struct spi_master *master, struct spi_device *spi,
+                          struct device_node *nc)
 {
-       struct spi_device *spi;
-       int rc;
        u32 value;
-
-       /* Alloc an spi_device */
-       spi = spi_alloc_device(master);
-       if (!spi) {
-               dev_err(&master->dev, "spi_device alloc error for %s\n",
-                       nc->full_name);
-               rc = -ENOMEM;
-               goto err_out;
-       }
-
-       /* Select device driver */
-       rc = of_modalias_node(nc, spi->modalias,
-                               sizeof(spi->modalias));
-       if (rc < 0) {
-               dev_err(&master->dev, "cannot find modalias for %s\n",
-                       nc->full_name);
-               goto err_out;
-       }
+       int rc;
 
        /* Device address */
        rc = of_property_read_u32(nc, "reg", &value);
        if (rc) {
                dev_err(&master->dev, "%s has no valid 'reg' property (%d)\n",
                        nc->full_name, rc);
-               goto err_out;
+               return rc;
        }
        spi->chip_select = value;
 
@@ -1590,10 +1573,41 @@ of_register_spi_device(struct spi_master *master, struct device_node *nc)
        if (rc) {
                dev_err(&master->dev, "%s has no valid 'spi-max-frequency' property (%d)\n",
                        nc->full_name, rc);
-               goto err_out;
+               return rc;
        }
        spi->max_speed_hz = value;
 
+       return 0;
+}
+
+static struct spi_device *
+of_register_spi_device(struct spi_master *master, struct device_node *nc)
+{
+       struct spi_device *spi;
+       int rc;
+
+       /* Alloc an spi_device */
+       spi = spi_alloc_device(master);
+       if (!spi) {
+               dev_err(&master->dev, "spi_device alloc error for %s\n",
+                       nc->full_name);
+               rc = -ENOMEM;
+               goto err_out;
+       }
+
+       /* Select device driver */
+       rc = of_modalias_node(nc, spi->modalias,
+                               sizeof(spi->modalias));
+       if (rc < 0) {
+               dev_err(&master->dev, "cannot find modalias for %s\n",
+                       nc->full_name);
+               goto err_out;
+       }
+
+       rc = of_spi_parse_dt(master, spi, nc);
+       if (rc)
+               goto err_out;
+
        /* Store a pointer to the node in the device structure */
        of_node_get(nc);
        spi->dev.of_node = nc;
@@ -1603,11 +1617,13 @@ of_register_spi_device(struct spi_master *master, struct device_node *nc)
        if (rc) {
                dev_err(&master->dev, "spi_device register error %s\n",
                        nc->full_name);
-               goto err_out;
+               goto err_of_node_put;
        }
 
        return spi;
 
+err_of_node_put:
+       of_node_put(nc);
 err_out:
        spi_dev_put(spi);
        return ERR_PTR(rc);
@@ -1722,13 +1738,15 @@ static acpi_status acpi_register_spi_device(struct spi_master *master,
                return AE_OK;
        }
 
+       acpi_set_modalias(adev, acpi_device_hid(adev), spi->modalias,
+                         sizeof(spi->modalias));
+
        if (spi->irq < 0)
                spi->irq = acpi_dev_gpio_irq_get(adev, 0);
 
        acpi_device_set_enumerated(adev);
 
        adev->power.flags.ignore_parent = true;
-       strlcpy(spi->modalias, acpi_device_hid(adev), sizeof(spi->modalias));
        if (spi_add_device(spi)) {
                adev->power.flags.ignore_parent = false;
                dev_err(&master->dev, "failed to add SPI device %s from ACPI\n",
index 250caa00de5e9f4665978ef0105a8b42c2e49420..51384bdde450786940fed5fd14fafba55564a68b 100644 (file)
@@ -474,17 +474,20 @@ static void gb_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
        gb_gpio_set_value_operation(ggc, (u8)offset, !!value);
 }
 
-static int gb_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
-                                       unsigned debounce)
+static int gb_gpio_set_config(struct gpio_chip *chip, unsigned offset,
+                             unsigned long config)
 {
        struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip);
-       u16 usec;
+       u32 debounce;
 
+       if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
+               return -ENOTSUPP;
+
+       debounce = pinconf_to_config_argument(config);
        if (debounce > U16_MAX)
                return -EINVAL;
-       usec = (u16)debounce;
 
-       return gb_gpio_set_debounce_operation(ggc, (u8)offset, usec);
+       return gb_gpio_set_debounce_operation(ggc, (u8)offset, (u16)debounce);
 }
 
 static int gb_gpio_controller_setup(struct gb_gpio_controller *ggc)
@@ -689,7 +692,7 @@ static int gb_gpio_probe(struct gbphy_device *gbphy_dev,
        gpio->direction_output = gb_gpio_direction_output;
        gpio->get = gb_gpio_get;
        gpio->set = gb_gpio_set;
-       gpio->set_debounce = gb_gpio_set_debounce;
+       gpio->set_config = gb_gpio_set_config;
        gpio->to_irq = gb_gpio_to_irq;
        gpio->base = -1;                /* Allocate base dynamically */
        gpio->ngpio = ggc->line_max + 1;
index c27d7e9a1bdbe84059b484c7971f0f6ff9a16c33..8b2117ee0f602b43826aabd75e532df4606ecc88 100644 (file)
@@ -129,7 +129,7 @@ __vpfe_video_get_format(struct vpfe_video_device *video,
 /* make a note of pipeline details */
 static int vpfe_prepare_pipeline(struct vpfe_video_device *video)
 {
-       struct media_entity_graph graph;
+       struct media_graph graph;
        struct media_entity *entity = &video->video_dev.entity;
        struct media_device *mdev = entity->graph_obj.mdev;
        struct vpfe_pipeline *pipe = &video->pipe;
@@ -145,13 +145,13 @@ static int vpfe_prepare_pipeline(struct vpfe_video_device *video)
                pipe->outputs[pipe->output_num++] = video;
 
        mutex_lock(&mdev->graph_mutex);
-       ret = media_entity_graph_walk_init(&graph, entity->graph_obj.mdev);
+       ret = media_graph_walk_init(&graph, mdev);
        if (ret) {
                mutex_unlock(&mdev->graph_mutex);
                return -ENOMEM;
        }
-       media_entity_graph_walk_start(&graph, entity);
-       while ((entity = media_entity_graph_walk_next(&graph))) {
+       media_graph_walk_start(&graph, entity);
+       while ((entity = media_graph_walk_next(&graph))) {
                if (entity == &video->video_dev.entity)
                        continue;
                if (!is_media_entity_v4l2_video_device(entity))
@@ -162,7 +162,7 @@ static int vpfe_prepare_pipeline(struct vpfe_video_device *video)
                else
                        pipe->outputs[pipe->output_num++] = far_end;
        }
-       media_entity_graph_walk_cleanup(&graph);
+       media_graph_walk_cleanup(&graph);
        mutex_unlock(&mdev->graph_mutex);
 
        return 0;
@@ -300,12 +300,11 @@ static int vpfe_pipeline_enable(struct vpfe_pipeline *pipe)
 
        mdev = entity->graph_obj.mdev;
        mutex_lock(&mdev->graph_mutex);
-       ret = media_entity_graph_walk_init(&pipe->graph,
-                                          entity->graph_obj.mdev);
+       ret = media_graph_walk_init(&pipe->graph, mdev);
        if (ret)
                goto out;
-       media_entity_graph_walk_start(&pipe->graph, entity);
-       while ((entity = media_entity_graph_walk_next(&pipe->graph))) {
+       media_graph_walk_start(&pipe->graph, entity);
+       while ((entity = media_graph_walk_next(&pipe->graph))) {
 
                if (!is_media_entity_v4l2_subdev(entity))
                        continue;
@@ -316,7 +315,7 @@ static int vpfe_pipeline_enable(struct vpfe_pipeline *pipe)
        }
 out:
        if (ret)
-               media_entity_graph_walk_cleanup(&pipe->graph);
+               media_graph_walk_cleanup(&pipe->graph);
        mutex_unlock(&mdev->graph_mutex);
        return ret;
 }
@@ -346,9 +345,9 @@ static int vpfe_pipeline_disable(struct vpfe_pipeline *pipe)
 
        mdev = entity->graph_obj.mdev;
        mutex_lock(&mdev->graph_mutex);
-       media_entity_graph_walk_start(&pipe->graph, entity);
+       media_graph_walk_start(&pipe->graph, entity);
 
-       while ((entity = media_entity_graph_walk_next(&pipe->graph))) {
+       while ((entity = media_graph_walk_next(&pipe->graph))) {
 
                if (!is_media_entity_v4l2_subdev(entity))
                        continue;
@@ -359,7 +358,7 @@ static int vpfe_pipeline_disable(struct vpfe_pipeline *pipe)
        }
        mutex_unlock(&mdev->graph_mutex);
 
-       media_entity_graph_walk_cleanup(&pipe->graph);
+       media_graph_walk_cleanup(&pipe->graph);
        return ret ? -ETIMEDOUT : 0;
 }
 
index aaec4403df3b695b83fca64065dd1b50d4858d30..22136d3dadcbe946b65360372c8c0e5d2b59a1a1 100644 (file)
@@ -52,7 +52,7 @@ enum vpfe_video_state {
 struct vpfe_pipeline {
        /* media pipeline */
        struct media_pipeline           *pipe;
-       struct media_entity_graph       graph;
+       struct media_graph      graph;
        /* state of the pipeline, continuous,
         * single-shot or stopped
         */
index 25b7e7ccf55479ec7a3d83a6e4b8b6aaba207a26..bc67da254262318f43cb81ab58fb2053339f2e73 100644 (file)
@@ -12,26 +12,6 @@ menuconfig LIRC_STAGING
 
 if LIRC_STAGING
 
-config LIRC_BT829
-        tristate "BT829 based hardware"
-       depends on LIRC && PCI
-       help
-         Driver for the IR interface on BT829-based hardware
-
-config LIRC_IMON
-       tristate "Legacy SoundGraph iMON Receiver and Display"
-       depends on LIRC && USB
-       help
-         Driver for the original SoundGraph iMON IR Receiver and Display
-
-         Current generation iMON devices use the input layer imon driver.
-
-config LIRC_PARALLEL
-       tristate "Homebrew Parallel Port Receiver"
-       depends on LIRC && PARPORT
-       help
-         Driver for Homebrew Parallel Port Receivers
-
 config LIRC_SASEM
        tristate "Sasem USB IR Remote"
        depends on LIRC && USB
@@ -40,7 +20,7 @@ config LIRC_SASEM
 
 config LIRC_SIR
        tristate "Built-in SIR IrDA port"
-       depends on LIRC
+       depends on RC_CORE
        help
          Driver for the SIR IrDA port
 
index 7f919eab1989e33f49917f51e9857bc439f51d1f..28740c94349c4e412ee0b77bc800c8fb0705297c 100644 (file)
@@ -3,9 +3,6 @@
 
 # Each configuration option enables a list of files.
 
-obj-$(CONFIG_LIRC_BT829)       += lirc_bt829.o
-obj-$(CONFIG_LIRC_IMON)                += lirc_imon.o
-obj-$(CONFIG_LIRC_PARALLEL)    += lirc_parallel.o
 obj-$(CONFIG_LIRC_SASEM)       += lirc_sasem.o
 obj-$(CONFIG_LIRC_SIR)         += lirc_sir.o
 obj-$(CONFIG_LIRC_ZILOG)       += lirc_zilog.o
diff --git a/drivers/staging/media/lirc/lirc_bt829.c b/drivers/staging/media/lirc/lirc_bt829.c
deleted file mode 100644 (file)
index 04d881b..0000000
+++ /dev/null
@@ -1,401 +0,0 @@
-/*
- * Remote control driver for the TV-card based on bt829
- *
- *  by Leonid Froenchenko <lfroen@galileo.co.il>
- *
- *  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
-*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/threads.h>
-#include <linux/sched.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-
-#include <media/lirc_dev.h>
-
-static int poll_main(void);
-static int atir_init_start(void);
-
-static void write_index(unsigned char index, unsigned int value);
-static unsigned int read_index(unsigned char index);
-
-static void do_i2c_start(void);
-static void do_i2c_stop(void);
-
-static void seems_wr_byte(unsigned char al);
-static unsigned char seems_rd_byte(void);
-
-static unsigned int read_index(unsigned char al);
-static void write_index(unsigned char ah, unsigned int edx);
-
-static void cycle_delay(int cycle);
-
-static void do_set_bits(unsigned char bl);
-static unsigned char do_get_bits(void);
-
-#define DATA_PCI_OFF 0x7FFC00
-#define WAIT_CYCLE   20
-
-#define DRIVER_NAME "lirc_bt829"
-
-static bool debug;
-
-static int atir_minor;
-static phys_addr_t pci_addr_phys;
-static unsigned char __iomem *pci_addr_lin;
-
-static struct lirc_driver atir_driver;
-
-static struct pci_dev *do_pci_probe(void)
-{
-       struct pci_dev *my_dev;
-
-       my_dev = pci_get_device(PCI_VENDOR_ID_ATI,
-                               PCI_DEVICE_ID_ATI_264VT, NULL);
-       if (my_dev) {
-               pr_err("Using device: %s\n", pci_name(my_dev));
-               pci_addr_phys = 0;
-               if (my_dev->resource[0].flags & IORESOURCE_MEM) {
-                       pci_addr_phys = my_dev->resource[0].start;
-                       pr_info("memory at %pa\n", &pci_addr_phys);
-               }
-               if (pci_addr_phys == 0) {
-                       pr_err("no memory resource ?\n");
-                       pci_dev_put(my_dev);
-                       return NULL;
-               }
-       } else {
-               pr_err("pci_probe failed\n");
-               return NULL;
-       }
-       return my_dev;
-}
-
-static int atir_add_to_buf(void *data, struct lirc_buffer *buf)
-{
-       unsigned char key;
-       int status;
-
-       status = poll_main();
-       key = (status >> 8) & 0xFF;
-       if (status & 0xFF) {
-               dev_dbg(atir_driver.dev, "reading key %02X\n", key);
-               lirc_buffer_write(buf, &key);
-               return 0;
-       }
-       return -ENODATA;
-}
-
-static int atir_set_use_inc(void *data)
-{
-       dev_dbg(atir_driver.dev, "driver is opened\n");
-       return 0;
-}
-
-static void atir_set_use_dec(void *data)
-{
-       dev_dbg(atir_driver.dev, "driver is closed\n");
-}
-
-int init_module(void)
-{
-       struct pci_dev *pdev;
-       int rc;
-
-       pdev = do_pci_probe();
-       if (!pdev)
-               return -ENODEV;
-
-       rc = pci_enable_device(pdev);
-       if (rc)
-               goto err_put_dev;
-
-       if (!atir_init_start()) {
-               rc = -ENODEV;
-               goto err_disable;
-       }
-
-       strcpy(atir_driver.name, "ATIR");
-       atir_driver.minor       = -1;
-       atir_driver.code_length = 8;
-       atir_driver.sample_rate = 10;
-       atir_driver.data        = NULL;
-       atir_driver.add_to_buf  = atir_add_to_buf;
-       atir_driver.set_use_inc = atir_set_use_inc;
-       atir_driver.set_use_dec = atir_set_use_dec;
-       atir_driver.dev         = &pdev->dev;
-       atir_driver.owner       = THIS_MODULE;
-
-       atir_minor = lirc_register_driver(&atir_driver);
-       if (atir_minor < 0) {
-               pr_err("failed to register driver!\n");
-               rc = atir_minor;
-               goto err_unmap;
-       }
-       dev_dbg(atir_driver.dev, "driver is registered on minor %d\n",
-                               atir_minor);
-
-       return 0;
-
-err_unmap:
-       iounmap(pci_addr_lin);
-err_disable:
-       pci_disable_device(pdev);
-err_put_dev:
-       pci_dev_put(pdev);
-       return rc;
-}
-
-void cleanup_module(void)
-{
-       struct pci_dev *pdev = to_pci_dev(atir_driver.dev);
-
-       lirc_unregister_driver(atir_minor);
-       iounmap(pci_addr_lin);
-       pci_disable_device(pdev);
-       pci_dev_put(pdev);
-}
-
-static int atir_init_start(void)
-{
-       pci_addr_lin = ioremap(pci_addr_phys + DATA_PCI_OFF, 0x400);
-       if (!pci_addr_lin) {
-               pr_info("pci mem must be mapped\n");
-               return 0;
-       }
-       return 1;
-}
-
-static void cycle_delay(int cycle)
-{
-       udelay(WAIT_CYCLE * cycle);
-}
-
-static int poll_main(void)
-{
-       unsigned char status_high, status_low;
-
-       do_i2c_start();
-
-       seems_wr_byte(0xAA);
-       seems_wr_byte(0x01);
-
-       do_i2c_start();
-
-       seems_wr_byte(0xAB);
-
-       status_low = seems_rd_byte();
-       status_high = seems_rd_byte();
-
-       do_i2c_stop();
-
-       return (status_high << 8) | status_low;
-}
-
-static void do_i2c_start(void)
-{
-       do_set_bits(3);
-       cycle_delay(4);
-
-       do_set_bits(1);
-       cycle_delay(7);
-
-       do_set_bits(0);
-       cycle_delay(2);
-}
-
-static void do_i2c_stop(void)
-{
-       unsigned char bits;
-
-       bits =  do_get_bits() & 0xFD;
-       do_set_bits(bits);
-       cycle_delay(1);
-
-       bits |= 1;
-       do_set_bits(bits);
-       cycle_delay(2);
-
-       bits |= 2;
-       do_set_bits(bits);
-       bits = 3;
-       do_set_bits(bits);
-       cycle_delay(2);
-}
-
-static void seems_wr_byte(unsigned char value)
-{
-       int i;
-       unsigned char reg;
-
-       reg = do_get_bits();
-       for (i = 0; i < 8; i++) {
-               if (value & 0x80)
-                       reg |= 0x02;
-               else
-                       reg &= 0xFD;
-
-               do_set_bits(reg);
-               cycle_delay(1);
-
-               reg |= 1;
-               do_set_bits(reg);
-               cycle_delay(1);
-
-               reg &= 0xFE;
-               do_set_bits(reg);
-               cycle_delay(1);
-               value <<= 1;
-       }
-       cycle_delay(2);
-
-       reg |= 2;
-       do_set_bits(reg);
-
-       reg |= 1;
-       do_set_bits(reg);
-
-       cycle_delay(1);
-       do_get_bits();
-
-       reg &= 0xFE;
-       do_set_bits(reg);
-       cycle_delay(3);
-}
-
-static unsigned char seems_rd_byte(void)
-{
-       int i;
-       int rd_byte;
-       unsigned char bits_2, bits_1;
-
-       bits_1 = do_get_bits() | 2;
-       do_set_bits(bits_1);
-
-       rd_byte = 0;
-       for (i = 0; i < 8; i++) {
-               bits_1 &= 0xFE;
-               do_set_bits(bits_1);
-               cycle_delay(2);
-
-               bits_1 |= 1;
-               do_set_bits(bits_1);
-               cycle_delay(1);
-
-               bits_2 = do_get_bits();
-               if (bits_2 & 2)
-                       rd_byte |= 1;
-
-               rd_byte <<= 1;
-       }
-
-       bits_1 = 0;
-       if (bits_2 == 0)
-               bits_1 |= 2;
-
-       do_set_bits(bits_1);
-       cycle_delay(2);
-
-       bits_1 |= 1;
-       do_set_bits(bits_1);
-       cycle_delay(3);
-
-       bits_1 &= 0xFE;
-       do_set_bits(bits_1);
-       cycle_delay(2);
-
-       rd_byte >>= 1;
-       rd_byte &= 0xFF;
-       return rd_byte;
-}
-
-static void do_set_bits(unsigned char new_bits)
-{
-       int reg_val;
-
-       reg_val = read_index(0x34);
-       if (new_bits & 2) {
-               reg_val &= 0xFFFFFFDF;
-               reg_val |= 1;
-       } else {
-               reg_val &= 0xFFFFFFFE;
-               reg_val |= 0x20;
-       }
-       reg_val |= 0x10;
-       write_index(0x34, reg_val);
-
-       reg_val = read_index(0x31);
-       if (new_bits & 1)
-               reg_val |= 0x1000000;
-       else
-               reg_val &= 0xFEFFFFFF;
-
-       reg_val |= 0x8000000;
-       write_index(0x31, reg_val);
-}
-
-static unsigned char do_get_bits(void)
-{
-       unsigned char bits;
-       int reg_val;
-
-       reg_val = read_index(0x34);
-       reg_val |= 0x10;
-       reg_val &= 0xFFFFFFDF;
-       write_index(0x34, reg_val);
-
-       reg_val = read_index(0x34);
-       bits = 0;
-       if (reg_val & 8)
-               bits |= 2;
-       else
-               bits &= 0xFD;
-
-       reg_val = read_index(0x31);
-       if (reg_val & 0x1000000)
-               bits |= 1;
-       else
-               bits &= 0xFE;
-
-       return bits;
-}
-
-static unsigned int read_index(unsigned char index)
-{
-       unsigned char __iomem *addr;
-       /*  addr = pci_addr_lin + DATA_PCI_OFF + ((index & 0xFF) << 2); */
-       addr = pci_addr_lin + ((index & 0xFF) << 2);
-       return readl(addr);
-}
-
-static void write_index(unsigned char index, unsigned int reg_val)
-{
-       unsigned char __iomem *addr;
-
-       addr = pci_addr_lin + ((index & 0xFF) << 2);
-       writel(reg_val, addr);
-}
-
-MODULE_AUTHOR("Froenchenko Leonid");
-MODULE_DESCRIPTION("IR remote driver for bt829 based TV cards");
-MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/staging/media/lirc/lirc_imon.c b/drivers/staging/media/lirc/lirc_imon.c
deleted file mode 100644 (file)
index 1e650fb..0000000
+++ /dev/null
@@ -1,979 +0,0 @@
-/*
- *   lirc_imon.c:  LIRC/VFD/LCD driver for SoundGraph iMON IR/VFD/LCD
- *                including the iMON PAD model
- *
- *   Copyright(C) 2004  Venky Raju(dev@venky.ws)
- *   Copyright(C) 2009  Jarod Wilson <jarod@wilsonet.com>
- *
- *   lirc_imon 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.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-#include <linux/usb.h>
-
-#include <media/lirc.h>
-#include <media/lirc_dev.h>
-
-#define MOD_AUTHOR     "Venky Raju <dev@venky.ws>"
-#define MOD_DESC       "Driver for SoundGraph iMON MultiMedia IR/Display"
-#define MOD_NAME       "lirc_imon"
-#define MOD_VERSION    "0.8"
-
-#define DISPLAY_MINOR_BASE     144
-#define DEVICE_NAME    "lcd%d"
-
-#define BUF_CHUNK_SIZE 4
-#define BUF_SIZE       128
-
-#define BIT_DURATION   250     /* each bit received is 250us */
-
-/*** P R O T O T Y P E S ***/
-
-/* USB Callback prototypes */
-static int imon_probe(struct usb_interface *interface,
-                     const struct usb_device_id *id);
-static void imon_disconnect(struct usb_interface *interface);
-static void usb_rx_callback(struct urb *urb);
-static void usb_tx_callback(struct urb *urb);
-
-/* suspend/resume support */
-static int imon_resume(struct usb_interface *intf);
-static int imon_suspend(struct usb_interface *intf, pm_message_t message);
-
-/* Display file_operations function prototypes */
-static int display_open(struct inode *inode, struct file *file);
-static int display_close(struct inode *inode, struct file *file);
-
-/* VFD write operation */
-static ssize_t vfd_write(struct file *file, const char __user *buf,
-                        size_t n_bytes, loff_t *pos);
-
-/* LIRC driver function prototypes */
-static int ir_open(void *data);
-static void ir_close(void *data);
-
-/*** G L O B A L S ***/
-#define IMON_DATA_BUF_SZ       35
-
-struct imon_context {
-       struct usb_device *usbdev;
-       /* Newer devices have two interfaces */
-       int display;                    /* not all controllers do */
-       int display_isopen;             /* display port has been opened */
-       int ir_isopen;                  /* IR port open */
-       int dev_present;                /* USB device presence */
-       struct mutex ctx_lock;          /* to lock this object */
-       wait_queue_head_t remove_ok;    /* For unexpected USB disconnects */
-
-       int vfd_proto_6p;               /* some VFD require a 6th packet */
-
-       struct lirc_driver *driver;
-       struct usb_endpoint_descriptor *rx_endpoint;
-       struct usb_endpoint_descriptor *tx_endpoint;
-       struct urb *rx_urb;
-       struct urb *tx_urb;
-       unsigned char usb_rx_buf[8];
-       unsigned char usb_tx_buf[8];
-
-       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[IMON_DATA_BUF_SZ]; /* user data buffer */
-               struct completion finished;     /* wait for write to finish */
-               atomic_t busy;                  /* write in progress */
-               int status;                     /* status of tx completion */
-       } tx;
-};
-
-static const struct file_operations display_fops = {
-       .owner          = THIS_MODULE,
-       .open           = &display_open,
-       .write          = &vfd_write,
-       .release        = &display_close,
-       .llseek         = noop_llseek,
-};
-
-/*
- * USB Device ID for iMON USB Control Boards
- *
- * The Windows drivers contain 6 different inf files, more or less one for
- * each new device until the 0x0034-0x0046 devices, which all use the same
- * driver. Some of the devices in the 34-46 range haven't been definitively
- * identified yet. Early devices have either a TriGem Computer, Inc. or a
- * Samsung vendor ID (0x0aa8 and 0x04e8 respectively), while all later
- * devices use the SoundGraph vendor ID (0x15c2).
- */
-static struct usb_device_id imon_usb_id_table[] = {
-       /* TriGem iMON (IR only) -- TG_iMON.inf */
-       { USB_DEVICE(0x0aa8, 0x8001) },
-
-       /* SoundGraph iMON (IR only) -- sg_imon.inf */
-       { USB_DEVICE(0x04e8, 0xff30) },
-
-       /* SoundGraph iMON VFD (IR & VFD) -- iMON_VFD.inf */
-       { USB_DEVICE(0x0aa8, 0xffda) },
-
-       /* SoundGraph iMON SS (IR & VFD) -- iMON_SS.inf */
-       { USB_DEVICE(0x15c2, 0xffda) },
-
-       {}
-};
-
-/* Some iMON VFD models requires a 6th packet for VFD writes */
-static struct usb_device_id vfd_proto_6p_list[] = {
-       { USB_DEVICE(0x15c2, 0xffda) },
-       {}
-};
-
-/* Some iMON devices have no lcd/vfd, don't set one up */
-static struct usb_device_id ir_only_list[] = {
-       { USB_DEVICE(0x0aa8, 0x8001) },
-       { USB_DEVICE(0x04e8, 0xff30) },
-       {}
-};
-
-/* USB Device data */
-static struct usb_driver imon_driver = {
-       .name           = MOD_NAME,
-       .probe          = imon_probe,
-       .disconnect     = imon_disconnect,
-       .suspend        = imon_suspend,
-       .resume         = imon_resume,
-       .id_table       = imon_usb_id_table,
-};
-
-static struct usb_class_driver imon_class = {
-       .name           = DEVICE_NAME,
-       .fops           = &display_fops,
-       .minor_base     = DISPLAY_MINOR_BASE,
-};
-
-/* to prevent races between open() and disconnect(), probing, etc */
-static DEFINE_MUTEX(driver_lock);
-
-static int debug;
-
-/***  M O D U L E   C O D E ***/
-
-MODULE_AUTHOR(MOD_AUTHOR);
-MODULE_DESCRIPTION(MOD_DESC);
-MODULE_VERSION(MOD_VERSION);
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(usb, imon_usb_id_table);
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes(default: no)");
-
-static void free_imon_context(struct imon_context *context)
-{
-       struct device *dev = context->driver->dev;
-
-       usb_free_urb(context->tx_urb);
-       usb_free_urb(context->rx_urb);
-       lirc_buffer_free(context->driver->rbuf);
-       kfree(context->driver->rbuf);
-       kfree(context->driver);
-       kfree(context);
-
-       dev_dbg(dev, "%s: iMON context freed\n", __func__);
-}
-
-static void deregister_from_lirc(struct imon_context *context)
-{
-       int retval;
-       int minor = context->driver->minor;
-
-       retval = lirc_unregister_driver(minor);
-       if (retval)
-               dev_err(&context->usbdev->dev,
-                       "unable to deregister from lirc(%d)", retval);
-       else
-               dev_info(&context->usbdev->dev,
-                        "Deregistered iMON driver (minor:%d)\n", minor);
-}
-
-/**
- * Called when the Display device (e.g. /dev/lcd0)
- * is opened by the application.
- */
-static int display_open(struct inode *inode, struct file *file)
-{
-       struct usb_interface *interface;
-       struct imon_context *context = NULL;
-       int subminor;
-       int retval = 0;
-
-       /* prevent races with disconnect */
-       mutex_lock(&driver_lock);
-
-       subminor = iminor(inode);
-       interface = usb_find_interface(&imon_driver, subminor);
-       if (!interface) {
-               pr_err("%s: could not find interface for minor %d\n",
-                      __func__, subminor);
-               retval = -ENODEV;
-               goto exit;
-       }
-       context = usb_get_intfdata(interface);
-
-       if (!context) {
-               dev_err(&interface->dev, "no context found for minor %d\n",
-                       subminor);
-               retval = -ENODEV;
-               goto exit;
-       }
-
-       mutex_lock(&context->ctx_lock);
-
-       if (!context->display) {
-               dev_err(&interface->dev,
-                       "%s: display not supported by device\n", __func__);
-               retval = -ENODEV;
-       } else if (context->display_isopen) {
-               dev_err(&interface->dev,
-                       "%s: display port is already open\n", __func__);
-               retval = -EBUSY;
-       } else {
-               context->display_isopen = 1;
-               file->private_data = context;
-               dev_info(context->driver->dev, "display port opened\n");
-       }
-
-       mutex_unlock(&context->ctx_lock);
-
-exit:
-       mutex_unlock(&driver_lock);
-       return retval;
-}
-
-/**
- * Called when the display device (e.g. /dev/lcd0)
- * is closed by the application.
- */
-static int display_close(struct inode *inode, struct file *file)
-{
-       struct imon_context *context = NULL;
-       int retval = 0;
-
-       context = file->private_data;
-
-       if (!context) {
-               pr_err("%s: no context for device\n", __func__);
-               return -ENODEV;
-       }
-
-       mutex_lock(&context->ctx_lock);
-
-       if (!context->display) {
-               dev_err(&context->usbdev->dev,
-                       "%s: display not supported by device\n", __func__);
-               retval = -ENODEV;
-       } else if (!context->display_isopen) {
-               dev_err(&context->usbdev->dev,
-                       "%s: display is not open\n", __func__);
-               retval = -EIO;
-       } else {
-               context->display_isopen = 0;
-               dev_info(context->driver->dev, "display port closed\n");
-               if (!context->dev_present && !context->ir_isopen) {
-                       /*
-                        * Device disconnected before close and IR port is not
-                        * open. If IR port is open, context will be deleted by
-                        * ir_close.
-                        */
-                       mutex_unlock(&context->ctx_lock);
-                       free_imon_context(context);
-                       return retval;
-               }
-       }
-
-       mutex_unlock(&context->ctx_lock);
-       return retval;
-}
-
-/**
- * Sends a packet to the device -- this function must be called
- * with context->ctx_lock held.
- */
-static int send_packet(struct imon_context *context)
-{
-       unsigned int pipe;
-       int interval = 0;
-       int retval = 0;
-
-       /* Check if we need to use control or interrupt urb */
-       pipe = usb_sndintpipe(context->usbdev,
-                             context->tx_endpoint->bEndpointAddress);
-       interval = context->tx_endpoint->bInterval;
-
-       usb_fill_int_urb(context->tx_urb, context->usbdev, pipe,
-                        context->usb_tx_buf,
-                        sizeof(context->usb_tx_buf),
-                        usb_tx_callback, context, interval);
-
-       context->tx_urb->actual_length = 0;
-
-       reinit_completion(&context->tx.finished);
-       atomic_set(&context->tx.busy, 1);
-
-       retval = usb_submit_urb(context->tx_urb, GFP_KERNEL);
-       if (retval) {
-               atomic_set(&context->tx.busy, 0);
-               dev_err(&context->usbdev->dev, "error submitting urb(%d)\n",
-                       retval);
-       } else {
-               /* Wait for transmission to complete (or abort) */
-               mutex_unlock(&context->ctx_lock);
-               retval = wait_for_completion_interruptible(
-                               &context->tx.finished);
-               if (retval)
-                       dev_err(&context->usbdev->dev,
-                               "%s: task interrupted\n", __func__);
-               mutex_lock(&context->ctx_lock);
-
-               retval = context->tx.status;
-               if (retval)
-                       dev_err(&context->usbdev->dev,
-                               "packet tx failed (%d)\n", retval);
-       }
-
-       return retval;
-}
-
-/**
- * Writes data to the VFD.  The iMON VFD is 2x16 characters
- * and requires data in 5 consecutive USB interrupt packets,
- * each packet but the last carrying 7 bytes.
- *
- * I don't know if the VFD board supports features such as
- * scrolling, clearing rows, blanking, etc. so at
- * the caller must provide a full screen of data.  If fewer
- * than 32 bytes are provided spaces will be appended to
- * generate a full screen.
- */
-static ssize_t vfd_write(struct file *file, const char __user *buf,
-                        size_t n_bytes, loff_t *pos)
-{
-       int i;
-       int offset;
-       int seq;
-       int retval = 0;
-       struct imon_context *context;
-       const unsigned char vfd_packet6[] = {
-               0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF };
-       int *data_buf = NULL;
-
-       context = file->private_data;
-       if (!context) {
-               pr_err("%s: no context for device\n", __func__);
-               return -ENODEV;
-       }
-
-       mutex_lock(&context->ctx_lock);
-
-       if (!context->dev_present) {
-               dev_err(&context->usbdev->dev,
-                       "%s: no iMON device present\n", __func__);
-               retval = -ENODEV;
-               goto exit;
-       }
-
-       if (n_bytes <= 0 || n_bytes > IMON_DATA_BUF_SZ - 3) {
-               dev_err(&context->usbdev->dev,
-                       "%s: invalid payload size\n", __func__);
-               retval = -EINVAL;
-               goto exit;
-       }
-
-       data_buf = memdup_user(buf, n_bytes);
-       if (IS_ERR(data_buf)) {
-               mutex_unlock(&context->ctx_lock);
-               return PTR_ERR(data_buf);
-       }
-
-       memcpy(context->tx.data_buf, data_buf, n_bytes);
-
-       /* Pad with spaces */
-       for (i = n_bytes; i < IMON_DATA_BUF_SZ - 3; ++i)
-               context->tx.data_buf[i] = ' ';
-
-       for (i = IMON_DATA_BUF_SZ - 3; i < IMON_DATA_BUF_SZ; ++i)
-               context->tx.data_buf[i] = 0xFF;
-
-       offset = 0;
-       seq = 0;
-
-       do {
-               memcpy(context->usb_tx_buf, context->tx.data_buf + offset, 7);
-               context->usb_tx_buf[7] = (unsigned char)seq;
-
-               retval = send_packet(context);
-               if (retval) {
-                       dev_err(&context->usbdev->dev,
-                               "send packet failed for packet #%d\n",
-                               seq / 2);
-                       goto exit;
-               } else {
-                       seq += 2;
-                       offset += 7;
-               }
-
-       } while (offset < IMON_DATA_BUF_SZ);
-
-       if (context->vfd_proto_6p) {
-               /* Send packet #6 */
-               memcpy(context->usb_tx_buf, &vfd_packet6, sizeof(vfd_packet6));
-               context->usb_tx_buf[7] = (unsigned char)seq;
-               retval = send_packet(context);
-               if (retval)
-                       dev_err(&context->usbdev->dev,
-                               "send packet failed for packet #%d\n",
-                               seq / 2);
-       }
-
-exit:
-       mutex_unlock(&context->ctx_lock);
-       kfree(data_buf);
-
-       return (!retval) ? n_bytes : retval;
-}
-
-/**
- * Callback function for USB core API: transmit data
- */
-static void usb_tx_callback(struct urb *urb)
-{
-       struct imon_context *context;
-
-       if (!urb)
-               return;
-       context = (struct imon_context *)urb->context;
-       if (!context)
-               return;
-
-       context->tx.status = urb->status;
-
-       /* notify waiters that write has finished */
-       atomic_set(&context->tx.busy, 0);
-       complete(&context->tx.finished);
-}
-
-/**
- * Called by lirc_dev when the application opens /dev/lirc
- */
-static int ir_open(void *data)
-{
-       struct imon_context *context;
-
-       /* prevent races with disconnect */
-       mutex_lock(&driver_lock);
-
-       context = data;
-
-       /* initial IR protocol decode variables */
-       context->rx.count = 0;
-       context->rx.initial_space = 1;
-       context->rx.prev_bit = 0;
-
-       init_completion(&context->tx.finished);
-
-       context->ir_isopen = 1;
-       dev_info(context->driver->dev, "IR port opened\n");
-
-       mutex_unlock(&driver_lock);
-       return 0;
-}
-
-/**
- * Called by lirc_dev when the application closes /dev/lirc
- */
-static void ir_close(void *data)
-{
-       struct imon_context *context;
-
-       context = data;
-       if (!context) {
-               pr_err("%s: no context for device\n", __func__);
-               return;
-       }
-
-       mutex_lock(&context->ctx_lock);
-
-       context->ir_isopen = 0;
-       dev_info(context->driver->dev, "IR port closed\n");
-
-       if (!context->dev_present) {
-               /*
-                * Device disconnected while IR port was still open. Driver
-                * was not deregistered at disconnect time, so do it now.
-                */
-               deregister_from_lirc(context);
-
-               if (!context->display_isopen) {
-                       mutex_unlock(&context->ctx_lock);
-                       free_imon_context(context);
-                       return;
-               }
-               /*
-                * If display port is open, context will be deleted by
-                * display_close
-                */
-       }
-
-       mutex_unlock(&context->ctx_lock);
-}
-
-/**
- * Convert bit count to time duration (in us) and submit
- * the value to lirc_dev.
- */
-static void submit_data(struct imon_context *context)
-{
-       unsigned char buf[4];
-       int value = context->rx.count;
-       int i;
-
-       dev_dbg(context->driver->dev, "submitting data to LIRC\n");
-
-       value *= BIT_DURATION;
-       value &= PULSE_MASK;
-       if (context->rx.prev_bit)
-               value |= PULSE_BIT;
-
-       for (i = 0; i < 4; ++i)
-               buf[i] = value >> (i * 8);
-
-       lirc_buffer_write(context->driver->rbuf, buf);
-       wake_up(&context->driver->rbuf->wait_poll);
-}
-
-/**
- * Process the incoming packet
- */
-static void imon_incoming_packet(struct imon_context *context,
-                                struct urb *urb, int intf)
-{
-       int len = urb->actual_length;
-       unsigned char *buf = urb->transfer_buffer;
-       struct device *dev = context->driver->dev;
-       int octet, bit;
-       unsigned char mask;
-
-       /*
-        * just bail out if no listening IR client
-        */
-       if (!context->ir_isopen)
-               return;
-
-       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;
-       }
-}
-
-/**
- * Callback function for USB core API: receive data
- */
-static void usb_rx_callback(struct urb *urb)
-{
-       struct imon_context *context;
-       int intfnum = 0;
-
-       if (!urb)
-               return;
-
-       context = (struct imon_context *)urb->context;
-       if (!context)
-               return;
-
-       switch (urb->status) {
-       case -ENOENT:           /* usbcore unlink successful! */
-               return;
-
-       case 0:
-               imon_incoming_packet(context, urb, intfnum);
-               break;
-
-       default:
-               dev_warn(context->driver->dev, "imon %s: status(%d): ignored\n",
-                        __func__, urb->status);
-               break;
-       }
-
-       usb_submit_urb(context->rx_urb, GFP_ATOMIC);
-}
-
-/**
- * Callback function for USB core API: Probe
- */
-static int imon_probe(struct usb_interface *interface,
-                     const struct usb_device_id *id)
-{
-       struct usb_device *usbdev = NULL;
-       struct usb_host_interface *iface_desc = NULL;
-       struct usb_endpoint_descriptor *rx_endpoint = NULL;
-       struct usb_endpoint_descriptor *tx_endpoint = NULL;
-       struct urb *rx_urb = NULL;
-       struct urb *tx_urb = NULL;
-       struct lirc_driver *driver = NULL;
-       struct lirc_buffer *rbuf = NULL;
-       struct device *dev = &interface->dev;
-       int ifnum;
-       int lirc_minor = 0;
-       int num_endpts;
-       int retval = -ENOMEM;
-       int display_ep_found = 0;
-       int ir_ep_found = 0;
-       int vfd_proto_6p = 0;
-       struct imon_context *context = NULL;
-       int i;
-       u16 vendor, product;
-
-       /* prevent races probing devices w/multiple interfaces */
-       mutex_lock(&driver_lock);
-
-       context = kzalloc(sizeof(*context), GFP_KERNEL);
-       if (!context)
-               goto driver_unlock;
-
-       /*
-        * Try to auto-detect the type of display if the user hasn't set
-        * it by hand via the display_type modparam. Default is VFD.
-        */
-       if (usb_match_id(interface, ir_only_list))
-               context->display = 0;
-       else
-               context->display = 1;
-
-       usbdev     = usb_get_dev(interface_to_usbdev(interface));
-       iface_desc = interface->cur_altsetting;
-       num_endpts = iface_desc->desc.bNumEndpoints;
-       ifnum      = iface_desc->desc.bInterfaceNumber;
-       vendor     = le16_to_cpu(usbdev->descriptor.idVendor);
-       product    = le16_to_cpu(usbdev->descriptor.idProduct);
-
-       dev_dbg(dev, "%s: found iMON device (%04x:%04x, intf%d)\n",
-               __func__, vendor, product, ifnum);
-
-       /*
-        * Scan the endpoint list and set:
-        *      first input endpoint = IR endpoint
-        *      first output endpoint = display endpoint
-        */
-       for (i = 0; i < num_endpts && !(ir_ep_found && display_ep_found); ++i) {
-               struct usb_endpoint_descriptor *ep;
-               int ep_dir;
-               int ep_type;
-
-               ep = &iface_desc->endpoint[i].desc;
-               ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK;
-               ep_type = usb_endpoint_type(ep);
-
-               if (!ir_ep_found &&
-                       ep_dir == USB_DIR_IN &&
-                       ep_type == USB_ENDPOINT_XFER_INT) {
-
-                       rx_endpoint = ep;
-                       ir_ep_found = 1;
-                       dev_dbg(dev, "%s: found IR endpoint\n", __func__);
-
-               } else if (!display_ep_found && ep_dir == USB_DIR_OUT &&
-                          ep_type == USB_ENDPOINT_XFER_INT) {
-                       tx_endpoint = ep;
-                       display_ep_found = 1;
-                       dev_dbg(dev, "%s: found display endpoint\n", __func__);
-               }
-       }
-
-       /*
-        * Some iMON receivers have no display. Unfortunately, it seems
-        * that SoundGraph recycles device IDs between devices both with
-        * and without... :\
-        */
-       if (context->display == 0) {
-               display_ep_found = 0;
-               dev_dbg(dev, "%s: device has no display\n", __func__);
-       }
-
-       /* Input endpoint is mandatory */
-       if (!ir_ep_found) {
-               dev_err(dev, "%s: no valid input (IR) endpoint found.\n",
-                       __func__);
-               retval = -ENODEV;
-               goto free_context;
-       }
-
-       /* Determine if display requires 6 packets */
-       if (display_ep_found) {
-               if (usb_match_id(interface, vfd_proto_6p_list))
-                       vfd_proto_6p = 1;
-
-               dev_dbg(dev, "%s: vfd_proto_6p: %d\n",
-                       __func__, vfd_proto_6p);
-       }
-
-       driver = kzalloc(sizeof(*driver), GFP_KERNEL);
-       if (!driver)
-               goto free_context;
-
-       rbuf = kmalloc(sizeof(*rbuf), GFP_KERNEL);
-       if (!rbuf)
-               goto free_driver;
-
-       if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) {
-               dev_err(dev, "%s: lirc_buffer_init failed\n", __func__);
-               goto free_rbuf;
-       }
-       rx_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!rx_urb)
-               goto free_lirc_buf;
-       tx_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!tx_urb)
-               goto free_rx_urb;
-
-       mutex_init(&context->ctx_lock);
-       context->vfd_proto_6p = vfd_proto_6p;
-
-       strcpy(driver->name, MOD_NAME);
-       driver->minor = -1;
-       driver->code_length = BUF_CHUNK_SIZE * 8;
-       driver->sample_rate = 0;
-       driver->features = LIRC_CAN_REC_MODE2;
-       driver->data = context;
-       driver->rbuf = rbuf;
-       driver->set_use_inc = ir_open;
-       driver->set_use_dec = ir_close;
-       driver->dev = &interface->dev;
-       driver->owner = THIS_MODULE;
-
-       mutex_lock(&context->ctx_lock);
-
-       context->driver = driver;
-       /* start out in keyboard mode */
-
-       lirc_minor = lirc_register_driver(driver);
-       if (lirc_minor < 0) {
-               dev_err(dev, "%s: lirc_register_driver failed\n", __func__);
-               goto free_tx_urb;
-       }
-
-       dev_info(dev, "Registered iMON driver (lirc minor: %d)\n",
-                lirc_minor);
-
-       /* Needed while unregistering! */
-       driver->minor = lirc_minor;
-
-       context->usbdev = usbdev;
-       context->dev_present = 1;
-       context->rx_endpoint = rx_endpoint;
-       context->rx_urb = rx_urb;
-
-       /*
-        * tx is used to send characters to lcd/vfd, associate RF
-        * remotes, set IR protocol, and maybe more...
-        */
-       context->tx_endpoint = tx_endpoint;
-       context->tx_urb = tx_urb;
-
-       if (display_ep_found)
-               context->display = 1;
-
-       usb_fill_int_urb(context->rx_urb, context->usbdev,
-                        usb_rcvintpipe(context->usbdev,
-                        context->rx_endpoint->bEndpointAddress),
-               context->usb_rx_buf, sizeof(context->usb_rx_buf),
-               usb_rx_callback, context,
-               context->rx_endpoint->bInterval);
-
-       retval = usb_submit_urb(context->rx_urb, GFP_KERNEL);
-       if (retval) {
-               dev_err(dev, "usb_submit_urb failed for intf0 (%d)\n", retval);
-               goto unregister_lirc;
-       }
-
-       usb_set_intfdata(interface, context);
-
-       if (context->display && ifnum == 0) {
-               dev_dbg(dev, "%s: Registering iMON display with sysfs\n",
-                       __func__);
-
-               if (usb_register_dev(interface, &imon_class)) {
-                       /* Not a fatal error, so ignore */
-                       dev_info(dev, "%s: could not get a minor number for display\n",
-                                __func__);
-               }
-       }
-
-       dev_info(dev, "iMON device (%04x:%04x, intf%d) on usb<%d:%d> initialized\n",
-                vendor, product, ifnum, usbdev->bus->busnum, usbdev->devnum);
-
-       /* Everything went fine. Just unlock and return retval (with is 0) */
-       mutex_unlock(&context->ctx_lock);
-       goto driver_unlock;
-
-unregister_lirc:
-       lirc_unregister_driver(driver->minor);
-
-free_tx_urb:
-       mutex_unlock(&context->ctx_lock);
-       usb_free_urb(tx_urb);
-
-free_rx_urb:
-       usb_free_urb(rx_urb);
-
-free_lirc_buf:
-       lirc_buffer_free(rbuf);
-
-free_rbuf:
-       kfree(rbuf);
-
-free_driver:
-       kfree(driver);
-free_context:
-       kfree(context);
-       context = NULL;
-
-driver_unlock:
-       mutex_unlock(&driver_lock);
-
-       return retval;
-}
-
-/**
- * Callback function for USB core API: disconnect
- */
-static void imon_disconnect(struct usb_interface *interface)
-{
-       struct imon_context *context;
-       int ifnum;
-
-       /* prevent races with ir_open()/display_open() */
-       mutex_lock(&driver_lock);
-
-       context = usb_get_intfdata(interface);
-       ifnum = interface->cur_altsetting->desc.bInterfaceNumber;
-
-       mutex_lock(&context->ctx_lock);
-
-       usb_set_intfdata(interface, NULL);
-
-       /* Abort ongoing write */
-       if (atomic_read(&context->tx.busy)) {
-               usb_kill_urb(context->tx_urb);
-               complete(&context->tx.finished);
-       }
-
-       context->dev_present = 0;
-       usb_kill_urb(context->rx_urb);
-       if (context->display)
-               usb_deregister_dev(interface, &imon_class);
-
-       if (!context->ir_isopen && !context->dev_present) {
-               deregister_from_lirc(context);
-               mutex_unlock(&context->ctx_lock);
-               if (!context->display_isopen)
-                       free_imon_context(context);
-       } else
-               mutex_unlock(&context->ctx_lock);
-
-       mutex_unlock(&driver_lock);
-
-       dev_info(&interface->dev, "%s: iMON device (intf%d) disconnected\n",
-                __func__, ifnum);
-}
-
-static int imon_suspend(struct usb_interface *intf, pm_message_t message)
-{
-       struct imon_context *context = usb_get_intfdata(intf);
-
-       usb_kill_urb(context->rx_urb);
-
-       return 0;
-}
-
-static int imon_resume(struct usb_interface *intf)
-{
-       struct imon_context *context = usb_get_intfdata(intf);
-
-       usb_fill_int_urb(context->rx_urb, context->usbdev,
-                        usb_rcvintpipe(context->usbdev,
-                        context->rx_endpoint->bEndpointAddress),
-               context->usb_rx_buf, sizeof(context->usb_rx_buf),
-               usb_rx_callback, context,
-               context->rx_endpoint->bInterval);
-
-       return usb_submit_urb(context->rx_urb, GFP_ATOMIC);
-}
-
-module_usb_driver(imon_driver);
diff --git a/drivers/staging/media/lirc/lirc_parallel.c b/drivers/staging/media/lirc/lirc_parallel.c
deleted file mode 100644 (file)
index bfb76a4..0000000
+++ /dev/null
@@ -1,741 +0,0 @@
-/*
- * lirc_parallel.c
- *
- * lirc_parallel - device driver for infra-red signal receiving and
- *                 transmitting unit built by the author
- *
- * Copyright (C) 1998 Christoph Bartelmus <lirc@bartelmus.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
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-/*** Includes ***/
-
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/ktime.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/uaccess.h>
-#include <asm/div64.h>
-
-#include <linux/poll.h>
-#include <linux/parport.h>
-#include <linux/platform_device.h>
-
-#include <media/lirc.h>
-#include <media/lirc_dev.h>
-
-#include "lirc_parallel.h"
-
-#define LIRC_DRIVER_NAME "lirc_parallel"
-
-#ifndef LIRC_IRQ
-#define LIRC_IRQ 7
-#endif
-#ifndef LIRC_PORT
-#define LIRC_PORT 0x378
-#endif
-#ifndef LIRC_TIMER
-#define LIRC_TIMER 65536
-#endif
-
-/*** Global Variables ***/
-
-static bool debug;
-static bool check_pselecd;
-
-static unsigned int irq = LIRC_IRQ;
-static unsigned int io = LIRC_PORT;
-#ifdef LIRC_TIMER
-static unsigned int timer;
-static unsigned int default_timer = LIRC_TIMER;
-#endif
-
-#define RBUF_SIZE (256) /* this must be a power of 2 larger than 1 */
-
-static int rbuf[RBUF_SIZE];
-
-static DECLARE_WAIT_QUEUE_HEAD(lirc_wait);
-
-static unsigned int rptr;
-static unsigned int wptr;
-static unsigned int lost_irqs;
-static int is_open;
-
-static struct parport *pport;
-static struct pardevice *ppdevice;
-static int is_claimed;
-
-static unsigned int tx_mask = 1;
-
-/*** Internal Functions ***/
-
-static unsigned int in(int offset)
-{
-       switch (offset) {
-       case LIRC_LP_BASE:
-               return parport_read_data(pport);
-       case LIRC_LP_STATUS:
-               return parport_read_status(pport);
-       case LIRC_LP_CONTROL:
-               return parport_read_control(pport);
-       }
-       return 0; /* make compiler happy */
-}
-
-static void out(int offset, int value)
-{
-       switch (offset) {
-       case LIRC_LP_BASE:
-               parport_write_data(pport, value);
-               break;
-       case LIRC_LP_CONTROL:
-               parport_write_control(pport, value);
-               break;
-       case LIRC_LP_STATUS:
-               pr_info("attempt to write to status register\n");
-               break;
-       }
-}
-
-static unsigned int lirc_get_timer(void)
-{
-       return in(LIRC_PORT_TIMER) & LIRC_PORT_TIMER_BIT;
-}
-
-static unsigned int lirc_get_signal(void)
-{
-       return in(LIRC_PORT_SIGNAL) & LIRC_PORT_SIGNAL_BIT;
-}
-
-static void lirc_on(void)
-{
-       out(LIRC_PORT_DATA, tx_mask);
-}
-
-static void lirc_off(void)
-{
-       out(LIRC_PORT_DATA, 0);
-}
-
-static unsigned int init_lirc_timer(void)
-{
-       ktime_t kt, now, timeout;
-       unsigned int level, newlevel, timeelapsed, newtimer;
-       int count = 0;
-
-       kt = ktime_get();
-       /* wait max. 1 sec. */
-       timeout = ktime_add_ns(kt, NSEC_PER_SEC);
-       level = lirc_get_timer();
-       do {
-               newlevel = lirc_get_timer();
-               if (level == 0 && newlevel != 0)
-                       count++;
-               level = newlevel;
-               now = ktime_get();
-       } while (count < 1000 && (ktime_before(now, timeout)));
-       timeelapsed = ktime_us_delta(now, kt);
-       if (count >= 1000 && timeelapsed > 0) {
-               if (default_timer == 0) {
-                       /* autodetect timer */
-                       newtimer = (1000000 * count) / timeelapsed;
-                       pr_info("%u Hz timer detected\n", newtimer);
-                       return newtimer;
-               }
-               newtimer = (1000000 * count) / timeelapsed;
-               if (abs(newtimer - default_timer) > default_timer / 10) {
-                       /* bad timer */
-                       pr_notice("bad timer: %u Hz\n", newtimer);
-                       pr_notice("using default timer: %u Hz\n",
-                                 default_timer);
-                       return default_timer;
-               }
-               pr_info("%u Hz timer detected\n", newtimer);
-               return newtimer; /* use detected value */
-       }
-
-       pr_notice("no timer detected\n");
-       return 0;
-}
-
-static int lirc_claim(void)
-{
-       if (parport_claim(ppdevice) != 0) {
-               pr_warn("could not claim port\n");
-               pr_warn("waiting for port becoming available\n");
-               if (parport_claim_or_block(ppdevice) < 0) {
-                       pr_notice("could not claim port, giving up\n");
-                       return 0;
-               }
-       }
-       out(LIRC_LP_CONTROL, LP_PSELECP | LP_PINITP);
-       is_claimed = 1;
-       return 1;
-}
-
-/*** interrupt handler ***/
-
-static void rbuf_write(int signal)
-{
-       unsigned int nwptr;
-
-       nwptr = (wptr + 1) & (RBUF_SIZE - 1);
-       if (nwptr == rptr) {
-               /* no new signals will be accepted */
-               lost_irqs++;
-               pr_notice("buffer overrun\n");
-               return;
-       }
-       rbuf[wptr] = signal;
-       wptr = nwptr;
-}
-
-static void lirc_lirc_irq_handler(void *blah)
-{
-       ktime_t kt, delkt;
-       static ktime_t lastkt;
-       static int init;
-       long signal;
-       int data;
-       unsigned int level, newlevel;
-       unsigned int timeout;
-
-       if (!is_open)
-               return;
-
-       if (!is_claimed)
-               return;
-
-#if 0
-       /* disable interrupt */
-         disable_irq(irq);
-         out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ) & (~LP_PINTEN));
-#endif
-       if (check_pselecd && (in(1) & LP_PSELECD))
-               return;
-
-#ifdef LIRC_TIMER
-       if (init) {
-               kt = ktime_get();
-
-               delkt = ktime_sub(kt, lastkt);
-               if (ktime_compare(delkt, ktime_set(15, 0)) > 0)
-                       /* really long time */
-                       data = PULSE_MASK;
-               else
-                       data = (int)(ktime_to_us(delkt) + LIRC_SFH506_DELAY);
-
-               rbuf_write(data); /* space */
-       } else {
-               if (timer == 0) {
-                       /*
-                        * wake up; we'll lose this signal, but it will be
-                        * garbage if the device is turned on anyway
-                        */
-                       timer = init_lirc_timer();
-                       /* enable_irq(irq); */
-                       return;
-               }
-               init = 1;
-       }
-
-       timeout = timer / 10;   /* timeout after 1/10 sec. */
-       signal = 1;
-       level = lirc_get_timer();
-       do {
-               newlevel = lirc_get_timer();
-               if (level == 0 && newlevel != 0)
-                       signal++;
-               level = newlevel;
-
-               /* giving up */
-               if (signal > timeout
-                   || (check_pselecd && (in(1) & LP_PSELECD))) {
-                       signal = 0;
-                       pr_notice("timeout\n");
-                       break;
-               }
-       } while (lirc_get_signal());
-
-       if (signal != 0) {
-               /* adjust value to usecs */
-               __u64 helper;
-
-               helper = ((__u64)signal) * 1000000;
-               do_div(helper, timer);
-               signal = (long)helper;
-
-               if (signal > LIRC_SFH506_DELAY)
-                       data = signal - LIRC_SFH506_DELAY;
-               else
-                       data = 1;
-               rbuf_write(PULSE_BIT | data); /* pulse */
-       }
-       lastkt = ktime_get();
-#else
-       /* add your code here */
-#endif
-
-       wake_up_interruptible(&lirc_wait);
-
-       /* enable interrupt */
-       /*
-        * enable_irq(irq);
-        * out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ)|LP_PINTEN);
-        */
-}
-
-/*** file operations ***/
-
-static loff_t lirc_lseek(struct file *filep, loff_t offset, int orig)
-{
-       return -ESPIPE;
-}
-
-static ssize_t lirc_read(struct file *filep, char __user *buf, size_t n,
-                        loff_t *ppos)
-{
-       int result = 0;
-       int count = 0;
-       DECLARE_WAITQUEUE(wait, current);
-
-       if (n % sizeof(int))
-               return -EINVAL;
-
-       add_wait_queue(&lirc_wait, &wait);
-       set_current_state(TASK_INTERRUPTIBLE);
-       while (count < n) {
-               if (rptr != wptr) {
-                       if (copy_to_user(buf + count, &rbuf[rptr],
-                                        sizeof(int))) {
-                               result = -EFAULT;
-                               break;
-                       }
-                       rptr = (rptr + 1) & (RBUF_SIZE - 1);
-                       count += sizeof(int);
-               } else {
-                       if (filep->f_flags & O_NONBLOCK) {
-                               result = -EAGAIN;
-                               break;
-                       }
-                       if (signal_pending(current)) {
-                               result = -ERESTARTSYS;
-                               break;
-                       }
-                       schedule();
-                       set_current_state(TASK_INTERRUPTIBLE);
-               }
-       }
-       remove_wait_queue(&lirc_wait, &wait);
-       set_current_state(TASK_RUNNING);
-       return count ? count : result;
-}
-
-static ssize_t lirc_write(struct file *filep, const char __user *buf, size_t n,
-                         loff_t *ppos)
-{
-       int count;
-       unsigned int i;
-       unsigned int level, newlevel;
-       unsigned long flags;
-       int counttimer;
-       int *wbuf;
-       ssize_t ret;
-
-       if (!is_claimed)
-               return -EBUSY;
-
-       count = n / sizeof(int);
-
-       if (n % sizeof(int) || count % 2 == 0)
-               return -EINVAL;
-
-       wbuf = memdup_user(buf, n);
-       if (IS_ERR(wbuf))
-               return PTR_ERR(wbuf);
-
-#ifdef LIRC_TIMER
-       if (timer == 0) {
-               /* try again if device is ready */
-               timer = init_lirc_timer();
-               if (timer == 0) {
-                       ret = -EIO;
-                       goto out;
-               }
-       }
-
-       /* adjust values from usecs */
-       for (i = 0; i < count; i++) {
-               __u64 helper;
-
-               helper = ((__u64)wbuf[i]) * timer;
-               do_div(helper, 1000000);
-               wbuf[i] = (int)helper;
-       }
-
-       local_irq_save(flags);
-       i = 0;
-       while (i < count) {
-               level = lirc_get_timer();
-               counttimer = 0;
-               lirc_on();
-               do {
-                       newlevel = lirc_get_timer();
-                       if (level == 0 && newlevel != 0)
-                               counttimer++;
-                       level = newlevel;
-                       if (check_pselecd && (in(1) & LP_PSELECD)) {
-                               lirc_off();
-                               local_irq_restore(flags);
-                               ret = -EIO;
-                               goto out;
-                       }
-               } while (counttimer < wbuf[i]);
-               i++;
-
-               lirc_off();
-               if (i == count)
-                       break;
-               counttimer = 0;
-               do {
-                       newlevel = lirc_get_timer();
-                       if (level == 0 && newlevel != 0)
-                               counttimer++;
-                       level = newlevel;
-                       if (check_pselecd && (in(1) & LP_PSELECD)) {
-                               local_irq_restore(flags);
-                               ret = -EIO;
-                               goto out;
-                       }
-               } while (counttimer < wbuf[i]);
-               i++;
-       }
-       local_irq_restore(flags);
-#else
-       /* place code that handles write without external timer here */
-#endif
-       ret = n;
-out:
-       kfree(wbuf);
-
-       return ret;
-}
-
-static unsigned int lirc_poll(struct file *file, poll_table *wait)
-{
-       poll_wait(file, &lirc_wait, wait);
-       if (rptr != wptr)
-               return POLLIN | POLLRDNORM;
-       return 0;
-}
-
-static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
-{
-       int result;
-       u32 __user *uptr = (u32 __user *)arg;
-       u32 features = LIRC_CAN_SET_TRANSMITTER_MASK |
-                      LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2;
-       u32 mode;
-       u32 value;
-
-       switch (cmd) {
-       case LIRC_GET_FEATURES:
-               result = put_user(features, uptr);
-               if (result)
-                       return result;
-               break;
-       case LIRC_GET_SEND_MODE:
-               result = put_user(LIRC_MODE_PULSE, uptr);
-               if (result)
-                       return result;
-               break;
-       case LIRC_GET_REC_MODE:
-               result = put_user(LIRC_MODE_MODE2, uptr);
-               if (result)
-                       return result;
-               break;
-       case LIRC_SET_SEND_MODE:
-               result = get_user(mode, uptr);
-               if (result)
-                       return result;
-               if (mode != LIRC_MODE_PULSE)
-                       return -EINVAL;
-               break;
-       case LIRC_SET_REC_MODE:
-               result = get_user(mode, uptr);
-               if (result)
-                       return result;
-               if (mode != LIRC_MODE_MODE2)
-                       return -ENOSYS;
-               break;
-       case LIRC_SET_TRANSMITTER_MASK:
-               result = get_user(value, uptr);
-               if (result)
-                       return result;
-               if ((value & LIRC_PARALLEL_TRANSMITTER_MASK) != value)
-                       return LIRC_PARALLEL_MAX_TRANSMITTERS;
-               tx_mask = value;
-               break;
-       default:
-               return -ENOIOCTLCMD;
-       }
-       return 0;
-}
-
-static int lirc_open(struct inode *node, struct file *filep)
-{
-       if (is_open || !lirc_claim())
-               return -EBUSY;
-
-       parport_enable_irq(pport);
-
-       /* init read ptr */
-       rptr = 0;
-       wptr = 0;
-       lost_irqs = 0;
-
-       is_open = 1;
-       return 0;
-}
-
-static int lirc_close(struct inode *node, struct file *filep)
-{
-       if (is_claimed) {
-               is_claimed = 0;
-               parport_release(ppdevice);
-       }
-       is_open = 0;
-       return 0;
-}
-
-static const struct file_operations lirc_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = lirc_lseek,
-       .read           = lirc_read,
-       .write          = lirc_write,
-       .poll           = lirc_poll,
-       .unlocked_ioctl = lirc_ioctl,
-#ifdef CONFIG_COMPAT
-       .compat_ioctl   = lirc_ioctl,
-#endif
-       .open           = lirc_open,
-       .release        = lirc_close
-};
-
-static int set_use_inc(void *data)
-{
-       return 0;
-}
-
-static void set_use_dec(void *data)
-{
-}
-
-static struct lirc_driver driver = {
-       .name           = LIRC_DRIVER_NAME,
-       .minor          = -1,
-       .code_length    = 1,
-       .sample_rate    = 0,
-       .data           = NULL,
-       .add_to_buf     = NULL,
-       .set_use_inc    = set_use_inc,
-       .set_use_dec    = set_use_dec,
-       .fops           = &lirc_fops,
-       .dev            = NULL,
-       .owner          = THIS_MODULE,
-};
-
-static struct platform_device *lirc_parallel_dev;
-
-static int lirc_parallel_probe(struct platform_device *dev)
-{
-       return 0;
-}
-
-static int lirc_parallel_remove(struct platform_device *dev)
-{
-       return 0;
-}
-
-static int lirc_parallel_suspend(struct platform_device *dev,
-                                       pm_message_t state)
-{
-       return 0;
-}
-
-static int lirc_parallel_resume(struct platform_device *dev)
-{
-       return 0;
-}
-
-static struct platform_driver lirc_parallel_driver = {
-       .probe  = lirc_parallel_probe,
-       .remove = lirc_parallel_remove,
-       .suspend        = lirc_parallel_suspend,
-       .resume = lirc_parallel_resume,
-       .driver = {
-               .name   = LIRC_DRIVER_NAME,
-       },
-};
-
-static int pf(void *handle)
-{
-       parport_disable_irq(pport);
-       is_claimed = 0;
-       return 0;
-}
-
-static void kf(void *handle)
-{
-       if (!is_open)
-               return;
-       if (!lirc_claim())
-               return;
-       parport_enable_irq(pport);
-       lirc_off();
-       /* this is a bit annoying when you actually print...*/
-       /*
-        * printk(KERN_INFO "%s: reclaimed port\n", LIRC_DRIVER_NAME);
-       */
-}
-
-/*** module initialization and cleanup ***/
-
-static int __init lirc_parallel_init(void)
-{
-       int result;
-
-       result = platform_driver_register(&lirc_parallel_driver);
-       if (result) {
-               pr_notice("platform_driver_register returned %d\n", result);
-               return result;
-       }
-
-       lirc_parallel_dev = platform_device_alloc(LIRC_DRIVER_NAME, 0);
-       if (!lirc_parallel_dev) {
-               result = -ENOMEM;
-               goto exit_driver_unregister;
-       }
-
-       result = platform_device_add(lirc_parallel_dev);
-       if (result)
-               goto exit_device_put;
-
-       pport = parport_find_base(io);
-       if (!pport) {
-               pr_notice("no port at %x found\n", io);
-               result = -ENXIO;
-               goto exit_device_del;
-       }
-       ppdevice = parport_register_device(pport, LIRC_DRIVER_NAME,
-                                          pf, kf, lirc_lirc_irq_handler, 0,
-                                          NULL);
-       parport_put_port(pport);
-       if (!ppdevice) {
-               pr_notice("parport_register_device() failed\n");
-               result = -ENXIO;
-               goto exit_device_del;
-       }
-       if (parport_claim(ppdevice) != 0)
-               goto skip_init;
-       is_claimed = 1;
-       out(LIRC_LP_CONTROL, LP_PSELECP | LP_PINITP);
-
-#ifdef LIRC_TIMER
-       if (debug)
-               out(LIRC_PORT_DATA, tx_mask);
-
-       timer = init_lirc_timer();
-
-#if 0  /* continue even if device is offline */
-       if (timer == 0) {
-               is_claimed = 0;
-               parport_release(pport);
-               parport_unregister_device(ppdevice);
-               result = -EIO;
-               goto exit_device_del;
-       }
-
-#endif
-       if (debug)
-               out(LIRC_PORT_DATA, 0);
-#endif
-
-       is_claimed = 0;
-       parport_release(ppdevice);
- skip_init:
-       driver.dev = &lirc_parallel_dev->dev;
-       driver.minor = lirc_register_driver(&driver);
-       if (driver.minor < 0) {
-               pr_notice("register_chrdev() failed\n");
-               parport_unregister_device(ppdevice);
-               result = -EIO;
-               goto exit_device_del;
-       }
-       pr_info("installed using port 0x%04x irq %d\n", io, irq);
-       return 0;
-
-exit_device_del:
-       platform_device_del(lirc_parallel_dev);
-exit_device_put:
-       platform_device_put(lirc_parallel_dev);
-exit_driver_unregister:
-       platform_driver_unregister(&lirc_parallel_driver);
-       return result;
-}
-
-static void __exit lirc_parallel_exit(void)
-{
-       parport_unregister_device(ppdevice);
-       lirc_unregister_driver(driver.minor);
-
-       platform_device_unregister(lirc_parallel_dev);
-       platform_driver_unregister(&lirc_parallel_driver);
-}
-
-module_init(lirc_parallel_init);
-module_exit(lirc_parallel_exit);
-
-MODULE_DESCRIPTION("Infrared receiver driver for parallel ports.");
-MODULE_AUTHOR("Christoph Bartelmus");
-MODULE_LICENSE("GPL");
-
-module_param(io, int, S_IRUGO);
-MODULE_PARM_DESC(io, "I/O address base (0x3bc, 0x378 or 0x278)");
-
-module_param(irq, int, S_IRUGO);
-MODULE_PARM_DESC(irq, "Interrupt (7 or 5)");
-
-module_param(tx_mask, int, S_IRUGO);
-MODULE_PARM_DESC(tx_mask, "Transmitter mask (default: 0x01)");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Enable debugging messages");
-
-module_param(check_pselecd, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(check_pselecd, "Check for printer (default: 0)");
diff --git a/drivers/staging/media/lirc/lirc_parallel.h b/drivers/staging/media/lirc/lirc_parallel.h
deleted file mode 100644 (file)
index 4bed6af..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/* lirc_parallel.h */
-
-#ifndef _LIRC_PARALLEL_H
-#define _LIRC_PARALLEL_H
-
-#include <linux/lp.h>
-
-#define LIRC_PORT_LEN 3
-
-#define LIRC_LP_BASE    0
-#define LIRC_LP_STATUS  1
-#define LIRC_LP_CONTROL 2
-
-#define LIRC_PORT_DATA           LIRC_LP_BASE    /* base */
-#define LIRC_PORT_TIMER        LIRC_LP_STATUS    /* status port */
-#define LIRC_PORT_TIMER_BIT          LP_PBUSY    /* busy signal */
-#define LIRC_PORT_SIGNAL       LIRC_LP_STATUS    /* status port */
-#define LIRC_PORT_SIGNAL_BIT          LP_PACK    /* ack signal */
-#define LIRC_PORT_IRQ         LIRC_LP_CONTROL    /* control port */
-
-#define LIRC_SFH506_DELAY 0             /* delay t_phl in usecs */
-
-#define LIRC_PARALLEL_MAX_TRANSMITTERS 8
-#define LIRC_PARALLEL_TRANSMITTER_MASK ((1<<LIRC_PARALLEL_MAX_TRANSMITTERS) - 1)
-
-#endif
index 4f326e97ad75e9180b9013c0916fe2a2ad1747ab..c75ae43095ba55a7250fe504e579b3dde8016bf2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * LIRC SIR driver, (C) 2000 Milan Pikula <www@fornax.sk>
  *
- * lirc_sir - Device driver for use with SIR (serial infra red)
+ * sir_ir - Device driver for use with SIR (serial infra red)
  * mode of IrDA on many notebooks.
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -58,8 +58,7 @@
 
 #include <linux/timer.h>
 
-#include <media/lirc.h>
-#include <media/lirc_dev.h>
+#include <media/rc-core.h>
 
 /* SECTION: Definitions */
 
@@ -87,11 +86,6 @@ static void init_act200(void);
 static void init_act220(void);
 #endif
 
-#define RBUF_LEN 1024
-#define WBUF_LEN 1024
-
-#define LIRC_DRIVER_NAME "lirc_sir"
-
 #define PULSE '['
 
 #ifndef LIRC_SIR_TEKRAM
@@ -131,28 +125,19 @@ static ktime_t last;
 /* time of last UART data ready interrupt */
 static ktime_t last_intr_time;
 static int last_value;
+static struct rc_dev *rcdev;
 
-static DECLARE_WAIT_QUEUE_HEAD(lirc_read_queue);
+static struct platform_device *sir_ir_dev;
 
 static DEFINE_SPINLOCK(hardware_lock);
 
-static int rx_buf[RBUF_LEN];
-static unsigned int rx_tail, rx_head;
-
 static bool debug;
 
 /* SECTION: Prototypes */
 
 /* Communication with user-space */
-static unsigned int lirc_poll(struct file *file, poll_table *wait);
-static ssize_t lirc_read(struct file *file, char __user *buf, size_t count,
-                        loff_t *ppos);
-static ssize_t lirc_write(struct file *file, const char __user *buf, size_t n,
-                         loff_t *pos);
-static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
 static void add_read_queue(int flag, unsigned long val);
 static int init_chrdev(void);
-static void drop_chrdev(void);
 /* Hardware */
 static irqreturn_t sir_interrupt(int irq, void *dev_id);
 static void send_space(unsigned long len);
@@ -189,72 +174,14 @@ static void safe_udelay(unsigned long usecs)
 }
 
 /* SECTION: Communication with user-space */
-
-static unsigned int lirc_poll(struct file *file, poll_table *wait)
-{
-       poll_wait(file, &lirc_read_queue, wait);
-       if (rx_head != rx_tail)
-               return POLLIN | POLLRDNORM;
-       return 0;
-}
-
-static ssize_t lirc_read(struct file *file, char __user *buf, size_t count,
-                        loff_t *ppos)
-{
-       int n = 0;
-       int retval = 0;
-       DECLARE_WAITQUEUE(wait, current);
-
-       if (count % sizeof(int))
-               return -EINVAL;
-
-       add_wait_queue(&lirc_read_queue, &wait);
-       set_current_state(TASK_INTERRUPTIBLE);
-       while (n < count) {
-               if (rx_head != rx_tail) {
-                       if (copy_to_user(buf + n,
-                                        rx_buf + rx_head,
-                                        sizeof(int))) {
-                               retval = -EFAULT;
-                               break;
-                       }
-                       rx_head = (rx_head + 1) & (RBUF_LEN - 1);
-                       n += sizeof(int);
-               } else {
-                       if (file->f_flags & O_NONBLOCK) {
-                               retval = -EAGAIN;
-                               break;
-                       }
-                       if (signal_pending(current)) {
-                               retval = -ERESTARTSYS;
-                               break;
-                       }
-                       schedule();
-                       set_current_state(TASK_INTERRUPTIBLE);
-               }
-       }
-       remove_wait_queue(&lirc_read_queue, &wait);
-       set_current_state(TASK_RUNNING);
-       return n ? n : retval;
-}
-static ssize_t lirc_write(struct file *file, const char __user *buf, size_t n,
-                         loff_t *pos)
+static int sir_tx_ir(struct rc_dev *dev, unsigned int *tx_buf,
+                    unsigned int count)
 {
        unsigned long flags;
-       int i, count;
-       int *tx_buf;
-
-       count = n / sizeof(int);
-       if (n % sizeof(int) || count % 2 == 0)
-               return -EINVAL;
-       tx_buf = memdup_user(buf, n);
-       if (IS_ERR(tx_buf))
-               return PTR_ERR(tx_buf);
-       i = 0;
+       int i;
+
        local_irq_save(flags);
-       while (1) {
-               if (i >= count)
-                       break;
+       for (i = 0; i < count;) {
                if (tx_buf[i])
                        send_pulse(tx_buf[i]);
                i++;
@@ -265,138 +192,53 @@ static ssize_t lirc_write(struct file *file, const char __user *buf, size_t n,
                i++;
        }
        local_irq_restore(flags);
-       kfree(tx_buf);
-       return count;
-}
-
-static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
-{
-       u32 __user *uptr = (u32 __user *)arg;
-       int retval = 0;
-       u32 value = 0;
-
-       if (cmd == LIRC_GET_FEATURES)
-               value = LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2;
-       else if (cmd == LIRC_GET_SEND_MODE)
-               value = LIRC_MODE_PULSE;
-       else if (cmd == LIRC_GET_REC_MODE)
-               value = LIRC_MODE_MODE2;
-
-       switch (cmd) {
-       case LIRC_GET_FEATURES:
-       case LIRC_GET_SEND_MODE:
-       case LIRC_GET_REC_MODE:
-               retval = put_user(value, uptr);
-               break;
-
-       case LIRC_SET_SEND_MODE:
-       case LIRC_SET_REC_MODE:
-               retval = get_user(value, uptr);
-               break;
-       default:
-               retval = -ENOIOCTLCMD;
-
-       }
-
-       if (retval)
-               return retval;
-       if (cmd == LIRC_SET_REC_MODE) {
-               if (value != LIRC_MODE_MODE2)
-                       retval = -ENOSYS;
-       } else if (cmd == LIRC_SET_SEND_MODE) {
-               if (value != LIRC_MODE_PULSE)
-                       retval = -ENOSYS;
-       }
 
-       return retval;
+       return count;
 }
 
 static void add_read_queue(int flag, unsigned long val)
 {
-       unsigned int new_rx_tail;
-       int newval;
+       DEFINE_IR_RAW_EVENT(ev);
 
        pr_debug("add flag %d with val %lu\n", flag, val);
 
-       newval = val & PULSE_MASK;
-
        /*
         * statistically, pulses are ~TIME_CONST/2 too long. we could
         * maybe make this more exact, but this is good enough
         */
        if (flag) {
                /* pulse */
-               if (newval > TIME_CONST/2)
-                       newval -= TIME_CONST/2;
+               if (val > TIME_CONST / 2)
+                       val -= TIME_CONST / 2;
                else /* should not ever happen */
-                       newval = 1;
-               newval |= PULSE_BIT;
+                       val = 1;
+               ev.pulse = true;
        } else {
-               newval += TIME_CONST/2;
+               val += TIME_CONST / 2;
        }
-       new_rx_tail = (rx_tail + 1) & (RBUF_LEN - 1);
-       if (new_rx_tail == rx_head) {
-               pr_debug("Buffer overrun.\n");
-               return;
-       }
-       rx_buf[rx_tail] = newval;
-       rx_tail = new_rx_tail;
-       wake_up_interruptible(&lirc_read_queue);
-}
+       ev.duration = US_TO_NS(val);
 
-static const struct file_operations lirc_fops = {
-       .owner          = THIS_MODULE,
-       .read           = lirc_read,
-       .write          = lirc_write,
-       .poll           = lirc_poll,
-       .unlocked_ioctl = lirc_ioctl,
-#ifdef CONFIG_COMPAT
-       .compat_ioctl   = lirc_ioctl,
-#endif
-       .open           = lirc_dev_fop_open,
-       .release        = lirc_dev_fop_close,
-       .llseek         = no_llseek,
-};
-
-static int set_use_inc(void *data)
-{
-       return 0;
+       ir_raw_event_store_with_filter(rcdev, &ev);
 }
 
-static void set_use_dec(void *data)
-{
-}
-
-static struct lirc_driver driver = {
-       .name           = LIRC_DRIVER_NAME,
-       .minor          = -1,
-       .code_length    = 1,
-       .sample_rate    = 0,
-       .data           = NULL,
-       .add_to_buf     = NULL,
-       .set_use_inc    = set_use_inc,
-       .set_use_dec    = set_use_dec,
-       .fops           = &lirc_fops,
-       .dev            = NULL,
-       .owner          = THIS_MODULE,
-};
-
-static struct platform_device *lirc_sir_dev;
-
 static int init_chrdev(void)
 {
-       driver.dev = &lirc_sir_dev->dev;
-       driver.minor = lirc_register_driver(&driver);
-       if (driver.minor < 0) {
-               pr_err("init_chrdev() failed.\n");
-               return -EIO;
-       }
-       return 0;
-}
-
-static void drop_chrdev(void)
-{
-       lirc_unregister_driver(driver.minor);
+       rcdev = devm_rc_allocate_device(&sir_ir_dev->dev, RC_DRIVER_IR_RAW);
+       if (!rcdev)
+               return -ENOMEM;
+
+       rcdev->input_phys = KBUILD_MODNAME "/input0";
+       rcdev->input_id.bustype = BUS_HOST;
+       rcdev->input_id.vendor = 0x0001;
+       rcdev->input_id.product = 0x0001;
+       rcdev->input_id.version = 0x0100;
+       rcdev->tx_ir = sir_tx_ir;
+       rcdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
+       rcdev->map_name = RC_MAP_RC6_MCE;
+       rcdev->timeout = IR_DEFAULT_TIMEOUT;
+       rcdev->dev.parent = &sir_ir_dev->dev;
+
+       return devm_rc_register_device(&sir_ir_dev->dev, rcdev);
 }
 
 /* SECTION: Hardware */
@@ -420,14 +262,15 @@ static void sir_timeout(unsigned long data)
                /* determine 'virtual' pulse end: */
                pulse_end = min_t(unsigned long,
                                  ktime_us_delta(last, last_intr_time),
-                                 PULSE_MASK);
-               dev_dbg(driver.dev, "timeout add %d for %lu usec\n",
-                                   last_value, pulse_end);
+                                 IR_MAX_DURATION);
+               dev_dbg(&sir_ir_dev->dev, "timeout add %d for %lu usec\n",
+                       last_value, pulse_end);
                add_read_queue(last_value, pulse_end);
                last_value = 0;
                last = last_intr_time;
        }
        spin_unlock_irqrestore(&timer_lock, flags);
+       ir_raw_event_handle(rcdev);
 }
 
 static irqreturn_t sir_interrupt(int irq, void *dev_id)
@@ -462,20 +305,20 @@ static irqreturn_t sir_interrupt(int irq, void *dev_id)
                                curr_time = ktime_get();
                                delt = min_t(unsigned long,
                                             ktime_us_delta(last, curr_time),
-                                            PULSE_MASK);
+                                            IR_MAX_DURATION);
                                deltintr = min_t(unsigned long,
                                                 ktime_us_delta(last_intr_time,
                                                                curr_time),
-                                                PULSE_MASK);
-                               dev_dbg(driver.dev, "t %lu, d %d\n",
-                                                   deltintr, (int)data);
+                                                IR_MAX_DURATION);
+                               dev_dbg(&sir_ir_dev->dev, "t %lu, d %d\n",
+                                       deltintr, (int)data);
                                /*
                                 * if nothing came in last X cycles,
                                 * it was gap
                                 */
                                if (deltintr > TIME_CONST * threshold) {
                                        if (last_value) {
-                                               dev_dbg(driver.dev, "GAP\n");
+                                               dev_dbg(&sir_ir_dev->dev, "GAP\n");
                                                /* simulate signal change */
                                                add_read_queue(last_value,
                                                               delt -
@@ -517,6 +360,7 @@ static irqreturn_t sir_interrupt(int irq, void *dev_id)
                        break;
                }
        }
+       ir_raw_event_handle(rcdev);
        return IRQ_RETVAL(IRQ_HANDLED);
 }
 
@@ -655,12 +499,12 @@ static int init_port(void)
        int retval;
 
        /* get I/O port access and IRQ line */
-       if (request_region(io, 8, LIRC_DRIVER_NAME) == NULL) {
+       if (!request_region(io, 8, KBUILD_MODNAME)) {
                pr_err("i/o port 0x%.4x already in use.\n", io);
                return -EBUSY;
        }
        retval = request_irq(irq, sir_interrupt, 0,
-                            LIRC_DRIVER_NAME, NULL);
+                            KBUILD_MODNAME, NULL);
        if (retval < 0) {
                release_region(io, 8);
                pr_err("IRQ %d already in use.\n", irq);
@@ -882,11 +726,10 @@ void init_act220(void)
 }
 #endif
 
-static int init_lirc_sir(void)
+static int init_sir_ir(void)
 {
        int retval;
 
-       init_waitqueue_head(&lirc_read_queue);
        retval = init_port();
        if (retval < 0)
                return retval;
@@ -895,42 +738,42 @@ static int init_lirc_sir(void)
        return 0;
 }
 
-static int lirc_sir_probe(struct platform_device *dev)
+static int sir_ir_probe(struct platform_device *dev)
 {
        return 0;
 }
 
-static int lirc_sir_remove(struct platform_device *dev)
+static int sir_ir_remove(struct platform_device *dev)
 {
        return 0;
 }
 
-static struct platform_driver lirc_sir_driver = {
-       .probe          = lirc_sir_probe,
-       .remove         = lirc_sir_remove,
+static struct platform_driver sir_ir_driver = {
+       .probe          = sir_ir_probe,
+       .remove         = sir_ir_remove,
        .driver         = {
-               .name   = "lirc_sir",
+               .name   = "sir_ir",
        },
 };
 
-static int __init lirc_sir_init(void)
+static int __init sir_ir_init(void)
 {
        int retval;
 
-       retval = platform_driver_register(&lirc_sir_driver);
+       retval = platform_driver_register(&sir_ir_driver);
        if (retval) {
                pr_err("Platform driver register failed!\n");
                return -ENODEV;
        }
 
-       lirc_sir_dev = platform_device_alloc("lirc_dev", 0);
-       if (!lirc_sir_dev) {
+       sir_ir_dev = platform_device_alloc("sir_ir", 0);
+       if (!sir_ir_dev) {
                pr_err("Platform device alloc failed!\n");
                retval = -ENOMEM;
                goto pdev_alloc_fail;
        }
 
-       retval = platform_device_add(lirc_sir_dev);
+       retval = platform_device_add(sir_ir_dev);
        if (retval) {
                pr_err("Platform device add failed!\n");
                retval = -ENODEV;
@@ -941,35 +784,32 @@ static int __init lirc_sir_init(void)
        if (retval < 0)
                goto fail;
 
-       retval = init_lirc_sir();
-       if (retval) {
-               drop_chrdev();
+       retval = init_sir_ir();
+       if (retval)
                goto fail;
-       }
 
        return 0;
 
 fail:
-       platform_device_del(lirc_sir_dev);
+       platform_device_del(sir_ir_dev);
 pdev_add_fail:
-       platform_device_put(lirc_sir_dev);
+       platform_device_put(sir_ir_dev);
 pdev_alloc_fail:
-       platform_driver_unregister(&lirc_sir_driver);
+       platform_driver_unregister(&sir_ir_driver);
        return retval;
 }
 
-static void __exit lirc_sir_exit(void)
+static void __exit sir_ir_exit(void)
 {
        drop_hardware();
-       drop_chrdev();
        drop_port();
-       platform_device_unregister(lirc_sir_dev);
-       platform_driver_unregister(&lirc_sir_driver);
+       platform_device_unregister(sir_ir_dev);
+       platform_driver_unregister(&sir_ir_driver);
        pr_info("Uninstalled.\n");
 }
 
-module_init(lirc_sir_init);
-module_exit(lirc_sir_exit);
+module_init(sir_ir_init);
+module_exit(sir_ir_exit);
 
 #ifdef LIRC_SIR_TEKRAM
 MODULE_DESCRIPTION("Infrared receiver driver for Tekram Irmate 210");
index c16927ac8eb0b259ca1ece37da1043c53ecf279b..bb0e3b4a4558ab6f69da99891c77cadc634681a0 100644 (file)
@@ -205,21 +205,21 @@ iss_video_remote_subdev(struct iss_video *video, u32 *pad)
 static struct iss_video *
 iss_video_far_end(struct iss_video *video)
 {
-       struct media_entity_graph graph;
+       struct media_graph graph;
        struct media_entity *entity = &video->video.entity;
        struct media_device *mdev = entity->graph_obj.mdev;
        struct iss_video *far_end = NULL;
 
        mutex_lock(&mdev->graph_mutex);
 
-       if (media_entity_graph_walk_init(&graph, mdev)) {
+       if (media_graph_walk_init(&graph, mdev)) {
                mutex_unlock(&mdev->graph_mutex);
                return NULL;
        }
 
-       media_entity_graph_walk_start(&graph, entity);
+       media_graph_walk_start(&graph, entity);
 
-       while ((entity = media_entity_graph_walk_next(&graph))) {
+       while ((entity = media_graph_walk_next(&graph))) {
                if (entity == &video->video.entity)
                        continue;
 
@@ -235,7 +235,7 @@ iss_video_far_end(struct iss_video *video)
 
        mutex_unlock(&mdev->graph_mutex);
 
-       media_entity_graph_walk_cleanup(&graph);
+       media_graph_walk_cleanup(&graph);
 
        return far_end;
 }
@@ -854,7 +854,7 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
 {
        struct iss_video_fh *vfh = to_iss_video_fh(fh);
        struct iss_video *video = video_drvdata(file);
-       struct media_entity_graph graph;
+       struct media_graph graph;
        struct media_entity *entity = &video->video.entity;
        enum iss_pipeline_state state;
        struct iss_pipeline *pipe;
@@ -880,19 +880,19 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
        if (ret)
                goto err_graph_walk_init;
 
-       ret = media_entity_graph_walk_init(&graph, entity->graph_obj.mdev);
+       ret = media_graph_walk_init(&graph, entity->graph_obj.mdev);
        if (ret)
                goto err_graph_walk_init;
 
        if (video->iss->pdata->set_constraints)
                video->iss->pdata->set_constraints(video->iss, true);
 
-       ret = media_entity_pipeline_start(entity, &pipe->pipe);
+       ret = media_pipeline_start(entity, &pipe->pipe);
        if (ret < 0)
-               goto err_media_entity_pipeline_start;
+               goto err_media_pipeline_start;
 
-       media_entity_graph_walk_start(&graph, entity);
-       while ((entity = media_entity_graph_walk_next(&graph)))
+       media_graph_walk_start(&graph, entity);
+       while ((entity = media_graph_walk_next(&graph)))
                media_entity_enum_set(&pipe->ent_enum, entity);
 
        /* Verify that the currently configured format matches the output of
@@ -963,7 +963,7 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
                spin_unlock_irqrestore(&video->qlock, flags);
        }
 
-       media_entity_graph_walk_cleanup(&graph);
+       media_graph_walk_cleanup(&graph);
 
        mutex_unlock(&video->stream_lock);
 
@@ -972,13 +972,13 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
 err_omap4iss_set_stream:
        vb2_streamoff(&vfh->queue, type);
 err_iss_video_check_format:
-       media_entity_pipeline_stop(&video->video.entity);
-err_media_entity_pipeline_start:
+       media_pipeline_stop(&video->video.entity);
+err_media_pipeline_start:
        if (video->iss->pdata->set_constraints)
                video->iss->pdata->set_constraints(video->iss, false);
        video->queue = NULL;
 
-       media_entity_graph_walk_cleanup(&graph);
+       media_graph_walk_cleanup(&graph);
 
 err_graph_walk_init:
        media_entity_enum_cleanup(&pipe->ent_enum);
@@ -1026,7 +1026,7 @@ iss_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
 
        if (video->iss->pdata->set_constraints)
                video->iss->pdata->set_constraints(video->iss, false);
-       media_entity_pipeline_stop(&video->video.entity);
+       media_pipeline_stop(&video->video.entity);
 
 done:
        mutex_unlock(&video->stream_lock);
@@ -1141,6 +1141,7 @@ static int iss_video_open(struct file *file)
 done:
        if (ret < 0) {
                v4l2_fh_del(&handle->vfh);
+               v4l2_fh_exit(&handle->vfh);
                kfree(handle);
        }
 
@@ -1162,6 +1163,7 @@ static int iss_video_release(struct file *file)
        vb2_queue_release(&handle->queue);
 
        v4l2_fh_del(vfh);
+       v4l2_fh_exit(vfh);
        kfree(handle);
        file->private_data = NULL;
 
index ddfd955da0d40d48e830fe41395f1a2f37dae2e8..7a3489df3e70c1e3fe1ef9145f2c2f48d9ea4d1b 100644 (file)
@@ -1,6 +1,6 @@
 config VIDEO_SAMSUNG_S5P_CEC
        tristate "Samsung S5P CEC driver"
-       depends on VIDEO_DEV && MEDIA_CEC_SUPPORT && (PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST)
+       depends on VIDEO_DEV && MEDIA_CEC_SUPPORT && (ARCH_EXYNOS || COMPILE_TEST)
        ---help---
          This is a driver for Samsung S5P HDMI CEC interface. It uses the
          generic CEC framework interface.
index 3e4fc7b05e83155c4c7adf0dee2baad0f34259ef..7d9453505dcee32e61359d188b80d77043e73a74 100644 (file)
@@ -14,7 +14,6 @@
 #define _EXYNOS_HDMI_CEC_H_ __FILE__
 
 #include <linux/regmap.h>
-#include <linux/miscdevice.h>
 #include "s5p_cec.h"
 
 void s5p_cec_set_divider(struct s5p_cec_dev *cec);
index ce95e0fcd882f20b1009c996269b0cb4eb1d5e62..1edf667d562a4df64a4806e947f192aa2a24357f 100644 (file)
@@ -87,7 +87,6 @@ void s5p_cec_mask_tx_interrupts(struct s5p_cec_dev *cec)
        reg |= S5P_CEC_IRQ_TX_DONE;
        reg |= S5P_CEC_IRQ_TX_ERROR;
        writeb(reg, cec->reg + S5P_CEC_IRQ_MASK);
-
 }
 
 void s5p_cec_unmask_tx_interrupts(struct s5p_cec_dev *cec)
@@ -186,13 +185,13 @@ u32 s5p_cec_get_status(struct s5p_cec_dev *cec)
 void s5p_clr_pending_tx(struct s5p_cec_dev *cec)
 {
        writeb(S5P_CEC_IRQ_TX_DONE | S5P_CEC_IRQ_TX_ERROR,
-                                       cec->reg + S5P_CEC_IRQ_CLEAR);
+              cec->reg + S5P_CEC_IRQ_CLEAR);
 }
 
 void s5p_clr_pending_rx(struct s5p_cec_dev *cec)
 {
        writeb(S5P_CEC_IRQ_RX_DONE | S5P_CEC_IRQ_RX_ERROR,
-                                       cec->reg + S5P_CEC_IRQ_CLEAR);
+              cec->reg + S5P_CEC_IRQ_CLEAR);
 }
 
 void s5p_cec_get_rx_buf(struct s5p_cec_dev *cec, u32 size, u8 *buffer)
index 257361280510b5b69532ec890941a9fde79e45d6..e2bc99980f7553e75cd043f8315551520714f80e 100644 (file)
@@ -4,6 +4,7 @@ menuconfig TARGET_CORE
        depends on SCSI && BLOCK
        select CONFIGFS_FS
        select CRC_T10DIF
+       select BLK_SCSI_REQUEST # only for scsi_command_size_tbl..
        default n
        help
        Say Y or M here to enable the TCM Storage Engine and ConfigFS enabled
index 04d7aa7390d0fcea217daabb05a0db725eac227d..a8f8e53f2f574852de573a08a86ad1c25b4cf332 100644 (file)
@@ -1005,7 +1005,8 @@ pscsi_execute_cmd(struct se_cmd *cmd)
                scsi_command_size(cmd->t_task_cdb));
 
        req = blk_get_request(pdv->pdv_sd->request_queue,
-                       (cmd->data_direction == DMA_TO_DEVICE),
+                       cmd->data_direction == DMA_TO_DEVICE ?
+                       REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN,
                        GFP_KERNEL);
        if (IS_ERR(req)) {
                pr_err("PSCSI: blk_get_request() failed\n");
@@ -1013,7 +1014,7 @@ pscsi_execute_cmd(struct se_cmd *cmd)
                goto fail;
        }
 
-       blk_rq_set_block_pc(req);
+       scsi_req_init(req);
 
        if (sgl) {
                ret = pscsi_map_sg(cmd, sgl, sgl_nents, req);
@@ -1023,10 +1024,8 @@ pscsi_execute_cmd(struct se_cmd *cmd)
 
        req->end_io = pscsi_req_done;
        req->end_io_data = cmd;
-       req->cmd_len = scsi_command_size(pt->pscsi_cdb);
-       req->cmd = &pt->pscsi_cdb[0];
-       req->sense = &pt->pscsi_sense[0];
-       req->sense_len = 0;
+       scsi_req(req)->cmd_len = scsi_command_size(pt->pscsi_cdb);
+       scsi_req(req)->cmd = &pt->pscsi_cdb[0];
        if (pdv->pdv_sd->type == TYPE_DISK)
                req->timeout = PS_TIMEOUT_DISK;
        else
@@ -1075,7 +1074,7 @@ static void pscsi_req_done(struct request *req, int uptodate)
        struct pscsi_plugin_task *pt = cmd->priv;
 
        pt->pscsi_result = req->errors;
-       pt->pscsi_resid = req->resid_len;
+       pt->pscsi_resid = scsi_req(req)->resid_len;
 
        cmd->scsi_status = status_byte(pt->pscsi_result) << 1;
        if (cmd->scsi_status) {
@@ -1096,6 +1095,7 @@ static void pscsi_req_done(struct request *req, int uptodate)
                break;
        }
 
+       memcpy(pt->pscsi_sense, scsi_req(req)->sense, TRANSPORT_SENSE_BUFFER);
        __blk_put_request(req->q, req);
        kfree(pt);
 }
index 9ce0e9eef9230c725eb510692f47e794ece255e9..85fdbf762fa02ac4d70ed231a603afe23bb5013d 100644 (file)
@@ -297,8 +297,6 @@ static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device,
        if (!power_table)
                return -ENOMEM;
 
-       rcu_read_lock();
-
        for (freq = 0, i = 0;
             opp = dev_pm_opp_find_freq_ceil(dev, &freq), !IS_ERR(opp);
             freq++, i++) {
@@ -306,13 +304,13 @@ static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device,
                u64 power;
 
                if (i >= num_opps) {
-                       rcu_read_unlock();
                        ret = -EAGAIN;
                        goto free_power_table;
                }
 
                freq_mhz = freq / 1000000;
                voltage_mv = dev_pm_opp_get_voltage(opp) / 1000;
+               dev_pm_opp_put(opp);
 
                /*
                 * Do the multiplication with MHz and millivolt so as
@@ -328,8 +326,6 @@ static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device,
                power_table[i].power = power;
        }
 
-       rcu_read_unlock();
-
        if (i != num_opps) {
                ret = PTR_ERR(opp);
                goto free_power_table;
@@ -433,13 +429,10 @@ static int get_static_power(struct cpufreq_cooling_device *cpufreq_device,
                return 0;
        }
 
-       rcu_read_lock();
-
        opp = dev_pm_opp_find_freq_exact(cpufreq_device->cpu_dev, freq_hz,
                                         true);
        voltage = dev_pm_opp_get_voltage(opp);
-
-       rcu_read_unlock();
+       dev_pm_opp_put(opp);
 
        if (voltage == 0) {
                dev_warn_ratelimited(cpufreq_device->cpu_dev,
index 5a737fd5f1aa470104406ccfafbd3e50d03b9a03..ba7a5cd994dc9229351bd4ee057941afabcab8fc 100644 (file)
@@ -113,15 +113,15 @@ static int partition_enable_opps(struct devfreq_cooling_device *dfc,
                unsigned int freq = dfc->freq_table[i];
                bool want_enable = i >= cdev_state ? true : false;
 
-               rcu_read_lock();
                opp = dev_pm_opp_find_freq_exact(dev, freq, !want_enable);
-               rcu_read_unlock();
 
                if (PTR_ERR(opp) == -ERANGE)
                        continue;
                else if (IS_ERR(opp))
                        return PTR_ERR(opp);
 
+               dev_pm_opp_put(opp);
+
                if (want_enable)
                        ret = dev_pm_opp_enable(dev, freq);
                else
@@ -221,15 +221,12 @@ get_static_power(struct devfreq_cooling_device *dfc, unsigned long freq)
        if (!dfc->power_ops->get_static_power)
                return 0;
 
-       rcu_read_lock();
-
        opp = dev_pm_opp_find_freq_exact(dev, freq, true);
        if (IS_ERR(opp) && (PTR_ERR(opp) == -ERANGE))
                opp = dev_pm_opp_find_freq_exact(dev, freq, false);
 
        voltage = dev_pm_opp_get_voltage(opp) / 1000; /* mV */
-
-       rcu_read_unlock();
+       dev_pm_opp_put(opp);
 
        if (voltage == 0) {
                dev_warn_ratelimited(dev,
@@ -412,18 +409,14 @@ static int devfreq_cooling_gen_tables(struct devfreq_cooling_device *dfc)
                unsigned long power_dyn, voltage;
                struct dev_pm_opp *opp;
 
-               rcu_read_lock();
-
                opp = dev_pm_opp_find_freq_floor(dev, &freq);
                if (IS_ERR(opp)) {
-                       rcu_read_unlock();
                        ret = PTR_ERR(opp);
                        goto free_tables;
                }
 
                voltage = dev_pm_opp_get_voltage(opp) / 1000; /* mV */
-
-               rcu_read_unlock();
+               dev_pm_opp_put(opp);
 
                if (dfc->power_ops) {
                        power_dyn = get_dynamic_power(dfc, freq, voltage);
index fff718352e0cda323d4d5d30817a92af36e9de16..5d61d0871f2e9beaffeefb7a34978e86d41a5b67 100644 (file)
@@ -1329,17 +1329,20 @@ static int cp210x_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio,
        return 0;
 }
 
-static int cp210x_gpio_set_single_ended(struct gpio_chip *gc, unsigned int gpio,
-                                       enum single_ended_mode mode)
+static int cp210x_gpio_set_config(struct gpio_chip *gc, unsigned int gpio,
+                                 unsigned long config)
 {
        struct usb_serial *serial = gpiochip_get_data(gc);
        struct cp210x_serial_private *priv = usb_get_serial_data(serial);
+       enum pin_config_param param = pinconf_to_config_param(config);
 
        /* Succeed only if in correct mode (this can't be set at runtime) */
-       if ((mode == LINE_MODE_PUSH_PULL) && (priv->gpio_mode & BIT(gpio)))
+       if ((param == PIN_CONFIG_DRIVE_PUSH_PULL) &&
+           (priv->gpio_mode & BIT(gpio)))
                return 0;
 
-       if ((mode == LINE_MODE_OPEN_DRAIN) && !(priv->gpio_mode & BIT(gpio)))
+       if ((param == PIN_CONFIG_DRIVE_OPEN_DRAIN) &&
+           !(priv->gpio_mode & BIT(gpio)))
                return 0;
 
        return -ENOTSUPP;
@@ -1402,7 +1405,7 @@ static int cp2105_shared_gpio_init(struct usb_serial *serial)
        priv->gc.direction_output = cp210x_gpio_direction_output;
        priv->gc.get = cp210x_gpio_get;
        priv->gc.set = cp210x_gpio_set;
-       priv->gc.set_single_ended = cp210x_gpio_set_single_ended;
+       priv->gc.set_config = cp210x_gpio_set_config;
        priv->gc.owner = THIS_MODULE;
        priv->gc.parent = &serial->interface->dev;
        priv->gc.base = -1;
index 5676aefdf2bca72bd8734ff2642c3720b480d43a..0003912a8111959a101803f52ed8be80f4ae2f30 100644 (file)
@@ -68,13 +68,12 @@ static void vcpu_hotplug(unsigned int cpu)
 }
 
 static void handle_vcpu_hotplug_event(struct xenbus_watch *watch,
-                                       const char **vec, unsigned int len)
+                                     const char *path, const char *token)
 {
        unsigned int cpu;
        char *cpustr;
-       const char *node = vec[XS_WATCH_PATH];
 
-       cpustr = strstr(node, "cpu/");
+       cpustr = strstr(path, "cpu/");
        if (cpustr != NULL) {
                sscanf(cpustr, "cpu/%u", &cpu);
                vcpu_hotplug(cpu);
@@ -107,7 +106,7 @@ static int __init setup_vcpu_hotplug_event(void)
                .notifier_call = setup_cpu_watcher };
 
 #ifdef CONFIG_X86
-       if (!xen_pv_domain())
+       if (!xen_pv_domain() && !xen_pvh_domain())
 #else
        if (!xen_domain())
 #endif
index fd8e872d29434633eb831e5077ff4d5d1dbd342c..6a53577772c92127aa25dac3cd7bc7fe18fe09d9 100644 (file)
@@ -1704,7 +1704,6 @@ void __init xen_init_IRQ(void)
                pirq_eoi_map = (void *)__get_free_page(GFP_KERNEL|__GFP_ZERO);
                eoi_gmfn.gmfn = virt_to_gfn(pirq_eoi_map);
                rc = HYPERVISOR_physdev_op(PHYSDEVOP_pirq_eoi_gmfn_v2, &eoi_gmfn);
-               /* TODO: No PVH support for PIRQ EOI */
                if (rc != 0) {
                        free_page((unsigned long) pirq_eoi_map);
                        pirq_eoi_map = NULL;
index bb36b1e1dbcc68fd31490079fcb4e1feee0b70d7..d6786b87e13b2392c366cfa807c35cf2401c8387 100644 (file)
@@ -1146,13 +1146,13 @@ EXPORT_SYMBOL_GPL(gnttab_init);
 
 static int __gnttab_init(void)
 {
+       if (!xen_domain())
+               return -ENODEV;
+
        /* Delay grant-table initialization in the PV on HVM case */
-       if (xen_hvm_domain())
+       if (xen_hvm_domain() && !xen_pvh_domain())
                return 0;
 
-       if (!xen_pv_domain())
-               return -ENODEV;
-
        return gnttab_init();
 }
 /* Starts after core_initcall so that xen_pvh_gnttab_setup can be called
index 26e5e8507f031f3118229f5164286160d3bcece6..c1ec8ee80924837914ecc0fb2f3ca09cfd00bbcc 100644 (file)
@@ -218,7 +218,7 @@ static struct shutdown_handler shutdown_handlers[] = {
 };
 
 static void shutdown_handler(struct xenbus_watch *watch,
-                            const char **vec, unsigned int len)
+                            const char *path, const char *token)
 {
        char *str;
        struct xenbus_transaction xbt;
@@ -266,8 +266,8 @@ static void shutdown_handler(struct xenbus_watch *watch,
 }
 
 #ifdef CONFIG_MAGIC_SYSRQ
-static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
-                         unsigned int len)
+static void sysrq_handler(struct xenbus_watch *watch, const char *path,
+                         const char *token)
 {
        char sysrq_key = '\0';
        struct xenbus_transaction xbt;
@@ -277,7 +277,7 @@ static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
        err = xenbus_transaction_start(&xbt);
        if (err)
                return;
-       if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
+       if (xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key) < 0) {
                pr_err("Unable to read sysrq code in control/sysrq\n");
                xenbus_transaction_end(xbt, 1);
                return;
index 6e3306f4a5250c85d7661a7145df7f8d254d5783..2077a3ac7c0ca5ac12b111981ec7c64a59fa77f0 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/pagemap.h>
 #include <linux/seq_file.h>
 #include <linux/miscdevice.h>
+#include <linux/moduleparam.h>
 
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
@@ -32,6 +33,7 @@
 #include <xen/xen.h>
 #include <xen/privcmd.h>
 #include <xen/interface/xen.h>
+#include <xen/interface/hvm/dm_op.h>
 #include <xen/features.h>
 #include <xen/page.h>
 #include <xen/xen-ops.h>
@@ -43,16 +45,36 @@ MODULE_LICENSE("GPL");
 
 #define PRIV_VMA_LOCKED ((void *)1)
 
+static unsigned int privcmd_dm_op_max_num = 16;
+module_param_named(dm_op_max_nr_bufs, privcmd_dm_op_max_num, uint, 0644);
+MODULE_PARM_DESC(dm_op_max_nr_bufs,
+                "Maximum number of buffers per dm_op hypercall");
+
+static unsigned int privcmd_dm_op_buf_max_size = 4096;
+module_param_named(dm_op_buf_max_size, privcmd_dm_op_buf_max_size, uint,
+                  0644);
+MODULE_PARM_DESC(dm_op_buf_max_size,
+                "Maximum size of a dm_op hypercall buffer");
+
+struct privcmd_data {
+       domid_t domid;
+};
+
 static int privcmd_vma_range_is_mapped(
                struct vm_area_struct *vma,
                unsigned long addr,
                unsigned long nr_pages);
 
-static long privcmd_ioctl_hypercall(void __user *udata)
+static long privcmd_ioctl_hypercall(struct file *file, void __user *udata)
 {
+       struct privcmd_data *data = file->private_data;
        struct privcmd_hypercall hypercall;
        long ret;
 
+       /* Disallow arbitrary hypercalls if restricted */
+       if (data->domid != DOMID_INVALID)
+               return -EPERM;
+
        if (copy_from_user(&hypercall, udata, sizeof(hypercall)))
                return -EFAULT;
 
@@ -229,8 +251,9 @@ static int mmap_gfn_range(void *data, void *state)
        return 0;
 }
 
-static long privcmd_ioctl_mmap(void __user *udata)
+static long privcmd_ioctl_mmap(struct file *file, void __user *udata)
 {
+       struct privcmd_data *data = file->private_data;
        struct privcmd_mmap mmapcmd;
        struct mm_struct *mm = current->mm;
        struct vm_area_struct *vma;
@@ -245,6 +268,10 @@ static long privcmd_ioctl_mmap(void __user *udata)
        if (copy_from_user(&mmapcmd, udata, sizeof(mmapcmd)))
                return -EFAULT;
 
+       /* If restriction is in place, check the domid matches */
+       if (data->domid != DOMID_INVALID && data->domid != mmapcmd.dom)
+               return -EPERM;
+
        rc = gather_array(&pagelist,
                          mmapcmd.num, sizeof(struct privcmd_mmap_entry),
                          mmapcmd.entry);
@@ -416,8 +443,10 @@ static int alloc_empty_pages(struct vm_area_struct *vma, int numpgs)
 
 static const struct vm_operations_struct privcmd_vm_ops;
 
-static long privcmd_ioctl_mmap_batch(void __user *udata, int version)
+static long privcmd_ioctl_mmap_batch(
+       struct file *file, void __user *udata, int version)
 {
+       struct privcmd_data *data = file->private_data;
        int ret;
        struct privcmd_mmapbatch_v2 m;
        struct mm_struct *mm = current->mm;
@@ -446,6 +475,10 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version)
                return -EINVAL;
        }
 
+       /* If restriction is in place, check the domid matches */
+       if (data->domid != DOMID_INVALID && data->domid != m.dom)
+               return -EPERM;
+
        nr_pages = DIV_ROUND_UP(m.num, XEN_PFN_PER_PAGE);
        if ((m.num <= 0) || (nr_pages > (LONG_MAX >> PAGE_SHIFT)))
                return -EINVAL;
@@ -548,37 +581,210 @@ out_unlock:
        goto out;
 }
 
+static int lock_pages(
+       struct privcmd_dm_op_buf kbufs[], unsigned int num,
+       struct page *pages[], unsigned int nr_pages)
+{
+       unsigned int i;
+
+       for (i = 0; i < num; i++) {
+               unsigned int requested;
+               int pinned;
+
+               requested = DIV_ROUND_UP(
+                       offset_in_page(kbufs[i].uptr) + kbufs[i].size,
+                       PAGE_SIZE);
+               if (requested > nr_pages)
+                       return -ENOSPC;
+
+               pinned = get_user_pages_fast(
+                       (unsigned long) kbufs[i].uptr,
+                       requested, FOLL_WRITE, pages);
+               if (pinned < 0)
+                       return pinned;
+
+               nr_pages -= pinned;
+               pages += pinned;
+       }
+
+       return 0;
+}
+
+static void unlock_pages(struct page *pages[], unsigned int nr_pages)
+{
+       unsigned int i;
+
+       if (!pages)
+               return;
+
+       for (i = 0; i < nr_pages; i++) {
+               if (pages[i])
+                       put_page(pages[i]);
+       }
+}
+
+static long privcmd_ioctl_dm_op(struct file *file, void __user *udata)
+{
+       struct privcmd_data *data = file->private_data;
+       struct privcmd_dm_op kdata;
+       struct privcmd_dm_op_buf *kbufs;
+       unsigned int nr_pages = 0;
+       struct page **pages = NULL;
+       struct xen_dm_op_buf *xbufs = NULL;
+       unsigned int i;
+       long rc;
+
+       if (copy_from_user(&kdata, udata, sizeof(kdata)))
+               return -EFAULT;
+
+       /* If restriction is in place, check the domid matches */
+       if (data->domid != DOMID_INVALID && data->domid != kdata.dom)
+               return -EPERM;
+
+       if (kdata.num == 0)
+               return 0;
+
+       if (kdata.num > privcmd_dm_op_max_num)
+               return -E2BIG;
+
+       kbufs = kcalloc(kdata.num, sizeof(*kbufs), GFP_KERNEL);
+       if (!kbufs)
+               return -ENOMEM;
+
+       if (copy_from_user(kbufs, kdata.ubufs,
+                          sizeof(*kbufs) * kdata.num)) {
+               rc = -EFAULT;
+               goto out;
+       }
+
+       for (i = 0; i < kdata.num; i++) {
+               if (kbufs[i].size > privcmd_dm_op_buf_max_size) {
+                       rc = -E2BIG;
+                       goto out;
+               }
+
+               if (!access_ok(VERIFY_WRITE, kbufs[i].uptr,
+                              kbufs[i].size)) {
+                       rc = -EFAULT;
+                       goto out;
+               }
+
+               nr_pages += DIV_ROUND_UP(
+                       offset_in_page(kbufs[i].uptr) + kbufs[i].size,
+                       PAGE_SIZE);
+       }
+
+       pages = kcalloc(nr_pages, sizeof(*pages), GFP_KERNEL);
+       if (!pages) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       xbufs = kcalloc(kdata.num, sizeof(*xbufs), GFP_KERNEL);
+       if (!xbufs) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       rc = lock_pages(kbufs, kdata.num, pages, nr_pages);
+       if (rc)
+               goto out;
+
+       for (i = 0; i < kdata.num; i++) {
+               set_xen_guest_handle(xbufs[i].h, kbufs[i].uptr);
+               xbufs[i].size = kbufs[i].size;
+       }
+
+       xen_preemptible_hcall_begin();
+       rc = HYPERVISOR_dm_op(kdata.dom, kdata.num, xbufs);
+       xen_preemptible_hcall_end();
+
+out:
+       unlock_pages(pages, nr_pages);
+       kfree(xbufs);
+       kfree(pages);
+       kfree(kbufs);
+
+       return rc;
+}
+
+static long privcmd_ioctl_restrict(struct file *file, void __user *udata)
+{
+       struct privcmd_data *data = file->private_data;
+       domid_t dom;
+
+       if (copy_from_user(&dom, udata, sizeof(dom)))
+               return -EFAULT;
+
+       /* Set restriction to the specified domain, or check it matches */
+       if (data->domid == DOMID_INVALID)
+               data->domid = dom;
+       else if (data->domid != dom)
+               return -EINVAL;
+
+       return 0;
+}
+
 static long privcmd_ioctl(struct file *file,
                          unsigned int cmd, unsigned long data)
 {
-       int ret = -ENOSYS;
+       int ret = -ENOTTY;
        void __user *udata = (void __user *) data;
 
        switch (cmd) {
        case IOCTL_PRIVCMD_HYPERCALL:
-               ret = privcmd_ioctl_hypercall(udata);
+               ret = privcmd_ioctl_hypercall(file, udata);
                break;
 
        case IOCTL_PRIVCMD_MMAP:
-               ret = privcmd_ioctl_mmap(udata);
+               ret = privcmd_ioctl_mmap(file, udata);
                break;
 
        case IOCTL_PRIVCMD_MMAPBATCH:
-               ret = privcmd_ioctl_mmap_batch(udata, 1);
+               ret = privcmd_ioctl_mmap_batch(file, udata, 1);
                break;
 
        case IOCTL_PRIVCMD_MMAPBATCH_V2:
-               ret = privcmd_ioctl_mmap_batch(udata, 2);
+               ret = privcmd_ioctl_mmap_batch(file, udata, 2);
+               break;
+
+       case IOCTL_PRIVCMD_DM_OP:
+               ret = privcmd_ioctl_dm_op(file, udata);
+               break;
+
+       case IOCTL_PRIVCMD_RESTRICT:
+               ret = privcmd_ioctl_restrict(file, udata);
                break;
 
        default:
-               ret = -EINVAL;
                break;
        }
 
        return ret;
 }
 
+static int privcmd_open(struct inode *ino, struct file *file)
+{
+       struct privcmd_data *data = kzalloc(sizeof(*data), GFP_KERNEL);
+
+       if (!data)
+               return -ENOMEM;
+
+       /* DOMID_INVALID implies no restriction */
+       data->domid = DOMID_INVALID;
+
+       file->private_data = data;
+       return 0;
+}
+
+static int privcmd_release(struct inode *ino, struct file *file)
+{
+       struct privcmd_data *data = file->private_data;
+
+       kfree(data);
+       return 0;
+}
+
 static void privcmd_close(struct vm_area_struct *vma)
 {
        struct page **pages = vma->vm_private_data;
@@ -647,6 +853,8 @@ static int privcmd_vma_range_is_mapped(
 const struct file_operations xen_privcmd_fops = {
        .owner = THIS_MODULE,
        .unlocked_ioctl = privcmd_ioctl,
+       .open = privcmd_open,
+       .release = privcmd_release,
        .mmap = privcmd_mmap,
 };
 EXPORT_SYMBOL_GPL(xen_privcmd_fops);
index 79865b8901baa29cf9427eb2237fad364c44bb31..e7715cb62eefc307a354a77902baaaa5916a157c 100644 (file)
@@ -55,7 +55,7 @@ static int register_balloon(struct device *dev);
 
 /* React to a change in the target key */
 static void watch_target(struct xenbus_watch *watch,
-                        const char **vec, unsigned int len)
+                        const char *path, const char *token)
 {
        unsigned long long new_target;
        int err;
index 3f0aee0a068b213803b4a4a3a771c1285562b43e..3814b44bf1f76e2dc16964c557f731315a4c8876 100644 (file)
@@ -652,7 +652,7 @@ out:
 }
 
 static void xen_pcibk_be_watch(struct xenbus_watch *watch,
-                            const char **vec, unsigned int len)
+                              const char *path, const char *token)
 {
        struct xen_pcibk_device *pdev =
            container_of(watch, struct xen_pcibk_device, be_watch);
diff --git a/drivers/xen/xenbus/xenbus.h b/drivers/xen/xenbus/xenbus.h
new file mode 100644 (file)
index 0000000..149c5e7
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Private include for xenbus communications.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ * Copyright (C) 2005 XenSource 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 _XENBUS_XENBUS_H
+#define _XENBUS_XENBUS_H
+
+#include <linux/mutex.h>
+#include <linux/uio.h>
+#include <xen/xenbus.h>
+
+#define XEN_BUS_ID_SIZE                        20
+
+struct xen_bus_type {
+       char *root;
+       unsigned int levels;
+       int (*get_bus_id)(char bus_id[XEN_BUS_ID_SIZE], const char *nodename);
+       int (*probe)(struct xen_bus_type *bus, const char *type,
+                    const char *dir);
+       void (*otherend_changed)(struct xenbus_watch *watch, const char *path,
+                                const char *token);
+       struct bus_type bus;
+};
+
+enum xenstore_init {
+       XS_UNKNOWN,
+       XS_PV,
+       XS_HVM,
+       XS_LOCAL,
+};
+
+struct xs_watch_event {
+       struct list_head list;
+       unsigned int len;
+       struct xenbus_watch *handle;
+       const char *path;
+       const char *token;
+       char body[];
+};
+
+enum xb_req_state {
+       xb_req_state_queued,
+       xb_req_state_wait_reply,
+       xb_req_state_got_reply,
+       xb_req_state_aborted
+};
+
+struct xb_req_data {
+       struct list_head list;
+       wait_queue_head_t wq;
+       struct xsd_sockmsg msg;
+       enum xsd_sockmsg_type type;
+       char *body;
+       const struct kvec *vec;
+       int num_vecs;
+       int err;
+       enum xb_req_state state;
+       void (*cb)(struct xb_req_data *);
+       void *par;
+};
+
+extern enum xenstore_init xen_store_domain_type;
+extern const struct attribute_group *xenbus_dev_groups[];
+extern struct mutex xs_response_mutex;
+extern struct list_head xs_reply_list;
+extern struct list_head xb_write_list;
+extern wait_queue_head_t xb_waitq;
+extern struct mutex xb_write_mutex;
+
+int xs_init(void);
+int xb_init_comms(void);
+void xb_deinit_comms(void);
+int xs_watch_msg(struct xs_watch_event *event);
+void xs_request_exit(struct xb_req_data *req);
+
+int xenbus_match(struct device *_dev, struct device_driver *_drv);
+int xenbus_dev_probe(struct device *_dev);
+int xenbus_dev_remove(struct device *_dev);
+int xenbus_register_driver_common(struct xenbus_driver *drv,
+                                 struct xen_bus_type *bus,
+                                 struct module *owner,
+                                 const char *mod_name);
+int xenbus_probe_node(struct xen_bus_type *bus,
+                     const char *type,
+                     const char *nodename);
+int xenbus_probe_devices(struct xen_bus_type *bus);
+
+void xenbus_dev_changed(const char *node, struct xen_bus_type *bus);
+
+void xenbus_dev_shutdown(struct device *_dev);
+
+int xenbus_dev_suspend(struct device *dev);
+int xenbus_dev_resume(struct device *dev);
+int xenbus_dev_cancel(struct device *dev);
+
+void xenbus_otherend_changed(struct xenbus_watch *watch,
+                            const char *path, const char *token,
+                            int ignore_on_shutdown);
+
+int xenbus_read_otherend_details(struct xenbus_device *xendev,
+                                char *id_node, char *path_node);
+
+void xenbus_ring_ops_init(void);
+
+int xenbus_dev_request_and_reply(struct xsd_sockmsg *msg, void *par);
+void xenbus_dev_queue_reply(struct xb_req_data *req);
+
+#endif
index 056da6ee1a357ed22211e884d78b1186619a3343..82a8866758ee0d5ac235430059f74a7bb56b09f8 100644 (file)
@@ -47,7 +47,7 @@
 #include <xen/xen.h>
 #include <xen/features.h>
 
-#include "xenbus_probe.h"
+#include "xenbus.h"
 
 #define XENBUS_PAGES(_grants)  (DIV_ROUND_UP(_grants, XEN_PFN_PER_PAGE))
 
@@ -115,7 +115,7 @@ EXPORT_SYMBOL_GPL(xenbus_strstate);
 int xenbus_watch_path(struct xenbus_device *dev, const char *path,
                      struct xenbus_watch *watch,
                      void (*callback)(struct xenbus_watch *,
-                                      const char **, unsigned int))
+                                      const char *, const char *))
 {
        int err;
 
@@ -153,7 +153,7 @@ EXPORT_SYMBOL_GPL(xenbus_watch_path);
 int xenbus_watch_pathfmt(struct xenbus_device *dev,
                         struct xenbus_watch *watch,
                         void (*callback)(struct xenbus_watch *,
-                                       const char **, unsigned int),
+                                         const char *, const char *),
                         const char *pathfmt, ...)
 {
        int err;
@@ -259,53 +259,34 @@ int xenbus_frontend_closed(struct xenbus_device *dev)
 }
 EXPORT_SYMBOL_GPL(xenbus_frontend_closed);
 
-/**
- * Return the path to the error node for the given device, or NULL on failure.
- * If the value returned is non-NULL, then it is the caller's to kfree.
- */
-static char *error_path(struct xenbus_device *dev)
-{
-       return kasprintf(GFP_KERNEL, "error/%s", dev->nodename);
-}
-
-
 static void xenbus_va_dev_error(struct xenbus_device *dev, int err,
                                const char *fmt, va_list ap)
 {
        unsigned int len;
-       char *printf_buffer = NULL;
-       char *path_buffer = NULL;
+       char *printf_buffer;
+       char *path_buffer;
 
 #define PRINTF_BUFFER_SIZE 4096
+
        printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL);
-       if (printf_buffer == NULL)
-               goto fail;
+       if (!printf_buffer)
+               return;
 
        len = sprintf(printf_buffer, "%i ", -err);
-       vsnprintf(printf_buffer+len, PRINTF_BUFFER_SIZE-len, fmt, ap);
+       vsnprintf(printf_buffer + len, PRINTF_BUFFER_SIZE - len, fmt, ap);
 
        dev_err(&dev->dev, "%s\n", printf_buffer);
 
-       path_buffer = error_path(dev);
-
-       if (path_buffer == NULL) {
+       path_buffer = kasprintf(GFP_KERNEL, "error/%s", dev->nodename);
+       if (!path_buffer ||
+           xenbus_write(XBT_NIL, path_buffer, "error", printf_buffer))
                dev_err(&dev->dev, "failed to write error node for %s (%s)\n",
-                      dev->nodename, printf_buffer);
-               goto fail;
-       }
+                       dev->nodename, printf_buffer);
 
-       if (xenbus_write(XBT_NIL, path_buffer, "error", printf_buffer) != 0) {
-               dev_err(&dev->dev, "failed to write error node for %s (%s)\n",
-                      dev->nodename, printf_buffer);
-               goto fail;
-       }
-
-fail:
        kfree(printf_buffer);
        kfree(path_buffer);
 }
 
-
 /**
  * xenbus_dev_error
  * @dev: xenbus device
index ecdecce80a6c9600fd5b78773cdcca070eb444bb..856ada5d39c9764ca6d741544961cc0f81a5afa0 100644 (file)
 
 #include <linux/wait.h>
 #include <linux/interrupt.h>
+#include <linux/kthread.h>
 #include <linux/sched.h>
 #include <linux/err.h>
 #include <xen/xenbus.h>
 #include <asm/xen/hypervisor.h>
 #include <xen/events.h>
 #include <xen/page.h>
-#include "xenbus_comms.h"
+#include "xenbus.h"
+
+/* A list of replies. Currently only one will ever be outstanding. */
+LIST_HEAD(xs_reply_list);
+
+/* A list of write requests. */
+LIST_HEAD(xb_write_list);
+DECLARE_WAIT_QUEUE_HEAD(xb_waitq);
+DEFINE_MUTEX(xb_write_mutex);
+
+/* Protect xenbus reader thread against save/restore. */
+DEFINE_MUTEX(xs_response_mutex);
 
 static int xenbus_irq;
+static struct task_struct *xenbus_task;
 
 static DECLARE_WORK(probe_work, xenbus_probe);
 
-static DECLARE_WAIT_QUEUE_HEAD(xb_waitq);
 
 static irqreturn_t wake_waiting(int irq, void *unused)
 {
@@ -84,30 +96,31 @@ static const void *get_input_chunk(XENSTORE_RING_IDX cons,
        return buf + MASK_XENSTORE_IDX(cons);
 }
 
+static int xb_data_to_write(void)
+{
+       struct xenstore_domain_interface *intf = xen_store_interface;
+
+       return (intf->req_prod - intf->req_cons) != XENSTORE_RING_SIZE &&
+               !list_empty(&xb_write_list);
+}
+
 /**
  * xb_write - low level write
  * @data: buffer to send
  * @len: length of buffer
  *
- * Returns 0 on success, error otherwise.
+ * Returns number of bytes written or -err.
  */
-int xb_write(const void *data, unsigned len)
+static int xb_write(const void *data, unsigned int len)
 {
        struct xenstore_domain_interface *intf = xen_store_interface;
        XENSTORE_RING_IDX cons, prod;
-       int rc;
+       unsigned int bytes = 0;
 
        while (len != 0) {
                void *dst;
                unsigned int avail;
 
-               rc = wait_event_interruptible(
-                       xb_waitq,
-                       (intf->req_prod - intf->req_cons) !=
-                       XENSTORE_RING_SIZE);
-               if (rc < 0)
-                       return rc;
-
                /* Read indexes, then verify. */
                cons = intf->req_cons;
                prod = intf->req_prod;
@@ -115,6 +128,11 @@ int xb_write(const void *data, unsigned len)
                        intf->req_cons = intf->req_prod = 0;
                        return -EIO;
                }
+               if (!xb_data_to_write())
+                       return bytes;
+
+               /* Must write data /after/ reading the consumer index. */
+               virt_mb();
 
                dst = get_output_chunk(cons, prod, intf->req, &avail);
                if (avail == 0)
@@ -122,52 +140,45 @@ int xb_write(const void *data, unsigned len)
                if (avail > len)
                        avail = len;
 
-               /* Must write data /after/ reading the consumer index. */
-               virt_mb();
-
                memcpy(dst, data, avail);
                data += avail;
                len -= avail;
+               bytes += avail;
 
                /* Other side must not see new producer until data is there. */
                virt_wmb();
                intf->req_prod += avail;
 
                /* Implies mb(): other side will see the updated producer. */
-               notify_remote_via_evtchn(xen_store_evtchn);
+               if (prod <= intf->req_cons)
+                       notify_remote_via_evtchn(xen_store_evtchn);
        }
 
-       return 0;
+       return bytes;
 }
 
-int xb_data_to_read(void)
+static int xb_data_to_read(void)
 {
        struct xenstore_domain_interface *intf = xen_store_interface;
        return (intf->rsp_cons != intf->rsp_prod);
 }
 
-int xb_wait_for_data_to_read(void)
-{
-       return wait_event_interruptible(xb_waitq, xb_data_to_read());
-}
-
-int xb_read(void *data, unsigned len)
+static int xb_read(void *data, unsigned int len)
 {
        struct xenstore_domain_interface *intf = xen_store_interface;
        XENSTORE_RING_IDX cons, prod;
-       int rc;
+       unsigned int bytes = 0;
 
        while (len != 0) {
                unsigned int avail;
                const char *src;
 
-               rc = xb_wait_for_data_to_read();
-               if (rc < 0)
-                       return rc;
-
                /* Read indexes, then verify. */
                cons = intf->rsp_cons;
                prod = intf->rsp_prod;
+               if (cons == prod)
+                       return bytes;
+
                if (!check_indexes(cons, prod)) {
                        intf->rsp_cons = intf->rsp_prod = 0;
                        return -EIO;
@@ -185,17 +196,243 @@ int xb_read(void *data, unsigned len)
                memcpy(data, src, avail);
                data += avail;
                len -= avail;
+               bytes += avail;
 
                /* Other side must not see free space until we've copied out */
                virt_mb();
                intf->rsp_cons += avail;
 
-               pr_debug("Finished read of %i bytes (%i to go)\n", avail, len);
-
                /* Implies mb(): other side will see the updated consumer. */
-               notify_remote_via_evtchn(xen_store_evtchn);
+               if (intf->rsp_prod - cons >= XENSTORE_RING_SIZE)
+                       notify_remote_via_evtchn(xen_store_evtchn);
+       }
+
+       return bytes;
+}
+
+static int process_msg(void)
+{
+       static struct {
+               struct xsd_sockmsg msg;
+               char *body;
+               union {
+                       void *alloc;
+                       struct xs_watch_event *watch;
+               };
+               bool in_msg;
+               bool in_hdr;
+               unsigned int read;
+       } state;
+       struct xb_req_data *req;
+       int err;
+       unsigned int len;
+
+       if (!state.in_msg) {
+               state.in_msg = true;
+               state.in_hdr = true;
+               state.read = 0;
+
+               /*
+                * We must disallow save/restore while reading a message.
+                * A partial read across s/r leaves us out of sync with
+                * xenstored.
+                * xs_response_mutex is locked as long as we are processing one
+                * message. state.in_msg will be true as long as we are holding
+                * the lock here.
+                */
+               mutex_lock(&xs_response_mutex);
+
+               if (!xb_data_to_read()) {
+                       /* We raced with save/restore: pending data 'gone'. */
+                       mutex_unlock(&xs_response_mutex);
+                       state.in_msg = false;
+                       return 0;
+               }
+       }
+
+       if (state.in_hdr) {
+               if (state.read != sizeof(state.msg)) {
+                       err = xb_read((void *)&state.msg + state.read,
+                                     sizeof(state.msg) - state.read);
+                       if (err < 0)
+                               goto out;
+                       state.read += err;
+                       if (state.read != sizeof(state.msg))
+                               return 0;
+                       if (state.msg.len > XENSTORE_PAYLOAD_MAX) {
+                               err = -EINVAL;
+                               goto out;
+                       }
+               }
+
+               len = state.msg.len + 1;
+               if (state.msg.type == XS_WATCH_EVENT)
+                       len += sizeof(*state.watch);
+
+               state.alloc = kmalloc(len, GFP_NOIO | __GFP_HIGH);
+               if (!state.alloc)
+                       return -ENOMEM;
+
+               if (state.msg.type == XS_WATCH_EVENT)
+                       state.body = state.watch->body;
+               else
+                       state.body = state.alloc;
+               state.in_hdr = false;
+               state.read = 0;
+       }
+
+       err = xb_read(state.body + state.read, state.msg.len - state.read);
+       if (err < 0)
+               goto out;
+
+       state.read += err;
+       if (state.read != state.msg.len)
+               return 0;
+
+       state.body[state.msg.len] = '\0';
+
+       if (state.msg.type == XS_WATCH_EVENT) {
+               state.watch->len = state.msg.len;
+               err = xs_watch_msg(state.watch);
+       } else {
+               err = -ENOENT;
+               mutex_lock(&xb_write_mutex);
+               list_for_each_entry(req, &xs_reply_list, list) {
+                       if (req->msg.req_id == state.msg.req_id) {
+                               if (req->state == xb_req_state_wait_reply) {
+                                       req->msg.type = state.msg.type;
+                                       req->msg.len = state.msg.len;
+                                       req->body = state.body;
+                                       req->state = xb_req_state_got_reply;
+                                       list_del(&req->list);
+                                       req->cb(req);
+                               } else {
+                                       list_del(&req->list);
+                                       kfree(req);
+                               }
+                               err = 0;
+                               break;
+                       }
+               }
+               mutex_unlock(&xb_write_mutex);
+               if (err)
+                       goto out;
        }
 
+       mutex_unlock(&xs_response_mutex);
+
+       state.in_msg = false;
+       state.alloc = NULL;
+       return err;
+
+ out:
+       mutex_unlock(&xs_response_mutex);
+       state.in_msg = false;
+       kfree(state.alloc);
+       state.alloc = NULL;
+       return err;
+}
+
+static int process_writes(void)
+{
+       static struct {
+               struct xb_req_data *req;
+               int idx;
+               unsigned int written;
+       } state;
+       void *base;
+       unsigned int len;
+       int err = 0;
+
+       if (!xb_data_to_write())
+               return 0;
+
+       mutex_lock(&xb_write_mutex);
+
+       if (!state.req) {
+               state.req = list_first_entry(&xb_write_list,
+                                            struct xb_req_data, list);
+               state.idx = -1;
+               state.written = 0;
+       }
+
+       if (state.req->state == xb_req_state_aborted)
+               goto out_err;
+
+       while (state.idx < state.req->num_vecs) {
+               if (state.idx < 0) {
+                       base = &state.req->msg;
+                       len = sizeof(state.req->msg);
+               } else {
+                       base = state.req->vec[state.idx].iov_base;
+                       len = state.req->vec[state.idx].iov_len;
+               }
+               err = xb_write(base + state.written, len - state.written);
+               if (err < 0)
+                       goto out_err;
+               state.written += err;
+               if (state.written != len)
+                       goto out;
+
+               state.idx++;
+               state.written = 0;
+       }
+
+       list_del(&state.req->list);
+       state.req->state = xb_req_state_wait_reply;
+       list_add_tail(&state.req->list, &xs_reply_list);
+       state.req = NULL;
+
+ out:
+       mutex_unlock(&xb_write_mutex);
+
+       return 0;
+
+ out_err:
+       state.req->msg.type = XS_ERROR;
+       state.req->err = err;
+       list_del(&state.req->list);
+       if (state.req->state == xb_req_state_aborted)
+               kfree(state.req);
+       else {
+               state.req->state = xb_req_state_got_reply;
+               wake_up(&state.req->wq);
+       }
+
+       mutex_unlock(&xb_write_mutex);
+
+       state.req = NULL;
+
+       return err;
+}
+
+static int xb_thread_work(void)
+{
+       return xb_data_to_read() || xb_data_to_write();
+}
+
+static int xenbus_thread(void *unused)
+{
+       int err;
+
+       while (!kthread_should_stop()) {
+               if (wait_event_interruptible(xb_waitq, xb_thread_work()))
+                       continue;
+
+               err = process_msg();
+               if (err == -ENOMEM)
+                       schedule();
+               else if (err)
+                       pr_warn_ratelimited("error %d while reading message\n",
+                                           err);
+
+               err = process_writes();
+               if (err)
+                       pr_warn_ratelimited("error %d while writing message\n",
+                                           err);
+       }
+
+       xenbus_task = NULL;
        return 0;
 }
 
@@ -223,6 +460,7 @@ int xb_init_comms(void)
                rebind_evtchn_irq(xen_store_evtchn, xenbus_irq);
        } else {
                int err;
+
                err = bind_evtchn_to_irqhandler(xen_store_evtchn, wake_waiting,
                                                0, "xenbus", &xb_waitq);
                if (err < 0) {
@@ -231,6 +469,13 @@ int xb_init_comms(void)
                }
 
                xenbus_irq = err;
+
+               if (!xenbus_task) {
+                       xenbus_task = kthread_run(xenbus_thread, NULL,
+                                                 "xenbus");
+                       if (IS_ERR(xenbus_task))
+                               return PTR_ERR(xenbus_task);
+               }
        }
 
        return 0;
diff --git a/drivers/xen/xenbus/xenbus_comms.h b/drivers/xen/xenbus/xenbus_comms.h
deleted file mode 100644 (file)
index 867a2e4..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Private include for xenbus communications.
- *
- * Copyright (C) 2005 Rusty Russell, IBM 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; or, when distributed
- * separately from the Linux kernel or incorporated into other
- * software packages, subject to the following license:
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this source file (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy, modify,
- * merge, publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * 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 _XENBUS_COMMS_H
-#define _XENBUS_COMMS_H
-
-#include <linux/fs.h>
-
-int xs_init(void);
-int xb_init_comms(void);
-void xb_deinit_comms(void);
-
-/* Low level routines. */
-int xb_write(const void *data, unsigned len);
-int xb_read(void *data, unsigned len);
-int xb_data_to_read(void);
-int xb_wait_for_data_to_read(void);
-extern struct xenstore_domain_interface *xen_store_interface;
-extern int xen_store_evtchn;
-extern enum xenstore_init xen_store_domain_type;
-
-extern const struct file_operations xen_xenbus_fops;
-
-#endif /* _XENBUS_COMMS_H */
index 4a41ac9af966baf1c6e64f47e325d1c818ec8344..1126701e212ec4b7a86bb9c27298fd8b0fc24b42 100644 (file)
@@ -16,7 +16,7 @@
 #include <xen/events.h>
 #include <asm/xen/hypervisor.h>
 
-#include "xenbus_comms.h"
+#include "xenbus.h"
 
 static int xenbus_backend_open(struct inode *inode, struct file *filp)
 {
index 79130b31024754dc7560f60732545a8f28c103b1..4d343eed08f51e1a3d2a0628dccb256b95858fae 100644 (file)
 #include <linux/miscdevice.h>
 #include <linux/init.h>
 
-#include "xenbus_comms.h"
-
 #include <xen/xenbus.h>
 #include <xen/xen.h>
 #include <asm/xen/hypervisor.h>
 
+#include "xenbus.h"
+
 /*
  * An element of a list of outstanding transactions, for which we're
  * still waiting a reply.
@@ -113,6 +113,7 @@ struct xenbus_file_priv {
        struct list_head read_buffers;
        wait_queue_head_t read_waitq;
 
+       struct kref kref;
 };
 
 /* Read out any raw xenbus messages queued up. */
@@ -258,26 +259,23 @@ out_fail:
 }
 
 static void watch_fired(struct xenbus_watch *watch,
-                       const char **vec,
-                       unsigned int len)
+                       const char *path,
+                       const char *token)
 {
        struct watch_adapter *adap;
        struct xsd_sockmsg hdr;
-       const char *path, *token;
-       int path_len, tok_len, body_len, data_len = 0;
+       const char *token_caller;
+       int path_len, tok_len, body_len;
        int ret;
        LIST_HEAD(staging_q);
 
        adap = container_of(watch, struct watch_adapter, watch);
 
-       path = vec[XS_WATCH_PATH];
-       token = adap->token;
+       token_caller = adap->token;
 
        path_len = strlen(path) + 1;
-       tok_len = strlen(token) + 1;
-       if (len > 2)
-               data_len = vec[len] - vec[2] + 1;
-       body_len = path_len + tok_len + data_len;
+       tok_len = strlen(token_caller) + 1;
+       body_len = path_len + tok_len;
 
        hdr.type = XS_WATCH_EVENT;
        hdr.len = body_len;
@@ -288,9 +286,7 @@ static void watch_fired(struct xenbus_watch *watch,
        if (!ret)
                ret = queue_reply(&staging_q, path, path_len);
        if (!ret)
-               ret = queue_reply(&staging_q, token, tok_len);
-       if (!ret && len > 2)
-               ret = queue_reply(&staging_q, vec[2], data_len);
+               ret = queue_reply(&staging_q, token_caller, tok_len);
 
        if (!ret) {
                /* success: pass reply list onto watcher */
@@ -302,6 +298,107 @@ static void watch_fired(struct xenbus_watch *watch,
        mutex_unlock(&adap->dev_data->reply_mutex);
 }
 
+static void xenbus_file_free(struct kref *kref)
+{
+       struct xenbus_file_priv *u;
+       struct xenbus_transaction_holder *trans, *tmp;
+       struct watch_adapter *watch, *tmp_watch;
+       struct read_buffer *rb, *tmp_rb;
+
+       u = container_of(kref, struct xenbus_file_priv, kref);
+
+       /*
+        * No need for locking here because there are no other users,
+        * by definition.
+        */
+
+       list_for_each_entry_safe(trans, tmp, &u->transactions, list) {
+               xenbus_transaction_end(trans->handle, 1);
+               list_del(&trans->list);
+               kfree(trans);
+       }
+
+       list_for_each_entry_safe(watch, tmp_watch, &u->watches, list) {
+               unregister_xenbus_watch(&watch->watch);
+               list_del(&watch->list);
+               free_watch_adapter(watch);
+       }
+
+       list_for_each_entry_safe(rb, tmp_rb, &u->read_buffers, list) {
+               list_del(&rb->list);
+               kfree(rb);
+       }
+       kfree(u);
+}
+
+static struct xenbus_transaction_holder *xenbus_get_transaction(
+       struct xenbus_file_priv *u, uint32_t tx_id)
+{
+       struct xenbus_transaction_holder *trans;
+
+       list_for_each_entry(trans, &u->transactions, list)
+               if (trans->handle.id == tx_id)
+                       return trans;
+
+       return NULL;
+}
+
+void xenbus_dev_queue_reply(struct xb_req_data *req)
+{
+       struct xenbus_file_priv *u = req->par;
+       struct xenbus_transaction_holder *trans = NULL;
+       int rc;
+       LIST_HEAD(staging_q);
+
+       xs_request_exit(req);
+
+       mutex_lock(&u->msgbuffer_mutex);
+
+       if (req->type == XS_TRANSACTION_START) {
+               trans = xenbus_get_transaction(u, 0);
+               if (WARN_ON(!trans))
+                       goto out;
+               if (req->msg.type == XS_ERROR) {
+                       list_del(&trans->list);
+                       kfree(trans);
+               } else {
+                       rc = kstrtou32(req->body, 10, &trans->handle.id);
+                       if (WARN_ON(rc))
+                               goto out;
+               }
+       } else if (req->msg.type == XS_TRANSACTION_END) {
+               trans = xenbus_get_transaction(u, req->msg.tx_id);
+               if (WARN_ON(!trans))
+                       goto out;
+               list_del(&trans->list);
+               kfree(trans);
+       }
+
+       mutex_unlock(&u->msgbuffer_mutex);
+
+       mutex_lock(&u->reply_mutex);
+       rc = queue_reply(&staging_q, &req->msg, sizeof(req->msg));
+       if (!rc)
+               rc = queue_reply(&staging_q, req->body, req->msg.len);
+       if (!rc) {
+               list_splice_tail(&staging_q, &u->read_buffers);
+               wake_up(&u->read_waitq);
+       } else {
+               queue_cleanup(&staging_q);
+       }
+       mutex_unlock(&u->reply_mutex);
+
+       kfree(req->body);
+       kfree(req);
+
+       kref_put(&u->kref, xenbus_file_free);
+
+       return;
+
+ out:
+       mutex_unlock(&u->msgbuffer_mutex);
+}
+
 static int xenbus_command_reply(struct xenbus_file_priv *u,
                                unsigned int msg_type, const char *reply)
 {
@@ -322,6 +419,9 @@ static int xenbus_command_reply(struct xenbus_file_priv *u,
        wake_up(&u->read_waitq);
        mutex_unlock(&u->reply_mutex);
 
+       if (!rc)
+               kref_put(&u->kref, xenbus_file_free);
+
        return rc;
 }
 
@@ -329,57 +429,22 @@ static int xenbus_write_transaction(unsigned msg_type,
                                    struct xenbus_file_priv *u)
 {
        int rc;
-       void *reply;
        struct xenbus_transaction_holder *trans = NULL;
-       LIST_HEAD(staging_q);
 
        if (msg_type == XS_TRANSACTION_START) {
-               trans = kmalloc(sizeof(*trans), GFP_KERNEL);
+               trans = kzalloc(sizeof(*trans), GFP_KERNEL);
                if (!trans) {
                        rc = -ENOMEM;
                        goto out;
                }
-       } else if (u->u.msg.tx_id != 0) {
-               list_for_each_entry(trans, &u->transactions, list)
-                       if (trans->handle.id == u->u.msg.tx_id)
-                               break;
-               if (&trans->list == &u->transactions)
-                       return xenbus_command_reply(u, XS_ERROR, "ENOENT");
-       }
-
-       reply = xenbus_dev_request_and_reply(&u->u.msg);
-       if (IS_ERR(reply)) {
-               if (msg_type == XS_TRANSACTION_START)
-                       kfree(trans);
-               rc = PTR_ERR(reply);
-               goto out;
-       }
+               list_add(&trans->list, &u->transactions);
+       } else if (u->u.msg.tx_id != 0 &&
+                  !xenbus_get_transaction(u, u->u.msg.tx_id))
+               return xenbus_command_reply(u, XS_ERROR, "ENOENT");
 
-       if (msg_type == XS_TRANSACTION_START) {
-               if (u->u.msg.type == XS_ERROR)
-                       kfree(trans);
-               else {
-                       trans->handle.id = simple_strtoul(reply, NULL, 0);
-                       list_add(&trans->list, &u->transactions);
-               }
-       } else if (u->u.msg.type == XS_TRANSACTION_END) {
-               list_del(&trans->list);
+       rc = xenbus_dev_request_and_reply(&u->u.msg, u);
+       if (rc)
                kfree(trans);
-       }
-
-       mutex_lock(&u->reply_mutex);
-       rc = queue_reply(&staging_q, &u->u.msg, sizeof(u->u.msg));
-       if (!rc)
-               rc = queue_reply(&staging_q, reply, u->u.msg.len);
-       if (!rc) {
-               list_splice_tail(&staging_q, &u->read_buffers);
-               wake_up(&u->read_waitq);
-       } else {
-               queue_cleanup(&staging_q);
-       }
-       mutex_unlock(&u->reply_mutex);
-
-       kfree(reply);
 
 out:
        return rc;
@@ -511,6 +576,8 @@ static ssize_t xenbus_file_write(struct file *filp,
         * OK, now we have a complete message.  Do something with it.
         */
 
+       kref_get(&u->kref);
+
        msg_type = u->u.msg.type;
 
        switch (msg_type) {
@@ -525,8 +592,10 @@ static ssize_t xenbus_file_write(struct file *filp,
                ret = xenbus_write_transaction(msg_type, u);
                break;
        }
-       if (ret != 0)
+       if (ret != 0) {
                rc = ret;
+               kref_put(&u->kref, xenbus_file_free);
+       }
 
        /* Buffered message consumed */
        u->len = 0;
@@ -551,6 +620,8 @@ static int xenbus_file_open(struct inode *inode, struct file *filp)
        if (u == NULL)
                return -ENOMEM;
 
+       kref_init(&u->kref);
+
        INIT_LIST_HEAD(&u->transactions);
        INIT_LIST_HEAD(&u->watches);
        INIT_LIST_HEAD(&u->read_buffers);
@@ -567,32 +638,8 @@ static int xenbus_file_open(struct inode *inode, struct file *filp)
 static int xenbus_file_release(struct inode *inode, struct file *filp)
 {
        struct xenbus_file_priv *u = filp->private_data;
-       struct xenbus_transaction_holder *trans, *tmp;
-       struct watch_adapter *watch, *tmp_watch;
-       struct read_buffer *rb, *tmp_rb;
-
-       /*
-        * No need for locking here because there are no other users,
-        * by definition.
-        */
-
-       list_for_each_entry_safe(trans, tmp, &u->transactions, list) {
-               xenbus_transaction_end(trans->handle, 1);
-               list_del(&trans->list);
-               kfree(trans);
-       }
-
-       list_for_each_entry_safe(watch, tmp_watch, &u->watches, list) {
-               unregister_xenbus_watch(&watch->watch);
-               list_del(&watch->list);
-               free_watch_adapter(watch);
-       }
 
-       list_for_each_entry_safe(rb, tmp_rb, &u->read_buffers, list) {
-               list_del(&rb->list);
-               kfree(rb);
-       }
-       kfree(u);
+       kref_put(&u->kref, xenbus_file_free);
 
        return 0;
 }
index 4bdf654041e98c6f6485c18d8d5c704f46165a79..74888cacd0b0bdcd250135e6436e0c1e39fc330f 100644 (file)
@@ -62,8 +62,7 @@
 
 #include <xen/hvm.h>
 
-#include "xenbus_comms.h"
-#include "xenbus_probe.h"
+#include "xenbus.h"
 
 
 int xen_store_evtchn;
@@ -170,7 +169,7 @@ int xenbus_read_otherend_details(struct xenbus_device *xendev,
 EXPORT_SYMBOL_GPL(xenbus_read_otherend_details);
 
 void xenbus_otherend_changed(struct xenbus_watch *watch,
-                            const char **vec, unsigned int len,
+                            const char *path, const char *token,
                             int ignore_on_shutdown)
 {
        struct xenbus_device *dev =
@@ -181,18 +180,15 @@ void xenbus_otherend_changed(struct xenbus_watch *watch,
        /* Protect us against watches firing on old details when the otherend
           details change, say immediately after a resume. */
        if (!dev->otherend ||
-           strncmp(dev->otherend, vec[XS_WATCH_PATH],
-                   strlen(dev->otherend))) {
-               dev_dbg(&dev->dev, "Ignoring watch at %s\n",
-                       vec[XS_WATCH_PATH]);
+           strncmp(dev->otherend, path, strlen(dev->otherend))) {
+               dev_dbg(&dev->dev, "Ignoring watch at %s\n", path);
                return;
        }
 
        state = xenbus_read_driver_state(dev->otherend);
 
        dev_dbg(&dev->dev, "state is %d, (%s), %s, %s\n",
-               state, xenbus_strstate(state), dev->otherend_watch.node,
-               vec[XS_WATCH_PATH]);
+               state, xenbus_strstate(state), dev->otherend_watch.node, path);
 
        /*
         * Ignore xenbus transitions during shutdown. This prevents us doing
diff --git a/drivers/xen/xenbus/xenbus_probe.h b/drivers/xen/xenbus/xenbus_probe.h
deleted file mode 100644 (file)
index c9ec7ca..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/******************************************************************************
- * xenbus_probe.h
- *
- * Talks to Xen Store to figure out what devices we have.
- *
- * Copyright (C) 2005 Rusty Russell, IBM Corporation
- * Copyright (C) 2005 XenSource 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; or, when distributed
- * separately from the Linux kernel or incorporated into other
- * software packages, subject to the following license:
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this source file (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy, modify,
- * merge, publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * 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 _XENBUS_PROBE_H
-#define _XENBUS_PROBE_H
-
-#define XEN_BUS_ID_SIZE                        20
-
-struct xen_bus_type {
-       char *root;
-       unsigned int levels;
-       int (*get_bus_id)(char bus_id[XEN_BUS_ID_SIZE], const char *nodename);
-       int (*probe)(struct xen_bus_type *bus, const char *type,
-                    const char *dir);
-       void (*otherend_changed)(struct xenbus_watch *watch, const char **vec,
-                                unsigned int len);
-       struct bus_type bus;
-};
-
-enum xenstore_init {
-       XS_UNKNOWN,
-       XS_PV,
-       XS_HVM,
-       XS_LOCAL,
-};
-
-extern const struct attribute_group *xenbus_dev_groups[];
-
-extern int xenbus_match(struct device *_dev, struct device_driver *_drv);
-extern int xenbus_dev_probe(struct device *_dev);
-extern int xenbus_dev_remove(struct device *_dev);
-extern int xenbus_register_driver_common(struct xenbus_driver *drv,
-                                        struct xen_bus_type *bus,
-                                        struct module *owner,
-                                        const char *mod_name);
-extern int xenbus_probe_node(struct xen_bus_type *bus,
-                            const char *type,
-                            const char *nodename);
-extern int xenbus_probe_devices(struct xen_bus_type *bus);
-
-extern void xenbus_dev_changed(const char *node, struct xen_bus_type *bus);
-
-extern void xenbus_dev_shutdown(struct device *_dev);
-
-extern int xenbus_dev_suspend(struct device *dev);
-extern int xenbus_dev_resume(struct device *dev);
-extern int xenbus_dev_cancel(struct device *dev);
-
-extern void xenbus_otherend_changed(struct xenbus_watch *watch,
-                                   const char **vec, unsigned int len,
-                                   int ignore_on_shutdown);
-
-extern int xenbus_read_otherend_details(struct xenbus_device *xendev,
-                                       char *id_node, char *path_node);
-
-void xenbus_ring_ops_init(void);
-
-#endif
index 37929df829a31898fcf786398e71127b2e25d2bf..b0bed4faf44cc85a918a4fdb8a3929b846c13ec8 100644 (file)
@@ -53,8 +53,7 @@
 #include <xen/xenbus.h>
 #include <xen/features.h>
 
-#include "xenbus_comms.h"
-#include "xenbus_probe.h"
+#include "xenbus.h"
 
 /* backend/<type>/<fe-uuid>/<id> => <type>-<fe-domid>-<id> */
 static int backend_bus_id(char bus_id[XEN_BUS_ID_SIZE], const char *nodename)
@@ -182,9 +181,9 @@ static int xenbus_probe_backend(struct xen_bus_type *bus, const char *type,
 }
 
 static void frontend_changed(struct xenbus_watch *watch,
-                           const char **vec, unsigned int len)
+                            const char *path, const char *token)
 {
-       xenbus_otherend_changed(watch, vec, len, 0);
+       xenbus_otherend_changed(watch, path, token, 0);
 }
 
 static struct xen_bus_type xenbus_backend = {
@@ -205,11 +204,11 @@ static struct xen_bus_type xenbus_backend = {
 };
 
 static void backend_changed(struct xenbus_watch *watch,
-                           const char **vec, unsigned int len)
+                           const char *path, const char *token)
 {
        DPRINTK("");
 
-       xenbus_dev_changed(vec[XS_WATCH_PATH], &xenbus_backend);
+       xenbus_dev_changed(path, &xenbus_backend);
 }
 
 static struct xenbus_watch be_watch = {
index 6d40a972ffb24585c7e386d5817f53672841e0fc..19e45ce21f891e19dc82e01e30cc5aedeb79a951 100644 (file)
@@ -27,8 +27,7 @@
 
 #include <xen/platform_pci.h>
 
-#include "xenbus_comms.h"
-#include "xenbus_probe.h"
+#include "xenbus.h"
 
 
 
@@ -87,9 +86,9 @@ static int xenbus_uevent_frontend(struct device *_dev,
 
 
 static void backend_changed(struct xenbus_watch *watch,
-                           const char **vec, unsigned int len)
+                           const char *path, const char *token)
 {
-       xenbus_otherend_changed(watch, vec, len, 1);
+       xenbus_otherend_changed(watch, path, token, 1);
 }
 
 static void xenbus_frontend_delayed_resume(struct work_struct *w)
@@ -154,11 +153,11 @@ static struct xen_bus_type xenbus_frontend = {
 };
 
 static void frontend_changed(struct xenbus_watch *watch,
-                            const char **vec, unsigned int len)
+                            const char *path, const char *token)
 {
        DPRINTK("");
 
-       xenbus_dev_changed(vec[XS_WATCH_PATH], &xenbus_frontend);
+       xenbus_dev_changed(path, &xenbus_frontend);
 }
 
 
@@ -333,13 +332,13 @@ static DECLARE_WAIT_QUEUE_HEAD(backend_state_wq);
 static int backend_state;
 
 static void xenbus_reset_backend_state_changed(struct xenbus_watch *w,
-                                       const char **v, unsigned int l)
+                                       const char *path, const char *token)
 {
-       if (xenbus_scanf(XBT_NIL, v[XS_WATCH_PATH], "", "%i",
+       if (xenbus_scanf(XBT_NIL, path, "", "%i",
                         &backend_state) != 1)
                backend_state = XenbusStateUnknown;
        printk(KERN_DEBUG "XENBUS: backend %s %s\n",
-                       v[XS_WATCH_PATH], xenbus_strstate(backend_state));
+              path, xenbus_strstate(backend_state));
        wake_up(&backend_state_wq);
 }
 
index 6afb993c58094448b1a2783845bd49028154cbfe..e460802149555b6f0d5def7659d8e8207828eb53 100644 (file)
 #include <linux/slab.h>
 #include <linux/fcntl.h>
 #include <linux/kthread.h>
+#include <linux/reboot.h>
 #include <linux/rwsem.h>
 #include <linux/mutex.h>
 #include <asm/xen/hypervisor.h>
 #include <xen/xenbus.h>
 #include <xen/xen.h>
-#include "xenbus_comms.h"
-#include "xenbus_probe.h"
-
-struct xs_stored_msg {
-       struct list_head list;
-
-       struct xsd_sockmsg hdr;
-
-       union {
-               /* Queued replies. */
-               struct {
-                       char *body;
-               } reply;
-
-               /* Queued watch events. */
-               struct {
-                       struct xenbus_watch *handle;
-                       char **vec;
-                       unsigned int vec_size;
-               } watch;
-       } u;
-};
+#include "xenbus.h"
 
-struct xs_handle {
-       /* A list of replies. Currently only one will ever be outstanding. */
-       struct list_head reply_list;
-       spinlock_t reply_lock;
-       wait_queue_head_t reply_waitq;
-
-       /*
-        * Mutex ordering: transaction_mutex -> watch_mutex -> request_mutex.
-        * response_mutex is never taken simultaneously with the other three.
-        *
-        * transaction_mutex must be held before incrementing
-        * transaction_count. The mutex is held when a suspend is in
-        * progress to prevent new transactions starting.
-        *
-        * When decrementing transaction_count to zero the wait queue
-        * should be woken up, the suspend code waits for count to
-        * reach zero.
-        */
-
-       /* One request at a time. */
-       struct mutex request_mutex;
-
-       /* Protect xenbus reader thread against save/restore. */
-       struct mutex response_mutex;
-
-       /* Protect transactions against save/restore. */
-       struct mutex transaction_mutex;
-       atomic_t transaction_count;
-       wait_queue_head_t transaction_wq;
-
-       /* Protect watch (de)register against save/restore. */
-       struct rw_semaphore watch_mutex;
-};
+/*
+ * Framework to protect suspend/resume handling against normal Xenstore
+ * message handling:
+ * During suspend/resume there must be no open transaction and no pending
+ * Xenstore request.
+ * New watch events happening in this time can be ignored by firing all watches
+ * after resume.
+ */
+
+/* Lock protecting enter/exit critical region. */
+static DEFINE_SPINLOCK(xs_state_lock);
+/* Number of users in critical region (protected by xs_state_lock). */
+static unsigned int xs_state_users;
+/* Suspend handler waiting or already active (protected by xs_state_lock)? */
+static int xs_suspend_active;
+/* Unique Xenstore request id (protected by xs_state_lock). */
+static uint32_t xs_request_id;
 
-static struct xs_handle xs_state;
+/* Wait queue for all callers waiting for critical region to become usable. */
+static DECLARE_WAIT_QUEUE_HEAD(xs_state_enter_wq);
+/* Wait queue for suspend handling waiting for critical region being empty. */
+static DECLARE_WAIT_QUEUE_HEAD(xs_state_exit_wq);
 
 /* List of registered watches, and a lock to protect it. */
 static LIST_HEAD(watches);
@@ -115,6 +82,9 @@ static DEFINE_SPINLOCK(watches_lock);
 static LIST_HEAD(watch_events);
 static DEFINE_SPINLOCK(watch_events_lock);
 
+/* Protect watch (de)register against save/restore. */
+static DECLARE_RWSEM(xs_watch_rwsem);
+
 /*
  * Details of the xenwatch callback kernel thread. The thread waits on the
  * watch_events_waitq for work to do (queued on watch_events list). When it
@@ -125,6 +95,59 @@ static pid_t xenwatch_pid;
 static DEFINE_MUTEX(xenwatch_mutex);
 static DECLARE_WAIT_QUEUE_HEAD(watch_events_waitq);
 
+static void xs_suspend_enter(void)
+{
+       spin_lock(&xs_state_lock);
+       xs_suspend_active++;
+       spin_unlock(&xs_state_lock);
+       wait_event(xs_state_exit_wq, xs_state_users == 0);
+}
+
+static void xs_suspend_exit(void)
+{
+       spin_lock(&xs_state_lock);
+       xs_suspend_active--;
+       spin_unlock(&xs_state_lock);
+       wake_up_all(&xs_state_enter_wq);
+}
+
+static uint32_t xs_request_enter(struct xb_req_data *req)
+{
+       uint32_t rq_id;
+
+       req->type = req->msg.type;
+
+       spin_lock(&xs_state_lock);
+
+       while (!xs_state_users && xs_suspend_active) {
+               spin_unlock(&xs_state_lock);
+               wait_event(xs_state_enter_wq, xs_suspend_active == 0);
+               spin_lock(&xs_state_lock);
+       }
+
+       if (req->type == XS_TRANSACTION_START)
+               xs_state_users++;
+       xs_state_users++;
+       rq_id = xs_request_id++;
+
+       spin_unlock(&xs_state_lock);
+
+       return rq_id;
+}
+
+void xs_request_exit(struct xb_req_data *req)
+{
+       spin_lock(&xs_state_lock);
+       xs_state_users--;
+       if ((req->type == XS_TRANSACTION_START && req->msg.type == XS_ERROR) ||
+           req->type == XS_TRANSACTION_END)
+               xs_state_users--;
+       spin_unlock(&xs_state_lock);
+
+       if (xs_suspend_active && !xs_state_users)
+               wake_up(&xs_state_exit_wq);
+}
+
 static int get_error(const char *errorstring)
 {
        unsigned int i;
@@ -162,21 +185,24 @@ static bool xenbus_ok(void)
        }
        return false;
 }
-static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len)
+
+static bool test_reply(struct xb_req_data *req)
 {
-       struct xs_stored_msg *msg;
-       char *body;
+       if (req->state == xb_req_state_got_reply || !xenbus_ok())
+               return true;
+
+       /* Make sure to reread req->state each time. */
+       barrier();
 
-       spin_lock(&xs_state.reply_lock);
+       return false;
+}
+
+static void *read_reply(struct xb_req_data *req)
+{
+       while (req->state != xb_req_state_got_reply) {
+               wait_event(req->wq, test_reply(req));
 
-       while (list_empty(&xs_state.reply_list)) {
-               spin_unlock(&xs_state.reply_lock);
-               if (xenbus_ok())
-                       /* XXX FIXME: Avoid synchronous wait for response here. */
-                       wait_event_timeout(xs_state.reply_waitq,
-                                          !list_empty(&xs_state.reply_list),
-                                          msecs_to_jiffies(500));
-               else {
+               if (!xenbus_ok())
                        /*
                         * If we are in the process of being shut-down there is
                         * no point of trying to contact XenBus - it is either
@@ -184,76 +210,82 @@ static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len)
                         * has been killed or is unreachable.
                         */
                        return ERR_PTR(-EIO);
-               }
-               spin_lock(&xs_state.reply_lock);
+               if (req->err)
+                       return ERR_PTR(req->err);
+
        }
 
-       msg = list_entry(xs_state.reply_list.next,
-                        struct xs_stored_msg, list);
-       list_del(&msg->list);
+       return req->body;
+}
 
-       spin_unlock(&xs_state.reply_lock);
+static void xs_send(struct xb_req_data *req, struct xsd_sockmsg *msg)
+{
+       bool notify;
 
-       *type = msg->hdr.type;
-       if (len)
-               *len = msg->hdr.len;
-       body = msg->u.reply.body;
+       req->msg = *msg;
+       req->err = 0;
+       req->state = xb_req_state_queued;
+       init_waitqueue_head(&req->wq);
 
-       kfree(msg);
+       req->msg.req_id = xs_request_enter(req);
 
-       return body;
-}
+       mutex_lock(&xb_write_mutex);
+       list_add_tail(&req->list, &xb_write_list);
+       notify = list_is_singular(&xb_write_list);
+       mutex_unlock(&xb_write_mutex);
 
-static void transaction_start(void)
-{
-       mutex_lock(&xs_state.transaction_mutex);
-       atomic_inc(&xs_state.transaction_count);
-       mutex_unlock(&xs_state.transaction_mutex);
+       if (notify)
+               wake_up(&xb_waitq);
 }
 
-static void transaction_end(void)
+static void *xs_wait_for_reply(struct xb_req_data *req, struct xsd_sockmsg *msg)
 {
-       if (atomic_dec_and_test(&xs_state.transaction_count))
-               wake_up(&xs_state.transaction_wq);
-}
+       void *ret;
 
-static void transaction_suspend(void)
-{
-       mutex_lock(&xs_state.transaction_mutex);
-       wait_event(xs_state.transaction_wq,
-                  atomic_read(&xs_state.transaction_count) == 0);
+       ret = read_reply(req);
+
+       xs_request_exit(req);
+
+       msg->type = req->msg.type;
+       msg->len = req->msg.len;
+
+       mutex_lock(&xb_write_mutex);
+       if (req->state == xb_req_state_queued ||
+           req->state == xb_req_state_wait_reply)
+               req->state = xb_req_state_aborted;
+       else
+               kfree(req);
+       mutex_unlock(&xb_write_mutex);
+
+       return ret;
 }
 
-static void transaction_resume(void)
+static void xs_wake_up(struct xb_req_data *req)
 {
-       mutex_unlock(&xs_state.transaction_mutex);
+       wake_up(&req->wq);
 }
 
-void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg)
+int xenbus_dev_request_and_reply(struct xsd_sockmsg *msg, void *par)
 {
-       void *ret;
-       enum xsd_sockmsg_type type = msg->type;
-       int err;
-
-       if (type == XS_TRANSACTION_START)
-               transaction_start();
+       struct xb_req_data *req;
+       struct kvec *vec;
 
-       mutex_lock(&xs_state.request_mutex);
+       req = kmalloc(sizeof(*req) + sizeof(*vec), GFP_KERNEL);
+       if (!req)
+               return -ENOMEM;
 
-       err = xb_write(msg, sizeof(*msg) + msg->len);
-       if (err) {
-               msg->type = XS_ERROR;
-               ret = ERR_PTR(err);
-       } else
-               ret = read_reply(&msg->type, &msg->len);
+       vec = (struct kvec *)(req + 1);
+       vec->iov_len = msg->len;
+       vec->iov_base = msg + 1;
 
-       mutex_unlock(&xs_state.request_mutex);
+       req->vec = vec;
+       req->num_vecs = 1;
+       req->cb = xenbus_dev_queue_reply;
+       req->par = par;
 
-       if ((msg->type == XS_TRANSACTION_END) ||
-           ((type == XS_TRANSACTION_START) && (msg->type == XS_ERROR)))
-               transaction_end();
+       xs_send(req, msg);
 
-       return ret;
+       return 0;
 }
 EXPORT_SYMBOL(xenbus_dev_request_and_reply);
 
@@ -264,37 +296,31 @@ static void *xs_talkv(struct xenbus_transaction t,
                      unsigned int num_vecs,
                      unsigned int *len)
 {
+       struct xb_req_data *req;
        struct xsd_sockmsg msg;
        void *ret = NULL;
        unsigned int i;
        int err;
 
+       req = kmalloc(sizeof(*req), GFP_NOIO | __GFP_HIGH);
+       if (!req)
+               return ERR_PTR(-ENOMEM);
+
+       req->vec = iovec;
+       req->num_vecs = num_vecs;
+       req->cb = xs_wake_up;
+
        msg.tx_id = t.id;
-       msg.req_id = 0;
        msg.type = type;
        msg.len = 0;
        for (i = 0; i < num_vecs; i++)
                msg.len += iovec[i].iov_len;
 
-       mutex_lock(&xs_state.request_mutex);
-
-       err = xb_write(&msg, sizeof(msg));
-       if (err) {
-               mutex_unlock(&xs_state.request_mutex);
-               return ERR_PTR(err);
-       }
-
-       for (i = 0; i < num_vecs; i++) {
-               err = xb_write(iovec[i].iov_base, iovec[i].iov_len);
-               if (err) {
-                       mutex_unlock(&xs_state.request_mutex);
-                       return ERR_PTR(err);
-               }
-       }
-
-       ret = read_reply(&msg.type, len);
+       xs_send(req, &msg);
 
-       mutex_unlock(&xs_state.request_mutex);
+       ret = xs_wait_for_reply(req, &msg);
+       if (len)
+               *len = msg.len;
 
        if (IS_ERR(ret))
                return ret;
@@ -501,13 +527,9 @@ int xenbus_transaction_start(struct xenbus_transaction *t)
 {
        char *id_str;
 
-       transaction_start();
-
        id_str = xs_single(XBT_NIL, XS_TRANSACTION_START, "", NULL);
-       if (IS_ERR(id_str)) {
-               transaction_end();
+       if (IS_ERR(id_str))
                return PTR_ERR(id_str);
-       }
 
        t->id = simple_strtoul(id_str, NULL, 0);
        kfree(id_str);
@@ -521,18 +543,13 @@ EXPORT_SYMBOL_GPL(xenbus_transaction_start);
 int xenbus_transaction_end(struct xenbus_transaction t, int abort)
 {
        char abortstr[2];
-       int err;
 
        if (abort)
                strcpy(abortstr, "F");
        else
                strcpy(abortstr, "T");
 
-       err = xs_error(xs_single(t, XS_TRANSACTION_END, abortstr, NULL));
-
-       transaction_end();
-
-       return err;
+       return xs_error(xs_single(t, XS_TRANSACTION_END, abortstr, NULL));
 }
 EXPORT_SYMBOL_GPL(xenbus_transaction_end);
 
@@ -665,6 +682,30 @@ static struct xenbus_watch *find_watch(const char *token)
 
        return NULL;
 }
+
+int xs_watch_msg(struct xs_watch_event *event)
+{
+       if (count_strings(event->body, event->len) != 2) {
+               kfree(event);
+               return -EINVAL;
+       }
+       event->path = (const char *)event->body;
+       event->token = (const char *)strchr(event->body, '\0') + 1;
+
+       spin_lock(&watches_lock);
+       event->handle = find_watch(event->token);
+       if (event->handle != NULL) {
+               spin_lock(&watch_events_lock);
+               list_add_tail(&event->list, &watch_events);
+               wake_up(&watch_events_waitq);
+               spin_unlock(&watch_events_lock);
+       } else
+               kfree(event);
+       spin_unlock(&watches_lock);
+
+       return 0;
+}
+
 /*
  * Certain older XenBus toolstack cannot handle reading values that are
  * not populated. Some Xen 3.4 installation are incapable of doing this
@@ -713,7 +754,7 @@ int register_xenbus_watch(struct xenbus_watch *watch)
 
        sprintf(token, "%lX", (long)watch);
 
-       down_read(&xs_state.watch_mutex);
+       down_read(&xs_watch_rwsem);
 
        spin_lock(&watches_lock);
        BUG_ON(find_watch(token));
@@ -728,7 +769,7 @@ int register_xenbus_watch(struct xenbus_watch *watch)
                spin_unlock(&watches_lock);
        }
 
-       up_read(&xs_state.watch_mutex);
+       up_read(&xs_watch_rwsem);
 
        return err;
 }
@@ -736,13 +777,13 @@ EXPORT_SYMBOL_GPL(register_xenbus_watch);
 
 void unregister_xenbus_watch(struct xenbus_watch *watch)
 {
-       struct xs_stored_msg *msg, *tmp;
+       struct xs_watch_event *event, *tmp;
        char token[sizeof(watch) * 2 + 1];
        int err;
 
        sprintf(token, "%lX", (long)watch);
 
-       down_read(&xs_state.watch_mutex);
+       down_read(&xs_watch_rwsem);
 
        spin_lock(&watches_lock);
        BUG_ON(!find_watch(token));
@@ -753,7 +794,7 @@ void unregister_xenbus_watch(struct xenbus_watch *watch)
        if (err)
                pr_warn("Failed to release watch %s: %i\n", watch->node, err);
 
-       up_read(&xs_state.watch_mutex);
+       up_read(&xs_watch_rwsem);
 
        /* Make sure there are no callbacks running currently (unless
           its us) */
@@ -762,12 +803,11 @@ void unregister_xenbus_watch(struct xenbus_watch *watch)
 
        /* Cancel pending watch events. */
        spin_lock(&watch_events_lock);
-       list_for_each_entry_safe(msg, tmp, &watch_events, list) {
-               if (msg->u.watch.handle != watch)
+       list_for_each_entry_safe(event, tmp, &watch_events, list) {
+               if (event->handle != watch)
                        continue;
-               list_del(&msg->list);
-               kfree(msg->u.watch.vec);
-               kfree(msg);
+               list_del(&event->list);
+               kfree(event);
        }
        spin_unlock(&watch_events_lock);
 
@@ -778,10 +818,10 @@ EXPORT_SYMBOL_GPL(unregister_xenbus_watch);
 
 void xs_suspend(void)
 {
-       transaction_suspend();
-       down_write(&xs_state.watch_mutex);
-       mutex_lock(&xs_state.request_mutex);
-       mutex_lock(&xs_state.response_mutex);
+       xs_suspend_enter();
+
+       down_write(&xs_watch_rwsem);
+       mutex_lock(&xs_response_mutex);
 }
 
 void xs_resume(void)
@@ -791,31 +831,31 @@ void xs_resume(void)
 
        xb_init_comms();
 
-       mutex_unlock(&xs_state.response_mutex);
-       mutex_unlock(&xs_state.request_mutex);
-       transaction_resume();
+       mutex_unlock(&xs_response_mutex);
+
+       xs_suspend_exit();
 
-       /* No need for watches_lock: the watch_mutex is sufficient. */
+       /* No need for watches_lock: the xs_watch_rwsem is sufficient. */
        list_for_each_entry(watch, &watches, list) {
                sprintf(token, "%lX", (long)watch);
                xs_watch(watch->node, token);
        }
 
-       up_write(&xs_state.watch_mutex);
+       up_write(&xs_watch_rwsem);
 }
 
 void xs_suspend_cancel(void)
 {
-       mutex_unlock(&xs_state.response_mutex);
-       mutex_unlock(&xs_state.request_mutex);
-       up_write(&xs_state.watch_mutex);
-       mutex_unlock(&xs_state.transaction_mutex);
+       mutex_unlock(&xs_response_mutex);
+       up_write(&xs_watch_rwsem);
+
+       xs_suspend_exit();
 }
 
 static int xenwatch_thread(void *unused)
 {
        struct list_head *ent;
-       struct xs_stored_msg *msg;
+       struct xs_watch_event *event;
 
        for (;;) {
                wait_event_interruptible(watch_events_waitq,
@@ -833,13 +873,10 @@ static int xenwatch_thread(void *unused)
                spin_unlock(&watch_events_lock);
 
                if (ent != &watch_events) {
-                       msg = list_entry(ent, struct xs_stored_msg, list);
-                       msg->u.watch.handle->callback(
-                               msg->u.watch.handle,
-                               (const char **)msg->u.watch.vec,
-                               msg->u.watch.vec_size);
-                       kfree(msg->u.watch.vec);
-                       kfree(msg);
+                       event = list_entry(ent, struct xs_watch_event, list);
+                       event->handle->callback(event->handle, event->path,
+                                               event->token);
+                       kfree(event);
                }
 
                mutex_unlock(&xenwatch_mutex);
@@ -848,126 +885,37 @@ static int xenwatch_thread(void *unused)
        return 0;
 }
 
-static int process_msg(void)
+/*
+ * Wake up all threads waiting for a xenstore reply. In case of shutdown all
+ * pending replies will be marked as "aborted" in order to let the waiters
+ * return in spite of xenstore possibly no longer being able to reply. This
+ * will avoid blocking shutdown by a thread waiting for xenstore but being
+ * necessary for shutdown processing to proceed.
+ */
+static int xs_reboot_notify(struct notifier_block *nb,
+                           unsigned long code, void *unused)
 {
-       struct xs_stored_msg *msg;
-       char *body;
-       int err;
-
-       /*
-        * We must disallow save/restore while reading a xenstore message.
-        * A partial read across s/r leaves us out of sync with xenstored.
-        */
-       for (;;) {
-               err = xb_wait_for_data_to_read();
-               if (err)
-                       return err;
-               mutex_lock(&xs_state.response_mutex);
-               if (xb_data_to_read())
-                       break;
-               /* We raced with save/restore: pending data 'disappeared'. */
-               mutex_unlock(&xs_state.response_mutex);
-       }
-
-
-       msg = kmalloc(sizeof(*msg), GFP_NOIO | __GFP_HIGH);
-       if (msg == NULL) {
-               err = -ENOMEM;
-               goto out;
-       }
-
-       err = xb_read(&msg->hdr, sizeof(msg->hdr));
-       if (err) {
-               kfree(msg);
-               goto out;
-       }
-
-       if (msg->hdr.len > XENSTORE_PAYLOAD_MAX) {
-               kfree(msg);
-               err = -EINVAL;
-               goto out;
-       }
-
-       body = kmalloc(msg->hdr.len + 1, GFP_NOIO | __GFP_HIGH);
-       if (body == NULL) {
-               kfree(msg);
-               err = -ENOMEM;
-               goto out;
-       }
-
-       err = xb_read(body, msg->hdr.len);
-       if (err) {
-               kfree(body);
-               kfree(msg);
-               goto out;
-       }
-       body[msg->hdr.len] = '\0';
-
-       if (msg->hdr.type == XS_WATCH_EVENT) {
-               msg->u.watch.vec = split(body, msg->hdr.len,
-                                        &msg->u.watch.vec_size);
-               if (IS_ERR(msg->u.watch.vec)) {
-                       err = PTR_ERR(msg->u.watch.vec);
-                       kfree(msg);
-                       goto out;
-               }
-
-               spin_lock(&watches_lock);
-               msg->u.watch.handle = find_watch(
-                       msg->u.watch.vec[XS_WATCH_TOKEN]);
-               if (msg->u.watch.handle != NULL) {
-                       spin_lock(&watch_events_lock);
-                       list_add_tail(&msg->list, &watch_events);
-                       wake_up(&watch_events_waitq);
-                       spin_unlock(&watch_events_lock);
-               } else {
-                       kfree(msg->u.watch.vec);
-                       kfree(msg);
-               }
-               spin_unlock(&watches_lock);
-       } else {
-               msg->u.reply.body = body;
-               spin_lock(&xs_state.reply_lock);
-               list_add_tail(&msg->list, &xs_state.reply_list);
-               spin_unlock(&xs_state.reply_lock);
-               wake_up(&xs_state.reply_waitq);
-       }
+       struct xb_req_data *req;
 
- out:
-       mutex_unlock(&xs_state.response_mutex);
-       return err;
+       mutex_lock(&xb_write_mutex);
+       list_for_each_entry(req, &xs_reply_list, list)
+               wake_up(&req->wq);
+       list_for_each_entry(req, &xb_write_list, list)
+               wake_up(&req->wq);
+       mutex_unlock(&xb_write_mutex);
+       return NOTIFY_DONE;
 }
 
-static int xenbus_thread(void *unused)
-{
-       int err;
-
-       for (;;) {
-               err = process_msg();
-               if (err)
-                       pr_warn("error %d while reading message\n", err);
-               if (kthread_should_stop())
-                       break;
-       }
-
-       return 0;
-}
+static struct notifier_block xs_reboot_nb = {
+       .notifier_call = xs_reboot_notify,
+};
 
 int xs_init(void)
 {
        int err;
        struct task_struct *task;
 
-       INIT_LIST_HEAD(&xs_state.reply_list);
-       spin_lock_init(&xs_state.reply_lock);
-       init_waitqueue_head(&xs_state.reply_waitq);
-
-       mutex_init(&xs_state.request_mutex);
-       mutex_init(&xs_state.response_mutex);
-       mutex_init(&xs_state.transaction_mutex);
-       init_rwsem(&xs_state.watch_mutex);
-       atomic_set(&xs_state.transaction_count, 0);
-       init_waitqueue_head(&xs_state.transaction_wq);
+       register_reboot_notifier(&xs_reboot_nb);
 
        /* Initialize the shared memory rings to talk to xenstored */
        err = xb_init_comms();
@@ -979,10 +927,6 @@ int xs_init(void)
                return PTR_ERR(task);
        xenwatch_pid = task->pid;
 
-       task = kthread_run(xenbus_thread, NULL, "xenbus");
-       if (IS_ERR(task))
-               return PTR_ERR(task);
-
        /* shutdown watches for kexec boot */
        xs_reset_watches();
 
index 8559a71f36b1a7d6fe2bd2b57b588321ad92f26c..328c3987b112dcf84fe40005d936bfbfed601f91 100644 (file)
 #include <linux/magic.h>
 
 #include <xen/xen.h>
+#include <xen/xenbus.h>
 
 #include "xenfs.h"
 #include "../privcmd.h"
-#include "../xenbus/xenbus_comms.h"
 
 #include <asm/xen/hypervisor.h>
 
index fef20dbc6a5c2dfada86792f4eea7e7a631085e8..82fd2a396d96b27260e3320fb57a1ffc101fe32c 100644 (file)
@@ -4,9 +4,9 @@
 #include <linux/fs.h>
 
 #include <xen/page.h>
+#include <xen/xenbus.h>
 
 #include "xenfs.h"
-#include "../xenbus/xenbus_comms.h"
 
 static ssize_t xsd_read(struct file *file, char __user *buf,
                            size_t size, loff_t *off)
index 3c47614a4b32c75c4d5cf75d436389305c145288..73031ec54a7be5ff34be619581cb20cef81cb8f5 100644 (file)
@@ -884,6 +884,8 @@ static void bdev_evict_inode(struct inode *inode)
        spin_lock(&bdev_lock);
        list_del_init(&bdev->bd_list);
        spin_unlock(&bdev_lock);
+       if (bdev->bd_bdi != &noop_backing_dev_info)
+               bdi_put(bdev->bd_bdi);
 }
 
 static const struct super_operations bdev_sops = {
@@ -954,6 +956,21 @@ static int bdev_set(struct inode *inode, void *data)
 
 static LIST_HEAD(all_bdevs);
 
+/*
+ * If there is a bdev inode for this device, unhash it so that it gets evicted
+ * as soon as last inode reference is dropped.
+ */
+void bdev_unhash_inode(dev_t dev)
+{
+       struct inode *inode;
+
+       inode = ilookup5(blockdev_superblock, hash(dev), bdev_test, &dev);
+       if (inode) {
+               remove_inode_hash(inode);
+               iput(inode);
+       }
+}
+
 struct block_device *bdget(dev_t dev)
 {
        struct block_device *bdev;
@@ -971,6 +988,7 @@ struct block_device *bdget(dev_t dev)
                bdev->bd_contains = NULL;
                bdev->bd_super = NULL;
                bdev->bd_inode = inode;
+               bdev->bd_bdi = &noop_backing_dev_info;
                bdev->bd_block_size = (1 << inode->i_blkbits);
                bdev->bd_part_count = 0;
                bdev->bd_invalidated = 0;
@@ -1527,6 +1545,8 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
                bdev->bd_disk = disk;
                bdev->bd_queue = disk->queue;
                bdev->bd_contains = bdev;
+               if (bdev->bd_bdi == &noop_backing_dev_info)
+                       bdev->bd_bdi = bdi_get(disk->queue->backing_dev_info);
 
                if (!partno) {
                        ret = -ENXIO;
@@ -1622,6 +1642,8 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
        bdev->bd_disk = NULL;
        bdev->bd_part = NULL;
        bdev->bd_queue = NULL;
+       bdi_put(bdev->bd_bdi);
+       bdev->bd_bdi = &noop_backing_dev_info;
        if (bdev != bdev->bd_contains)
                __blkdev_put(bdev->bd_contains, mode, 1);
        bdev->bd_contains = NULL;
index 18004169552c6527511a888a2e936be265e01aba..37a31b12bb0c02e40c183d3ad57dfdf7879efa91 100644 (file)
@@ -1800,7 +1800,7 @@ static int btrfs_congested_fn(void *congested_data, int bdi_bits)
        list_for_each_entry_rcu(device, &info->fs_devices->devices, dev_list) {
                if (!device->bdev)
                        continue;
-               bdi = blk_get_backing_dev_info(device->bdev);
+               bdi = device->bdev->bd_bdi;
                if (bdi_congested(bdi, bdi_bits)) {
                        ret = 1;
                        break;
index 3c3c69c0eee41494d751b2638d20cf6bf0811ca1..b2e70073a10dc3cf3e1bb37771e33ffb8263a8bb 100644 (file)
@@ -366,7 +366,7 @@ static noinline void run_scheduled_bios(struct btrfs_device *device)
         */
        blk_start_plug(&plug);
 
-       bdi = blk_get_backing_dev_info(device->bdev);
+       bdi = device->bdev->bd_bdi;
        limit = btrfs_async_submit_limit(fs_info);
        limit = limit * 2 / 3;
 
index e7b478b4998532231278ca1c07be4481c1951576..034f00f213902332816a10746560478b1e5fc16e 100644 (file)
@@ -9,8 +9,6 @@ config CIFS
        select CRYPTO_ARC4
        select CRYPTO_ECB
        select CRYPTO_DES
-       select CRYPTO_SHA256
-       select CRYPTO_CMAC
        help
          This is the client VFS module for the Common Internet File System
          (CIFS) protocol which is the successor to the Server Message Block
@@ -169,11 +167,15 @@ config CIFS_NFSD_EXPORT
 
 config CIFS_SMB2
        bool "SMB2 and SMB3 network file system support"
-       depends on CIFS && INET
-       select NLS
+       depends on CIFS
        select KEYS
        select FSCACHE
        select DNS_RESOLVER
+       select CRYPTO_AES
+       select CRYPTO_SHA256
+       select CRYPTO_CMAC
+       select CRYPTO_AEAD2
+       select CRYPTO_CCM
 
        help
          This enables support for the Server Message Block version 2
@@ -194,7 +196,7 @@ config CIFS_SMB2
 
 config CIFS_SMB311
        bool "SMB3.1.1 network file system support (Experimental)"
-       depends on CIFS_SMB2 && INET
+       depends on CIFS_SMB2
 
        help
          This enables experimental support for the newest, SMB3.1.1, dialect.
index 66bd7fa9b7a6f739f7f5fda0d0b6fe4c79192a47..058ac9b36f0470a4d04478377cdc12a041df0db4 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/random.h>
 #include <linux/highmem.h>
 #include <crypto/skcipher.h>
+#include <crypto/aead.h>
 
 static int
 cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server)
@@ -75,24 +76,20 @@ int __cifs_calc_signature(struct smb_rqst *rqst,
        struct kvec *iov = rqst->rq_iov;
        int n_vec = rqst->rq_nvec;
 
-       for (i = 0; i < n_vec; i++) {
+       if (n_vec < 2 || iov[0].iov_len != 4)
+               return -EIO;
+
+       for (i = 1; i < n_vec; i++) {
                if (iov[i].iov_len == 0)
                        continue;
                if (iov[i].iov_base == NULL) {
                        cifs_dbg(VFS, "null iovec entry\n");
                        return -EIO;
                }
-               /* The first entry includes a length field (which does not get
-                  signed that occupies the first 4 bytes before the header */
-               if (i == 0) {
-                       if (iov[0].iov_len <= 8) /* cmd field at offset 9 */
-                               break; /* nothing to sign or corrupt header */
-                       rc = crypto_shash_update(shash,
-                               iov[i].iov_base + 4, iov[i].iov_len - 4);
-               } else {
-                       rc = crypto_shash_update(shash,
-                               iov[i].iov_base, iov[i].iov_len);
-               }
+               if (i == 1 && iov[1].iov_len <= 4)
+                       break; /* nothing to sign or corrupt header */
+               rc = crypto_shash_update(shash,
+                                        iov[i].iov_base, iov[i].iov_len);
                if (rc) {
                        cifs_dbg(VFS, "%s: Could not update with payload\n",
                                 __func__);
@@ -168,6 +165,10 @@ int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
        char smb_signature[20];
        struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
 
+       if (rqst->rq_iov[0].iov_len != 4 ||
+           rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
+               return -EIO;
+
        if ((cifs_pdu == NULL) || (server == NULL))
                return -EINVAL;
 
@@ -209,12 +210,14 @@ int cifs_sign_smbv(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
 int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
                  __u32 *pexpected_response_sequence_number)
 {
-       struct kvec iov;
+       struct kvec iov[2];
 
-       iov.iov_base = cifs_pdu;
-       iov.iov_len = be32_to_cpu(cifs_pdu->smb_buf_length) + 4;
+       iov[0].iov_base = cifs_pdu;
+       iov[0].iov_len = 4;
+       iov[1].iov_base = (char *)cifs_pdu + 4;
+       iov[1].iov_len = be32_to_cpu(cifs_pdu->smb_buf_length);
 
-       return cifs_sign_smbv(&iov, 1, server,
+       return cifs_sign_smbv(iov, 2, server,
                              pexpected_response_sequence_number);
 }
 
@@ -227,6 +230,10 @@ int cifs_verify_signature(struct smb_rqst *rqst,
        char what_we_think_sig_should_be[20];
        struct smb_hdr *cifs_pdu = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
 
+       if (rqst->rq_iov[0].iov_len != 4 ||
+           rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
+               return -EIO;
+
        if (cifs_pdu == NULL || server == NULL)
                return -EINVAL;
 
@@ -868,7 +875,7 @@ out:
 }
 
 void
-cifs_crypto_shash_release(struct TCP_Server_Info *server)
+cifs_crypto_secmech_release(struct TCP_Server_Info *server)
 {
        if (server->secmech.cmacaes) {
                crypto_free_shash(server->secmech.cmacaes);
@@ -890,6 +897,16 @@ cifs_crypto_shash_release(struct TCP_Server_Info *server)
                server->secmech.hmacmd5 = NULL;
        }
 
+       if (server->secmech.ccmaesencrypt) {
+               crypto_free_aead(server->secmech.ccmaesencrypt);
+               server->secmech.ccmaesencrypt = NULL;
+       }
+
+       if (server->secmech.ccmaesdecrypt) {
+               crypto_free_aead(server->secmech.ccmaesdecrypt);
+               server->secmech.ccmaesdecrypt = NULL;
+       }
+
        kfree(server->secmech.sdesccmacaes);
        server->secmech.sdesccmacaes = NULL;
        kfree(server->secmech.sdeschmacsha256);
index 70f4e65fced233613746e33422cf6efa4e9b0ea0..15e1db8738aecad0c8a86888c0fa1ada5f9b7623 100644 (file)
@@ -1365,5 +1365,19 @@ MODULE_DESCRIPTION
     ("VFS to access servers complying with the SNIA CIFS Specification "
      "e.g. Samba and Windows");
 MODULE_VERSION(CIFS_VERSION);
+MODULE_SOFTDEP("pre: arc4");
+MODULE_SOFTDEP("pre: des");
+MODULE_SOFTDEP("pre: ecb");
+MODULE_SOFTDEP("pre: hmac");
+MODULE_SOFTDEP("pre: md4");
+MODULE_SOFTDEP("pre: md5");
+MODULE_SOFTDEP("pre: nls");
+#ifdef CONFIG_CIFS_SMB2
+MODULE_SOFTDEP("pre: aes");
+MODULE_SOFTDEP("pre: cmac");
+MODULE_SOFTDEP("pre: sha256");
+MODULE_SOFTDEP("pre: aead2");
+MODULE_SOFTDEP("pre: ccm");
+#endif /* CONFIG_CIFS_SMB2 */
 module_init(init_cifs)
 module_exit(exit_cifs)
index 7ea8a3393936c87976208677d816258eb3a94465..1a90bb3e29866c4f0e9a44e637f75e41469c04f8 100644 (file)
@@ -136,6 +136,8 @@ struct cifs_secmech {
        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 crypto_aead *ccmaesencrypt; /* smb3 encryption aead */
+       struct crypto_aead *ccmaesdecrypt; /* smb3 decryption aead */
 };
 
 /* per smb session structure/fields */
@@ -208,7 +210,7 @@ struct cifsInodeInfo;
 struct cifs_open_parms;
 
 struct smb_version_operations {
-       int (*send_cancel)(struct TCP_Server_Info *, void *,
+       int (*send_cancel)(struct TCP_Server_Info *, struct smb_rqst *,
                           struct mid_q_entry *);
        bool (*compare_fids)(struct cifsFileInfo *, struct cifsFileInfo *);
        /* setup request: allocate mid, sign message */
@@ -433,6 +435,14 @@ struct smb_version_operations {
        bool (*dir_needs_close)(struct cifsFileInfo *);
        long (*fallocate)(struct file *, struct cifs_tcon *, int, loff_t,
                          loff_t);
+       /* init transform request - used for encryption for now */
+       int (*init_transform_rq)(struct TCP_Server_Info *, struct smb_rqst *,
+                                struct smb_rqst *);
+       /* free transform request */
+       void (*free_transform_rq)(struct smb_rqst *);
+       int (*is_transform_hdr)(void *buf);
+       int (*receive_transform)(struct TCP_Server_Info *,
+                                struct mid_q_entry **);
 };
 
 struct smb_version_values {
@@ -1119,7 +1129,10 @@ struct cifs_readdata {
        int (*read_into_pages)(struct TCP_Server_Info *server,
                                struct cifs_readdata *rdata,
                                unsigned int len);
-       struct kvec                     iov;
+       int (*copy_into_pages)(struct TCP_Server_Info *server,
+                               struct cifs_readdata *rdata,
+                               struct iov_iter *iter);
+       struct kvec                     iov[2];
        unsigned int                    pagesz;
        unsigned int                    tailsz;
        unsigned int                    credits;
@@ -1302,6 +1315,13 @@ typedef int (mid_receive_t)(struct TCP_Server_Info *server,
  */
 typedef void (mid_callback_t)(struct mid_q_entry *mid);
 
+/*
+ * This is the protopyte for mid handle function. This is called once the mid
+ * has been recognized after decryption of the message.
+ */
+typedef int (mid_handle_t)(struct TCP_Server_Info *server,
+                           struct mid_q_entry *mid);
+
 /* one of these for every pending CIFS request to the server */
 struct mid_q_entry {
        struct list_head qhead; /* mids waiting on reply from this server */
@@ -1316,6 +1336,7 @@ struct mid_q_entry {
 #endif
        mid_receive_t *receive; /* call receive callback */
        mid_callback_t *callback; /* call completion callback */
+       mid_handle_t *handle; /* call handle mid callback */
        void *callback_data;      /* general purpose pointer for callback */
        void *resp_buf;         /* pointer to received SMB header */
        int mid_state;  /* wish this were enum but can not pass to wait_event */
@@ -1323,6 +1344,7 @@ struct mid_q_entry {
        bool large_buf:1;       /* if valid response, is pointer to large buf */
        bool multiRsp:1;        /* multiple trans2 responses for one request  */
        bool multiEnd:1;        /* both received */
+       bool decrypted:1;       /* decrypted entry */
 };
 
 /*     Make code in transport.c a little cleaner by moving
@@ -1475,7 +1497,9 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param,
 #define   CIFS_OBREAK_OP   0x0100    /* oplock break request */
 #define   CIFS_NEG_OP      0x0200    /* negotiate request */
 #define   CIFS_OP_MASK     0x0380    /* mask request type */
+
 #define   CIFS_HAS_CREDITS 0x0400    /* already has credits */
+#define   CIFS_TRANSFORM_REQ 0x0800    /* transform request before sending */
 
 /* Security Flags: indicate type of session setup needed */
 #define   CIFSSEC_MAY_SIGN     0x00001
index c7b3c841e6604d150e22d2ed40695c2cec3d3d99..406d2c10ba78d0e53d5754fcb17d08586e534cdf 100644 (file)
@@ -75,10 +75,16 @@ extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer,
 extern void DeleteMidQEntry(struct mid_q_entry *midEntry);
 extern void cifs_delete_mid(struct mid_q_entry *mid);
 extern void cifs_wake_up_task(struct mid_q_entry *mid);
+extern int cifs_handle_standard(struct TCP_Server_Info *server,
+                               struct mid_q_entry *mid);
+extern int cifs_discard_remaining_data(struct TCP_Server_Info *server);
 extern int cifs_call_async(struct TCP_Server_Info *server,
                        struct smb_rqst *rqst,
                        mid_receive_t *receive, mid_callback_t *callback,
-                       void *cbdata, const int flags);
+                       mid_handle_t *handle, void *cbdata, const int flags);
+extern int cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
+                         struct smb_rqst *rqst, int *resp_buf_type,
+                         const int flags, struct kvec *resp_iov);
 extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *,
                        struct smb_hdr * /* input */ ,
                        struct smb_hdr * /* out */ ,
@@ -96,7 +102,8 @@ extern int cifs_wait_mtu_credits(struct TCP_Server_Info *server,
                                 unsigned int *credits);
 extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *,
                        struct kvec *, int /* nvec to send */,
-                       int * /* type of buf returned */ , const int flags);
+                       int * /* type of buf returned */, const int flags,
+                       struct kvec * /* resp vec */);
 extern int SendReceiveBlockingLock(const unsigned int xid,
                        struct cifs_tcon *ptcon,
                        struct smb_hdr *in_buf ,
@@ -441,7 +448,7 @@ extern int SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *,
                        const struct nls_table *);
 extern int setup_ntlm_response(struct cifs_ses *, const struct nls_table *);
 extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *);
-extern void cifs_crypto_shash_release(struct TCP_Server_Info *);
+extern void cifs_crypto_secmech_release(struct TCP_Server_Info *server);
 extern int calc_seckey(struct cifs_ses *);
 extern int generate_smb30signingkey(struct cifs_ses *);
 extern int generate_smb311signingkey(struct cifs_ses *);
index b47261858e6ddde793182f1be7040083522867f1..f5099fb8a22f14e4c1ca2b18ff135d6b29de8e01 100644 (file)
@@ -673,6 +673,7 @@ CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
                return rc;
 
        rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
+       cifs_small_buf_release(smb_buffer);
        if (rc)
                cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
 
@@ -707,9 +708,9 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
 {
        ECHO_REQ *smb;
        int rc = 0;
-       struct kvec iov;
-       struct smb_rqst rqst = { .rq_iov = &iov,
-                                .rq_nvec = 1 };
+       struct kvec iov[2];
+       struct smb_rqst rqst = { .rq_iov = iov,
+                                .rq_nvec = 2 };
 
        cifs_dbg(FYI, "In echo request\n");
 
@@ -724,10 +725,13 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
        put_bcc(1, &smb->hdr);
        smb->Data[0] = 'a';
        inc_rfc1001_len(smb, 3);
-       iov.iov_base = smb;
-       iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
 
-       rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback,
+       iov[0].iov_len = 4;
+       iov[0].iov_base = smb;
+       iov[1].iov_len = get_rfc1002_length(smb);
+       iov[1].iov_base = (char *)smb + 4;
+
+       rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
                             server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
        if (rc)
                cifs_dbg(FYI, "Echo request failed: %d\n", rc);
@@ -772,6 +776,7 @@ CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
 
        pSMB->AndXCommand = 0xFF;
        rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
+       cifs_small_buf_release(pSMB);
 session_already_dead:
        mutex_unlock(&ses->session_mutex);
 
@@ -1394,8 +1399,8 @@ openRetry:
  * Discard any remaining data in the current SMB. To do this, we borrow the
  * current bigbuf.
  */
-static int
-discard_remaining_data(struct TCP_Server_Info *server)
+int
+cifs_discard_remaining_data(struct TCP_Server_Info *server)
 {
        unsigned int rfclen = get_rfc1002_length(server->smallbuf);
        int remaining = rfclen + 4 - server->total_read;
@@ -1421,7 +1426,7 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
        int length;
        struct cifs_readdata *rdata = mid->callback_data;
 
-       length = discard_remaining_data(server);
+       length = cifs_discard_remaining_data(server);
        dequeue_mid(mid, rdata->result);
        return length;
 }
@@ -1454,7 +1459,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 
        if (server->ops->is_status_pending &&
            server->ops->is_status_pending(buf, server, 0)) {
-               discard_remaining_data(server);
+               cifs_discard_remaining_data(server);
                return -1;
        }
 
@@ -1507,10 +1512,12 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
        }
 
        /* set up first iov for signature check */
-       rdata->iov.iov_base = buf;
-       rdata->iov.iov_len = server->total_read;
-       cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
-                rdata->iov.iov_base, rdata->iov.iov_len);
+       rdata->iov[0].iov_base = buf;
+       rdata->iov[0].iov_len = 4;
+       rdata->iov[1].iov_base = buf + 4;
+       rdata->iov[1].iov_len = server->total_read - 4;
+       cifs_dbg(FYI, "0: iov_base=%p iov_len=%u\n",
+                rdata->iov[0].iov_base, server->total_read);
 
        /* how much data is in the response? */
        data_len = server->ops->read_data_length(buf);
@@ -1543,8 +1550,8 @@ cifs_readv_callback(struct mid_q_entry *mid)
        struct cifs_readdata *rdata = mid->callback_data;
        struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
        struct TCP_Server_Info *server = tcon->ses->server;
-       struct smb_rqst rqst = { .rq_iov = &rdata->iov,
-                                .rq_nvec = 1,
+       struct smb_rqst rqst = { .rq_iov = rdata->iov,
+                                .rq_nvec = 2,
                                 .rq_pages = rdata->pages,
                                 .rq_npages = rdata->nr_pages,
                                 .rq_pagesz = rdata->pagesz,
@@ -1599,8 +1606,8 @@ cifs_async_readv(struct cifs_readdata *rdata)
        READ_REQ *smb = NULL;
        int wct;
        struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
-       struct smb_rqst rqst = { .rq_iov = &rdata->iov,
-                                .rq_nvec = 1 };
+       struct smb_rqst rqst = { .rq_iov = rdata->iov,
+                                .rq_nvec = 2 };
 
        cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
                 __func__, rdata->offset, rdata->bytes);
@@ -1640,12 +1647,14 @@ cifs_async_readv(struct cifs_readdata *rdata)
        }
 
        /* 4 for RFC1001 length + 1 for BCC */
-       rdata->iov.iov_base = smb;
-       rdata->iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
+       rdata->iov[0].iov_base = smb;
+       rdata->iov[0].iov_len = 4;
+       rdata->iov[1].iov_base = (char *)smb + 4;
+       rdata->iov[1].iov_len = get_rfc1002_length(smb);
 
        kref_get(&rdata->refcount);
        rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
-                            cifs_readv_callback, rdata, 0);
+                            cifs_readv_callback, NULL, rdata, 0);
 
        if (rc == 0)
                cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
@@ -1667,6 +1676,7 @@ CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
        int wct;
        int resp_buf_type = 0;
        struct kvec iov[1];
+       struct kvec rsp_iov;
        __u32 pid = io_parms->pid;
        __u16 netfid = io_parms->netfid;
        __u64 offset = io_parms->offset;
@@ -1716,10 +1726,11 @@ CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
 
        iov[0].iov_base = (char *)pSMB;
        iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
-       rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
-                        &resp_buf_type, CIFS_LOG_ERROR);
+       rc = SendReceive2(xid, tcon->ses, iov, 1, &resp_buf_type,
+                         CIFS_LOG_ERROR, &rsp_iov);
+       cifs_small_buf_release(pSMB);
        cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
-       pSMBr = (READ_RSP *)iov[0].iov_base;
+       pSMBr = (READ_RSP *)rsp_iov.iov_base;
        if (rc) {
                cifs_dbg(VFS, "Send error in read = %d\n", rc);
        } else {
@@ -1747,12 +1758,11 @@ CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
                }
        }
 
-/*     cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
        if (*buf) {
-               free_rsp_buf(resp_buf_type, iov[0].iov_base);
+               free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
        } else if (resp_buf_type != CIFS_NO_BUFFER) {
                /* return buffer to caller to free */
-               *buf = iov[0].iov_base;
+               *buf = rsp_iov.iov_base;
                if (resp_buf_type == CIFS_SMALL_BUFFER)
                        *pbuf_type = CIFS_SMALL_BUFFER;
                else if (resp_buf_type == CIFS_LARGE_BUFFER)
@@ -2093,7 +2103,7 @@ cifs_async_writev(struct cifs_writedata *wdata,
        WRITE_REQ *smb = NULL;
        int wct;
        struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
-       struct kvec iov;
+       struct kvec iov[2];
        struct smb_rqst rqst = { };
 
        if (tcon->ses->capabilities & CAP_LARGE_FILES) {
@@ -2126,11 +2136,13 @@ cifs_async_writev(struct cifs_writedata *wdata,
            cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
 
        /* 4 for RFC1001 length + 1 for BCC */
-       iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
-       iov.iov_base = smb;
+       iov[0].iov_len = 4;
+       iov[0].iov_base = smb;
+       iov[1].iov_len = get_rfc1002_length(smb) + 1;
+       iov[1].iov_base = (char *)smb + 4;
 
-       rqst.rq_iov = &iov;
-       rqst.rq_nvec = 1;
+       rqst.rq_iov = iov;
+       rqst.rq_nvec = 2;
        rqst.rq_pages = wdata->pages;
        rqst.rq_npages = wdata->nr_pages;
        rqst.rq_pagesz = wdata->pagesz;
@@ -2151,12 +2163,12 @@ cifs_async_writev(struct cifs_writedata *wdata,
                                (struct smb_com_writex_req *)smb;
                inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
                put_bcc(wdata->bytes + 5, &smbw->hdr);
-               iov.iov_len += 4; /* pad bigger by four bytes */
+               iov[1].iov_len += 4; /* pad bigger by four bytes */
        }
 
        kref_get(&wdata->refcount);
        rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
-                               cifs_writev_callback, wdata, 0);
+                               cifs_writev_callback, NULL, wdata, 0);
 
        if (rc == 0)
                cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
@@ -2182,6 +2194,7 @@ CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
        __u64 offset = io_parms->offset;
        struct cifs_tcon *tcon = io_parms->tcon;
        unsigned int count = io_parms->length;
+       struct kvec rsp_iov;
 
        *nbytes = 0;
 
@@ -2240,8 +2253,9 @@ CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
        else /* wct == 12 pad bigger by four bytes */
                iov[0].iov_len = smb_hdr_len + 8;
 
-
-       rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
+       rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0,
+                         &rsp_iov);
+       cifs_small_buf_release(pSMB);
        cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
        if (rc) {
                cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
@@ -2249,7 +2263,7 @@ CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
                /* presumably this can not happen, but best to be safe */
                rc = -EIO;
        } else {
-               WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
+               WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base;
                *nbytes = le16_to_cpu(pSMBr->CountHigh);
                *nbytes = (*nbytes) << 16;
                *nbytes += le16_to_cpu(pSMBr->Count);
@@ -2263,8 +2277,7 @@ CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
                        *nbytes &= 0xFFFF;
        }
 
-/*     cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
-       free_rsp_buf(resp_buf_type, iov[0].iov_base);
+       free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
 
        /* Note: On -EAGAIN error only caller can retry on handle based calls
                since file handle passed in no longer valid */
@@ -2279,6 +2292,7 @@ int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
        int rc = 0;
        LOCK_REQ *pSMB = NULL;
        struct kvec iov[2];
+       struct kvec rsp_iov;
        int resp_buf_type;
        __u16 count;
 
@@ -2307,7 +2321,9 @@ int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
        iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
 
        cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
-       rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
+       rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP,
+                         &rsp_iov);
+       cifs_small_buf_release(pSMB);
        if (rc)
                cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
 
@@ -2368,14 +2384,12 @@ CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
        inc_rfc1001_len(pSMB, count);
        pSMB->ByteCount = cpu_to_le16(count);
 
-       if (waitFlag) {
+       if (waitFlag)
                rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
                        (struct smb_hdr *) pSMB, &bytes_returned);
-               cifs_small_buf_release(pSMB);
-       } else {
+       else
                rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
-               /* SMB buffer freed by function above */
-       }
+       cifs_small_buf_release(pSMB);
        cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
        if (rc)
                cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
@@ -2401,6 +2415,7 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
        int resp_buf_type = 0;
        __u16 params, param_offset, offset, byte_count, count;
        struct kvec iov[1];
+       struct kvec rsp_iov;
 
        cifs_dbg(FYI, "Posix Lock\n");
 
@@ -2462,11 +2477,10 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
                iov[0].iov_base = (char *)pSMB;
                iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
                rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
-                               &resp_buf_type, timeout);
-               pSMB = NULL; /* request buf already freed by SendReceive2. Do
-                               not try to free it twice below on exit */
-               pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
+                               &resp_buf_type, timeout, &rsp_iov);
+               pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
        }
+       cifs_small_buf_release(pSMB);
 
        if (rc) {
                cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
@@ -2506,10 +2520,7 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
        }
 
 plk_err_exit:
-       if (pSMB)
-               cifs_small_buf_release(pSMB);
-
-       free_rsp_buf(resp_buf_type, iov[0].iov_base);
+       free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
 
        /* Note: On -EAGAIN error only caller can retry on handle based calls
           since file handle passed in no longer valid */
@@ -2536,6 +2547,7 @@ CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
        pSMB->LastWriteTime = 0xFFFFFFFF;
        pSMB->ByteCount = 0;
        rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
+       cifs_small_buf_release(pSMB);
        cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
        if (rc) {
                if (rc != -EINTR) {
@@ -2565,6 +2577,7 @@ CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
        pSMB->FileID = (__u16) smb_file_id;
        pSMB->ByteCount = 0;
        rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
+       cifs_small_buf_release(pSMB);
        cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
        if (rc)
                cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
@@ -3820,6 +3833,7 @@ CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
        int buf_type = 0;
        QUERY_SEC_DESC_REQ *pSMB;
        struct kvec iov[1];
+       struct kvec rsp_iov;
 
        cifs_dbg(FYI, "GetCifsACL\n");
 
@@ -3843,7 +3857,8 @@ CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
        iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
 
        rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
-                        0);
+                         0, &rsp_iov);
+       cifs_small_buf_release(pSMB);
        cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
        if (rc) {
                cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
@@ -3855,11 +3870,11 @@ CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
                char *pdata;
 
 /* validate_nttransact */
-               rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
+               rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm,
                                        &pdata, &parm_len, pbuflen);
                if (rc)
                        goto qsec_out;
-               pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
+               pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base;
 
                cifs_dbg(FYI, "smb %p parm %p data %p\n",
                         pSMBr, parm, *acl_inf);
@@ -3896,8 +3911,7 @@ CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
                }
        }
 qsec_out:
-       free_rsp_buf(buf_type, iov[0].iov_base);
-/*     cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
+       free_rsp_buf(buf_type, rsp_iov.iov_base);
        return rc;
 }
 
@@ -4666,6 +4680,7 @@ CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
        pSMB->FileID = searchHandle;
        pSMB->ByteCount = 0;
        rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
+       cifs_small_buf_release(pSMB);
        if (rc)
                cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
 
@@ -5687,6 +5702,7 @@ CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
        inc_rfc1001_len(pSMB, byte_count);
        pSMB->ByteCount = cpu_to_le16(byte_count);
        rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
+       cifs_small_buf_release(pSMB);
        if (rc) {
                cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
                         rc);
@@ -5758,6 +5774,7 @@ CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
        pSMB->ByteCount = cpu_to_le16(byte_count);
        memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
        rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
+       cifs_small_buf_release(pSMB);
        if (rc)
                cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
                         rc);
@@ -5818,6 +5835,7 @@ CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
        pSMB->ByteCount = cpu_to_le16(byte_count);
        *data_offset = delete_file ? 1 : 0;
        rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
+       cifs_small_buf_release(pSMB);
        if (rc)
                cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
 
@@ -6057,6 +6075,7 @@ CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
        cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
 
        rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
+       cifs_small_buf_release(pSMB);
        if (rc)
                cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
                         rc);
index 35ae49ed1f76e499a19cbd940a28ba28872c8c4e..777ad9f4fc3c84acbb5d96878939c589341b7f86 100644 (file)
@@ -787,6 +787,15 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 
        dump_smb(buf, server->total_read);
 
+       return cifs_handle_standard(server, mid);
+}
+
+int
+cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
+{
+       char *buf = server->large_buf ? server->bigbuf : server->smallbuf;
+       int length;
+
        /*
         * We know that we received enough to get to the MID as we
         * checked the pdu_length earlier. Now check to see
@@ -872,12 +881,19 @@ cifs_demultiplex_thread(void *p)
                        continue;
                server->total_read += length;
 
-               mid_entry = server->ops->find_mid(server, buf);
+               if (server->ops->is_transform_hdr &&
+                   server->ops->receive_transform &&
+                   server->ops->is_transform_hdr(buf)) {
+                       length = server->ops->receive_transform(server,
+                                                               &mid_entry);
+               } else {
+                       mid_entry = server->ops->find_mid(server, buf);
 
-               if (!mid_entry || !mid_entry->receive)
-                       length = standard_receive3(server, mid_entry);
-               else
-                       length = mid_entry->receive(server, mid_entry);
+                       if (!mid_entry || !mid_entry->receive)
+                               length = standard_receive3(server, mid_entry);
+                       else
+                               length = mid_entry->receive(server, mid_entry);
+               }
 
                if (length < 0)
                        continue;
@@ -2154,7 +2170,7 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
        server->tcpStatus = CifsExiting;
        spin_unlock(&GlobalMid_Lock);
 
-       cifs_crypto_shash_release(server);
+       cifs_crypto_secmech_release(server);
        cifs_fscache_release_client_cookie(server);
 
        kfree(server->session_key.response);
@@ -2273,7 +2289,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
        return tcp_ses;
 
 out_err_crypto_release:
-       cifs_crypto_shash_release(tcp_ses);
+       cifs_crypto_secmech_release(tcp_ses);
 
        put_net(cifs_net_ns(tcp_ses));
 
@@ -2614,12 +2630,18 @@ get_ses_fail:
        return ERR_PTR(rc);
 }
 
-static int match_tcon(struct cifs_tcon *tcon, const char *unc)
+static int match_tcon(struct cifs_tcon *tcon, struct smb_vol *volume_info)
 {
        if (tcon->tidStatus == CifsExiting)
                return 0;
-       if (strncmp(tcon->treeName, unc, MAX_TREE_SIZE))
+       if (strncmp(tcon->treeName, volume_info->UNC, MAX_TREE_SIZE))
                return 0;
+       if (tcon->seal != volume_info->seal)
+               return 0;
+#ifdef CONFIG_CIFS_SMB2
+       if (tcon->snapshot_time != volume_info->snapshot_time)
+               return 0;
+#endif /* CONFIG_CIFS_SMB2 */
        return 1;
 }
 
@@ -2632,14 +2654,8 @@ cifs_find_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
        spin_lock(&cifs_tcp_ses_lock);
        list_for_each(tmp, &ses->tcon_list) {
                tcon = list_entry(tmp, struct cifs_tcon, tcon_list);
-               if (!match_tcon(tcon, volume_info->UNC))
-                       continue;
-
-#ifdef CONFIG_CIFS_SMB2
-               if (tcon->snapshot_time != volume_info->snapshot_time)
+               if (!match_tcon(tcon, volume_info))
                        continue;
-#endif /* CONFIG_CIFS_SMB2 */
-
                ++tcon->tc_count;
                spin_unlock(&cifs_tcp_ses_lock);
                return tcon;
@@ -2685,8 +2701,6 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
                cifs_dbg(FYI, "Found match on UNC path\n");
                /* existing tcon already has a reference */
                cifs_put_smb_ses(ses);
-               if (tcon->seal != volume_info->seal)
-                       cifs_dbg(VFS, "transport encryption setting conflicts with existing tid\n");
                return tcon;
        }
 
@@ -2742,7 +2756,6 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
                tcon->Flags &= ~SMB_SHARE_IS_IN_DFS;
                cifs_dbg(FYI, "DFS disabled (%d)\n", tcon->Flags);
        }
-       tcon->seal = volume_info->seal;
        tcon->use_persistent = false;
        /* check if SMB2 or later, CIFS does not support persistent handles */
        if (volume_info->persistent) {
@@ -2779,6 +2792,24 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
                tcon->use_resilient = true;
        }
 
+       if (volume_info->seal) {
+               if (ses->server->vals->protocol_id == 0) {
+                       cifs_dbg(VFS,
+                                "SMB3 or later required for encryption\n");
+                       rc = -EOPNOTSUPP;
+                       goto out_fail;
+#ifdef CONFIG_CIFS_SMB2
+               } else if (tcon->ses->server->capabilities &
+                                       SMB2_GLOBAL_CAP_ENCRYPTION)
+                       tcon->seal = true;
+               else {
+                       cifs_dbg(VFS, "Encryption is not supported on share\n");
+                       rc = -EOPNOTSUPP;
+                       goto out_fail;
+#endif /* CONFIG_CIFS_SMB2 */
+               }
+       }
+
        /*
         * We can have only one retry value for a connection to a share so for
         * resources mounted more than once to the same server share the last
@@ -2910,7 +2941,7 @@ cifs_match_super(struct super_block *sb, void *data)
 
        if (!match_server(tcp_srv, volume_info) ||
            !match_session(ses, volume_info) ||
-           !match_tcon(tcon, volume_info->UNC) ||
+           !match_tcon(tcon, volume_info) ||
            !match_prepath(sb, mnt_data)) {
                rc = 0;
                goto out;
index 18a1e1d6671fc0825b2f265280a96e065e6c6aae..98dc842e724512cb5eb71d5f1d94ccb0afe1222e 100644 (file)
@@ -2884,7 +2884,15 @@ cifs_readdata_to_iov(struct cifs_readdata *rdata, struct iov_iter *iter)
        for (i = 0; i < rdata->nr_pages; i++) {
                struct page *page = rdata->pages[i];
                size_t copy = min_t(size_t, remaining, PAGE_SIZE);
-               size_t written = copy_page_to_iter(page, 0, copy, iter);
+               size_t written;
+
+               if (unlikely(iter->type & ITER_PIPE)) {
+                       void *addr = kmap_atomic(page);
+
+                       written = copy_to_iter(addr, copy, iter);
+                       kunmap_atomic(addr);
+               } else
+                       written = copy_page_to_iter(page, 0, copy, iter);
                remaining -= written;
                if (written < copy && iov_iter_count(iter) > 0)
                        break;
@@ -2903,8 +2911,9 @@ cifs_uncached_readv_complete(struct work_struct *work)
 }
 
 static int
-cifs_uncached_read_into_pages(struct TCP_Server_Info *server,
-                       struct cifs_readdata *rdata, unsigned int len)
+uncached_fill_pages(struct TCP_Server_Info *server,
+                   struct cifs_readdata *rdata, struct iov_iter *iter,
+                   unsigned int len)
 {
        int result = 0;
        unsigned int i;
@@ -2933,7 +2942,10 @@ cifs_uncached_read_into_pages(struct TCP_Server_Info *server,
                        rdata->tailsz = len;
                        len = 0;
                }
-               result = cifs_read_page_from_socket(server, page, n);
+               if (iter)
+                       result = copy_page_from_iter(page, 0, n, iter);
+               else
+                       result = cifs_read_page_from_socket(server, page, n);
                if (result < 0)
                        break;
 
@@ -2944,6 +2956,21 @@ cifs_uncached_read_into_pages(struct TCP_Server_Info *server,
                                                rdata->got_bytes : result;
 }
 
+static int
+cifs_uncached_read_into_pages(struct TCP_Server_Info *server,
+                             struct cifs_readdata *rdata, unsigned int len)
+{
+       return uncached_fill_pages(server, rdata, NULL, len);
+}
+
+static int
+cifs_uncached_copy_into_pages(struct TCP_Server_Info *server,
+                             struct cifs_readdata *rdata,
+                             struct iov_iter *iter)
+{
+       return uncached_fill_pages(server, rdata, iter, iter->count);
+}
+
 static int
 cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file,
                     struct cifs_sb_info *cifs_sb, struct list_head *rdata_list)
@@ -2991,6 +3018,7 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file,
                rdata->pid = pid;
                rdata->pagesz = PAGE_SIZE;
                rdata->read_into_pages = cifs_uncached_read_into_pages;
+               rdata->copy_into_pages = cifs_uncached_copy_into_pages;
                rdata->credits = credits;
 
                if (!rdata->cfile->invalidHandle ||
@@ -3341,8 +3369,9 @@ cifs_readv_complete(struct work_struct *work)
 }
 
 static int
-cifs_readpages_read_into_pages(struct TCP_Server_Info *server,
-                       struct cifs_readdata *rdata, unsigned int len)
+readpages_fill_pages(struct TCP_Server_Info *server,
+                    struct cifs_readdata *rdata, struct iov_iter *iter,
+                    unsigned int len)
 {
        int result = 0;
        unsigned int i;
@@ -3396,7 +3425,10 @@ cifs_readpages_read_into_pages(struct TCP_Server_Info *server,
                        continue;
                }
 
-               result = cifs_read_page_from_socket(server, page, n);
+               if (iter)
+                       result = copy_page_from_iter(page, 0, n, iter);
+               else
+                       result = cifs_read_page_from_socket(server, page, n);
                if (result < 0)
                        break;
 
@@ -3407,6 +3439,21 @@ cifs_readpages_read_into_pages(struct TCP_Server_Info *server,
                                                rdata->got_bytes : result;
 }
 
+static int
+cifs_readpages_read_into_pages(struct TCP_Server_Info *server,
+                              struct cifs_readdata *rdata, unsigned int len)
+{
+       return readpages_fill_pages(server, rdata, NULL, len);
+}
+
+static int
+cifs_readpages_copy_into_pages(struct TCP_Server_Info *server,
+                              struct cifs_readdata *rdata,
+                              struct iov_iter *iter)
+{
+       return readpages_fill_pages(server, rdata, iter, iter->count);
+}
+
 static int
 readpages_get_pages(struct address_space *mapping, struct list_head *page_list,
                    unsigned int rsize, struct list_head *tmplist,
@@ -3561,6 +3608,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                rdata->pid = pid;
                rdata->pagesz = PAGE_SIZE;
                rdata->read_into_pages = cifs_readpages_read_into_pages;
+               rdata->copy_into_pages = cifs_readpages_copy_into_pages;
                rdata->credits = credits;
 
                list_for_each_entry_safe(page, tpage, &tmplist, lru) {
index 538d9b55699a10f1185b8df25a1f36f9a24ae75c..dcbcc927399a0ffbaecf07c1f52fec42afeb3459 100644 (file)
@@ -344,13 +344,12 @@ void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
        /* BB is NTLMV2 session security format easier to use here? */
        flags = NTLMSSP_NEGOTIATE_56 |  NTLMSSP_REQUEST_TARGET |
                NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
-               NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC;
-       if (ses->server->sign) {
+               NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC |
+               NTLMSSP_NEGOTIATE_SEAL;
+       if (ses->server->sign)
                flags |= NTLMSSP_NEGOTIATE_SIGN;
-               if (!ses->server->session_estab ||
-                               ses->ntlmssp->sesskey_per_smbsess)
-                       flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
-       }
+       if (!ses->server->session_estab || ses->ntlmssp->sesskey_per_smbsess)
+               flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
 
        sec_blob->NegotiateFlags = cpu_to_le32(flags);
 
@@ -407,13 +406,12 @@ int build_ntlmssp_auth_blob(unsigned char **pbuffer,
        flags = NTLMSSP_NEGOTIATE_56 |
                NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO |
                NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
-               NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC;
-       if (ses->server->sign) {
+               NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC |
+               NTLMSSP_NEGOTIATE_SEAL;
+       if (ses->server->sign)
                flags |= NTLMSSP_NEGOTIATE_SIGN;
-               if (!ses->server->session_estab ||
-                               ses->ntlmssp->sesskey_per_smbsess)
-                       flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
-       }
+       if (!ses->server->session_estab || ses->ntlmssp->sesskey_per_smbsess)
+               flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
 
        tmp = *pbuffer + sizeof(AUTHENTICATE_MESSAGE);
        sec_blob->NegotiateFlags = cpu_to_le32(flags);
@@ -652,6 +650,7 @@ sess_sendreceive(struct sess_data *sess_data)
        int rc;
        struct smb_hdr *smb_buf = (struct smb_hdr *) sess_data->iov[0].iov_base;
        __u16 count;
+       struct kvec rsp_iov = { NULL, 0 };
 
        count = sess_data->iov[1].iov_len + sess_data->iov[2].iov_len;
        smb_buf->smb_buf_length =
@@ -661,7 +660,9 @@ sess_sendreceive(struct sess_data *sess_data)
        rc = SendReceive2(sess_data->xid, sess_data->ses,
                          sess_data->iov, 3 /* num_iovecs */,
                          &sess_data->buf0_type,
-                         CIFS_LOG_ERROR);
+                         CIFS_LOG_ERROR, &rsp_iov);
+       cifs_small_buf_release(sess_data->iov[0].iov_base);
+       memcpy(&sess_data->iov[0], &rsp_iov, sizeof(struct kvec));
 
        return rc;
 }
index fc537c29044edd8a158bb130a65e371370826164..67a987e4d026e0643a21dd1e4c520902d64deeae 100644 (file)
  * SMB_COM_NT_CANCEL request and then sends it.
  */
 static int
-send_nt_cancel(struct TCP_Server_Info *server, void *buf,
+send_nt_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
               struct mid_q_entry *mid)
 {
        int rc = 0;
-       struct smb_hdr *in_buf = (struct smb_hdr *)buf;
+       struct smb_hdr *in_buf = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
 
        /* -4 for RFC1001 length and +2 for BCC field */
        in_buf->smb_buf_length = cpu_to_be32(sizeof(struct smb_hdr) - 4  + 2);
index 0ffa180943357c5514b5ae025f61e4b19f574f38..401a5d8566367e2bb5d3d65df5679708e515b2f6 100644 (file)
@@ -61,4 +61,9 @@
 /* Maximum buffer size value we can send with 1 credit */
 #define SMB2_MAX_BUFFER_SIZE 65536
 
+static inline struct smb2_sync_hdr *get_sync_hdr(void *buf)
+{
+       return &(((struct smb2_hdr *)buf)->sync_hdr);
+}
+
 #endif /* _SMB2_GLOB_H */
index 8257a5a97cc0349e9f7231f02ab36e624de2c02a..3030a9dfb0ddcca131334217797bc96d0e2e3402 100644 (file)
@@ -26,6 +26,7 @@
 #include "smb2pdu.h"
 #include "smb2proto.h"
 #include "smb2status.h"
+#include "smb2glob.h"
 
 struct status_to_posix_error {
        __le32 smb2_status;
@@ -2449,10 +2450,10 @@ smb2_print_status(__le32 status)
 int
 map_smb2_to_linux_error(char *buf, bool log_err)
 {
-       struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
+       struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
        unsigned int i;
        int rc = -EIO;
-       __le32 smb2err = hdr->Status;
+       __le32 smb2err = shdr->Status;
 
        if (smb2err == 0)
                return 0;
index 3d383489b9cf313395e94a0bff4a719501b4b309..fd516ea8b8f89c46cb1d9977d53fbbb9d16de9d3 100644 (file)
 #include "cifs_debug.h"
 #include "cifs_unicode.h"
 #include "smb2status.h"
+#include "smb2glob.h"
 
 static int
-check_smb2_hdr(struct smb2_hdr *hdr, __u64 mid)
+check_smb2_hdr(struct smb2_sync_hdr *shdr, __u64 mid)
 {
-       __u64 wire_mid = le64_to_cpu(hdr->MessageId);
+       __u64 wire_mid = le64_to_cpu(shdr->MessageId);
 
        /*
         * Make sure that this really is an SMB, that it is a response,
         * and that the message ids match.
         */
-       if ((hdr->ProtocolId == SMB2_PROTO_NUMBER) &&
+       if ((shdr->ProtocolId == SMB2_PROTO_NUMBER) &&
            (mid == wire_mid)) {
-               if (hdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR)
+               if (shdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR)
                        return 0;
                else {
                        /* only one valid case where server sends us request */
-                       if (hdr->Command == SMB2_OPLOCK_BREAK)
+                       if (shdr->Command == SMB2_OPLOCK_BREAK)
                                return 0;
                        else
                                cifs_dbg(VFS, "Received Request not response\n");
                }
        } else { /* bad signature or mid */
-               if (hdr->ProtocolId != SMB2_PROTO_NUMBER)
+               if (shdr->ProtocolId != SMB2_PROTO_NUMBER)
                        cifs_dbg(VFS, "Bad protocol string signature header %x\n",
-                                le32_to_cpu(hdr->ProtocolId));
+                                le32_to_cpu(shdr->ProtocolId));
                if (mid != wire_mid)
                        cifs_dbg(VFS, "Mids do not match: %llu and %llu\n",
                                 mid, wire_mid);
@@ -95,8 +96,9 @@ static const __le16 smb2_rsp_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = {
 int
 smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
 {
-       struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
-       struct smb2_pdu *pdu = (struct smb2_pdu *)hdr;
+       struct smb2_pdu *pdu = (struct smb2_pdu *)buf;
+       struct smb2_hdr *hdr = &pdu->hdr;
+       struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
        __u64 mid;
        __u32 len = get_rfc1002_length(buf);
        __u32 clc_len;  /* calculated length */
@@ -111,7 +113,7 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
         * ie Validate the wct via smb2_struct_sizes table above
         */
 
-       if (hdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) {
+       if (shdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) {
                struct smb2_transform_hdr *thdr =
                        (struct smb2_transform_hdr *)buf;
                struct cifs_ses *ses = NULL;
@@ -133,10 +135,10 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
                }
        }
 
-
-       mid = le64_to_cpu(hdr->MessageId);
+       mid = le64_to_cpu(shdr->MessageId);
        if (length < sizeof(struct smb2_pdu)) {
-               if ((length >= sizeof(struct smb2_hdr)) && (hdr->Status != 0)) {
+               if ((length >= sizeof(struct smb2_hdr))
+                   && (shdr->Status != 0)) {
                        pdu->StructureSize2 = 0;
                        /*
                         * As with SMB/CIFS, on some error cases servers may
@@ -154,29 +156,30 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
                return 1;
        }
 
-       if (check_smb2_hdr(hdr, mid))
+       if (check_smb2_hdr(shdr, mid))
                return 1;
 
-       if (hdr->StructureSize != SMB2_HEADER_STRUCTURE_SIZE) {
+       if (shdr->StructureSize != SMB2_HEADER_STRUCTURE_SIZE) {
                cifs_dbg(VFS, "Illegal structure size %u\n",
-                        le16_to_cpu(hdr->StructureSize));
+                        le16_to_cpu(shdr->StructureSize));
                return 1;
        }
 
-       command = le16_to_cpu(hdr->Command);
+       command = le16_to_cpu(shdr->Command);
        if (command >= NUMBER_OF_SMB2_COMMANDS) {
                cifs_dbg(VFS, "Illegal SMB2 command %d\n", command);
                return 1;
        }
 
        if (smb2_rsp_struct_sizes[command] != pdu->StructureSize2) {
-               if (command != SMB2_OPLOCK_BREAK_HE && (hdr->Status == 0 ||
+               if (command != SMB2_OPLOCK_BREAK_HE && (shdr->Status == 0 ||
                    pdu->StructureSize2 != SMB2_ERROR_STRUCTURE_SIZE2)) {
                        /* error packets have 9 byte structure size */
                        cifs_dbg(VFS, "Illegal response size %u for command %d\n",
                                 le16_to_cpu(pdu->StructureSize2), command);
                        return 1;
-               } else if (command == SMB2_OPLOCK_BREAK_HE && (hdr->Status == 0)
+               } else if (command == SMB2_OPLOCK_BREAK_HE
+                          && (shdr->Status == 0)
                           && (le16_to_cpu(pdu->StructureSize2) != 44)
                           && (le16_to_cpu(pdu->StructureSize2) != 36)) {
                        /* special case for SMB2.1 lease break message */
@@ -199,7 +202,7 @@ smb2_check_message(char *buf, unsigned int length, struct TCP_Server_Info *srvr)
                         clc_len, 4 + len, mid);
                /* create failed on symlink */
                if (command == SMB2_CREATE_HE &&
-                   hdr->Status == STATUS_STOPPED_ON_SYMLINK)
+                   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)
@@ -261,11 +264,12 @@ static const bool has_smb2_data_area[NUMBER_OF_SMB2_COMMANDS] = {
 char *
 smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
 {
+       struct smb2_sync_hdr *shdr = get_sync_hdr(hdr);
        *off = 0;
        *len = 0;
 
        /* error responses do not have data area */
-       if (hdr->Status && hdr->Status != STATUS_MORE_PROCESSING_REQUIRED &&
+       if (shdr->Status && shdr->Status != STATUS_MORE_PROCESSING_REQUIRED &&
            (((struct smb2_err_rsp *)hdr)->StructureSize) ==
                                                SMB2_ERROR_STRUCTURE_SIZE2)
                return NULL;
@@ -275,7 +279,7 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
         * of the data buffer offset and data buffer length for the particular
         * command.
         */
-       switch (hdr->Command) {
+       switch (shdr->Command) {
        case SMB2_NEGOTIATE:
                *off = le16_to_cpu(
                    ((struct smb2_negotiate_rsp *)hdr)->SecurityBufferOffset);
@@ -346,7 +350,7 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
 
        /* return pointer to beginning of data area, ie offset from SMB start */
        if ((*off != 0) && (*len != 0))
-               return (char *)(&hdr->ProtocolId) + *off;
+               return (char *)shdr + *off;
        else
                return NULL;
 }
@@ -358,12 +362,13 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
 unsigned int
 smb2_calc_size(void *buf)
 {
-       struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
-       struct smb2_pdu *pdu = (struct smb2_pdu *)hdr;
+       struct smb2_pdu *pdu = (struct smb2_pdu *)buf;
+       struct smb2_hdr *hdr = &pdu->hdr;
+       struct smb2_sync_hdr *shdr = get_sync_hdr(hdr);
        int offset; /* the offset from the beginning of SMB to data area */
        int data_length; /* the length of the variable length data area */
        /* Structure Size has already been checked to make sure it is 64 */
-       int len = 4 + le16_to_cpu(pdu->hdr.StructureSize);
+       int len = 4 + le16_to_cpu(shdr->StructureSize);
 
        /*
         * StructureSize2, ie length of fixed parameter area has already
@@ -371,7 +376,7 @@ smb2_calc_size(void *buf)
         */
        len += le16_to_cpu(pdu->StructureSize2);
 
-       if (has_smb2_data_area[le16_to_cpu(hdr->Command)] == false)
+       if (has_smb2_data_area[le16_to_cpu(shdr->Command)] == false)
                goto calc_size_exit;
 
        smb2_get_data_area_len(&offset, &data_length, hdr);
@@ -582,7 +587,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
 
        cifs_dbg(FYI, "Checking for oplock break\n");
 
-       if (rsp->hdr.Command != SMB2_OPLOCK_BREAK)
+       if (rsp->hdr.sync_hdr.Command != SMB2_OPLOCK_BREAK)
                return false;
 
        if (rsp->StructureSize !=
index 5d456ebb381386e5299cf61123400f4985480e9a..a44b4dbe4aaec9985d40e2c39121ae5834fe1723 100644 (file)
@@ -20,6 +20,8 @@
 #include <linux/pagemap.h>
 #include <linux/vfs.h>
 #include <linux/falloc.h>
+#include <linux/scatterlist.h>
+#include <crypto/aead.h>
 #include "cifsglob.h"
 #include "smb2pdu.h"
 #include "smb2proto.h"
@@ -119,7 +121,9 @@ smb2_get_credits_field(struct TCP_Server_Info *server, const int optype)
 static unsigned int
 smb2_get_credits(struct mid_q_entry *mid)
 {
-       return le16_to_cpu(((struct smb2_hdr *)mid->resp_buf)->CreditRequest);
+       struct smb2_sync_hdr *shdr = get_sync_hdr(mid->resp_buf);
+
+       return le16_to_cpu(shdr->CreditRequest);
 }
 
 static int
@@ -184,10 +188,10 @@ static struct mid_q_entry *
 smb2_find_mid(struct TCP_Server_Info *server, char *buf)
 {
        struct mid_q_entry *mid;
-       struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
-       __u64 wire_mid = le64_to_cpu(hdr->MessageId);
+       struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
+       __u64 wire_mid = le64_to_cpu(shdr->MessageId);
 
-       if (hdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) {
+       if (shdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) {
                cifs_dbg(VFS, "encrypted frame parsing not supported yet");
                return NULL;
        }
@@ -196,7 +200,7 @@ smb2_find_mid(struct TCP_Server_Info *server, char *buf)
        list_for_each_entry(mid, &server->pending_mid_q, qhead) {
                if ((mid->mid == wire_mid) &&
                    (mid->mid_state == MID_REQUEST_SUBMITTED) &&
-                   (mid->command == hdr->Command)) {
+                   (mid->command == shdr->Command)) {
                        spin_unlock(&GlobalMid_Lock);
                        return mid;
                }
@@ -209,12 +213,12 @@ static void
 smb2_dump_detail(void *buf)
 {
 #ifdef CONFIG_CIFS_DEBUG2
-       struct smb2_hdr *smb = (struct smb2_hdr *)buf;
+       struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
 
        cifs_dbg(VFS, "Cmd: %d Err: 0x%x Flags: 0x%x Mid: %llu Pid: %d\n",
-                smb->Command, smb->Status, smb->Flags, smb->MessageId,
-                smb->ProcessId);
-       cifs_dbg(VFS, "smb buf %p len %u\n", smb, smb2_calc_size(smb));
+                shdr->Command, shdr->Status, shdr->Flags, shdr->MessageId,
+                shdr->ProcessId);
+       cifs_dbg(VFS, "smb buf %p len %u\n", buf, smb2_calc_size(buf));
 #endif
 }
 
@@ -1002,14 +1006,14 @@ smb2_close_dir(const unsigned int xid, struct cifs_tcon *tcon,
 static bool
 smb2_is_status_pending(char *buf, struct TCP_Server_Info *server, int length)
 {
-       struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
+       struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
 
-       if (hdr->Status != STATUS_PENDING)
+       if (shdr->Status != STATUS_PENDING)
                return false;
 
        if (!length) {
                spin_lock(&server->req_lock);
-               server->credits += le16_to_cpu(hdr->CreditRequest);
+               server->credits += le16_to_cpu(shdr->CreditRequest);
                spin_unlock(&server->req_lock);
                wake_up(&server->request_q);
        }
@@ -1545,6 +1549,633 @@ smb2_dir_needs_close(struct cifsFileInfo *cfile)
        return !cfile->invalidHandle;
 }
 
+static void
+fill_transform_hdr(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;
+       unsigned int orig_len = get_rfc1002_length(old_rq->rq_iov[0].iov_base);
+
+       memset(tr_hdr, 0, sizeof(struct smb2_transform_hdr));
+       tr_hdr->ProtocolId = SMB2_TRANSFORM_PROTO_NUM;
+       tr_hdr->OriginalMessageSize = cpu_to_le32(orig_len);
+       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, orig_len);
+}
+
+static struct scatterlist *
+init_sg(struct smb_rqst *rqst, u8 *sign)
+{
+       unsigned int sg_len = rqst->rq_nvec + rqst->rq_npages + 1;
+       unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 24;
+       struct scatterlist *sg;
+       unsigned int i;
+       unsigned int j;
+
+       sg = kmalloc_array(sg_len, sizeof(struct scatterlist), GFP_KERNEL);
+       if (!sg)
+               return NULL;
+
+       sg_init_table(sg, sg_len);
+       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,
+                                               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);
+       return sg;
+}
+
+struct cifs_crypt_result {
+       int err;
+       struct completion completion;
+};
+
+static void cifs_crypt_complete(struct crypto_async_request *req, int err)
+{
+       struct cifs_crypt_result *res = req->data;
+
+       if (err == -EINPROGRESS)
+               return;
+
+       res->err = err;
+       complete(&res->completion);
+}
+
+/*
+ * Encrypt or decrypt @rqst message. @rqst has the following format:
+ * iov[0] - transform header (associate data),
+ * iov[1-N] and pages - data to encrypt.
+ * On success return encrypted data in iov[1-N] and pages, leave iov[0]
+ * untouched.
+ */
+static int
+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;
+       struct cifs_ses *ses;
+       int rc = 0;
+       struct scatterlist *sg;
+       u8 sign[SMB2_SIGNATURE_SIZE] = {};
+       struct aead_request *req;
+       char *iv;
+       unsigned int iv_len;
+       struct cifs_crypt_result result = {0, };
+       struct crypto_aead *tfm;
+       unsigned int crypt_len = le32_to_cpu(tr_hdr->OriginalMessageSize);
+
+       init_completion(&result.completion);
+
+       ses = smb2_find_smb_ses(server, tr_hdr->SessionId);
+       if (!ses) {
+               cifs_dbg(VFS, "%s: Could not find session\n", __func__);
+               return 0;
+       }
+
+       rc = smb3_crypto_aead_allocate(server);
+       if (rc) {
+               cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__);
+               return rc;
+       }
+
+       tfm = enc ? server->secmech.ccmaesencrypt :
+                                               server->secmech.ccmaesdecrypt;
+       rc = crypto_aead_setkey(tfm, enc ? ses->smb3encryptionkey :
+                               ses->smb3decryptionkey, SMB3_SIGN_KEY_SIZE);
+       if (rc) {
+               cifs_dbg(VFS, "%s: Failed to set aead key %d\n", __func__, rc);
+               return rc;
+       }
+
+       rc = crypto_aead_setauthsize(tfm, SMB2_SIGNATURE_SIZE);
+       if (rc) {
+               cifs_dbg(VFS, "%s: Failed to set authsize %d\n", __func__, rc);
+               return rc;
+       }
+
+       req = aead_request_alloc(tfm, GFP_KERNEL);
+       if (!req) {
+               cifs_dbg(VFS, "%s: Failed to alloc aead request", __func__);
+               return -ENOMEM;
+       }
+
+       if (!enc) {
+               memcpy(sign, &tr_hdr->Signature, SMB2_SIGNATURE_SIZE);
+               crypt_len += SMB2_SIGNATURE_SIZE;
+       }
+
+       sg = init_sg(rqst, sign);
+       if (!sg) {
+               cifs_dbg(VFS, "%s: Failed to init sg %d", __func__, rc);
+               goto free_req;
+       }
+
+       iv_len = crypto_aead_ivsize(tfm);
+       iv = kzalloc(iv_len, GFP_KERNEL);
+       if (!iv) {
+               cifs_dbg(VFS, "%s: Failed to alloc IV", __func__);
+               goto free_sg;
+       }
+       iv[0] = 3;
+       memcpy(iv + 1, (char *)tr_hdr->Nonce, SMB3_AES128CMM_NONCE);
+
+       aead_request_set_crypt(req, sg, sg, crypt_len, iv);
+       aead_request_set_ad(req, assoc_data_len);
+
+       aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+                                 cifs_crypt_complete, &result);
+
+       rc = enc ? crypto_aead_encrypt(req) : crypto_aead_decrypt(req);
+
+       if (rc == -EINPROGRESS || rc == -EBUSY) {
+               wait_for_completion(&result.completion);
+               rc = result.err;
+       }
+
+       if (!rc && enc)
+               memcpy(&tr_hdr->Signature, sign, SMB2_SIGNATURE_SIZE);
+
+       kfree(iv);
+free_sg:
+       kfree(sg);
+free_req:
+       kfree(req);
+       return rc;
+}
+
+static int
+smb3_init_transform_rq(struct TCP_Server_Info *server, struct smb_rqst *new_rq,
+                      struct smb_rqst *old_rq)
+{
+       struct kvec *iov;
+       struct page **pages;
+       struct smb2_transform_hdr *tr_hdr;
+       unsigned int npages = old_rq->rq_npages;
+       int i;
+       int rc = -ENOMEM;
+
+       pages = kmalloc_array(npages, sizeof(struct page *), GFP_KERNEL);
+       if (!pages)
+               return rc;
+
+       new_rq->rq_pages = pages;
+       new_rq->rq_npages = old_rq->rq_npages;
+       new_rq->rq_pagesz = old_rq->rq_pagesz;
+       new_rq->rq_tailsz = old_rq->rq_tailsz;
+
+       for (i = 0; i < npages; i++) {
+               pages[i] = alloc_page(GFP_KERNEL|__GFP_HIGHMEM);
+               if (!pages[i])
+                       goto err_free_pages;
+       }
+
+       iov = kmalloc_array(old_rq->rq_nvec, sizeof(struct kvec), GFP_KERNEL);
+       if (!iov)
+               goto err_free_pages;
+
+       /* copy all iovs from the old except the 1st one (rfc1002 length) */
+       memcpy(&iov[1], &old_rq->rq_iov[1],
+                               sizeof(struct kvec) * (old_rq->rq_nvec - 1));
+       new_rq->rq_iov = iov;
+       new_rq->rq_nvec = old_rq->rq_nvec;
+
+       tr_hdr = kmalloc(sizeof(struct smb2_transform_hdr), GFP_KERNEL);
+       if (!tr_hdr)
+               goto err_free_iov;
+
+       /* fill the 1st iov with a transform header */
+       fill_transform_hdr(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);
+
+       /* copy pages form the old */
+       for (i = 0; i < npages; i++) {
+               char *dst = kmap(new_rq->rq_pages[i]);
+               char *src = kmap(old_rq->rq_pages[i]);
+               unsigned int len = (i < npages - 1) ? new_rq->rq_pagesz :
+                                                       new_rq->rq_tailsz;
+               memcpy(dst, src, len);
+               kunmap(new_rq->rq_pages[i]);
+               kunmap(old_rq->rq_pages[i]);
+       }
+
+       rc = crypt_message(server, new_rq, 1);
+       cifs_dbg(FYI, "encrypt message returned %d", rc);
+       if (rc)
+               goto err_free_tr_hdr;
+
+       return rc;
+
+err_free_tr_hdr:
+       kfree(tr_hdr);
+err_free_iov:
+       kfree(iov);
+err_free_pages:
+       for (i = i - 1; i >= 0; i--)
+               put_page(pages[i]);
+       kfree(pages);
+       return rc;
+}
+
+static void
+smb3_free_transform_rq(struct smb_rqst *rqst)
+{
+       int i = rqst->rq_npages - 1;
+
+       for (; i >= 0; i--)
+               put_page(rqst->rq_pages[i]);
+       kfree(rqst->rq_pages);
+       /* free transform header */
+       kfree(rqst->rq_iov[0].iov_base);
+       kfree(rqst->rq_iov);
+}
+
+static int
+smb3_is_transform_hdr(void *buf)
+{
+       struct smb2_transform_hdr *trhdr = buf;
+
+       return trhdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM;
+}
+
+static int
+decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
+                unsigned int buf_data_size, struct page **pages,
+                unsigned int npages, unsigned int page_data_size)
+{
+       struct kvec iov[2];
+       struct smb_rqst rqst = {NULL};
+       struct smb2_hdr *hdr;
+       int rc;
+
+       iov[0].iov_base = buf;
+       iov[0].iov_len = sizeof(struct smb2_transform_hdr);
+       iov[1].iov_base = buf + sizeof(struct smb2_transform_hdr);
+       iov[1].iov_len = buf_data_size;
+
+       rqst.rq_iov = iov;
+       rqst.rq_nvec = 2;
+       rqst.rq_pages = pages;
+       rqst.rq_npages = npages;
+       rqst.rq_pagesz = PAGE_SIZE;
+       rqst.rq_tailsz = (page_data_size % PAGE_SIZE) ? : PAGE_SIZE;
+
+       rc = crypt_message(server, &rqst, 0);
+       cifs_dbg(FYI, "decrypt message returned %d\n", rc);
+
+       if (rc)
+               return rc;
+
+       memmove(buf + 4, 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;
+
+       return rc;
+}
+
+static int
+read_data_into_pages(struct TCP_Server_Info *server, struct page **pages,
+                    unsigned int npages, unsigned int len)
+{
+       int i;
+       int length;
+
+       for (i = 0; i < npages; i++) {
+               struct page *page = pages[i];
+               size_t n;
+
+               n = len;
+               if (len >= PAGE_SIZE) {
+                       /* enough data to fill the page */
+                       n = PAGE_SIZE;
+                       len -= n;
+               } else {
+                       zero_user(page, len, PAGE_SIZE - len);
+                       len = 0;
+               }
+               length = cifs_read_page_from_socket(server, page, n);
+               if (length < 0)
+                       return length;
+               server->total_read += length;
+       }
+
+       return 0;
+}
+
+static int
+init_read_bvec(struct page **pages, unsigned int npages, unsigned int data_size,
+              unsigned int cur_off, struct bio_vec **page_vec)
+{
+       struct bio_vec *bvec;
+       int i;
+
+       bvec = kcalloc(npages, sizeof(struct bio_vec), GFP_KERNEL);
+       if (!bvec)
+               return -ENOMEM;
+
+       for (i = 0; i < npages; i++) {
+               bvec[i].bv_page = pages[i];
+               bvec[i].bv_offset = (i == 0) ? cur_off : 0;
+               bvec[i].bv_len = min_t(unsigned int, PAGE_SIZE, data_size);
+               data_size -= bvec[i].bv_len;
+       }
+
+       if (data_size != 0) {
+               cifs_dbg(VFS, "%s: something went wrong\n", __func__);
+               kfree(bvec);
+               return -EIO;
+       }
+
+       *page_vec = bvec;
+       return 0;
+}
+
+static int
+handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
+                char *buf, unsigned int buf_len, struct page **pages,
+                unsigned int npages, unsigned int page_data_size)
+{
+       unsigned int data_offset;
+       unsigned int data_len;
+       unsigned int cur_off;
+       unsigned int cur_page_idx;
+       unsigned int pad_len;
+       struct cifs_readdata *rdata = mid->callback_data;
+       struct smb2_sync_hdr *shdr = get_sync_hdr(buf);
+       struct bio_vec *bvec = NULL;
+       struct iov_iter iter;
+       struct kvec iov;
+       int length;
+
+       if (shdr->Command != SMB2_READ) {
+               cifs_dbg(VFS, "only big read responses are supported\n");
+               return -ENOTSUPP;
+       }
+
+       if (server->ops->is_status_pending &&
+                       server->ops->is_status_pending(buf, server, 0))
+               return -1;
+
+       rdata->result = server->ops->map_error(buf, false);
+       if (rdata->result != 0) {
+               cifs_dbg(FYI, "%s: server returned error %d\n",
+                        __func__, rdata->result);
+               dequeue_mid(mid, rdata->result);
+               return 0;
+       }
+
+       data_offset = server->ops->read_data_offset(buf) + 4;
+       data_len = server->ops->read_data_length(buf);
+
+       if (data_offset < server->vals->read_rsp_size) {
+               /*
+                * win2k8 sometimes sends an offset of 0 when the read
+                * is beyond the EOF. Treat it as if the data starts just after
+                * the header.
+                */
+               cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
+                        __func__, data_offset);
+               data_offset = server->vals->read_rsp_size;
+       } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
+               /* data_offset is beyond the end of smallbuf */
+               cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
+                        __func__, data_offset);
+               rdata->result = -EIO;
+               dequeue_mid(mid, rdata->result);
+               return 0;
+       }
+
+       pad_len = data_offset - server->vals->read_rsp_size;
+
+       if (buf_len <= data_offset) {
+               /* read response payload is in pages */
+               cur_page_idx = pad_len / PAGE_SIZE;
+               cur_off = pad_len % PAGE_SIZE;
+
+               if (cur_page_idx != 0) {
+                       /* data offset is beyond the 1st page of response */
+                       cifs_dbg(FYI, "%s: data offset (%u) beyond 1st page of response\n",
+                                __func__, data_offset);
+                       rdata->result = -EIO;
+                       dequeue_mid(mid, rdata->result);
+                       return 0;
+               }
+
+               if (data_len > page_data_size - pad_len) {
+                       /* data_len is corrupt -- discard frame */
+                       rdata->result = -EIO;
+                       dequeue_mid(mid, rdata->result);
+                       return 0;
+               }
+
+               rdata->result = init_read_bvec(pages, npages, page_data_size,
+                                              cur_off, &bvec);
+               if (rdata->result != 0) {
+                       dequeue_mid(mid, rdata->result);
+                       return 0;
+               }
+
+               iov_iter_bvec(&iter, WRITE | ITER_BVEC, bvec, npages, data_len);
+       } else if (buf_len >= data_offset + data_len) {
+               /* read response payload is in buf */
+               WARN_ONCE(npages > 0, "read data can be either in buf or in pages");
+               iov.iov_base = buf + data_offset;
+               iov.iov_len = data_len;
+               iov_iter_kvec(&iter, WRITE | ITER_KVEC, &iov, 1, data_len);
+       } else {
+               /* read response payload cannot be in both buf and pages */
+               WARN_ONCE(1, "buf can not contain only a part of read data");
+               rdata->result = -EIO;
+               dequeue_mid(mid, rdata->result);
+               return 0;
+       }
+
+       /* set up first iov for signature check */
+       rdata->iov[0].iov_base = buf;
+       rdata->iov[0].iov_len = 4;
+       rdata->iov[1].iov_base = buf + 4;
+       rdata->iov[1].iov_len = server->vals->read_rsp_size - 4;
+       cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
+                rdata->iov[0].iov_base, server->vals->read_rsp_size);
+
+       length = rdata->copy_into_pages(server, rdata, &iter);
+
+       kfree(bvec);
+
+       if (length < 0)
+               return length;
+
+       dequeue_mid(mid, false);
+       return length;
+}
+
+static int
+receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid)
+{
+       char *buf = server->smallbuf;
+       struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)buf;
+       unsigned int npages;
+       struct page **pages;
+       unsigned int len;
+       unsigned int buflen = get_rfc1002_length(buf) + 4;
+       int rc;
+       int i = 0;
+
+       len = min_t(unsigned int, buflen, server->vals->read_rsp_size - 4 +
+               sizeof(struct smb2_transform_hdr)) - HEADER_SIZE(server) + 1;
+
+       rc = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1, len);
+       if (rc < 0)
+               return rc;
+       server->total_read += rc;
+
+       len = le32_to_cpu(tr_hdr->OriginalMessageSize) + 4 -
+                                               server->vals->read_rsp_size;
+       npages = DIV_ROUND_UP(len, PAGE_SIZE);
+
+       pages = kmalloc_array(npages, sizeof(struct page *), GFP_KERNEL);
+       if (!pages) {
+               rc = -ENOMEM;
+               goto discard_data;
+       }
+
+       for (; i < npages; i++) {
+               pages[i] = alloc_page(GFP_KERNEL|__GFP_HIGHMEM);
+               if (!pages[i]) {
+                       rc = -ENOMEM;
+                       goto discard_data;
+               }
+       }
+
+       /* read read data into pages */
+       rc = read_data_into_pages(server, pages, npages, len);
+       if (rc)
+               goto free_pages;
+
+       rc = cifs_discard_remaining_data(server);
+       if (rc)
+               goto free_pages;
+
+       rc = decrypt_raw_data(server, buf, server->vals->read_rsp_size - 4,
+                             pages, npages, len);
+       if (rc)
+               goto free_pages;
+
+       *mid = smb2_find_mid(server, buf);
+       if (*mid == NULL)
+               cifs_dbg(FYI, "mid not found\n");
+       else {
+               cifs_dbg(FYI, "mid found\n");
+               (*mid)->decrypted = true;
+               rc = handle_read_data(server, *mid, buf,
+                                     server->vals->read_rsp_size,
+                                     pages, npages, len);
+       }
+
+free_pages:
+       for (i = i - 1; i >= 0; i--)
+               put_page(pages[i]);
+       kfree(pages);
+       return rc;
+discard_data:
+       cifs_discard_remaining_data(server);
+       goto free_pages;
+}
+
+static int
+receive_encrypted_standard(struct TCP_Server_Info *server,
+                          struct mid_q_entry **mid)
+{
+       int length;
+       char *buf = server->smallbuf;
+       unsigned int pdu_length = get_rfc1002_length(buf);
+       unsigned int buf_size;
+       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) {
+               server->large_buf = true;
+               memcpy(server->bigbuf, buf, server->total_read);
+               buf = server->bigbuf;
+       }
+
+       /* now read the rest */
+       length = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1,
+                               pdu_length - HEADER_SIZE(server) + 1 + 4);
+       if (length < 0)
+               return length;
+       server->total_read += length;
+
+       buf_size = pdu_length + 4 - sizeof(struct smb2_transform_hdr);
+       length = decrypt_raw_data(server, buf, buf_size, NULL, 0, 0);
+       if (length)
+               return length;
+
+       mid_entry = smb2_find_mid(server, buf);
+       if (mid_entry == NULL)
+               cifs_dbg(FYI, "mid not found\n");
+       else {
+               cifs_dbg(FYI, "mid found\n");
+               mid_entry->decrypted = true;
+       }
+
+       *mid = mid_entry;
+
+       if (mid_entry && mid_entry->handle)
+               return mid_entry->handle(server, mid_entry);
+
+       return cifs_handle_standard(server, mid_entry);
+}
+
+static int
+smb3_receive_transform(struct TCP_Server_Info *server, struct mid_q_entry **mid)
+{
+       char *buf = server->smallbuf;
+       unsigned int pdu_length = get_rfc1002_length(buf);
+       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) +
+                                               sizeof(struct smb2_sync_hdr)) {
+               cifs_dbg(VFS, "Transform message is too small (%u)\n",
+                        pdu_length);
+               cifs_reconnect(server);
+               wake_up(&server->response_q);
+               return -ECONNABORTED;
+       }
+
+       if (pdu_length + 4 < 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))
+               return receive_encrypted_read(server, mid);
+
+       return receive_encrypted_standard(server, mid);
+}
+
+int
+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,
+                               NULL, 0, 0);
+}
+
 struct smb_version_operations smb20_operations = {
        .compare_fids = smb2_compare_fids,
        .setup_request = smb2_setup_request,
@@ -1791,6 +2422,10 @@ struct smb_version_operations smb30_operations = {
        .dir_needs_close = smb2_dir_needs_close,
        .fallocate = smb3_fallocate,
        .enum_snapshots = smb3_enum_snapshots,
+       .init_transform_rq = smb3_init_transform_rq,
+       .free_transform_rq = smb3_free_transform_rq,
+       .is_transform_hdr = smb3_is_transform_hdr,
+       .receive_transform = smb3_receive_transform,
 };
 
 #ifdef CONFIG_CIFS_SMB311
@@ -1879,6 +2514,10 @@ struct smb_version_operations smb311_operations = {
        .dir_needs_close = smb2_dir_needs_close,
        .fallocate = smb3_fallocate,
        .enum_snapshots = smb3_enum_snapshots,
+       .init_transform_rq = smb3_init_transform_rq,
+       .free_transform_rq = smb3_free_transform_rq,
+       .is_transform_hdr = smb3_is_transform_hdr,
+       .receive_transform = smb3_receive_transform,
 };
 #endif /* CIFS_SMB311 */
 
index 87457227812c393fe1ee9e09bacd9f1c65d93f9e..ad83b3db284028afccf2e15e6d78300f055e48fe 100644 (file)
@@ -77,45 +77,42 @@ static const int smb2_req_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = {
        /* SMB2_OPLOCK_BREAK */ 24 /* BB this is 36 for LEASE_BREAK variant */
 };
 
+static int encryption_required(const struct cifs_tcon *tcon)
+{
+       if (!tcon)
+               return 0;
+       if ((tcon->ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA) ||
+           (tcon->share_flags & SHI1005_FLAGS_ENCRYPT_DATA))
+               return 1;
+       if (tcon->seal &&
+           (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION))
+               return 1;
+       return 0;
+}
 
 static void
-smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ ,
+smb2_hdr_assemble(struct smb2_sync_hdr *shdr, __le16 smb2_cmd,
                  const struct cifs_tcon *tcon)
 {
-       struct smb2_pdu *pdu = (struct smb2_pdu *)hdr;
-       char *temp = (char *)hdr;
-       /* lookup word count ie StructureSize from table */
-       __u16 parmsize = smb2_req_struct_sizes[le16_to_cpu(smb2_cmd)];
-
-       /*
-        * smaller than SMALL_BUFFER_SIZE but bigger than fixed area of
-        * largest operations (Create)
-        */
-       memset(temp, 0, 256);
-
-       /* Note this is only network field converted to big endian */
-       hdr->smb2_buf_length = cpu_to_be32(parmsize + sizeof(struct smb2_hdr)
-                       - 4 /*  RFC 1001 length field itself not counted */);
-
-       hdr->ProtocolId = SMB2_PROTO_NUMBER;
-       hdr->StructureSize = cpu_to_le16(64);
-       hdr->Command = smb2_cmd;
+       shdr->ProtocolId = SMB2_PROTO_NUMBER;
+       shdr->StructureSize = cpu_to_le16(64);
+       shdr->Command = smb2_cmd;
        if (tcon && tcon->ses && tcon->ses->server) {
                struct TCP_Server_Info *server = tcon->ses->server;
 
                spin_lock(&server->req_lock);
                /* Request up to 2 credits but don't go over the limit. */
                if (server->credits >= server->max_credits)
-                       hdr->CreditRequest = cpu_to_le16(0);
+                       shdr->CreditRequest = cpu_to_le16(0);
                else
-                       hdr->CreditRequest = cpu_to_le16(
+                       shdr->CreditRequest = cpu_to_le16(
                                min_t(int, server->max_credits -
                                                server->credits, 2));
                spin_unlock(&server->req_lock);
        } else {
-               hdr->CreditRequest = cpu_to_le16(2);
+               shdr->CreditRequest = cpu_to_le16(2);
        }
-       hdr->ProcessId = cpu_to_le32((__u16)current->tgid);
+       shdr->ProcessId = cpu_to_le32((__u16)current->tgid);
 
        if (!tcon)
                goto out;
@@ -124,13 +121,13 @@ smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ ,
        /* See sections 2.2.4 and 3.2.4.1.5 of MS-SMB2 */
        if ((tcon->ses) && (tcon->ses->server) &&
            (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
-               hdr->CreditCharge = cpu_to_le16(1);
+               shdr->CreditCharge = cpu_to_le16(1);
        /* else CreditCharge MBZ */
 
-       hdr->TreeId = tcon->tid;
+       shdr->TreeId = tcon->tid;
        /* Uid is not converted */
        if (tcon->ses)
-               hdr->SessionId = tcon->ses->Suid;
+               shdr->SessionId = tcon->ses->Suid;
 
        /*
         * If we would set SMB2_FLAGS_DFS_OPERATIONS on open we also would have
@@ -143,12 +140,12 @@ smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ ,
         * but it is safer to net set it for now.
         */
 /*     if (tcon->share_flags & SHI1005_FLAGS_DFS)
-               hdr->Flags |= SMB2_FLAGS_DFS_OPERATIONS; */
+               shdr->Flags |= SMB2_FLAGS_DFS_OPERATIONS; */
 
-       if (tcon->ses && tcon->ses->server && tcon->ses->server->sign)
-               hdr->Flags |= SMB2_FLAGS_SIGNED;
+       if (tcon->ses && tcon->ses->server && tcon->ses->server->sign &&
+           !encryption_required(tcon))
+               shdr->Flags |= SMB2_FLAGS_SIGNED;
 out:
-       pdu->StructureSize2 = cpu_to_le16(parmsize);
        return;
 }
 
@@ -289,16 +286,74 @@ out:
        return rc;
 }
 
+static void
+fill_small_buf(__le16 smb2_command, struct cifs_tcon *tcon, void *buf,
+              unsigned int *total_len)
+{
+       struct smb2_sync_pdu *spdu = (struct smb2_sync_pdu *)buf;
+       /* lookup word count ie StructureSize from table */
+       __u16 parmsize = smb2_req_struct_sizes[le16_to_cpu(smb2_command)];
+
+       /*
+        * smaller than SMALL_BUFFER_SIZE but bigger than fixed area of
+        * largest operations (Create)
+        */
+       memset(buf, 0, 256);
+
+       smb2_hdr_assemble(&spdu->sync_hdr, smb2_command, tcon);
+       spdu->StructureSize2 = cpu_to_le16(parmsize);
+
+       *total_len = parmsize + sizeof(struct smb2_sync_hdr);
+}
+
+/* init request without RFC1001 length at the beginning */
+static int
+smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon,
+                   void **request_buf, unsigned int *total_len)
+{
+       int rc;
+       struct smb2_sync_hdr *shdr;
+
+       rc = smb2_reconnect(smb2_command, tcon);
+       if (rc)
+               return rc;
+
+       /* BB eventually switch this to SMB2 specific small buf size */
+       *request_buf = cifs_small_buf_get();
+       if (*request_buf == NULL) {
+               /* BB should we add a retry in here if not a writepage? */
+               return -ENOMEM;
+       }
+
+       shdr = (struct smb2_sync_hdr *)(*request_buf);
+
+       fill_small_buf(smb2_command, tcon, shdr, total_len);
+
+       if (tcon != NULL) {
+#ifdef CONFIG_CIFS_STATS2
+               uint16_t com_code = le16_to_cpu(smb2_command);
+
+               cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_sent[com_code]);
+#endif
+               cifs_stats_inc(&tcon->num_smbs_sent);
+       }
+
+       return rc;
+}
+
 /*
  * Allocate and return pointer to an SMB request hdr, and set basic
  * SMB information in the SMB header. If the return code is zero, this
- * function must have filled in request_buf pointer.
+ * function must have filled in request_buf pointer. The returned buffer
+ * has RFC1001 length at the beginning.
  */
 static int
 small_smb2_init(__le16 smb2_command, struct cifs_tcon *tcon,
                void **request_buf)
 {
-       int rc = 0;
+       int rc;
+       unsigned int total_len;
+       struct smb2_pdu *pdu;
 
        rc = smb2_reconnect(smb2_command, tcon);
        if (rc)
@@ -311,7 +366,12 @@ small_smb2_init(__le16 smb2_command, struct cifs_tcon *tcon,
                return -ENOMEM;
        }
 
-       smb2_hdr_assemble((struct smb2_hdr *) *request_buf, smb2_command, tcon);
+       pdu = (struct smb2_pdu *)(*request_buf);
+
+       fill_small_buf(smb2_command, tcon, get_sync_hdr(pdu), &total_len);
+
+       /* Note this is only network field converted to big endian */
+       pdu->hdr.smb2_buf_length = cpu_to_be32(total_len);
 
        if (tcon != NULL) {
 #ifdef CONFIG_CIFS_STATS2
@@ -376,7 +436,6 @@ static void assemble_neg_contexts(struct smb2_negotiate_req *req)
 }
 #endif /* SMB311 */
 
-
 /*
  *
  *     SMB2 Worker functions follow:
@@ -398,6 +457,7 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
        struct smb2_negotiate_req *req;
        struct smb2_negotiate_rsp *rsp;
        struct kvec iov[1];
+       struct kvec rsp_iov;
        int rc = 0;
        int resp_buftype;
        struct TCP_Server_Info *server = ses->server;
@@ -416,7 +476,7 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
        if (rc)
                return rc;
 
-       req->hdr.SessionId = 0;
+       req->hdr.sync_hdr.SessionId = 0;
 
        req->Dialects[0] = cpu_to_le16(ses->server->vals->protocol_id);
 
@@ -446,9 +506,9 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
        /* 4 for rfc1002 length field */
        iov[0].iov_len = get_rfc1002_length(req) + 4;
 
-       rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, flags);
-
-       rsp = (struct smb2_negotiate_rsp *)iov[0].iov_base;
+       rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov);
+       cifs_small_buf_release(req);
+       rsp = (struct smb2_negotiate_rsp *)rsp_iov.iov_base;
        /*
         * No tcon so can't do
         * cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]);
@@ -627,14 +687,15 @@ SMB2_sess_alloc_buffer(struct SMB2_sess_data *sess_data)
        if (rc)
                return rc;
 
-       req->hdr.SessionId = 0; /* First session, not a reauthenticate */
+       /* First session, not a reauthenticate */
+       req->hdr.sync_hdr.SessionId = 0;
 
        /* if reconnect, we need to send previous sess id, otherwise it is 0 */
        req->PreviousSessionId = sess_data->previous_session;
 
        req->Flags = 0; /* MBZ */
        /* to enable echos and oplocks */
-       req->hdr.CreditRequest = cpu_to_le16(3);
+       req->hdr.sync_hdr.CreditRequest = cpu_to_le16(3);
 
        /* only one of SMB2 signing flags may be set in SMB2 request */
        if (server->sign)
@@ -671,6 +732,7 @@ SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data)
 {
        int rc;
        struct smb2_sess_setup_req *req = sess_data->iov[0].iov_base;
+       struct kvec rsp_iov = { NULL, 0 };
 
        /* Testing shows that buffer offset must be at location of Buffer[0] */
        req->SecurityBufferOffset =
@@ -685,7 +747,9 @@ SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data)
        rc = SendReceive2(sess_data->xid, sess_data->ses,
                                sess_data->iov, 2,
                                &sess_data->buf0_type,
-                               CIFS_LOG_ERROR | CIFS_NEG_OP);
+                               CIFS_LOG_ERROR | CIFS_NEG_OP, &rsp_iov);
+       cifs_small_buf_release(sess_data->iov[0].iov_base);
+       memcpy(&sess_data->iov[0], &rsp_iov, sizeof(struct kvec));
 
        return rc;
 }
@@ -697,15 +761,13 @@ SMB2_sess_establish_session(struct SMB2_sess_data *sess_data)
        struct cifs_ses *ses = sess_data->ses;
 
        mutex_lock(&ses->server->srv_mutex);
-       if (ses->server->sign && ses->server->ops->generate_signingkey) {
+       if (ses->server->ops->generate_signingkey) {
                rc = ses->server->ops->generate_signingkey(ses);
-               kfree(ses->auth_key.response);
-               ses->auth_key.response = NULL;
                if (rc) {
                        cifs_dbg(FYI,
                                "SMB3 session key generation failed\n");
                        mutex_unlock(&ses->server->srv_mutex);
-                       goto keygen_exit;
+                       return rc;
                }
        }
        if (!ses->server->session_estab) {
@@ -719,12 +781,6 @@ SMB2_sess_establish_session(struct SMB2_sess_data *sess_data)
        ses->status = CifsGood;
        ses->need_reconnect = false;
        spin_unlock(&GlobalMid_Lock);
-
-keygen_exit:
-       if (!ses->server->sign) {
-               kfree(ses->auth_key.response);
-               ses->auth_key.response = NULL;
-       }
        return rc;
 }
 
@@ -781,11 +837,9 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
                goto out_put_spnego_key;
 
        rsp = (struct smb2_sess_setup_rsp *)sess_data->iov[0].iov_base;
-       ses->Suid = rsp->hdr.SessionId;
+       ses->Suid = rsp->hdr.sync_hdr.SessionId;
 
        ses->session_flags = le16_to_cpu(rsp->SessionFlags);
-       if (ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA)
-               cifs_dbg(VFS, "SMB3 encryption not supported yet\n");
 
        rc = SMB2_sess_establish_session(sess_data);
 out_put_spnego_key:
@@ -859,7 +913,7 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
 
        /* If true, rc here is expected and not an error */
        if (sess_data->buf0_type != CIFS_NO_BUFFER &&
-               rsp->hdr.Status == STATUS_MORE_PROCESSING_REQUIRED)
+               rsp->hdr.sync_hdr.Status == STATUS_MORE_PROCESSING_REQUIRED)
                rc = 0;
 
        if (rc)
@@ -880,10 +934,8 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
        cifs_dbg(FYI, "rawntlmssp session setup challenge phase\n");
 
 
-       ses->Suid = rsp->hdr.SessionId;
+       ses->Suid = rsp->hdr.sync_hdr.SessionId;
        ses->session_flags = le16_to_cpu(rsp->SessionFlags);
-       if (ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA)
-               cifs_dbg(VFS, "SMB3 encryption not supported yet\n");
 
 out:
        kfree(ntlmssp_blob);
@@ -916,7 +968,7 @@ SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data)
                goto out;
 
        req = (struct smb2_sess_setup_req *) sess_data->iov[0].iov_base;
-       req->hdr.SessionId = ses->Suid;
+       req->hdr.sync_hdr.SessionId = ses->Suid;
 
        rc = build_ntlmssp_auth_blob(&ntlmssp_blob, &blob_length, ses,
                                        sess_data->nls_cp);
@@ -940,10 +992,8 @@ SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data)
 
        rsp = (struct smb2_sess_setup_rsp *)sess_data->iov[0].iov_base;
 
-       ses->Suid = rsp->hdr.SessionId;
+       ses->Suid = rsp->hdr.sync_hdr.SessionId;
        ses->session_flags = le16_to_cpu(rsp->SessionFlags);
-       if (ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA)
-               cifs_dbg(VFS, "SMB3 encryption not supported yet\n");
 
        rc = SMB2_sess_establish_session(sess_data);
 out:
@@ -1018,6 +1068,7 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
        struct smb2_logoff_req *req; /* response is also trivial struct */
        int rc = 0;
        struct TCP_Server_Info *server;
+       int flags = 0;
 
        cifs_dbg(FYI, "disconnect session %p\n", ses);
 
@@ -1035,11 +1086,15 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
                return rc;
 
         /* since no tcon, smb2_init can not do this, so do here */
-       req->hdr.SessionId = ses->Suid;
-       if (server->sign)
-               req->hdr.Flags |= SMB2_FLAGS_SIGNED;
+       req->hdr.sync_hdr.SessionId = ses->Suid;
+
+       if (ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA)
+               flags |= CIFS_TRANSFORM_REQ;
+       else if (server->sign)
+               req->hdr.sync_hdr.Flags |= SMB2_FLAGS_SIGNED;
 
-       rc = SendReceiveNoRsp(xid, ses, (char *) &req->hdr, 0);
+       rc = SendReceiveNoRsp(xid, ses, (char *) req, flags);
+       cifs_small_buf_release(req);
        /*
         * No tcon so can't do
         * cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]);
@@ -1071,11 +1126,13 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
        struct smb2_tree_connect_req *req;
        struct smb2_tree_connect_rsp *rsp = NULL;
        struct kvec iov[2];
+       struct kvec rsp_iov;
        int rc = 0;
        int resp_buftype;
        int unc_path_len;
        struct TCP_Server_Info *server;
        __le16 *unc_path = NULL;
+       int flags = 0;
 
        cifs_dbg(FYI, "TCON\n");
 
@@ -1087,12 +1144,6 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
        if (tcon && tcon->bad_network_name)
                return -ENOENT;
 
-       if ((tcon && tcon->seal) &&
-           ((ses->server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION) == 0)) {
-               cifs_dbg(VFS, "encryption requested but no server support");
-               return -EOPNOTSUPP;
-       }
-
        unc_path = kmalloc(MAX_SHARENAME_LENGTH * 2, GFP_KERNEL);
        if (unc_path == NULL)
                return -ENOMEM;
@@ -1111,11 +1162,15 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
        }
 
        if (tcon == NULL) {
+               if ((ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA))
+                       flags |= CIFS_TRANSFORM_REQ;
+
                /* since no tcon, smb2_init can not do this, so do here */
-               req->hdr.SessionId = ses->Suid;
+               req->hdr.sync_hdr.SessionId = ses->Suid;
                /* if (ses->server->sec_mode & SECMODE_SIGN_REQUIRED)
                        req->hdr.Flags |= SMB2_FLAGS_SIGNED; */
-       }
+       } else if (encryption_required(tcon))
+               flags |= CIFS_TRANSFORM_REQ;
 
        iov[0].iov_base = (char *)req;
        /* 4 for rfc1002 length field and 1 for pad */
@@ -1130,8 +1185,9 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
 
        inc_rfc1001_len(req, unc_path_len - 1 /* pad */);
 
-       rc = SendReceive2(xid, ses, iov, 2, &resp_buftype, 0);
-       rsp = (struct smb2_tree_connect_rsp *)iov[0].iov_base;
+       rc = SendReceive2(xid, ses, iov, 2, &resp_buftype, flags, &rsp_iov);
+       cifs_small_buf_release(req);
+       rsp = (struct smb2_tree_connect_rsp *)rsp_iov.iov_base;
 
        if (rc != 0) {
                if (tcon) {
@@ -1142,7 +1198,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
        }
 
        if (tcon == NULL) {
-               ses->ipc_tid = rsp->hdr.TreeId;
+               ses->ipc_tid = rsp->hdr.sync_hdr.TreeId;
                goto tcon_exit;
        }
 
@@ -1165,15 +1221,18 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
        tcon->maximal_access = le32_to_cpu(rsp->MaximalAccess);
        tcon->tidStatus = CifsGood;
        tcon->need_reconnect = false;
-       tcon->tid = rsp->hdr.TreeId;
+       tcon->tid = rsp->hdr.sync_hdr.TreeId;
        strlcpy(tcon->treeName, tree, sizeof(tcon->treeName));
 
        if ((rsp->Capabilities & SMB2_SHARE_CAP_DFS) &&
            ((tcon->share_flags & SHI1005_FLAGS_DFS) == 0))
                cifs_dbg(VFS, "DFS capability contradicts DFS flag\n");
+
+       if (tcon->seal &&
+           !(tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION))
+               cifs_dbg(VFS, "Encryption is requested but not supported\n");
+
        init_copy_chunk_defaults(tcon);
-       if (tcon->share_flags & SHI1005_FLAGS_ENCRYPT_DATA)
-               cifs_dbg(VFS, "Encrypted shares not supported");
        if (tcon->ses->server->ops->validate_negotiate)
                rc = tcon->ses->server->ops->validate_negotiate(xid, tcon);
 tcon_exit:
@@ -1182,7 +1241,7 @@ tcon_exit:
        return rc;
 
 tcon_error_exit:
-       if (rsp->hdr.Status == STATUS_BAD_NETWORK_NAME) {
+       if (rsp->hdr.sync_hdr.Status == STATUS_BAD_NETWORK_NAME) {
                cifs_dbg(VFS, "BAD_NETWORK_NAME: %s\n", tree);
                if (tcon)
                        tcon->bad_network_name = true;
@@ -1197,6 +1256,7 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
        int rc = 0;
        struct TCP_Server_Info *server;
        struct cifs_ses *ses = tcon->ses;
+       int flags = 0;
 
        cifs_dbg(FYI, "Tree Disconnect\n");
 
@@ -1212,7 +1272,11 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
        if (rc)
                return rc;
 
-       rc = SendReceiveNoRsp(xid, ses, (char *)&req->hdr, 0);
+       if (encryption_required(tcon))
+               flags |= CIFS_TRANSFORM_REQ;
+
+       rc = SendReceiveNoRsp(xid, ses, (char *)req, flags);
+       cifs_small_buf_release(req);
        if (rc)
                cifs_stats_fail_inc(tcon, SMB2_TREE_DISCONNECT_HE);
 
@@ -1474,14 +1538,16 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
        struct cifs_tcon *tcon = oparms->tcon;
        struct cifs_ses *ses = tcon->ses;
        struct kvec iov[4];
+       struct kvec rsp_iov;
        int resp_buftype;
        int uni_path_len;
        __le16 *copy_path = NULL;
        int copy_size;
        int rc = 0;
-       unsigned int num_iovecs = 2;
+       unsigned int n_iov = 2;
        __u32 file_attributes = 0;
        char *dhc_buf = NULL, *lc_buf = NULL;
+       int flags = 0;
 
        cifs_dbg(FYI, "create/open\n");
 
@@ -1494,6 +1560,9 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
        if (rc)
                return rc;
 
+       if (encryption_required(tcon))
+               flags |= CIFS_TRANSFORM_REQ;
+
        if (oparms->create_options & CREATE_OPTION_READONLY)
                file_attributes |= ATTR_READONLY;
        if (oparms->create_options & CREATE_OPTION_SPECIAL)
@@ -1544,25 +1613,25 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
            *oplock == SMB2_OPLOCK_LEVEL_NONE)
                req->RequestedOplockLevel = *oplock;
        else {
-               rc = add_lease_context(server, iov, &num_iovecs, oplock);
+               rc = add_lease_context(server, iov, &n_iov, oplock);
                if (rc) {
                        cifs_small_buf_release(req);
                        kfree(copy_path);
                        return rc;
                }
-               lc_buf = iov[num_iovecs-1].iov_base;
+               lc_buf = iov[n_iov-1].iov_base;
        }
 
        if (*oplock == SMB2_OPLOCK_LEVEL_BATCH) {
                /* need to set Next field of lease context if we request it */
                if (server->capabilities & SMB2_GLOBAL_CAP_LEASING) {
                        struct create_context *ccontext =
-                           (struct create_context *)iov[num_iovecs-1].iov_base;
+                           (struct create_context *)iov[n_iov-1].iov_base;
                        ccontext->Next =
                                cpu_to_le32(server->vals->create_lease_size);
                }
 
-               rc = add_durable_context(iov, &num_iovecs, oparms,
+               rc = add_durable_context(iov, &n_iov, oparms,
                                        tcon->use_persistent);
                if (rc) {
                        cifs_small_buf_release(req);
@@ -1570,11 +1639,12 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
                        kfree(lc_buf);
                        return rc;
                }
-               dhc_buf = iov[num_iovecs-1].iov_base;
+               dhc_buf = iov[n_iov-1].iov_base;
        }
 
-       rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buftype, 0);
-       rsp = (struct smb2_create_rsp *)iov[0].iov_base;
+       rc = SendReceive2(xid, ses, iov, n_iov, &resp_buftype, flags, &rsp_iov);
+       cifs_small_buf_release(req);
+       rsp = (struct smb2_create_rsp *)rsp_iov.iov_base;
 
        if (rc != 0) {
                cifs_stats_fail_inc(tcon, SMB2_CREATE_HE);
@@ -1618,12 +1688,15 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
 {
        struct smb2_ioctl_req *req;
        struct smb2_ioctl_rsp *rsp;
+       struct smb2_sync_hdr *shdr;
        struct TCP_Server_Info *server;
        struct cifs_ses *ses;
        struct kvec iov[2];
+       struct kvec rsp_iov;
        int resp_buftype;
-       int num_iovecs;
+       int n_iov;
        int rc = 0;
+       int flags = 0;
 
        cifs_dbg(FYI, "SMB2 IOCTL\n");
 
@@ -1648,6 +1721,9 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
        if (rc)
                return rc;
 
+       if (encryption_required(tcon))
+               flags |= CIFS_TRANSFORM_REQ;
+
        req->CtlCode = cpu_to_le32(opcode);
        req->PersistentFileId = persistent_fid;
        req->VolatileFileId = volatile_fid;
@@ -1659,9 +1735,9 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
                       cpu_to_le32(offsetof(struct smb2_ioctl_req, Buffer) - 4);
                iov[1].iov_base = in_data;
                iov[1].iov_len = indatalen;
-               num_iovecs = 2;
+               n_iov = 2;
        } else
-               num_iovecs = 1;
+               n_iov = 1;
 
        req->OutputOffset = 0;
        req->OutputCount = 0; /* MBZ */
@@ -1698,8 +1774,9 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
                iov[0].iov_len = get_rfc1002_length(req) + 4;
 
 
-       rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buftype, 0);
-       rsp = (struct smb2_ioctl_rsp *)iov[0].iov_base;
+       rc = SendReceive2(xid, ses, iov, n_iov, &resp_buftype, flags, &rsp_iov);
+       cifs_small_buf_release(req);
+       rsp = (struct smb2_ioctl_rsp *)rsp_iov.iov_base;
 
        if ((rc != 0) && (rc != -EINVAL)) {
                cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE);
@@ -1742,9 +1819,8 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
                goto ioctl_exit;
        }
 
-       memcpy(*out_data,
-              (char *)&rsp->hdr.ProtocolId + le32_to_cpu(rsp->OutputOffset),
-              *plen);
+       shdr = get_sync_hdr(rsp);
+       memcpy(*out_data, (char *)shdr + le32_to_cpu(rsp->OutputOffset), *plen);
 ioctl_exit:
        free_rsp_buf(resp_buftype, rsp);
        return rc;
@@ -1784,8 +1860,10 @@ SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
        struct TCP_Server_Info *server;
        struct cifs_ses *ses = tcon->ses;
        struct kvec iov[1];
+       struct kvec rsp_iov;
        int resp_buftype;
        int rc = 0;
+       int flags = 0;
 
        cifs_dbg(FYI, "Close\n");
 
@@ -1798,6 +1876,9 @@ SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
        if (rc)
                return rc;
 
+       if (encryption_required(tcon))
+               flags |= CIFS_TRANSFORM_REQ;
+
        req->PersistentFileId = persistent_fid;
        req->VolatileFileId = volatile_fid;
 
@@ -1805,8 +1886,9 @@ SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
        /* 4 for rfc1002 length field */
        iov[0].iov_len = get_rfc1002_length(req) + 4;
 
-       rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, 0);
-       rsp = (struct smb2_close_rsp *)iov[0].iov_base;
+       rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov);
+       cifs_small_buf_release(req);
+       rsp = (struct smb2_close_rsp *)rsp_iov.iov_base;
 
        if (rc != 0) {
                cifs_stats_fail_inc(tcon, SMB2_CLOSE_HE);
@@ -1885,10 +1967,12 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
        struct smb2_query_info_req *req;
        struct smb2_query_info_rsp *rsp = NULL;
        struct kvec iov[2];
+       struct kvec rsp_iov;
        int rc = 0;
        int resp_buftype;
        struct TCP_Server_Info *server;
        struct cifs_ses *ses = tcon->ses;
+       int flags = 0;
 
        cifs_dbg(FYI, "Query Info\n");
 
@@ -1901,6 +1985,9 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
        if (rc)
                return rc;
 
+       if (encryption_required(tcon))
+               flags |= CIFS_TRANSFORM_REQ;
+
        req->InfoType = SMB2_O_INFO_FILE;
        req->FileInfoClass = info_class;
        req->PersistentFileId = persistent_fid;
@@ -1914,8 +2001,9 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
        /* 4 for rfc1002 length field */
        iov[0].iov_len = get_rfc1002_length(req) + 4;
 
-       rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, 0);
-       rsp = (struct smb2_query_info_rsp *)iov[0].iov_base;
+       rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov);
+       cifs_small_buf_release(req);
+       rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
 
        if (rc) {
                cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
@@ -1963,11 +2051,11 @@ static void
 smb2_echo_callback(struct mid_q_entry *mid)
 {
        struct TCP_Server_Info *server = mid->callback_data;
-       struct smb2_echo_rsp *smb2 = (struct smb2_echo_rsp *)mid->resp_buf;
+       struct smb2_echo_rsp *rsp = (struct smb2_echo_rsp *)mid->resp_buf;
        unsigned int credits_received = 1;
 
        if (mid->mid_state == MID_RESPONSE_RECEIVED)
-               credits_received = le16_to_cpu(smb2->hdr.CreditRequest);
+               credits_received = le16_to_cpu(rsp->hdr.sync_hdr.CreditRequest);
 
        mutex_lock(&server->srv_mutex);
        DeleteMidQEntry(mid);
@@ -2029,9 +2117,9 @@ SMB2_echo(struct TCP_Server_Info *server)
 {
        struct smb2_echo_req *req;
        int rc = 0;
-       struct kvec iov;
-       struct smb_rqst rqst = { .rq_iov = &iov,
-                                .rq_nvec = 1 };
+       struct kvec iov[2];
+       struct smb_rqst rqst = { .rq_iov = iov,
+                                .rq_nvec = 2 };
 
        cifs_dbg(FYI, "In echo request\n");
 
@@ -2045,14 +2133,16 @@ SMB2_echo(struct TCP_Server_Info *server)
        if (rc)
                return rc;
 
-       req->hdr.CreditRequest = cpu_to_le16(1);
+       req->hdr.sync_hdr.CreditRequest = cpu_to_le16(1);
 
-       iov.iov_base = (char *)req;
        /* 4 for rfc1002 length field */
-       iov.iov_len = get_rfc1002_length(req) + 4;
+       iov[0].iov_len = 4;
+       iov[0].iov_base = (char *)req;
+       iov[1].iov_len = get_rfc1002_length(req);
+       iov[1].iov_base = (char *)req + 4;
 
-       rc = cifs_call_async(server, &rqst, NULL, smb2_echo_callback, server,
-                            CIFS_ECHO_OP);
+       rc = cifs_call_async(server, &rqst, NULL, smb2_echo_callback, NULL,
+                            server, CIFS_ECHO_OP);
        if (rc)
                cifs_dbg(FYI, "Echo request failed: %d\n", rc);
 
@@ -2068,8 +2158,10 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
        struct TCP_Server_Info *server;
        struct cifs_ses *ses = tcon->ses;
        struct kvec iov[1];
+       struct kvec rsp_iov;
        int resp_buftype;
        int rc = 0;
+       int flags = 0;
 
        cifs_dbg(FYI, "Flush\n");
 
@@ -2082,6 +2174,9 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
        if (rc)
                return rc;
 
+       if (encryption_required(tcon))
+               flags |= CIFS_TRANSFORM_REQ;
+
        req->PersistentFileId = persistent_fid;
        req->VolatileFileId = volatile_fid;
 
@@ -2089,12 +2184,13 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
        /* 4 for rfc1002 length field */
        iov[0].iov_len = get_rfc1002_length(req) + 4;
 
-       rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, 0);
+       rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, flags, &rsp_iov);
+       cifs_small_buf_release(req);
 
        if (rc != 0)
                cifs_stats_fail_inc(tcon, SMB2_FLUSH_HE);
 
-       free_rsp_buf(resp_buftype, iov[0].iov_base);
+       free_rsp_buf(resp_buftype, rsp_iov.iov_base);
        return rc;
 }
 
@@ -2103,19 +2199,23 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
  * have the end_of_chain boolean set to true.
  */
 static int
-smb2_new_read_req(struct kvec *iov, struct cifs_io_parms *io_parms,
-                 unsigned int remaining_bytes, int request_type)
+smb2_new_read_req(void **buf, unsigned int *total_len,
+                 struct cifs_io_parms *io_parms, unsigned int remaining_bytes,
+                 int request_type)
 {
        int rc = -EACCES;
-       struct smb2_read_req *req = NULL;
+       struct smb2_read_plain_req *req = NULL;
+       struct smb2_sync_hdr *shdr;
 
-       rc = small_smb2_init(SMB2_READ, io_parms->tcon, (void **) &req);
+       rc = smb2_plain_req_init(SMB2_READ, io_parms->tcon, (void **) &req,
+                                total_len);
        if (rc)
                return rc;
        if (io_parms->tcon->ses->server == NULL)
                return -ECONNABORTED;
 
-       req->hdr.ProcessId = cpu_to_le32(io_parms->pid);
+       shdr = &req->sync_hdr;
+       shdr->ProcessId = cpu_to_le32(io_parms->pid);
 
        req->PersistentFileId = io_parms->persistent_fid;
        req->VolatileFileId = io_parms->volatile_fid;
@@ -2128,19 +2228,19 @@ smb2_new_read_req(struct kvec *iov, struct cifs_io_parms *io_parms,
 
        if (request_type & CHAINED_REQUEST) {
                if (!(request_type & END_OF_CHAIN)) {
-                       /* 4 for rfc1002 length field */
-                       req->hdr.NextCommand =
-                               cpu_to_le32(get_rfc1002_length(req) + 4);
+                       /* next 8-byte aligned request */
+                       *total_len = DIV_ROUND_UP(*total_len, 8) * 8;
+                       shdr->NextCommand = cpu_to_le32(*total_len);
                } else /* END_OF_CHAIN */
-                       req->hdr.NextCommand = 0;
+                       shdr->NextCommand = 0;
                if (request_type & RELATED_REQUEST) {
-                       req->hdr.Flags |= SMB2_FLAGS_RELATED_OPERATIONS;
+                       shdr->Flags |= SMB2_FLAGS_RELATED_OPERATIONS;
                        /*
                         * Related requests use info from previous read request
                         * in chain.
                         */
-                       req->hdr.SessionId = 0xFFFFFFFF;
-                       req->hdr.TreeId = 0xFFFFFFFF;
+                       shdr->SessionId = 0xFFFFFFFF;
+                       shdr->TreeId = 0xFFFFFFFF;
                        req->PersistentFileId = 0xFFFFFFFF;
                        req->VolatileFileId = 0xFFFFFFFF;
                }
@@ -2150,9 +2250,7 @@ smb2_new_read_req(struct kvec *iov, struct cifs_io_parms *io_parms,
        else
                req->RemainingBytes = 0;
 
-       iov[0].iov_base = (char *)req;
-       /* 4 for rfc1002 length field */
-       iov[0].iov_len = get_rfc1002_length(req) + 4;
+       *buf = req;
        return rc;
 }
 
@@ -2162,10 +2260,11 @@ smb2_readv_callback(struct mid_q_entry *mid)
        struct cifs_readdata *rdata = mid->callback_data;
        struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
        struct TCP_Server_Info *server = tcon->ses->server;
-       struct smb2_hdr *buf = (struct smb2_hdr *)rdata->iov.iov_base;
+       struct smb2_sync_hdr *shdr =
+                               (struct smb2_sync_hdr *)rdata->iov[1].iov_base;
        unsigned int credits_received = 1;
-       struct smb_rqst rqst = { .rq_iov = &rdata->iov,
-                                .rq_nvec = 1,
+       struct smb_rqst rqst = { .rq_iov = rdata->iov,
+                                .rq_nvec = 2,
                                 .rq_pages = rdata->pages,
                                 .rq_npages = rdata->nr_pages,
                                 .rq_pagesz = rdata->pagesz,
@@ -2177,9 +2276,9 @@ smb2_readv_callback(struct mid_q_entry *mid)
 
        switch (mid->mid_state) {
        case MID_RESPONSE_RECEIVED:
-               credits_received = le16_to_cpu(buf->CreditRequest);
+               credits_received = le16_to_cpu(shdr->CreditRequest);
                /* result already set, check signature */
-               if (server->sign) {
+               if (server->sign && !mid->decrypted) {
                        int rc;
 
                        rc = smb2_verify_signature(&rqst, server);
@@ -2216,16 +2315,19 @@ smb2_readv_callback(struct mid_q_entry *mid)
        add_credits(server, credits_received, 0);
 }
 
-/* smb2_async_readv - send an async write, and set up mid to handle result */
+/* smb2_async_readv - send an async read, and set up mid to handle result */
 int
 smb2_async_readv(struct cifs_readdata *rdata)
 {
        int rc, flags = 0;
-       struct smb2_hdr *buf;
+       char *buf;
+       struct smb2_sync_hdr *shdr;
        struct cifs_io_parms io_parms;
-       struct smb_rqst rqst = { .rq_iov = &rdata->iov,
-                                .rq_nvec = 1 };
+       struct smb_rqst rqst = { .rq_iov = rdata->iov,
+                                .rq_nvec = 2 };
        struct TCP_Server_Info *server;
+       unsigned int total_len;
+       __be32 req_len;
 
        cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
                 __func__, rdata->offset, rdata->bytes);
@@ -2239,7 +2341,7 @@ smb2_async_readv(struct cifs_readdata *rdata)
 
        server = io_parms.tcon->ses->server;
 
-       rc = smb2_new_read_req(&rdata->iov, &io_parms, 0, 0);
+       rc = smb2_new_read_req((void **) &buf, &total_len, &io_parms, 0, 0);
        if (rc) {
                if (rc == -EAGAIN && rdata->credits) {
                        /* credits was reset by reconnect */
@@ -2252,26 +2354,34 @@ smb2_async_readv(struct cifs_readdata *rdata)
                return rc;
        }
 
-       buf = (struct smb2_hdr *)rdata->iov.iov_base;
-       /* 4 for rfc1002 length field */
-       rdata->iov.iov_len = get_rfc1002_length(rdata->iov.iov_base) + 4;
+       if (encryption_required(io_parms.tcon))
+               flags |= CIFS_TRANSFORM_REQ;
+
+       req_len = cpu_to_be32(total_len);
+
+       rdata->iov[0].iov_base = &req_len;
+       rdata->iov[0].iov_len = sizeof(__be32);
+       rdata->iov[1].iov_base = buf;
+       rdata->iov[1].iov_len = total_len;
+
+       shdr = (struct smb2_sync_hdr *)buf;
 
        if (rdata->credits) {
-               buf->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes,
+               shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes,
                                                SMB2_MAX_BUFFER_SIZE));
-               buf->CreditRequest = buf->CreditCharge;
+               shdr->CreditRequest = shdr->CreditCharge;
                spin_lock(&server->req_lock);
                server->credits += rdata->credits -
-                                               le16_to_cpu(buf->CreditCharge);
+                                               le16_to_cpu(shdr->CreditCharge);
                spin_unlock(&server->req_lock);
                wake_up(&server->request_q);
-               flags = CIFS_HAS_CREDITS;
+               flags |= CIFS_HAS_CREDITS;
        }
 
        kref_get(&rdata->refcount);
        rc = cifs_call_async(io_parms.tcon->ses->server, &rqst,
                             cifs_readv_receive, smb2_readv_callback,
-                            rdata, flags);
+                            smb3_handle_read_data, rdata, flags);
        if (rc) {
                kref_put(&rdata->refcount, cifs_readdata_release);
                cifs_stats_fail_inc(io_parms.tcon, SMB2_READ_HE);
@@ -2286,21 +2396,41 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
          unsigned int *nbytes, char **buf, int *buf_type)
 {
        int resp_buftype, rc = -EACCES;
+       struct smb2_read_plain_req *req = NULL;
        struct smb2_read_rsp *rsp = NULL;
-       struct kvec iov[1];
+       struct smb2_sync_hdr *shdr;
+       struct kvec iov[2];
+       struct kvec rsp_iov;
+       unsigned int total_len;
+       __be32 req_len;
+       struct smb_rqst rqst = { .rq_iov = iov,
+                                .rq_nvec = 2 };
+       int flags = CIFS_LOG_ERROR;
+       struct cifs_ses *ses = io_parms->tcon->ses;
 
        *nbytes = 0;
-       rc = smb2_new_read_req(iov, io_parms, 0, 0);
+       rc = smb2_new_read_req((void **)&req, &total_len, io_parms, 0, 0);
        if (rc)
                return rc;
 
-       rc = SendReceive2(xid, io_parms->tcon->ses, iov, 1,
-                         &resp_buftype, CIFS_LOG_ERROR);
+       if (encryption_required(io_parms->tcon))
+               flags |= CIFS_TRANSFORM_REQ;
 
-       rsp = (struct smb2_read_rsp *)iov[0].iov_base;
+       req_len = cpu_to_be32(total_len);
 
-       if (rsp->hdr.Status == STATUS_END_OF_FILE) {
-               free_rsp_buf(resp_buftype, iov[0].iov_base);
+       iov[0].iov_base = &req_len;
+       iov[0].iov_len = sizeof(__be32);
+       iov[1].iov_base = req;
+       iov[1].iov_len = total_len;
+
+       rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
+       cifs_small_buf_release(req);
+
+       rsp = (struct smb2_read_rsp *)rsp_iov.iov_base;
+       shdr = get_sync_hdr(rsp);
+
+       if (shdr->Status == STATUS_END_OF_FILE) {
+               free_rsp_buf(resp_buftype, rsp_iov.iov_base);
                return 0;
        }
 
@@ -2319,11 +2449,10 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
        }
 
        if (*buf) {
-               memcpy(*buf, (char *)&rsp->hdr.ProtocolId + rsp->DataOffset,
-                      *nbytes);
-               free_rsp_buf(resp_buftype, iov[0].iov_base);
+               memcpy(*buf, (char *)shdr + rsp->DataOffset, *nbytes);
+               free_rsp_buf(resp_buftype, rsp_iov.iov_base);
        } else if (resp_buftype != CIFS_NO_BUFFER) {
-               *buf = iov[0].iov_base;
+               *buf = rsp_iov.iov_base;
                if (resp_buftype == CIFS_SMALL_BUFFER)
                        *buf_type = CIFS_SMALL_BUFFER;
                else if (resp_buftype == CIFS_LARGE_BUFFER)
@@ -2348,7 +2477,7 @@ smb2_writev_callback(struct mid_q_entry *mid)
 
        switch (mid->mid_state) {
        case MID_RESPONSE_RECEIVED:
-               credits_received = le16_to_cpu(rsp->hdr.CreditRequest);
+               credits_received = le16_to_cpu(rsp->hdr.sync_hdr.CreditRequest);
                wdata->result = smb2_check_receive(mid, tcon->ses->server, 0);
                if (wdata->result != 0)
                        break;
@@ -2394,10 +2523,11 @@ smb2_async_writev(struct cifs_writedata *wdata,
 {
        int rc = -EACCES, flags = 0;
        struct smb2_write_req *req = NULL;
+       struct smb2_sync_hdr *shdr;
        struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
        struct TCP_Server_Info *server = tcon->ses->server;
-       struct kvec iov;
-       struct smb_rqst rqst;
+       struct kvec iov[2];
+       struct smb_rqst rqst = { };
 
        rc = small_smb2_init(SMB2_WRITE, tcon, (void **) &req);
        if (rc) {
@@ -2412,7 +2542,11 @@ smb2_async_writev(struct cifs_writedata *wdata,
                goto async_writev_out;
        }
 
-       req->hdr.ProcessId = cpu_to_le32(wdata->cfile->pid);
+       if (encryption_required(tcon))
+               flags |= CIFS_TRANSFORM_REQ;
+
+       shdr = get_sync_hdr(req);
+       shdr->ProcessId = cpu_to_le32(wdata->cfile->pid);
 
        req->PersistentFileId = wdata->cfile->fid.persistent_fid;
        req->VolatileFileId = wdata->cfile->fid.volatile_fid;
@@ -2426,11 +2560,13 @@ smb2_async_writev(struct cifs_writedata *wdata,
        req->RemainingBytes = 0;
 
        /* 4 for rfc1002 length field and 1 for Buffer */
-       iov.iov_len = get_rfc1002_length(req) + 4 - 1;
-       iov.iov_base = req;
+       iov[0].iov_len = 4;
+       iov[0].iov_base = req;
+       iov[1].iov_len = get_rfc1002_length(req) - 1;
+       iov[1].iov_base = (char *)req + 4;
 
-       rqst.rq_iov = &iov;
-       rqst.rq_nvec = 1;
+       rqst.rq_iov = iov;
+       rqst.rq_nvec = 2;
        rqst.rq_pages = wdata->pages;
        rqst.rq_npages = wdata->nr_pages;
        rqst.rq_pagesz = wdata->pagesz;
@@ -2444,20 +2580,20 @@ smb2_async_writev(struct cifs_writedata *wdata,
        inc_rfc1001_len(&req->hdr, wdata->bytes - 1 /* Buffer */);
 
        if (wdata->credits) {
-               req->hdr.CreditCharge = cpu_to_le16(DIV_ROUND_UP(wdata->bytes,
+               shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(wdata->bytes,
                                                    SMB2_MAX_BUFFER_SIZE));
-               req->hdr.CreditRequest = req->hdr.CreditCharge;
+               shdr->CreditRequest = shdr->CreditCharge;
                spin_lock(&server->req_lock);
                server->credits += wdata->credits -
-                                       le16_to_cpu(req->hdr.CreditCharge);
+                                               le16_to_cpu(shdr->CreditCharge);
                spin_unlock(&server->req_lock);
                wake_up(&server->request_q);
-               flags = CIFS_HAS_CREDITS;
+               flags |= CIFS_HAS_CREDITS;
        }
 
        kref_get(&wdata->refcount);
-       rc = cifs_call_async(server, &rqst, NULL, smb2_writev_callback, wdata,
-                            flags);
+       rc = cifs_call_async(server, &rqst, NULL, smb2_writev_callback, NULL,
+                            wdata, flags);
 
        if (rc) {
                kref_put(&wdata->refcount, release);
@@ -2483,6 +2619,9 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
        struct smb2_write_req *req = NULL;
        struct smb2_write_rsp *rsp = NULL;
        int resp_buftype;
+       struct kvec rsp_iov;
+       int flags = 0;
+
        *nbytes = 0;
 
        if (n_vec < 1)
@@ -2495,7 +2634,10 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
        if (io_parms->tcon->ses->server == NULL)
                return -ECONNABORTED;
 
-       req->hdr.ProcessId = cpu_to_le32(io_parms->pid);
+       if (encryption_required(io_parms->tcon))
+               flags |= CIFS_TRANSFORM_REQ;
+
+       req->hdr.sync_hdr.ProcessId = cpu_to_le32(io_parms->pid);
 
        req->PersistentFileId = io_parms->persistent_fid;
        req->VolatileFileId = io_parms->volatile_fid;
@@ -2517,8 +2659,9 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
        inc_rfc1001_len(req, io_parms->length - 1 /* Buffer */);
 
        rc = SendReceive2(xid, io_parms->tcon->ses, iov, n_vec + 1,
-                         &resp_buftype, 0);
-       rsp = (struct smb2_write_rsp *)iov[0].iov_base;
+                         &resp_buftype, flags, &rsp_iov);
+       cifs_small_buf_release(req);
+       rsp = (struct smb2_write_rsp *)rsp_iov.iov_base;
 
        if (rc) {
                cifs_stats_fail_inc(io_parms->tcon, SMB2_WRITE_HE);
@@ -2581,6 +2724,7 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
        struct smb2_query_directory_req *req;
        struct smb2_query_directory_rsp *rsp = NULL;
        struct kvec iov[2];
+       struct kvec rsp_iov;
        int rc = 0;
        int len;
        int resp_buftype = CIFS_NO_BUFFER;
@@ -2591,6 +2735,7 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
        char *end_of_smb;
        unsigned int output_size = CIFSMaxBufSize;
        size_t info_buf_size;
+       int flags = 0;
 
        if (ses && (ses->server))
                server = ses->server;
@@ -2601,6 +2746,9 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
        if (rc)
                return rc;
 
+       if (encryption_required(tcon))
+               flags |= CIFS_TRANSFORM_REQ;
+
        switch (srch_inf->info_level) {
        case SMB_FIND_FILE_DIRECTORY_INFO:
                req->FileInformationClass = FILE_DIRECTORY_INFORMATION;
@@ -2645,11 +2793,13 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
 
        inc_rfc1001_len(req, len - 1 /* Buffer */);
 
-       rc = SendReceive2(xid, ses, iov, 2, &resp_buftype, 0);
-       rsp = (struct smb2_query_directory_rsp *)iov[0].iov_base;
+       rc = SendReceive2(xid, ses, iov, 2, &resp_buftype, flags, &rsp_iov);
+       cifs_small_buf_release(req);
+       rsp = (struct smb2_query_directory_rsp *)rsp_iov.iov_base;
 
        if (rc) {
-               if (rc == -ENODATA && rsp->hdr.Status == STATUS_NO_MORE_FILES) {
+               if (rc == -ENODATA &&
+                   rsp->hdr.sync_hdr.Status == STATUS_NO_MORE_FILES) {
                        srch_inf->endOfSearch = true;
                        rc = 0;
                }
@@ -2705,11 +2855,13 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
        struct smb2_set_info_req *req;
        struct smb2_set_info_rsp *rsp = NULL;
        struct kvec *iov;
+       struct kvec rsp_iov;
        int rc = 0;
        int resp_buftype;
        unsigned int i;
        struct TCP_Server_Info *server;
        struct cifs_ses *ses = tcon->ses;
+       int flags = 0;
 
        if (ses && (ses->server))
                server = ses->server;
@@ -2729,7 +2881,10 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
                return rc;
        }
 
-       req->hdr.ProcessId = cpu_to_le32(pid);
+       if (encryption_required(tcon))
+               flags |= CIFS_TRANSFORM_REQ;
+
+       req->hdr.sync_hdr.ProcessId = cpu_to_le32(pid);
 
        req->InfoType = SMB2_O_INFO_FILE;
        req->FileInfoClass = info_class;
@@ -2756,8 +2911,9 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
                iov[i].iov_len = size[i];
        }
 
-       rc = SendReceive2(xid, ses, iov, num, &resp_buftype, 0);
-       rsp = (struct smb2_set_info_rsp *)iov[0].iov_base;
+       rc = SendReceive2(xid, ses, iov, num, &resp_buftype, flags, &rsp_iov);
+       cifs_small_buf_release(req);
+       rsp = (struct smb2_set_info_rsp *)rsp_iov.iov_base;
 
        if (rc != 0)
                cifs_stats_fail_inc(tcon, SMB2_SET_INFO_HE);
@@ -2885,20 +3041,23 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
 {
        int rc;
        struct smb2_oplock_break *req = NULL;
+       int flags = CIFS_OBREAK_OP;
 
        cifs_dbg(FYI, "SMB2_oplock_break\n");
        rc = small_smb2_init(SMB2_OPLOCK_BREAK, tcon, (void **) &req);
-
        if (rc)
                return rc;
 
+       if (encryption_required(tcon))
+               flags |= CIFS_TRANSFORM_REQ;
+
        req->VolatileFid = volatile_fid;
        req->PersistentFid = persistent_fid;
        req->OplockLevel = oplock_level;
-       req->hdr.CreditRequest = cpu_to_le16(1);
+       req->hdr.sync_hdr.CreditRequest = cpu_to_le16(1);
 
-       rc = SendReceiveNoRsp(xid, tcon->ses, (char *) req, CIFS_OBREAK_OP);
-       /* SMB2 buffer freed by function above */
+       rc = SendReceiveNoRsp(xid, tcon->ses, (char *) req, flags);
+       cifs_small_buf_release(req);
 
        if (rc) {
                cifs_stats_fail_inc(tcon, SMB2_OPLOCK_BREAK_HE);
@@ -2958,10 +3117,12 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
 {
        struct smb2_query_info_rsp *rsp = NULL;
        struct kvec iov;
+       struct kvec rsp_iov;
        int rc = 0;
        int resp_buftype;
        struct cifs_ses *ses = tcon->ses;
        struct smb2_fs_full_size_info *info = NULL;
+       int flags = 0;
 
        rc = build_qfs_info_req(&iov, tcon, FS_FULL_SIZE_INFORMATION,
                                sizeof(struct smb2_fs_full_size_info),
@@ -2969,12 +3130,16 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
        if (rc)
                return rc;
 
-       rc = SendReceive2(xid, ses, &iov, 1, &resp_buftype, 0);
+       if (encryption_required(tcon))
+               flags |= CIFS_TRANSFORM_REQ;
+
+       rc = SendReceive2(xid, ses, &iov, 1, &resp_buftype, flags, &rsp_iov);
+       cifs_small_buf_release(iov.iov_base);
        if (rc) {
                cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
                goto qfsinf_exit;
        }
-       rsp = (struct smb2_query_info_rsp *)iov.iov_base;
+       rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
 
        info = (struct smb2_fs_full_size_info *)(4 /* RFC1001 len */ +
                le16_to_cpu(rsp->OutputBufferOffset) + (char *)&rsp->hdr);
@@ -2985,7 +3150,7 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
                copy_fs_info_to_kstatfs(info, fsdata);
 
 qfsinf_exit:
-       free_rsp_buf(resp_buftype, iov.iov_base);
+       free_rsp_buf(resp_buftype, rsp_iov.iov_base);
        return rc;
 }
 
@@ -2995,10 +3160,12 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
 {
        struct smb2_query_info_rsp *rsp = NULL;
        struct kvec iov;
+       struct kvec rsp_iov;
        int rc = 0;
        int resp_buftype, max_len, min_len;
        struct cifs_ses *ses = tcon->ses;
        unsigned int rsp_len, offset;
+       int flags = 0;
 
        if (level == FS_DEVICE_INFORMATION) {
                max_len = sizeof(FILE_SYSTEM_DEVICE_INFO);
@@ -3019,12 +3186,16 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
        if (rc)
                return rc;
 
-       rc = SendReceive2(xid, ses, &iov, 1, &resp_buftype, 0);
+       if (encryption_required(tcon))
+               flags |= CIFS_TRANSFORM_REQ;
+
+       rc = SendReceive2(xid, ses, &iov, 1, &resp_buftype, flags, &rsp_iov);
+       cifs_small_buf_release(iov.iov_base);
        if (rc) {
                cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
                goto qfsattr_exit;
        }
-       rsp = (struct smb2_query_info_rsp *)iov.iov_base;
+       rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
 
        rsp_len = le32_to_cpu(rsp->OutputBufferLength);
        offset = le16_to_cpu(rsp->OutputBufferOffset);
@@ -3048,7 +3219,7 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
        }
 
 qfsattr_exit:
-       free_rsp_buf(resp_buftype, iov.iov_base);
+       free_rsp_buf(resp_buftype, rsp_iov.iov_base);
        return rc;
 }
 
@@ -3060,8 +3231,10 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
        int rc = 0;
        struct smb2_lock_req *req = NULL;
        struct kvec iov[2];
+       struct kvec rsp_iov;
        int resp_buf_type;
        unsigned int count;
+       int flags = CIFS_NO_RESP;
 
        cifs_dbg(FYI, "smb2_lockv num lock %d\n", num_lock);
 
@@ -3069,7 +3242,10 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
        if (rc)
                return rc;
 
-       req->hdr.ProcessId = cpu_to_le32(pid);
+       if (encryption_required(tcon))
+               flags |= CIFS_TRANSFORM_REQ;
+
+       req->hdr.sync_hdr.ProcessId = cpu_to_le32(pid);
        req->LockCount = cpu_to_le16(num_lock);
 
        req->PersistentFileId = persist_fid;
@@ -3085,7 +3261,9 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
        iov[1].iov_len = count;
 
        cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
-       rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
+       rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, flags,
+                         &rsp_iov);
+       cifs_small_buf_release(req);
        if (rc) {
                cifs_dbg(FYI, "Send error in smb2_lockv = %d\n", rc);
                cifs_stats_fail_inc(tcon, SMB2_LOCK_HE);
@@ -3117,22 +3295,25 @@ SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon,
 {
        int rc;
        struct smb2_lease_ack *req = NULL;
+       int flags = CIFS_OBREAK_OP;
 
        cifs_dbg(FYI, "SMB2_lease_break\n");
        rc = small_smb2_init(SMB2_OPLOCK_BREAK, tcon, (void **) &req);
-
        if (rc)
                return rc;
 
-       req->hdr.CreditRequest = cpu_to_le16(1);
+       if (encryption_required(tcon))
+               flags |= CIFS_TRANSFORM_REQ;
+
+       req->hdr.sync_hdr.CreditRequest = cpu_to_le16(1);
        req->StructureSize = cpu_to_le16(36);
        inc_rfc1001_len(req, 12);
 
        memcpy(req->LeaseKey, lease_key, 16);
        req->LeaseState = lease_state;
 
-       rc = SendReceiveNoRsp(xid, tcon->ses, (char *) req, CIFS_OBREAK_OP);
-       /* SMB2 buffer freed by function above */
+       rc = SendReceiveNoRsp(xid, tcon->ses, (char *) req, flags);
+       cifs_small_buf_release(req);
 
        if (rc) {
                cifs_stats_fail_inc(tcon, SMB2_OPLOCK_BREAK_HE);
index dc0d141f33e25730ea0242d2f946034e321cb1a4..c03b252501a155faf6fce1b19a759ddfa8f467dd 100644 (file)
 
 #define SMB2_HEADER_STRUCTURE_SIZE cpu_to_le16(64)
 
-struct smb2_hdr {
-       __be32 smb2_buf_length; /* big endian on wire */
-                               /* length is only two or three bytes - with
-                                one or two byte type preceding it that MBZ */
+struct smb2_sync_hdr {
        __le32 ProtocolId;      /* 0xFE 'S' 'M' 'B' */
        __le16 StructureSize;   /* 64 */
        __le16 CreditCharge;    /* MBZ */
@@ -120,16 +117,31 @@ struct smb2_hdr {
        __u8   Signature[16];
 } __packed;
 
+struct smb2_sync_pdu {
+       struct smb2_sync_hdr sync_hdr;
+       __le16 StructureSize2; /* size of wct area (varies, request specific) */
+} __packed;
+
+struct smb2_hdr {
+       __be32 smb2_buf_length; /* big endian on wire */
+                               /* length is only two or three bytes - with */
+                               /* one or two byte type preceding it that MBZ */
+       struct smb2_sync_hdr sync_hdr;
+} __packed;
+
 struct smb2_pdu {
        struct smb2_hdr hdr;
        __le16 StructureSize2; /* size of wct area (varies, request specific) */
 } __packed;
 
+#define SMB3_AES128CMM_NONCE 11
+#define SMB3_AES128GCM_NONCE 12
+
 struct smb2_transform_hdr {
        __be32 smb2_buf_length; /* big endian on wire */
                                /* length is only two or three bytes - with
                                 one or two byte type preceding it that MBZ */
-       __u8   ProtocolId[4];   /* 0xFD 'S' 'M' 'B' */
+       __le32 ProtocolId;      /* 0xFD 'S' 'M' 'B' */
        __u8   Signature[16];
        __u8   Nonce[16];
        __le32 OriginalMessageSize;
@@ -814,8 +826,9 @@ struct smb2_flush_rsp {
 #define SMB2_CHANNEL_RDMA_V1           0x00000001 /* SMB3 or later */
 #define SMB2_CHANNEL_RDMA_V1_INVALIDATE 0x00000001 /* SMB3.02 or later */
 
-struct smb2_read_req {
-       struct smb2_hdr hdr;
+/* SMB2 read request without RFC1001 length at the beginning */
+struct smb2_read_plain_req {
+       struct smb2_sync_hdr sync_hdr;
        __le16 StructureSize; /* Must be 49 */
        __u8   Padding; /* offset from start of SMB2 header to place read */
        __u8   Flags; /* MBZ unless SMB3.02 or later */
index f2d511a6971b88c0019526bcd5b3938383f4f106..85fc7a789334411f53dc0ba003475e693e1abadd 100644 (file)
@@ -56,6 +56,10 @@ extern void smb2_echo_request(struct work_struct *work);
 extern __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode);
 extern bool smb2_is_valid_oplock_break(char *buffer,
                                       struct TCP_Server_Info *srv);
+extern struct cifs_ses *smb2_find_smb_ses(struct TCP_Server_Info *server,
+                                         __u64 ses_id);
+extern int smb3_handle_read_data(struct TCP_Server_Info *server,
+                                struct mid_q_entry *mid);
 
 extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst,
                                   struct smb2_file_all_info *src);
@@ -97,6 +101,7 @@ extern int smb2_unlock_range(struct cifsFileInfo *cfile,
                             struct file_lock *flock, const unsigned int xid);
 extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile);
 extern void smb2_reconnect_server(struct work_struct *work);
+extern int smb3_crypto_aead_allocate(struct TCP_Server_Info *server);
 
 /*
  * SMB2 Worker functions - most of protocol specific implementation details
index bc9a7b63464347ad4036f41a60fc2a2fdc1bfe6e..7c3bb1bd7eedfd044e0a7716951a39181a9e1bae 100644 (file)
@@ -31,6 +31,7 @@
 #include <asm/processor.h>
 #include <linux/mempool.h>
 #include <linux/highmem.h>
+#include <crypto/aead.h>
 #include "smb2pdu.h"
 #include "cifsglob.h"
 #include "cifsproto.h"
@@ -114,14 +115,14 @@ smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
        return 0;
 }
 
-static struct cifs_ses *
-smb2_find_smb_ses(struct smb2_hdr *smb2hdr, struct TCP_Server_Info *server)
+struct cifs_ses *
+smb2_find_smb_ses(struct TCP_Server_Info *server, __u64 ses_id)
 {
        struct cifs_ses *ses;
 
        spin_lock(&cifs_tcp_ses_lock);
        list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
-               if (ses->Suid != smb2hdr->SessionId)
+               if (ses->Suid != ses_id)
                        continue;
                spin_unlock(&cifs_tcp_ses_lock);
                return ses;
@@ -131,7 +132,6 @@ smb2_find_smb_ses(struct smb2_hdr *smb2hdr, struct TCP_Server_Info *server)
        return NULL;
 }
 
-
 int
 smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 {
@@ -139,17 +139,17 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
        unsigned char smb2_signature[SMB2_HMACSHA256_SIZE];
        unsigned char *sigptr = smb2_signature;
        struct kvec *iov = rqst->rq_iov;
-       struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;
+       struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[1].iov_base;
        struct cifs_ses *ses;
 
-       ses = smb2_find_smb_ses(smb2_pdu, server);
+       ses = smb2_find_smb_ses(server, shdr->SessionId);
        if (!ses) {
                cifs_dbg(VFS, "%s: Could not find session\n", __func__);
                return 0;
        }
 
        memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE);
-       memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE);
+       memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE);
 
        rc = smb2_crypto_shash_allocate(server);
        if (rc) {
@@ -174,7 +174,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
                &server->secmech.sdeschmacsha256->shash);
 
        if (!rc)
-               memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE);
+               memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE);
 
        return rc;
 }
@@ -356,17 +356,17 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
        unsigned char smb3_signature[SMB2_CMACAES_SIZE];
        unsigned char *sigptr = smb3_signature;
        struct kvec *iov = rqst->rq_iov;
-       struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;
+       struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[1].iov_base;
        struct cifs_ses *ses;
 
-       ses = smb2_find_smb_ses(smb2_pdu, server);
+       ses = smb2_find_smb_ses(server, shdr->SessionId);
        if (!ses) {
                cifs_dbg(VFS, "%s: Could not find session\n", __func__);
                return 0;
        }
 
        memset(smb3_signature, 0x0, SMB2_CMACAES_SIZE);
-       memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE);
+       memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE);
 
        rc = crypto_shash_setkey(server->secmech.cmacaes,
                ses->smb3signingkey, SMB2_CMACAES_SIZE);
@@ -391,7 +391,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
                                   &server->secmech.sdesccmacaes->shash);
 
        if (!rc)
-               memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE);
+               memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE);
 
        return rc;
 }
@@ -401,14 +401,15 @@ static int
 smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 {
        int rc = 0;
-       struct smb2_hdr *smb2_pdu = rqst->rq_iov[0].iov_base;
+       struct smb2_sync_hdr *shdr =
+                       (struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base;
 
-       if (!(smb2_pdu->Flags & SMB2_FLAGS_SIGNED) ||
+       if (!(shdr->Flags & SMB2_FLAGS_SIGNED) ||
            server->tcpStatus == CifsNeedNegotiate)
                return rc;
 
        if (!server->session_estab) {
-               strncpy(smb2_pdu->Signature, "BSRSPYL", 8);
+               strncpy(shdr->Signature, "BSRSPYL", 8);
                return rc;
        }
 
@@ -422,11 +423,12 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 {
        unsigned int rc;
        char server_response_sig[16];
-       struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)rqst->rq_iov[0].iov_base;
+       struct smb2_sync_hdr *shdr =
+                       (struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base;
 
-       if ((smb2_pdu->Command == SMB2_NEGOTIATE) ||
-           (smb2_pdu->Command == SMB2_SESSION_SETUP) ||
-           (smb2_pdu->Command == SMB2_OPLOCK_BREAK) ||
+       if ((shdr->Command == SMB2_NEGOTIATE) ||
+           (shdr->Command == SMB2_SESSION_SETUP) ||
+           (shdr->Command == SMB2_OPLOCK_BREAK) ||
            (!server->session_estab))
                return 0;
 
@@ -436,17 +438,17 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
         */
 
        /* Do not need to verify session setups with signature "BSRSPYL " */
-       if (memcmp(smb2_pdu->Signature, "BSRSPYL ", 8) == 0)
+       if (memcmp(shdr->Signature, "BSRSPYL ", 8) == 0)
                cifs_dbg(FYI, "dummy signature received for smb command 0x%x\n",
-                        smb2_pdu->Command);
+                        shdr->Command);
 
        /*
         * Save off the origiginal signature so we can modify the smb and check
         * our calculated signature against what the server sent.
         */
-       memcpy(server_response_sig, smb2_pdu->Signature, SMB2_SIGNATURE_SIZE);
+       memcpy(server_response_sig, shdr->Signature, SMB2_SIGNATURE_SIZE);
 
-       memset(smb2_pdu->Signature, 0, SMB2_SIGNATURE_SIZE);
+       memset(shdr->Signature, 0, SMB2_SIGNATURE_SIZE);
 
        mutex_lock(&server->srv_mutex);
        rc = server->ops->calc_signature(rqst, server);
@@ -455,8 +457,7 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
        if (rc)
                return rc;
 
-       if (memcmp(server_response_sig, smb2_pdu->Signature,
-                  SMB2_SIGNATURE_SIZE))
+       if (memcmp(server_response_sig, shdr->Signature, SMB2_SIGNATURE_SIZE))
                return -EACCES;
        else
                return 0;
@@ -467,18 +468,19 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
  * and when srv_mutex is held.
  */
 static inline void
-smb2_seq_num_into_buf(struct TCP_Server_Info *server, struct smb2_hdr *hdr)
+smb2_seq_num_into_buf(struct TCP_Server_Info *server,
+                     struct smb2_sync_hdr *shdr)
 {
-       unsigned int i, num = le16_to_cpu(hdr->CreditCharge);
+       unsigned int i, num = le16_to_cpu(shdr->CreditCharge);
 
-       hdr->MessageId = get_next_mid64(server);
+       shdr->MessageId = get_next_mid64(server);
        /* skip message numbers according to CreditCharge field */
        for (i = 1; i < num; i++)
                get_next_mid(server);
 }
 
 static struct mid_q_entry *
-smb2_mid_entry_alloc(const struct smb2_hdr *smb_buffer,
+smb2_mid_entry_alloc(const struct smb2_sync_hdr *shdr,
                     struct TCP_Server_Info *server)
 {
        struct mid_q_entry *temp;
@@ -493,9 +495,9 @@ smb2_mid_entry_alloc(const struct smb2_hdr *smb_buffer,
                return temp;
        else {
                memset(temp, 0, sizeof(struct mid_q_entry));
-               temp->mid = le64_to_cpu(smb_buffer->MessageId);
+               temp->mid = le64_to_cpu(shdr->MessageId);
                temp->pid = current->pid;
-               temp->command = smb_buffer->Command;    /* Always LE */
+               temp->command = shdr->Command; /* Always LE */
                temp->when_alloc = jiffies;
                temp->server = server;
 
@@ -513,7 +515,7 @@ smb2_mid_entry_alloc(const struct smb2_hdr *smb_buffer,
 }
 
 static int
-smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_hdr *buf,
+smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_sync_hdr *shdr,
                   struct mid_q_entry **mid)
 {
        if (ses->server->tcpStatus == CifsExiting)
@@ -525,19 +527,19 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_hdr *buf,
        }
 
        if (ses->status == CifsNew) {
-               if ((buf->Command != SMB2_SESSION_SETUP) &&
-                   (buf->Command != SMB2_NEGOTIATE))
+               if ((shdr->Command != SMB2_SESSION_SETUP) &&
+                   (shdr->Command != SMB2_NEGOTIATE))
                        return -EAGAIN;
                /* else ok - we are setting up session */
        }
 
        if (ses->status == CifsExiting) {
-               if (buf->Command != SMB2_LOGOFF)
+               if (shdr->Command != SMB2_LOGOFF)
                        return -EAGAIN;
                /* else ok - we are shutting down the session */
        }
 
-       *mid = smb2_mid_entry_alloc(buf, ses->server);
+       *mid = smb2_mid_entry_alloc(shdr, ses->server);
        if (*mid == NULL)
                return -ENOMEM;
        spin_lock(&GlobalMid_Lock);
@@ -551,16 +553,18 @@ smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
                   bool log_error)
 {
        unsigned int len = get_rfc1002_length(mid->resp_buf);
-       struct kvec iov;
-       struct smb_rqst rqst = { .rq_iov = &iov,
-                                .rq_nvec = 1 };
+       struct kvec iov[2];
+       struct smb_rqst rqst = { .rq_iov = iov,
+                                .rq_nvec = 2 };
 
-       iov.iov_base = (char *)mid->resp_buf;
-       iov.iov_len = get_rfc1002_length(mid->resp_buf) + 4;
+       iov[0].iov_base = (char *)mid->resp_buf;
+       iov[0].iov_len = 4;
+       iov[1].iov_base = (char *)mid->resp_buf + 4;
+       iov[1].iov_len = len;
 
        dump_smb(mid->resp_buf, min_t(u32, 80, len));
        /* convert the length into a more usable form */
-       if (len > 24 && server->sign) {
+       if (len > 24 && server->sign && !mid->decrypted) {
                int rc;
 
                rc = smb2_verify_signature(&rqst, server);
@@ -576,12 +580,13 @@ struct mid_q_entry *
 smb2_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst)
 {
        int rc;
-       struct smb2_hdr *hdr = (struct smb2_hdr *)rqst->rq_iov[0].iov_base;
+       struct smb2_sync_hdr *shdr =
+                       (struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base;
        struct mid_q_entry *mid;
 
-       smb2_seq_num_into_buf(ses->server, hdr);
+       smb2_seq_num_into_buf(ses->server, shdr);
 
-       rc = smb2_get_mid_entry(ses, hdr, &mid);
+       rc = smb2_get_mid_entry(ses, shdr, &mid);
        if (rc)
                return ERR_PTR(rc);
        rc = smb2_sign_rqst(rqst, ses->server);
@@ -596,12 +601,13 @@ struct mid_q_entry *
 smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 {
        int rc;
-       struct smb2_hdr *hdr = (struct smb2_hdr *)rqst->rq_iov[0].iov_base;
+       struct smb2_sync_hdr *shdr =
+                       (struct smb2_sync_hdr *)rqst->rq_iov[1].iov_base;
        struct mid_q_entry *mid;
 
-       smb2_seq_num_into_buf(server, hdr);
+       smb2_seq_num_into_buf(server, shdr);
 
-       mid = smb2_mid_entry_alloc(hdr, server);
+       mid = smb2_mid_entry_alloc(shdr, server);
        if (mid == NULL)
                return ERR_PTR(-ENOMEM);
 
@@ -613,3 +619,33 @@ smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 
        return mid;
 }
+
+int
+smb3_crypto_aead_allocate(struct TCP_Server_Info *server)
+{
+       struct crypto_aead *tfm;
+
+       if (!server->secmech.ccmaesencrypt) {
+               tfm = crypto_alloc_aead("ccm(aes)", 0, 0);
+               if (IS_ERR(tfm)) {
+                       cifs_dbg(VFS, "%s: Failed to alloc encrypt aead\n",
+                                __func__);
+                       return PTR_ERR(tfm);
+               }
+               server->secmech.ccmaesencrypt = tfm;
+       }
+
+       if (!server->secmech.ccmaesdecrypt) {
+               tfm = crypto_alloc_aead("ccm(aes)", 0, 0);
+               if (IS_ERR(tfm)) {
+                       crypto_free_aead(server->secmech.ccmaesencrypt);
+                       server->secmech.ccmaesencrypt = NULL;
+                       cifs_dbg(VFS, "%s: Failed to alloc decrypt aead\n",
+                                __func__);
+                       return PTR_ERR(tfm);
+               }
+               server->secmech.ccmaesdecrypt = tfm;
+       }
+
+       return 0;
+}
index fbb84c08e3cdfd9814b59aa098c6aae69ccd1c65..526f0533cb4e8ca0eb1209561bd4bf59db9af864 100644 (file)
@@ -221,7 +221,7 @@ rqst_len(struct smb_rqst *rqst)
 }
 
 static int
-smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
+__smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 {
        int rc;
        struct kvec *iov = rqst->rq_iov;
@@ -245,8 +245,12 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
                return -EIO;
        }
 
+       if (n_vec < 2)
+               return -EIO;
+
        cifs_dbg(FYI, "Sending smb: smb_len=%u\n", smb_buf_length);
        dump_smb(iov[0].iov_base, iov[0].iov_len);
+       dump_smb(iov[1].iov_base, iov[1].iov_len);
 
        /* cork the socket */
        kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK,
@@ -309,24 +313,43 @@ uncork:
 }
 
 static int
-smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
+smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst, int flags)
 {
-       struct smb_rqst rqst = { .rq_iov = iov,
-                                .rq_nvec = n_vec };
+       struct smb_rqst cur_rqst;
+       int rc;
+
+       if (!(flags & CIFS_TRANSFORM_REQ))
+               return __smb_send_rqst(server, rqst);
+
+       if (!server->ops->init_transform_rq ||
+           !server->ops->free_transform_rq) {
+               cifs_dbg(VFS, "Encryption requested but transform callbacks are missed\n");
+               return -EIO;
+       }
+
+       rc = server->ops->init_transform_rq(server, &cur_rqst, rqst);
+       if (rc)
+               return rc;
 
-       return smb_send_rqst(server, &rqst);
+       rc = __smb_send_rqst(server, &cur_rqst);
+       server->ops->free_transform_rq(&cur_rqst);
+       return rc;
 }
 
 int
 smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
         unsigned int smb_buf_length)
 {
-       struct kvec iov;
+       struct kvec iov[2];
+       struct smb_rqst rqst = { .rq_iov = iov,
+                                .rq_nvec = 2 };
 
-       iov.iov_base = smb_buffer;
-       iov.iov_len = smb_buf_length + 4;
+       iov[0].iov_base = smb_buffer;
+       iov[0].iov_len = 4;
+       iov[1].iov_base = (char *)smb_buffer + 4;
+       iov[1].iov_len = smb_buf_length;
 
-       return smb_sendv(server, &iov, 1);
+       return __smb_send_rqst(server, &rqst);
 }
 
 static int
@@ -454,6 +477,10 @@ cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
        struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
        struct mid_q_entry *mid;
 
+       if (rqst->rq_iov[0].iov_len != 4 ||
+           rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
+               return ERR_PTR(-EIO);
+
        /* enable signing if server requires it */
        if (server->sign)
                hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
@@ -478,7 +505,7 @@ cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 int
 cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
                mid_receive_t *receive, mid_callback_t *callback,
-               void *cbdata, const int flags)
+               mid_handle_t *handle, void *cbdata, const int flags)
 {
        int rc, timeout, optype;
        struct mid_q_entry *mid;
@@ -505,6 +532,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
        mid->receive = receive;
        mid->callback = callback;
        mid->callback_data = cbdata;
+       mid->handle = handle;
        mid->mid_state = MID_REQUEST_SUBMITTED;
 
        /* put it on the pending_mid_q */
@@ -514,7 +542,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
 
 
        cifs_in_send_inc(server);
-       rc = smb_send_rqst(server, rqst);
+       rc = smb_send_rqst(server, rqst, flags);
        cifs_in_send_dec(server);
        cifs_save_when_sent(mid);
 
@@ -547,12 +575,13 @@ SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
 {
        int rc;
        struct kvec iov[1];
+       struct kvec rsp_iov;
        int resp_buf_type;
 
        iov[0].iov_base = in_buf;
        iov[0].iov_len = get_rfc1002_length(in_buf) + 4;
        flags |= CIFS_NO_RESP;
-       rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
+       rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov);
        cifs_dbg(NOISY, "SendRcvNoRsp flags %d rc %d\n", flags, rc);
 
        return rc;
@@ -595,10 +624,11 @@ cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
 }
 
 static inline int
-send_cancel(struct TCP_Server_Info *server, void *buf, struct mid_q_entry *mid)
+send_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
+           struct mid_q_entry *mid)
 {
        return server->ops->send_cancel ?
-                               server->ops->send_cancel(server, buf, mid) : 0;
+                               server->ops->send_cancel(server, rqst, mid) : 0;
 }
 
 int
@@ -611,13 +641,15 @@ cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
 
        /* convert the length into a more usable form */
        if (server->sign) {
-               struct kvec iov;
+               struct kvec iov[2];
                int rc = 0;
-               struct smb_rqst rqst = { .rq_iov = &iov,
-                                        .rq_nvec = 1 };
+               struct smb_rqst rqst = { .rq_iov = iov,
+                                        .rq_nvec = 2 };
 
-               iov.iov_base = mid->resp_buf;
-               iov.iov_len = len;
+               iov[0].iov_base = mid->resp_buf;
+               iov[0].iov_len = 4;
+               iov[1].iov_base = (char *)mid->resp_buf + 4;
+               iov[1].iov_len = len - 4;
                /* FIXME: add code to kill session */
                rc = cifs_verify_signature(&rqst, server,
                                           mid->sequence_number);
@@ -637,6 +669,10 @@ cifs_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst)
        struct smb_hdr *hdr = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
        struct mid_q_entry *mid;
 
+       if (rqst->rq_iov[0].iov_len != 4 ||
+           rqst->rq_iov[0].iov_base + 4 != rqst->rq_iov[1].iov_base)
+               return ERR_PTR(-EIO);
+
        rc = allocate_mid(ses, hdr, &mid);
        if (rc)
                return ERR_PTR(rc);
@@ -649,17 +685,15 @@ cifs_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst)
 }
 
 int
-SendReceive2(const unsigned int xid, struct cifs_ses *ses,
-            struct kvec *iov, int n_vec, int *resp_buf_type /* ret */,
-            const int flags)
+cifs_send_recv(const unsigned int xid, struct cifs_ses *ses,
+              struct smb_rqst *rqst, int *resp_buf_type, const int flags,
+              struct kvec *resp_iov)
 {
        int rc = 0;
        int timeout, optype;
        struct mid_q_entry *midQ;
-       char *buf = iov[0].iov_base;
        unsigned int credits = 1;
-       struct smb_rqst rqst = { .rq_iov = iov,
-                                .rq_nvec = n_vec };
+       char *buf;
 
        timeout = flags & CIFS_TIMEOUT_MASK;
        optype = flags & CIFS_OP_MASK;
@@ -667,15 +701,12 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
        *resp_buf_type = CIFS_NO_BUFFER;  /* no response buf yet */
 
        if ((ses == NULL) || (ses->server == NULL)) {
-               cifs_small_buf_release(buf);
                cifs_dbg(VFS, "Null session\n");
                return -EIO;
        }
 
-       if (ses->server->tcpStatus == CifsExiting) {
-               cifs_small_buf_release(buf);
+       if (ses->server->tcpStatus == CifsExiting)
                return -ENOENT;
-       }
 
        /*
         * Ensure that we do not send more than 50 overlapping requests
@@ -684,10 +715,8 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
         */
 
        rc = wait_for_free_request(ses->server, timeout, optype);
-       if (rc) {
-               cifs_small_buf_release(buf);
+       if (rc)
                return rc;
-       }
 
        /*
         * Make sure that we sign in the same order that we send on this socket
@@ -697,10 +726,9 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 
        mutex_lock(&ses->server->srv_mutex);
 
-       midQ = ses->server->ops->setup_request(ses, &rqst);
+       midQ = ses->server->ops->setup_request(ses, rqst);
        if (IS_ERR(midQ)) {
                mutex_unlock(&ses->server->srv_mutex);
-               cifs_small_buf_release(buf);
                /* Update # of requests on wire to server */
                add_credits(ses->server, 1, optype);
                return PTR_ERR(midQ);
@@ -708,7 +736,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
 
        midQ->mid_state = MID_REQUEST_SUBMITTED;
        cifs_in_send_inc(ses->server);
-       rc = smb_sendv(ses->server, iov, n_vec);
+       rc = smb_send_rqst(ses->server, rqst, flags);
        cifs_in_send_dec(ses->server);
        cifs_save_when_sent(midQ);
 
@@ -716,32 +744,25 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
                ses->server->sequence_number -= 2;
        mutex_unlock(&ses->server->srv_mutex);
 
-       if (rc < 0) {
-               cifs_small_buf_release(buf);
+       if (rc < 0)
                goto out;
-       }
 
-       if (timeout == CIFS_ASYNC_OP) {
-               cifs_small_buf_release(buf);
+       if (timeout == CIFS_ASYNC_OP)
                goto out;
-       }
 
        rc = wait_for_response(ses->server, midQ);
        if (rc != 0) {
-               send_cancel(ses->server, buf, midQ);
+               send_cancel(ses->server, rqst, midQ);
                spin_lock(&GlobalMid_Lock);
                if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
                        midQ->callback = DeleteMidQEntry;
                        spin_unlock(&GlobalMid_Lock);
-                       cifs_small_buf_release(buf);
                        add_credits(ses->server, 1, optype);
                        return rc;
                }
                spin_unlock(&GlobalMid_Lock);
        }
 
-       cifs_small_buf_release(buf);
-
        rc = cifs_sync_mid_result(midQ, ses->server);
        if (rc != 0) {
                add_credits(ses->server, 1, optype);
@@ -755,8 +776,8 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
        }
 
        buf = (char *)midQ->resp_buf;
-       iov[0].iov_base = buf;
-       iov[0].iov_len = get_rfc1002_length(buf) + 4;
+       resp_iov->iov_base = buf;
+       resp_iov->iov_len = get_rfc1002_length(buf) + 4;
        if (midQ->large_buf)
                *resp_buf_type = CIFS_LARGE_BUFFER;
        else
@@ -777,6 +798,36 @@ out:
        return rc;
 }
 
+int
+SendReceive2(const unsigned int xid, struct cifs_ses *ses,
+            struct kvec *iov, int n_vec, int *resp_buf_type /* ret */,
+            const int flags, struct kvec *resp_iov)
+{
+       struct smb_rqst rqst;
+       struct kvec *new_iov;
+       int rc;
+
+       new_iov = kmalloc(sizeof(struct kvec) * (n_vec + 1), GFP_KERNEL);
+       if (!new_iov)
+               return -ENOMEM;
+
+       /* 1st iov is a RFC1001 length followed by the rest of the packet */
+       memcpy(new_iov + 1, iov, (sizeof(struct kvec) * n_vec));
+
+       new_iov[0].iov_base = new_iov[1].iov_base;
+       new_iov[0].iov_len = 4;
+       new_iov[1].iov_base += 4;
+       new_iov[1].iov_len -= 4;
+
+       memset(&rqst, 0, sizeof(struct smb_rqst));
+       rqst.rq_iov = new_iov;
+       rqst.rq_nvec = n_vec + 1;
+
+       rc = cifs_send_recv(xid, ses, &rqst, resp_buf_type, flags, resp_iov);
+       kfree(new_iov);
+       return rc;
+}
+
 int
 SendReceive(const unsigned int xid, struct cifs_ses *ses,
            struct smb_hdr *in_buf, struct smb_hdr *out_buf,
@@ -784,6 +835,9 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 {
        int rc = 0;
        struct mid_q_entry *midQ;
+       unsigned int len = be32_to_cpu(in_buf->smb_buf_length);
+       struct kvec iov = { .iov_base = in_buf, .iov_len = len };
+       struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
 
        if (ses == NULL) {
                cifs_dbg(VFS, "Null smb session\n");
@@ -801,10 +855,9 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
           to the same server. We may make this configurable later or
           use ses->maxReq */
 
-       if (be32_to_cpu(in_buf->smb_buf_length) > CIFSMaxBufSize +
-                       MAX_CIFS_HDR_SIZE - 4) {
+       if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
                cifs_dbg(VFS, "Illegal length, greater than maximum frame, %d\n",
-                        be32_to_cpu(in_buf->smb_buf_length));
+                        len);
                return -EIO;
        }
 
@@ -835,7 +888,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
        midQ->mid_state = MID_REQUEST_SUBMITTED;
 
        cifs_in_send_inc(ses->server);
-       rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
+       rc = smb_send(ses->server, in_buf, len);
        cifs_in_send_dec(ses->server);
        cifs_save_when_sent(midQ);
 
@@ -852,7 +905,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
 
        rc = wait_for_response(ses->server, midQ);
        if (rc != 0) {
-               send_cancel(ses->server, in_buf, midQ);
+               send_cancel(ses->server, &rqst, midQ);
                spin_lock(&GlobalMid_Lock);
                if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
                        /* no longer considered to be "in-flight" */
@@ -921,6 +974,9 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
        int rstart = 0;
        struct mid_q_entry *midQ;
        struct cifs_ses *ses;
+       unsigned int len = be32_to_cpu(in_buf->smb_buf_length);
+       struct kvec iov = { .iov_base = in_buf, .iov_len = len };
+       struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 };
 
        if (tcon == NULL || tcon->ses == NULL) {
                cifs_dbg(VFS, "Null smb session\n");
@@ -940,10 +996,9 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
           to the same server. We may make this configurable later or
           use ses->maxReq */
 
-       if (be32_to_cpu(in_buf->smb_buf_length) > CIFSMaxBufSize +
-                       MAX_CIFS_HDR_SIZE - 4) {
+       if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
                cifs_dbg(VFS, "Illegal length, greater than maximum frame, %d\n",
-                        be32_to_cpu(in_buf->smb_buf_length));
+                        len);
                return -EIO;
        }
 
@@ -972,7 +1027,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 
        midQ->mid_state = MID_REQUEST_SUBMITTED;
        cifs_in_send_inc(ses->server);
-       rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
+       rc = smb_send(ses->server, in_buf, len);
        cifs_in_send_dec(ses->server);
        cifs_save_when_sent(midQ);
 
@@ -1001,7 +1056,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
                if (in_buf->Command == SMB_COM_TRANSACTION2) {
                        /* POSIX lock. We send a NT_CANCEL SMB to cause the
                           blocking lock to return. */
-                       rc = send_cancel(ses->server, in_buf, midQ);
+                       rc = send_cancel(ses->server, &rqst, midQ);
                        if (rc) {
                                cifs_delete_mid(midQ);
                                return rc;
@@ -1022,7 +1077,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 
                rc = wait_for_response(ses->server, midQ);
                if (rc) {
-                       send_cancel(ses->server, in_buf, midQ);
+                       send_cancel(ses->server, &rqst, midQ);
                        spin_lock(&GlobalMid_Lock);
                        if (midQ->mid_state == MID_REQUEST_SUBMITTED) {
                                /* no longer considered to be "in-flight" */
index f514978f66885ea045db8376ce72520b352adb98..08b46e6e3995872ee8c0c2029b83d21710bb677e 100644 (file)
@@ -1,6 +1,5 @@
 config FS_ENCRYPTION
        tristate "FS Encryption (Per-file encryption)"
-       depends on BLOCK
        select CRYPTO
        select CRYPTO_AES
        select CRYPTO_CBC
index f17684c48739c61c93b9a73dfea813998468106c..9f6607f17b53bfeba9d7940380928439f4e5b466 100644 (file)
@@ -1,3 +1,4 @@
 obj-$(CONFIG_FS_ENCRYPTION)    += fscrypto.o
 
 fscrypto-y := crypto.o fname.o policy.o keyinfo.o
+fscrypto-$(CONFIG_BLOCK) += bio.o
diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c
new file mode 100644 (file)
index 0000000..a409a84
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * This contains encryption functions for per-file encryption.
+ *
+ * Copyright (C) 2015, Google, Inc.
+ * Copyright (C) 2015, Motorola Mobility
+ *
+ * Written by Michael Halcrow, 2014.
+ *
+ * Filename encryption additions
+ *     Uday Savagaonkar, 2014
+ * Encryption policy handling additions
+ *     Ildar Muslukhov, 2014
+ * Add fscrypt_pullback_bio_page()
+ *     Jaegeuk Kim, 2015.
+ *
+ * This has not yet undergone a rigorous security audit.
+ *
+ * The usage of AES-XTS should conform to recommendations in NIST
+ * Special Publication 800-38E and IEEE P1619/D16.
+ */
+
+#include <linux/pagemap.h>
+#include <linux/module.h>
+#include <linux/bio.h>
+#include <linux/namei.h>
+#include "fscrypt_private.h"
+
+/*
+ * Call fscrypt_decrypt_page on every single page, reusing the encryption
+ * context.
+ */
+static void completion_pages(struct work_struct *work)
+{
+       struct fscrypt_ctx *ctx =
+               container_of(work, struct fscrypt_ctx, r.work);
+       struct bio *bio = ctx->r.bio;
+       struct bio_vec *bv;
+       int i;
+
+       bio_for_each_segment_all(bv, bio, i) {
+               struct page *page = bv->bv_page;
+               int ret = fscrypt_decrypt_page(page->mapping->host, page,
+                               PAGE_SIZE, 0, page->index);
+
+               if (ret) {
+                       WARN_ON_ONCE(1);
+                       SetPageError(page);
+               } else {
+                       SetPageUptodate(page);
+               }
+               unlock_page(page);
+       }
+       fscrypt_release_ctx(ctx);
+       bio_put(bio);
+}
+
+void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *ctx, struct bio *bio)
+{
+       INIT_WORK(&ctx->r.work, completion_pages);
+       ctx->r.bio = bio;
+       queue_work(fscrypt_read_workqueue, &ctx->r.work);
+}
+EXPORT_SYMBOL(fscrypt_decrypt_bio_pages);
+
+void fscrypt_pullback_bio_page(struct page **page, bool restore)
+{
+       struct fscrypt_ctx *ctx;
+       struct page *bounce_page;
+
+       /* The bounce data pages are unmapped. */
+       if ((*page)->mapping)
+               return;
+
+       /* The bounce data page is unmapped. */
+       bounce_page = *page;
+       ctx = (struct fscrypt_ctx *)page_private(bounce_page);
+
+       /* restore control page */
+       *page = ctx->w.control_page;
+
+       if (restore)
+               fscrypt_restore_control_page(bounce_page);
+}
+EXPORT_SYMBOL(fscrypt_pullback_bio_page);
+
+int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,
+                               sector_t pblk, unsigned int len)
+{
+       struct fscrypt_ctx *ctx;
+       struct page *ciphertext_page = NULL;
+       struct bio *bio;
+       int ret, err = 0;
+
+       BUG_ON(inode->i_sb->s_blocksize != PAGE_SIZE);
+
+       ctx = fscrypt_get_ctx(inode, GFP_NOFS);
+       if (IS_ERR(ctx))
+               return PTR_ERR(ctx);
+
+       ciphertext_page = fscrypt_alloc_bounce_page(ctx, GFP_NOWAIT);
+       if (IS_ERR(ciphertext_page)) {
+               err = PTR_ERR(ciphertext_page);
+               goto errout;
+       }
+
+       while (len--) {
+               err = fscrypt_do_page_crypto(inode, FS_ENCRYPT, lblk,
+                                            ZERO_PAGE(0), ciphertext_page,
+                                            PAGE_SIZE, 0, GFP_NOFS);
+               if (err)
+                       goto errout;
+
+               bio = bio_alloc(GFP_NOWAIT, 1);
+               if (!bio) {
+                       err = -ENOMEM;
+                       goto errout;
+               }
+               bio->bi_bdev = inode->i_sb->s_bdev;
+               bio->bi_iter.bi_sector =
+                       pblk << (inode->i_sb->s_blocksize_bits - 9);
+               bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
+               ret = bio_add_page(bio, ciphertext_page,
+                                       inode->i_sb->s_blocksize, 0);
+               if (ret != inode->i_sb->s_blocksize) {
+                       /* should never happen! */
+                       WARN_ON(1);
+                       bio_put(bio);
+                       err = -EIO;
+                       goto errout;
+               }
+               err = submit_bio_wait(bio);
+               if ((err == 0) && bio->bi_error)
+                       err = -EIO;
+               bio_put(bio);
+               if (err)
+                       goto errout;
+               lblk++;
+               pblk++;
+       }
+       err = 0;
+errout:
+       fscrypt_release_ctx(ctx);
+       return err;
+}
+EXPORT_SYMBOL(fscrypt_zeroout_range);
index ac8e4f6a377331b6202bb1a25545d22592f5ddfa..02a7a9286449d467741d64e8e817bb2902309926 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/module.h>
 #include <linux/scatterlist.h>
 #include <linux/ratelimit.h>
-#include <linux/bio.h>
 #include <linux/dcache.h>
 #include <linux/namei.h>
 #include "fscrypt_private.h"
@@ -44,7 +43,7 @@ static mempool_t *fscrypt_bounce_page_pool = NULL;
 static LIST_HEAD(fscrypt_free_ctxs);
 static DEFINE_SPINLOCK(fscrypt_ctx_lock);
 
-static struct workqueue_struct *fscrypt_read_workqueue;
+struct workqueue_struct *fscrypt_read_workqueue;
 static DEFINE_MUTEX(fscrypt_init_mutex);
 
 static struct kmem_cache *fscrypt_ctx_cachep;
@@ -141,16 +140,10 @@ static void page_crypt_complete(struct crypto_async_request *req, int res)
        complete(&ecr->completion);
 }
 
-typedef enum {
-       FS_DECRYPT = 0,
-       FS_ENCRYPT,
-} fscrypt_direction_t;
-
-static int do_page_crypto(const struct inode *inode,
-                       fscrypt_direction_t rw, u64 lblk_num,
-                       struct page *src_page, struct page *dest_page,
-                       unsigned int len, unsigned int offs,
-                       gfp_t gfp_flags)
+int fscrypt_do_page_crypto(const struct inode *inode, fscrypt_direction_t rw,
+                          u64 lblk_num, struct page *src_page,
+                          struct page *dest_page, unsigned int len,
+                          unsigned int offs, gfp_t gfp_flags)
 {
        struct {
                __le64 index;
@@ -205,7 +198,8 @@ static int do_page_crypto(const struct inode *inode,
        return 0;
 }
 
-static struct page *alloc_bounce_page(struct fscrypt_ctx *ctx, gfp_t gfp_flags)
+struct page *fscrypt_alloc_bounce_page(struct fscrypt_ctx *ctx,
+                                      gfp_t gfp_flags)
 {
        ctx->w.bounce_page = mempool_alloc(fscrypt_bounce_page_pool, gfp_flags);
        if (ctx->w.bounce_page == NULL)
@@ -260,9 +254,9 @@ struct page *fscrypt_encrypt_page(const struct inode *inode,
 
        if (inode->i_sb->s_cop->flags & FS_CFLG_OWN_PAGES) {
                /* with inplace-encryption we just encrypt the page */
-               err = do_page_crypto(inode, FS_ENCRYPT, lblk_num,
-                                       page, ciphertext_page,
-                                       len, offs, gfp_flags);
+               err = fscrypt_do_page_crypto(inode, FS_ENCRYPT, lblk_num, page,
+                                            ciphertext_page, len, offs,
+                                            gfp_flags);
                if (err)
                        return ERR_PTR(err);
 
@@ -276,14 +270,14 @@ struct page *fscrypt_encrypt_page(const struct inode *inode,
                return (struct page *)ctx;
 
        /* The encryption operation will require a bounce page. */
-       ciphertext_page = alloc_bounce_page(ctx, gfp_flags);
+       ciphertext_page = fscrypt_alloc_bounce_page(ctx, gfp_flags);
        if (IS_ERR(ciphertext_page))
                goto errout;
 
        ctx->w.control_page = page;
-       err = do_page_crypto(inode, FS_ENCRYPT, lblk_num,
-                                       page, ciphertext_page,
-                                       len, offs, gfp_flags);
+       err = fscrypt_do_page_crypto(inode, FS_ENCRYPT, lblk_num,
+                                    page, ciphertext_page, len, offs,
+                                    gfp_flags);
        if (err) {
                ciphertext_page = ERR_PTR(err);
                goto errout;
@@ -320,72 +314,11 @@ int fscrypt_decrypt_page(const struct inode *inode, struct page *page,
        if (!(inode->i_sb->s_cop->flags & FS_CFLG_OWN_PAGES))
                BUG_ON(!PageLocked(page));
 
-       return do_page_crypto(inode, FS_DECRYPT, lblk_num, page, page, len,
-                       offs, GFP_NOFS);
+       return fscrypt_do_page_crypto(inode, FS_DECRYPT, lblk_num, page, page,
+                                     len, offs, GFP_NOFS);
 }
 EXPORT_SYMBOL(fscrypt_decrypt_page);
 
-int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,
-                               sector_t pblk, unsigned int len)
-{
-       struct fscrypt_ctx *ctx;
-       struct page *ciphertext_page = NULL;
-       struct bio *bio;
-       int ret, err = 0;
-
-       BUG_ON(inode->i_sb->s_blocksize != PAGE_SIZE);
-
-       ctx = fscrypt_get_ctx(inode, GFP_NOFS);
-       if (IS_ERR(ctx))
-               return PTR_ERR(ctx);
-
-       ciphertext_page = alloc_bounce_page(ctx, GFP_NOWAIT);
-       if (IS_ERR(ciphertext_page)) {
-               err = PTR_ERR(ciphertext_page);
-               goto errout;
-       }
-
-       while (len--) {
-               err = do_page_crypto(inode, FS_ENCRYPT, lblk,
-                                       ZERO_PAGE(0), ciphertext_page,
-                                       PAGE_SIZE, 0, GFP_NOFS);
-               if (err)
-                       goto errout;
-
-               bio = bio_alloc(GFP_NOWAIT, 1);
-               if (!bio) {
-                       err = -ENOMEM;
-                       goto errout;
-               }
-               bio->bi_bdev = inode->i_sb->s_bdev;
-               bio->bi_iter.bi_sector =
-                       pblk << (inode->i_sb->s_blocksize_bits - 9);
-               bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
-               ret = bio_add_page(bio, ciphertext_page,
-                                       inode->i_sb->s_blocksize, 0);
-               if (ret != inode->i_sb->s_blocksize) {
-                       /* should never happen! */
-                       WARN_ON(1);
-                       bio_put(bio);
-                       err = -EIO;
-                       goto errout;
-               }
-               err = submit_bio_wait(bio);
-               if ((err == 0) && bio->bi_error)
-                       err = -EIO;
-               bio_put(bio);
-               if (err)
-                       goto errout;
-               lblk++;
-               pblk++;
-       }
-       err = 0;
-errout:
-       fscrypt_release_ctx(ctx);
-       return err;
-}
-EXPORT_SYMBOL(fscrypt_zeroout_range);
-
 /*
  * Validate dentries for encrypted directories to make sure we aren't
  * potentially caching stale data after a key has been added or
@@ -442,64 +375,6 @@ const struct dentry_operations fscrypt_d_ops = {
 };
 EXPORT_SYMBOL(fscrypt_d_ops);
 
-/*
- * Call fscrypt_decrypt_page on every single page, reusing the encryption
- * context.
- */
-static void completion_pages(struct work_struct *work)
-{
-       struct fscrypt_ctx *ctx =
-               container_of(work, struct fscrypt_ctx, r.work);
-       struct bio *bio = ctx->r.bio;
-       struct bio_vec *bv;
-       int i;
-
-       bio_for_each_segment_all(bv, bio, i) {
-               struct page *page = bv->bv_page;
-               int ret = fscrypt_decrypt_page(page->mapping->host, page,
-                               PAGE_SIZE, 0, page->index);
-
-               if (ret) {
-                       WARN_ON_ONCE(1);
-                       SetPageError(page);
-               } else {
-                       SetPageUptodate(page);
-               }
-               unlock_page(page);
-       }
-       fscrypt_release_ctx(ctx);
-       bio_put(bio);
-}
-
-void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *ctx, struct bio *bio)
-{
-       INIT_WORK(&ctx->r.work, completion_pages);
-       ctx->r.bio = bio;
-       queue_work(fscrypt_read_workqueue, &ctx->r.work);
-}
-EXPORT_SYMBOL(fscrypt_decrypt_bio_pages);
-
-void fscrypt_pullback_bio_page(struct page **page, bool restore)
-{
-       struct fscrypt_ctx *ctx;
-       struct page *bounce_page;
-
-       /* The bounce data pages are unmapped. */
-       if ((*page)->mapping)
-               return;
-
-       /* The bounce data page is unmapped. */
-       bounce_page = *page;
-       ctx = (struct fscrypt_ctx *)page_private(bounce_page);
-
-       /* restore control page */
-       *page = ctx->w.control_page;
-
-       if (restore)
-               fscrypt_restore_control_page(bounce_page);
-}
-EXPORT_SYMBOL(fscrypt_pullback_bio_page);
-
 void fscrypt_restore_control_page(struct page *page)
 {
        struct fscrypt_ctx *ctx;
index 56ad9d195f188892ecf74c41121e4861ecd6e57b..13052b85c3930f071be764c5fbbeb091429002d3 100644 (file)
@@ -332,7 +332,7 @@ int fscrypt_fname_usr_to_disk(struct inode *inode,
         * in a directory. Consequently, a user space name cannot be mapped to
         * a disk-space name
         */
-       return -EACCES;
+       return -ENOKEY;
 }
 EXPORT_SYMBOL(fscrypt_fname_usr_to_disk);
 
@@ -367,7 +367,7 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
                return 0;
        }
        if (!lookup)
-               return -EACCES;
+               return -ENOKEY;
 
        /*
         * We don't have the key and we are doing a lookup; decode the
index aeab032d7d35fcc4e0980342917ce7f2c170cd0d..fdbb8af32eafdb6bae492658d376abf15f8a3d69 100644 (file)
@@ -11,7 +11,7 @@
 #ifndef _FSCRYPT_PRIVATE_H
 #define _FSCRYPT_PRIVATE_H
 
-#include <linux/fscrypto.h>
+#include <linux/fscrypt_supp.h>
 
 #define FS_FNAME_CRYPTO_DIGEST_SIZE    32
 
@@ -71,6 +71,11 @@ struct fscrypt_info {
        u8 ci_master_key[FS_KEY_DESCRIPTOR_SIZE];
 };
 
+typedef enum {
+       FS_DECRYPT = 0,
+       FS_ENCRYPT,
+} fscrypt_direction_t;
+
 #define FS_CTX_REQUIRES_FREE_ENCRYPT_FL                0x00000001
 #define FS_CTX_HAS_BOUNCE_BUFFER_FL            0x00000002
 
@@ -81,11 +86,20 @@ struct fscrypt_completion_result {
 
 #define DECLARE_FS_COMPLETION_RESULT(ecr) \
        struct fscrypt_completion_result ecr = { \
-               COMPLETION_INITIALIZER((ecr).completion), 0 }
+               COMPLETION_INITIALIZER_ONSTACK((ecr).completion), 0 }
 
 
 /* crypto.c */
-int fscrypt_initialize(unsigned int cop_flags);
+extern int fscrypt_initialize(unsigned int cop_flags);
+extern struct workqueue_struct *fscrypt_read_workqueue;
+extern int fscrypt_do_page_crypto(const struct inode *inode,
+                                 fscrypt_direction_t rw, u64 lblk_num,
+                                 struct page *src_page,
+                                 struct page *dest_page,
+                                 unsigned int len, unsigned int offs,
+                                 gfp_t gfp_flags);
+extern struct page *fscrypt_alloc_bounce_page(struct fscrypt_ctx *ctx,
+                                             gfp_t gfp_flags);
 
 /* keyinfo.c */
 extern int fscrypt_get_crypt_info(struct inode *);
index 95cd4c3b06c326708a3315d3da86bdb9aafd5469..02eb6b9e44387d90daf6a35c03a052e7b855715d 100644 (file)
@@ -77,26 +77,22 @@ out:
 
 static int validate_user_key(struct fscrypt_info *crypt_info,
                        struct fscrypt_context *ctx, u8 *raw_key,
-                       u8 *prefix, int prefix_size)
+                       const char *prefix)
 {
-       u8 *full_key_descriptor;
+       char *description;
        struct key *keyring_key;
        struct fscrypt_key *master_key;
        const struct user_key_payload *ukp;
-       int full_key_len = prefix_size + (FS_KEY_DESCRIPTOR_SIZE * 2) + 1;
        int res;
 
-       full_key_descriptor = kmalloc(full_key_len, GFP_NOFS);
-       if (!full_key_descriptor)
+       description = kasprintf(GFP_NOFS, "%s%*phN", prefix,
+                               FS_KEY_DESCRIPTOR_SIZE,
+                               ctx->master_key_descriptor);
+       if (!description)
                return -ENOMEM;
 
-       memcpy(full_key_descriptor, prefix, prefix_size);
-       sprintf(full_key_descriptor + prefix_size,
-                       "%*phN", FS_KEY_DESCRIPTOR_SIZE,
-                       ctx->master_key_descriptor);
-       full_key_descriptor[full_key_len - 1] = '\0';
-       keyring_key = request_key(&key_type_logon, full_key_descriptor, NULL);
-       kfree(full_key_descriptor);
+       keyring_key = request_key(&key_type_logon, description, NULL);
+       kfree(description);
        if (IS_ERR(keyring_key))
                return PTR_ERR(keyring_key);
 
@@ -206,12 +202,15 @@ retry:
 
        res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
        if (res < 0) {
-               if (!fscrypt_dummy_context_enabled(inode))
+               if (!fscrypt_dummy_context_enabled(inode) ||
+                   inode->i_sb->s_cop->is_encrypted(inode))
                        return res;
+               /* Fake up a context for an unencrypted directory */
+               memset(&ctx, 0, sizeof(ctx));
                ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1;
                ctx.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS;
                ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS;
-               ctx.flags = 0;
+               memset(ctx.master_key_descriptor, 0x42, FS_KEY_DESCRIPTOR_SIZE);
        } else if (res != sizeof(ctx)) {
                return -EINVAL;
        }
@@ -247,21 +246,10 @@ retry:
        if (!raw_key)
                goto out;
 
-       if (fscrypt_dummy_context_enabled(inode)) {
-               memset(raw_key, 0x42, keysize/2);
-               memset(raw_key+keysize/2, 0x24, keysize - (keysize/2));
-               goto got_key;
-       }
-
-       res = validate_user_key(crypt_info, &ctx, raw_key,
-                       FS_KEY_DESC_PREFIX, FS_KEY_DESC_PREFIX_SIZE);
+       res = validate_user_key(crypt_info, &ctx, raw_key, FS_KEY_DESC_PREFIX);
        if (res && inode->i_sb->s_cop->key_prefix) {
-               u8 *prefix = NULL;
-               int prefix_size, res2;
-
-               prefix_size = inode->i_sb->s_cop->key_prefix(inode, &prefix);
-               res2 = validate_user_key(crypt_info, &ctx, raw_key,
-                                                       prefix, prefix_size);
+               int res2 = validate_user_key(crypt_info, &ctx, raw_key,
+                                            inode->i_sb->s_cop->key_prefix);
                if (res2) {
                        if (res2 == -ENOKEY)
                                res = -ENOKEY;
@@ -270,7 +258,6 @@ retry:
        } else if (res) {
                goto out;
        }
-got_key:
        ctfm = crypto_alloc_skcipher(cipher_str, 0, 0);
        if (!ctfm || IS_ERR(ctfm)) {
                res = ctfm ? PTR_ERR(ctfm) : -ENOMEM;
index d6cd7ea4851da877b13c7af306fd07f8468a54f4..14b76da71269487f22b941f82dbf01d6adea07c7 100644 (file)
 #include <linux/mount.h>
 #include "fscrypt_private.h"
 
-static int inode_has_encryption_context(struct inode *inode)
-{
-       if (!inode->i_sb->s_cop->get_context)
-               return 0;
-       return (inode->i_sb->s_cop->get_context(inode, NULL, 0L) > 0);
-}
-
 /*
- * check whether the policy is consistent with the encryption context
- * for the inode
+ * check whether an encryption policy is consistent with an encryption context
  */
-static int is_encryption_context_consistent_with_policy(struct inode *inode,
+static bool is_encryption_context_consistent_with_policy(
+                               const struct fscrypt_context *ctx,
                                const struct fscrypt_policy *policy)
 {
-       struct fscrypt_context ctx;
-       int res;
-
-       if (!inode->i_sb->s_cop->get_context)
-               return 0;
-
-       res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
-       if (res != sizeof(ctx))
-               return 0;
-
-       return (memcmp(ctx.master_key_descriptor, policy->master_key_descriptor,
-                       FS_KEY_DESCRIPTOR_SIZE) == 0 &&
-                       (ctx.flags == policy->flags) &&
-                       (ctx.contents_encryption_mode ==
-                        policy->contents_encryption_mode) &&
-                       (ctx.filenames_encryption_mode ==
-                        policy->filenames_encryption_mode));
+       return memcmp(ctx->master_key_descriptor, policy->master_key_descriptor,
+                     FS_KEY_DESCRIPTOR_SIZE) == 0 &&
+               (ctx->flags == policy->flags) &&
+               (ctx->contents_encryption_mode ==
+                policy->contents_encryption_mode) &&
+               (ctx->filenames_encryption_mode ==
+                policy->filenames_encryption_mode);
 }
 
 static int create_encryption_context_from_policy(struct inode *inode,
@@ -66,20 +49,12 @@ static int create_encryption_context_from_policy(struct inode *inode,
                                        FS_KEY_DESCRIPTOR_SIZE);
 
        if (!fscrypt_valid_contents_enc_mode(
-                               policy->contents_encryption_mode)) {
-               printk(KERN_WARNING
-                      "%s: Invalid contents encryption mode %d\n", __func__,
-                       policy->contents_encryption_mode);
+                               policy->contents_encryption_mode))
                return -EINVAL;
-       }
 
        if (!fscrypt_valid_filenames_enc_mode(
-                               policy->filenames_encryption_mode)) {
-               printk(KERN_WARNING
-                       "%s: Invalid filenames encryption mode %d\n", __func__,
-                       policy->filenames_encryption_mode);
+                               policy->filenames_encryption_mode))
                return -EINVAL;
-       }
 
        if (policy->flags & ~FS_POLICY_FLAGS_VALID)
                return -EINVAL;
@@ -98,6 +73,7 @@ int fscrypt_ioctl_set_policy(struct file *filp, const void __user *arg)
        struct fscrypt_policy policy;
        struct inode *inode = file_inode(filp);
        int ret;
+       struct fscrypt_context ctx;
 
        if (copy_from_user(&policy, arg, sizeof(policy)))
                return -EFAULT;
@@ -114,9 +90,10 @@ int fscrypt_ioctl_set_policy(struct file *filp, const void __user *arg)
 
        inode_lock(inode);
 
-       if (!inode_has_encryption_context(inode)) {
+       ret = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
+       if (ret == -ENODATA) {
                if (!S_ISDIR(inode->i_mode))
-                       ret = -EINVAL;
+                       ret = -ENOTDIR;
                else if (!inode->i_sb->s_cop->empty_dir)
                        ret = -EOPNOTSUPP;
                else if (!inode->i_sb->s_cop->empty_dir(inode))
@@ -124,12 +101,14 @@ int fscrypt_ioctl_set_policy(struct file *filp, const void __user *arg)
                else
                        ret = create_encryption_context_from_policy(inode,
                                                                    &policy);
-       } else if (!is_encryption_context_consistent_with_policy(inode,
-                                                                &policy)) {
-               printk(KERN_WARNING
-                      "%s: Policy inconsistent with encryption context\n",
-                      __func__);
-               ret = -EINVAL;
+       } else if (ret == sizeof(ctx) &&
+                  is_encryption_context_consistent_with_policy(&ctx,
+                                                               &policy)) {
+               /* The file already uses the same encryption policy. */
+               ret = 0;
+       } else if (ret >= 0 || ret == -ERANGE) {
+               /* The file already uses a different encryption policy. */
+               ret = -EEXIST;
        }
 
        inode_unlock(inode);
@@ -151,8 +130,10 @@ int fscrypt_ioctl_get_policy(struct file *filp, void __user *arg)
                return -ENODATA;
 
        res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
+       if (res < 0 && res != -ERANGE)
+               return res;
        if (res != sizeof(ctx))
-               return -ENODATA;
+               return -EINVAL;
        if (ctx.format != FS_ENCRYPTION_CONTEXT_FORMAT_V1)
                return -EINVAL;
 
@@ -217,9 +198,9 @@ EXPORT_SYMBOL(fscrypt_has_permitted_context);
  * @parent: Parent inode from which the context is inherited.
  * @child:  Child inode that inherits the context from @parent.
  * @fs_data:  private data given by FS.
- * @preload:  preload child i_crypt_info
+ * @preload:  preload child i_crypt_info if true
  *
- * Return: Zero on success, non-zero otherwise
+ * Return: 0 on success, -errno on failure
  */
 int fscrypt_inherit_context(struct inode *parent, struct inode *child,
                                                void *fs_data, bool preload)
@@ -240,19 +221,11 @@ int fscrypt_inherit_context(struct inode *parent, struct inode *child,
                return -ENOKEY;
 
        ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1;
-       if (fscrypt_dummy_context_enabled(parent)) {
-               ctx.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS;
-               ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS;
-               ctx.flags = 0;
-               memset(ctx.master_key_descriptor, 0x42, FS_KEY_DESCRIPTOR_SIZE);
-               res = 0;
-       } else {
-               ctx.contents_encryption_mode = ci->ci_data_mode;
-               ctx.filenames_encryption_mode = ci->ci_filename_mode;
-               ctx.flags = ci->ci_flags;
-               memcpy(ctx.master_key_descriptor, ci->ci_master_key,
-                               FS_KEY_DESCRIPTOR_SIZE);
-       }
+       ctx.contents_encryption_mode = ci->ci_data_mode;
+       ctx.filenames_encryption_mode = ci->ci_filename_mode;
+       ctx.flags = ci->ci_flags;
+       memcpy(ctx.master_key_descriptor, ci->ci_master_key,
+              FS_KEY_DESCRIPTOR_SIZE);
        get_random_bytes(ctx.nonce, FS_KEY_DERIVATION_NONCE_SIZE);
        res = parent->i_sb->s_cop->set_context(child, &ctx,
                                                sizeof(ctx), fs_data);
index c45598b912e14c981fdeb002b01c1535218c0ff2..e9cf8b4cd2346103b3ef4a76322a47b36e5dd8d6 100644 (file)
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -1086,8 +1086,12 @@ dax_iomap_rw(struct kiocb *iocb, struct iov_iter *iter,
        loff_t pos = iocb->ki_pos, ret = 0, done = 0;
        unsigned flags = 0;
 
-       if (iov_iter_rw(iter) == WRITE)
+       if (iov_iter_rw(iter) == WRITE) {
+               lockdep_assert_held_exclusive(&inode->i_rwsem);
                flags |= IOMAP_WRITE;
+       } else {
+               lockdep_assert_held(&inode->i_rwsem);
+       }
 
        while (iov_iter_count(iter)) {
                ret = iomap_apply(inode, pos, iov_iter_count(iter), flags, ops,
index f17fcf89e18eb077ca4231c344327852ea3b156f..7fb1732a3630bd82aba6e8d116bfca2317f57fd9 100644 (file)
@@ -248,6 +248,42 @@ static struct file_system_type debug_fs_type = {
 };
 MODULE_ALIAS_FS("debugfs");
 
+/**
+ * debugfs_lookup() - look up an existing debugfs file
+ * @name: a pointer to a string containing the name of the file to look up.
+ * @parent: a pointer to the parent dentry of the file.
+ *
+ * This function will return a pointer to a dentry if it succeeds.  If the file
+ * doesn't exist or an error occurs, %NULL will be returned.  The returned
+ * dentry must be passed to dput() when it is no longer needed.
+ *
+ * If debugfs is not enabled in the kernel, the value -%ENODEV will be
+ * returned.
+ */
+struct dentry *debugfs_lookup(const char *name, struct dentry *parent)
+{
+       struct dentry *dentry;
+
+       if (IS_ERR(parent))
+               return NULL;
+
+       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));
+
+       if (IS_ERR(dentry))
+               return NULL;
+       if (!d_really_is_positive(dentry)) {
+               dput(dentry);
+               return NULL;
+       }
+       return dentry;
+}
+EXPORT_SYMBOL_GPL(debugfs_lookup);
+
 static struct dentry *start_creating(const char *name, struct dentry *parent)
 {
        struct dentry *dentry;
index 2163c1e69f2a66151103f96b7d73268702784dfc..01d52b98f9a766377f7b8fe62f0e2b9f2832a920 100644 (file)
 #include <linux/percpu_counter.h>
 #include <linux/ratelimit.h>
 #include <crypto/hash.h>
-#include <linux/fscrypto.h>
+#ifdef CONFIG_EXT4_FS_ENCRYPTION
+#include <linux/fscrypt_supp.h>
+#else
+#include <linux/fscrypt_notsupp.h>
+#endif
 #include <linux/falloc.h>
 #include <linux/percpu-rwsem.h>
 #ifdef __KERNEL__
@@ -679,6 +683,16 @@ struct fsxattr {
 #define EXT4_IOC_FSGETXATTR            FS_IOC_FSGETXATTR
 #define EXT4_IOC_FSSETXATTR            FS_IOC_FSSETXATTR
 
+#define EXT4_IOC_SHUTDOWN _IOR ('X', 125, __u32)
+
+/*
+ * Flags for going down operation
+ */
+#define EXT4_GOING_FLAGS_DEFAULT               0x0     /* going down */
+#define EXT4_GOING_FLAGS_LOGFLUSH              0x1     /* flush log but not data */
+#define EXT4_GOING_FLAGS_NOLOGFLUSH            0x2     /* don't flush log nor data */
+
+
 #if defined(__KERNEL__) && defined(CONFIG_COMPAT)
 /*
  * ioctl commands in 32 bit emulation
@@ -1343,11 +1357,6 @@ struct ext4_super_block {
 /* Number of quota types we support */
 #define EXT4_MAXQUOTAS 3
 
-#ifdef CONFIG_EXT4_FS_ENCRYPTION
-#define EXT4_KEY_DESC_PREFIX "ext4:"
-#define EXT4_KEY_DESC_PREFIX_SIZE 5
-#endif
-
 /*
  * fourth extended-fs super-block data in memory
  */
@@ -1404,8 +1413,7 @@ struct ext4_sb_info {
        struct journal_s *s_journal;
        struct list_head s_orphan;
        struct mutex s_orphan_lock;
-       unsigned long s_resize_flags;           /* Flags indicating if there
-                                                  is a resizer */
+       unsigned long s_ext4_flags;             /* Ext4 superblock flags */
        unsigned long s_commit_interval;
        u32 s_max_batch_time;
        u32 s_min_batch_time;
@@ -1517,12 +1525,6 @@ struct ext4_sb_info {
 
        /* Barrier between changing inodes' journal flags and writepages ops. */
        struct percpu_rw_semaphore s_journal_flag_rwsem;
-
-       /* Encryption support */
-#ifdef CONFIG_EXT4_FS_ENCRYPTION
-       u8 key_prefix[EXT4_KEY_DESC_PREFIX_SIZE];
-       u8 key_prefix_size;
-#endif
 };
 
 static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb)
@@ -1844,6 +1846,18 @@ static inline bool ext4_has_incompat_features(struct super_block *sb)
        return (EXT4_SB(sb)->s_es->s_feature_incompat != 0);
 }
 
+/*
+ * Superblock flags
+ */
+#define EXT4_FLAGS_RESIZING    0
+#define EXT4_FLAGS_SHUTDOWN    1
+
+static inline int ext4_forced_shutdown(struct ext4_sb_info *sbi)
+{
+       return test_bit(EXT4_FLAGS_SHUTDOWN, &sbi->s_ext4_flags);
+}
+
+
 /*
  * Default values for user and/or group using reserved blocks
  */
@@ -2320,28 +2334,6 @@ static inline int ext4_fname_setup_filename(struct inode *dir,
 }
 static inline void ext4_fname_free_filename(struct ext4_filename *fname) { }
 
-#define fscrypt_set_d_op(i)
-#define fscrypt_get_ctx                        fscrypt_notsupp_get_ctx
-#define fscrypt_release_ctx            fscrypt_notsupp_release_ctx
-#define fscrypt_encrypt_page           fscrypt_notsupp_encrypt_page
-#define fscrypt_decrypt_page           fscrypt_notsupp_decrypt_page
-#define fscrypt_decrypt_bio_pages      fscrypt_notsupp_decrypt_bio_pages
-#define fscrypt_pullback_bio_page      fscrypt_notsupp_pullback_bio_page
-#define fscrypt_restore_control_page   fscrypt_notsupp_restore_control_page
-#define fscrypt_zeroout_range          fscrypt_notsupp_zeroout_range
-#define fscrypt_ioctl_set_policy       fscrypt_notsupp_ioctl_set_policy
-#define fscrypt_ioctl_get_policy       fscrypt_notsupp_ioctl_get_policy
-#define fscrypt_has_permitted_context  fscrypt_notsupp_has_permitted_context
-#define fscrypt_inherit_context                fscrypt_notsupp_inherit_context
-#define fscrypt_get_encryption_info    fscrypt_notsupp_get_encryption_info
-#define fscrypt_put_encryption_info    fscrypt_notsupp_put_encryption_info
-#define fscrypt_setup_filename         fscrypt_notsupp_setup_filename
-#define fscrypt_free_filename          fscrypt_notsupp_free_filename
-#define fscrypt_fname_encrypted_size   fscrypt_notsupp_fname_encrypted_size
-#define fscrypt_fname_alloc_buffer     fscrypt_notsupp_fname_alloc_buffer
-#define fscrypt_fname_free_buffer      fscrypt_notsupp_fname_free_buffer
-#define fscrypt_fname_disk_to_usr      fscrypt_notsupp_fname_disk_to_usr
-#define fscrypt_fname_usr_to_disk      fscrypt_notsupp_fname_usr_to_disk
 #endif
 
 /* dir.c */
@@ -3034,7 +3026,7 @@ extern int ext4_inline_data_fiemap(struct inode *inode,
 extern int ext4_try_to_evict_inline_data(handle_t *handle,
                                         struct inode *inode,
                                         int needed);
-extern void ext4_inline_data_truncate(struct inode *inode, int *has_inline);
+extern int ext4_inline_data_truncate(struct inode *inode, int *has_inline);
 
 extern int ext4_convert_inline_data(struct inode *inode);
 
@@ -3228,7 +3220,6 @@ static inline void ext4_inode_resume_unlocked_dio(struct inode *inode)
                                            EXT4_WQ_HASH_SZ])
 extern wait_queue_head_t ext4__ioend_wq[EXT4_WQ_HASH_SZ];
 
-#define EXT4_RESIZING  0
 extern int ext4_resize_begin(struct super_block *sb);
 extern void ext4_resize_end(struct super_block *sb);
 
index e770c1ee4613ed6084518f2ec9dca0ff9e53a29a..dd106b1d5d89155d850f5320b7739342455959bd 100644 (file)
@@ -43,6 +43,10 @@ static int ext4_journal_check_start(struct super_block *sb)
        journal_t *journal;
 
        might_sleep();
+
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(sb))))
+               return -EIO;
+
        if (sb->s_flags & MS_RDONLY)
                return -EROFS;
        WARN_ON(sb->s_writers.frozen == SB_FREEZE_COMPLETE);
@@ -161,6 +165,13 @@ 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,
index 3e295d3350a9470b61a0bb4a8a1fffc30a451292..2a97dff87b961771383c33e97dc57997eb6586fb 100644 (file)
@@ -5334,7 +5334,8 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
        ext4_lblk_t stop, *iterator, ex_start, ex_end;
 
        /* Let path point to the last extent */
-       path = ext4_find_extent(inode, EXT_MAX_BLOCKS - 1, NULL, 0);
+       path = ext4_find_extent(inode, EXT_MAX_BLOCKS - 1, NULL,
+                               EXT4_EX_NOCACHE);
        if (IS_ERR(path))
                return PTR_ERR(path);
 
@@ -5343,15 +5344,15 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
        if (!extent)
                goto out;
 
-       stop = le32_to_cpu(extent->ee_block) +
-                       ext4_ext_get_actual_len(extent);
+       stop = le32_to_cpu(extent->ee_block);
 
        /*
         * In case of left shift, Don't start shifting extents until we make
         * sure the hole is big enough to accommodate the shift.
        */
        if (SHIFT == SHIFT_LEFT) {
-               path = ext4_find_extent(inode, start - 1, &path, 0);
+               path = ext4_find_extent(inode, start - 1, &path,
+                                       EXT4_EX_NOCACHE);
                if (IS_ERR(path))
                        return PTR_ERR(path);
                depth = path->p_depth;
@@ -5383,9 +5384,14 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
        else
                iterator = &stop;
 
-       /* Its safe to start updating extents */
-       while (start < stop) {
-               path = ext4_find_extent(inode, *iterator, &path, 0);
+       /*
+        * Its safe to start updating extents.  Start and stop are unsigned, so
+        * in case of right shift if extent with 0 block is reached, iterator
+        * becomes NULL to indicate the end of the loop.
+        */
+       while (iterator && start <= stop) {
+               path = ext4_find_extent(inode, *iterator, &path,
+                                       EXT4_EX_NOCACHE);
                if (IS_ERR(path))
                        return PTR_ERR(path);
                depth = path->p_depth;
@@ -5412,8 +5418,11 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
                                        ext4_ext_get_actual_len(extent);
                } else {
                        extent = EXT_FIRST_EXTENT(path[depth].p_hdr);
-                       *iterator =  le32_to_cpu(extent->ee_block) > 0 ?
-                               le32_to_cpu(extent->ee_block) - 1 : 0;
+                       if (le32_to_cpu(extent->ee_block) > 0)
+                               *iterator = le32_to_cpu(extent->ee_block) - 1;
+                       else
+                               /* Beginning is reached, end of the loop */
+                               iterator = NULL;
                        /* Update path extent in case we need to stop */
                        while (le32_to_cpu(extent->ee_block) < start)
                                extent++;
index d663d3d7c81cb7fdff0f33f1903e9ed4d1f77f9a..87e11dfe3cde883c0bdd47c9b43fa6461ab4323d 100644 (file)
@@ -57,6 +57,9 @@ static ssize_t ext4_dax_read_iter(struct kiocb *iocb, struct iov_iter *to)
 
 static ssize_t ext4_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
 {
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(file_inode(iocb->ki_filp)->i_sb))))
+               return -EIO;
+
        if (!iov_iter_count(to))
                return 0; /* skip atime */
 
@@ -175,7 +178,6 @@ ext4_dax_write_iter(struct kiocb *iocb, struct iov_iter *from)
 {
        struct inode *inode = file_inode(iocb->ki_filp);
        ssize_t ret;
-       bool overwrite = false;
 
        inode_lock(inode);
        ret = ext4_write_checks(iocb, from);
@@ -188,16 +190,9 @@ ext4_dax_write_iter(struct kiocb *iocb, struct iov_iter *from)
        if (ret)
                goto out;
 
-       if (ext4_overwrite_io(inode, iocb->ki_pos, iov_iter_count(from))) {
-               overwrite = true;
-               downgrade_write(&inode->i_rwsem);
-       }
        ret = dax_iomap_rw(iocb, from, &ext4_iomap_ops);
 out:
-       if (!overwrite)
-               inode_unlock(inode);
-       else
-               inode_unlock_shared(inode);
+       inode_unlock(inode);
        if (ret > 0)
                ret = generic_write_sync(iocb, ret);
        return ret;
@@ -213,6 +208,9 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
        int overwrite = 0;
        ssize_t ret;
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
+               return -EIO;
+
 #ifdef CONFIG_FS_DAX
        if (IS_DAX(inode))
                return ext4_dax_write_iter(iocb, from);
@@ -348,6 +346,9 @@ static int ext4_file_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct inode *inode = file->f_mapping->host;
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
+               return -EIO;
+
        if (ext4_encrypted_inode(inode)) {
                int err = fscrypt_get_encryption_info(inode);
                if (err)
@@ -375,6 +376,9 @@ static int ext4_file_open(struct inode * inode, struct file * filp)
        char buf[64], *cp;
        int ret;
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
+               return -EIO;
+
        if (unlikely(!(sbi->s_mount_flags & EXT4_MF_MNTDIR_SAMPLED) &&
                     !(sb->s_flags & MS_RDONLY))) {
                sbi->s_mount_flags |= EXT4_MF_MNTDIR_SAMPLED;
index 88effb1053c7d83680b60270f7273cc0112e7ab6..9d549608fd30bb04466bf56ab5f71855a00af944 100644 (file)
@@ -100,6 +100,9 @@ int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
        tid_t commit_tid;
        bool needs_barrier = false;
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
+               return -EIO;
+
        J_ASSERT(ext4_journal_current_handle() == NULL);
 
        trace_ext4_sync_file_enter(file, datasync);
index e026aa941fd5a625db35ba0f1105e6cf025793ab..38b8a96eb97c2f59932993e704b15a4b6b89e207 100644 (file)
@@ -10,7 +10,8 @@
  */
 
 #include <linux/fs.h>
-#include <linux/cryptohash.h>
+#include <linux/compiler.h>
+#include <linux/bitops.h>
 #include "ext4.h"
 
 #define DELTA 0x9E3779B9
@@ -32,6 +33,74 @@ static void TEA_transform(__u32 buf[4], __u32 const in[])
        buf[1] += b1;
 }
 
+/* F, G and H are basic MD4 functions: selection, majority, parity */
+#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+/*
+ * The generic round function.  The application is so specific that
+ * we don't bother protecting all the arguments with parens, as is generally
+ * good macro practice, in favor of extra legibility.
+ * Rotation is separate from addition to prevent recomputation
+ */
+#define ROUND(f, a, b, c, d, x, s)     \
+       (a += f(b, c, d) + x, a = rol32(a, s))
+#define K1 0
+#define K2 013240474631UL
+#define K3 015666365641UL
+
+/*
+ * Basic cut-down MD4 transform.  Returns only 32 bits of result.
+ */
+static __u32 half_md4_transform(__u32 buf[4], __u32 const in[8])
+{
+       __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+       /* Round 1 */
+       ROUND(F, a, b, c, d, in[0] + K1,  3);
+       ROUND(F, d, a, b, c, in[1] + K1,  7);
+       ROUND(F, c, d, a, b, in[2] + K1, 11);
+       ROUND(F, b, c, d, a, in[3] + K1, 19);
+       ROUND(F, a, b, c, d, in[4] + K1,  3);
+       ROUND(F, d, a, b, c, in[5] + K1,  7);
+       ROUND(F, c, d, a, b, in[6] + K1, 11);
+       ROUND(F, b, c, d, a, in[7] + K1, 19);
+
+       /* Round 2 */
+       ROUND(G, a, b, c, d, in[1] + K2,  3);
+       ROUND(G, d, a, b, c, in[3] + K2,  5);
+       ROUND(G, c, d, a, b, in[5] + K2,  9);
+       ROUND(G, b, c, d, a, in[7] + K2, 13);
+       ROUND(G, a, b, c, d, in[0] + K2,  3);
+       ROUND(G, d, a, b, c, in[2] + K2,  5);
+       ROUND(G, c, d, a, b, in[4] + K2,  9);
+       ROUND(G, b, c, d, a, in[6] + K2, 13);
+
+       /* Round 3 */
+       ROUND(H, a, b, c, d, in[3] + K3,  3);
+       ROUND(H, d, a, b, c, in[7] + K3,  9);
+       ROUND(H, c, d, a, b, in[2] + K3, 11);
+       ROUND(H, b, c, d, a, in[6] + K3, 15);
+       ROUND(H, a, b, c, d, in[1] + K3,  3);
+       ROUND(H, d, a, b, c, in[5] + K3,  9);
+       ROUND(H, c, d, a, b, in[0] + K3, 11);
+       ROUND(H, b, c, d, a, in[4] + K3, 15);
+
+       buf[0] += a;
+       buf[1] += b;
+       buf[2] += c;
+       buf[3] += d;
+
+       return buf[1]; /* "most hashed" word */
+}
+#undef ROUND
+#undef K1
+#undef K2
+#undef K3
+#undef F
+#undef G
+#undef H
 
 /* The old legacy hash */
 static __u32 dx_hack_hash_unsigned(const char *name, int len)
index e57e8d90ea54a71745cf6257a7f1ef6437a0191b..b14bae2598bc5347ec98da206df043e081e15e33 100644 (file)
@@ -764,6 +764,9 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
        if (!dir || !dir->i_nlink)
                return ERR_PTR(-EPERM);
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(dir->i_sb))))
+               return ERR_PTR(-EIO);
+
        if ((ext4_encrypted_inode(dir) ||
             DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb))) &&
            (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) {
@@ -771,7 +774,7 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
                if (err)
                        return ERR_PTR(err);
                if (!fscrypt_has_encryption_key(dir))
-                       return ERR_PTR(-EPERM);
+                       return ERR_PTR(-ENOKEY);
                if (!handle)
                        nblocks += EXT4_DATA_TRANS_BLOCKS(dir->i_sb);
                encrypt = 1;
index 437df6a1a8417cec309c699cfef2166f02b6930a..30a9f210d1e32c8a01635821b2937407d5b21773 100644 (file)
@@ -215,6 +215,9 @@ static void ext4_write_inline_data(struct inode *inode, struct ext4_iloc *iloc,
        struct ext4_inode *raw_inode;
        int cp_len = 0;
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
+               return;
+
        BUG_ON(!EXT4_I(inode)->i_inline_off);
        BUG_ON(pos + len > EXT4_I(inode)->i_inline_size);
 
@@ -381,7 +384,7 @@ out:
 static int ext4_prepare_inline_data(handle_t *handle, struct inode *inode,
                                    unsigned int len)
 {
-       int ret, size;
+       int ret, size, no_expand;
        struct ext4_inode_info *ei = EXT4_I(inode);
 
        if (!ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA))
@@ -391,15 +394,14 @@ static int ext4_prepare_inline_data(handle_t *handle, struct inode *inode,
        if (size < len)
                return -ENOSPC;
 
-       down_write(&EXT4_I(inode)->xattr_sem);
+       ext4_write_lock_xattr(inode, &no_expand);
 
        if (ei->i_inline_off)
                ret = ext4_update_inline_data(handle, inode, len);
        else
                ret = ext4_create_inline_data(handle, inode, len);
 
-       up_write(&EXT4_I(inode)->xattr_sem);
-
+       ext4_write_unlock_xattr(inode, &no_expand);
        return ret;
 }
 
@@ -533,7 +535,7 @@ static int ext4_convert_inline_data_to_extent(struct address_space *mapping,
                                              struct inode *inode,
                                              unsigned flags)
 {
-       int ret, needed_blocks;
+       int ret, needed_blocks, no_expand;
        handle_t *handle = NULL;
        int retries = 0, sem_held = 0;
        struct page *page = NULL;
@@ -573,7 +575,7 @@ retry:
                goto out;
        }
 
-       down_write(&EXT4_I(inode)->xattr_sem);
+       ext4_write_lock_xattr(inode, &no_expand);
        sem_held = 1;
        /* If some one has already done this for us, just exit. */
        if (!ext4_has_inline_data(inode)) {
@@ -610,7 +612,7 @@ retry:
                put_page(page);
                page = NULL;
                ext4_orphan_add(handle, inode);
-               up_write(&EXT4_I(inode)->xattr_sem);
+               ext4_write_unlock_xattr(inode, &no_expand);
                sem_held = 0;
                ext4_journal_stop(handle);
                handle = NULL;
@@ -636,7 +638,7 @@ out:
                put_page(page);
        }
        if (sem_held)
-               up_write(&EXT4_I(inode)->xattr_sem);
+               ext4_write_unlock_xattr(inode, &no_expand);
        if (handle)
                ext4_journal_stop(handle);
        brelse(iloc.bh);
@@ -729,7 +731,7 @@ convert:
 int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len,
                               unsigned copied, struct page *page)
 {
-       int ret;
+       int ret, no_expand;
        void *kaddr;
        struct ext4_iloc iloc;
 
@@ -747,7 +749,7 @@ int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len,
                goto out;
        }
 
-       down_write(&EXT4_I(inode)->xattr_sem);
+       ext4_write_lock_xattr(inode, &no_expand);
        BUG_ON(!ext4_has_inline_data(inode));
 
        kaddr = kmap_atomic(page);
@@ -757,7 +759,7 @@ int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len,
        /* clear page dirty so that writepages wouldn't work for us. */
        ClearPageDirty(page);
 
-       up_write(&EXT4_I(inode)->xattr_sem);
+       ext4_write_unlock_xattr(inode, &no_expand);
        brelse(iloc.bh);
 out:
        return copied;
@@ -768,7 +770,7 @@ ext4_journalled_write_inline_data(struct inode *inode,
                                  unsigned len,
                                  struct page *page)
 {
-       int ret;
+       int ret, no_expand;
        void *kaddr;
        struct ext4_iloc iloc;
 
@@ -778,11 +780,11 @@ ext4_journalled_write_inline_data(struct inode *inode,
                return NULL;
        }
 
-       down_write(&EXT4_I(inode)->xattr_sem);
+       ext4_write_lock_xattr(inode, &no_expand);
        kaddr = kmap_atomic(page);
        ext4_write_inline_data(inode, &iloc, kaddr, 0, len);
        kunmap_atomic(kaddr);
-       up_write(&EXT4_I(inode)->xattr_sem);
+       ext4_write_unlock_xattr(inode, &no_expand);
 
        return iloc.bh;
 }
@@ -944,8 +946,15 @@ int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos,
                                  struct page *page)
 {
        int i_size_changed = 0;
+       int ret;
 
-       copied = ext4_write_inline_data_end(inode, pos, len, copied, page);
+       ret = ext4_write_inline_data_end(inode, pos, len, copied, page);
+       if (ret < 0) {
+               unlock_page(page);
+               put_page(page);
+               return ret;
+       }
+       copied = ret;
 
        /*
         * No need to use i_size_read() here, the i_size
@@ -1043,7 +1052,6 @@ static int ext4_add_dirent_to_inline(handle_t *handle,
        dir->i_mtime = dir->i_ctime = current_time(dir);
        ext4_update_dx_flag(dir);
        dir->i_version++;
-       ext4_mark_inode_dirty(handle, dir);
        return 1;
 }
 
@@ -1259,7 +1267,7 @@ out:
 int ext4_try_add_inline_entry(handle_t *handle, struct ext4_filename *fname,
                              struct inode *dir, struct inode *inode)
 {
-       int ret, inline_size;
+       int ret, inline_size, no_expand;
        void *inline_start;
        struct ext4_iloc iloc;
 
@@ -1267,7 +1275,7 @@ int ext4_try_add_inline_entry(handle_t *handle, struct ext4_filename *fname,
        if (ret)
                return ret;
 
-       down_write(&EXT4_I(dir)->xattr_sem);
+       ext4_write_lock_xattr(dir, &no_expand);
        if (!ext4_has_inline_data(dir))
                goto out;
 
@@ -1312,8 +1320,8 @@ int ext4_try_add_inline_entry(handle_t *handle, struct ext4_filename *fname,
        ret = ext4_convert_inline_data_nolock(handle, dir, &iloc);
 
 out:
+       ext4_write_unlock_xattr(dir, &no_expand);
        ext4_mark_inode_dirty(handle, dir);
-       up_write(&EXT4_I(dir)->xattr_sem);
        brelse(iloc.bh);
        return ret;
 }
@@ -1673,7 +1681,7 @@ int ext4_delete_inline_entry(handle_t *handle,
                             struct buffer_head *bh,
                             int *has_inline_data)
 {
-       int err, inline_size;
+       int err, inline_size, no_expand;
        struct ext4_iloc iloc;
        void *inline_start;
 
@@ -1681,7 +1689,7 @@ int ext4_delete_inline_entry(handle_t *handle,
        if (err)
                return err;
 
-       down_write(&EXT4_I(dir)->xattr_sem);
+       ext4_write_lock_xattr(dir, &no_expand);
        if (!ext4_has_inline_data(dir)) {
                *has_inline_data = 0;
                goto out;
@@ -1709,13 +1717,11 @@ int ext4_delete_inline_entry(handle_t *handle,
        if (err)
                goto out;
 
-       err = ext4_mark_inode_dirty(handle, dir);
-       if (unlikely(err))
-               goto out;
-
        ext4_show_inline_dir(dir, iloc.bh, inline_start, inline_size);
 out:
-       up_write(&EXT4_I(dir)->xattr_sem);
+       ext4_write_unlock_xattr(dir, &no_expand);
+       if (likely(err == 0))
+               err = ext4_mark_inode_dirty(handle, dir);
        brelse(iloc.bh);
        if (err != -ENOENT)
                ext4_std_error(dir->i_sb, err);
@@ -1814,11 +1820,11 @@ out:
 
 int ext4_destroy_inline_data(handle_t *handle, struct inode *inode)
 {
-       int ret;
+       int ret, no_expand;
 
-       down_write(&EXT4_I(inode)->xattr_sem);
+       ext4_write_lock_xattr(inode, &no_expand);
        ret = ext4_destroy_inline_data_nolock(handle, inode);
-       up_write(&EXT4_I(inode)->xattr_sem);
+       ext4_write_unlock_xattr(inode, &no_expand);
 
        return ret;
 }
@@ -1900,10 +1906,10 @@ out:
        return error;
 }
 
-void ext4_inline_data_truncate(struct inode *inode, int *has_inline)
+int ext4_inline_data_truncate(struct inode *inode, int *has_inline)
 {
        handle_t *handle;
-       int inline_size, value_len, needed_blocks;
+       int inline_size, value_len, needed_blocks, no_expand, err = 0;
        size_t i_size;
        void *value = NULL;
        struct ext4_xattr_ibody_find is = {
@@ -1918,19 +1924,19 @@ void ext4_inline_data_truncate(struct inode *inode, int *has_inline)
        needed_blocks = ext4_writepage_trans_blocks(inode);
        handle = ext4_journal_start(inode, EXT4_HT_INODE, needed_blocks);
        if (IS_ERR(handle))
-               return;
+               return PTR_ERR(handle);
 
-       down_write(&EXT4_I(inode)->xattr_sem);
+       ext4_write_lock_xattr(inode, &no_expand);
        if (!ext4_has_inline_data(inode)) {
                *has_inline = 0;
                ext4_journal_stop(handle);
-               return;
+               return 0;
        }
 
-       if (ext4_orphan_add(handle, inode))
+       if ((err = ext4_orphan_add(handle, inode)) != 0)
                goto out;
 
-       if (ext4_get_inode_loc(inode, &is.iloc))
+       if ((err = ext4_get_inode_loc(inode, &is.iloc)) != 0)
                goto out;
 
        down_write(&EXT4_I(inode)->i_data_sem);
@@ -1941,24 +1947,29 @@ void ext4_inline_data_truncate(struct inode *inode, int *has_inline)
        if (i_size < inline_size) {
                /* Clear the content in the xattr space. */
                if (inline_size > EXT4_MIN_INLINE_DATA_SIZE) {
-                       if (ext4_xattr_ibody_find(inode, &i, &is))
+                       if ((err = ext4_xattr_ibody_find(inode, &i, &is)) != 0)
                                goto out_error;
 
                        BUG_ON(is.s.not_found);
 
                        value_len = le32_to_cpu(is.s.here->e_value_size);
                        value = kmalloc(value_len, GFP_NOFS);
-                       if (!value)
+                       if (!value) {
+                               err = -ENOMEM;
                                goto out_error;
+                       }
 
-                       if (ext4_xattr_ibody_get(inode, i.name_index, i.name,
-                                               value, value_len))
+                       err = ext4_xattr_ibody_get(inode, i.name_index,
+                                                  i.name, value, value_len);
+                       if (err <= 0)
                                goto out_error;
 
                        i.value = value;
                        i.value_len = i_size > EXT4_MIN_INLINE_DATA_SIZE ?
                                        i_size - EXT4_MIN_INLINE_DATA_SIZE : 0;
-                       if (ext4_xattr_ibody_inline_set(handle, inode, &i, &is))
+                       err = ext4_xattr_ibody_inline_set(handle, inode,
+                                                         &i, &is);
+                       if (err)
                                goto out_error;
                }
 
@@ -1978,23 +1989,24 @@ out_error:
        up_write(&EXT4_I(inode)->i_data_sem);
 out:
        brelse(is.iloc.bh);
-       up_write(&EXT4_I(inode)->xattr_sem);
+       ext4_write_unlock_xattr(inode, &no_expand);
        kfree(value);
        if (inode->i_nlink)
                ext4_orphan_del(handle, inode);
 
-       inode->i_mtime = inode->i_ctime = current_time(inode);
-       ext4_mark_inode_dirty(handle, inode);
-       if (IS_SYNC(inode))
-               ext4_handle_sync(handle);
-
+       if (err == 0) {
+               inode->i_mtime = inode->i_ctime = current_time(inode);
+               err = ext4_mark_inode_dirty(handle, inode);
+               if (IS_SYNC(inode))
+                       ext4_handle_sync(handle);
+       }
        ext4_journal_stop(handle);
-       return;
+       return err;
 }
 
 int ext4_convert_inline_data(struct inode *inode)
 {
-       int error, needed_blocks;
+       int error, needed_blocks, no_expand;
        handle_t *handle;
        struct ext4_iloc iloc;
 
@@ -2016,15 +2028,10 @@ int ext4_convert_inline_data(struct inode *inode)
                goto out_free;
        }
 
-       down_write(&EXT4_I(inode)->xattr_sem);
-       if (!ext4_has_inline_data(inode)) {
-               up_write(&EXT4_I(inode)->xattr_sem);
-               goto out;
-       }
-
-       error = ext4_convert_inline_data_nolock(handle, inode, &iloc);
-       up_write(&EXT4_I(inode)->xattr_sem);
-out:
+       ext4_write_lock_xattr(inode, &no_expand);
+       if (ext4_has_inline_data(inode))
+               error = ext4_convert_inline_data_nolock(handle, inode, &iloc);
+       ext4_write_unlock_xattr(inode, &no_expand);
        ext4_journal_stop(handle);
 out_free:
        brelse(iloc.bh);
index 88d57af1b516c5bbfd7b2f1bc471a9d76382c3bc..f622d4a577e35d88f52e6e31dfe5791d34a905b8 100644 (file)
@@ -1189,6 +1189,9 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping,
        pgoff_t index;
        unsigned from, to;
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
+               return -EIO;
+
        trace_ext4_write_begin(inode, pos, len, flags);
        /*
         * Reserve one block more for addition to orphan list in case
@@ -1330,8 +1333,11 @@ static int ext4_write_end(struct file *file,
        if (ext4_has_inline_data(inode)) {
                ret = ext4_write_inline_data_end(inode, pos, len,
                                                 copied, page);
-               if (ret < 0)
+               if (ret < 0) {
+                       unlock_page(page);
+                       put_page(page);
                        goto errout;
+               }
                copied = ret;
        } else
                copied = block_write_end(file, mapping, pos,
@@ -1385,7 +1391,9 @@ errout:
  * set the buffer to be dirty, since in data=journalled mode we need
  * to call ext4_handle_dirty_metadata() instead.
  */
-static void zero_new_buffers(struct page *page, unsigned from, unsigned to)
+static void ext4_journalled_zero_new_buffers(handle_t *handle,
+                                           struct page *page,
+                                           unsigned from, unsigned to)
 {
        unsigned int block_start = 0, block_end;
        struct buffer_head *head, *bh;
@@ -1402,7 +1410,7 @@ static void zero_new_buffers(struct page *page, unsigned from, unsigned to)
                                        size = min(to, block_end) - start;
 
                                        zero_user(page, start, size);
-                                       set_buffer_uptodate(bh);
+                                       write_end_fn(handle, bh);
                                }
                                clear_buffer_new(bh);
                        }
@@ -1431,18 +1439,25 @@ static int ext4_journalled_write_end(struct file *file,
 
        BUG_ON(!ext4_handle_valid(handle));
 
-       if (ext4_has_inline_data(inode))
-               copied = ext4_write_inline_data_end(inode, pos, len,
-                                                   copied, page);
-       else {
-               if (copied < len) {
-                       if (!PageUptodate(page))
-                               copied = 0;
-                       zero_new_buffers(page, from+copied, to);
+       if (ext4_has_inline_data(inode)) {
+               ret = ext4_write_inline_data_end(inode, pos, len,
+                                                copied, page);
+               if (ret < 0) {
+                       unlock_page(page);
+                       put_page(page);
+                       goto errout;
                }
-
+               copied = ret;
+       } else if (unlikely(copied < len) && !PageUptodate(page)) {
+               copied = 0;
+               ext4_journalled_zero_new_buffers(handle, page, from, to);
+       } else {
+               if (unlikely(copied < len))
+                       ext4_journalled_zero_new_buffers(handle, page,
+                                                        from + copied, to);
                ret = ext4_walk_page_buffers(handle, page_buffers(page), from,
-                                            to, &partial, write_end_fn);
+                                            from + copied, &partial,
+                                            write_end_fn);
                if (!partial)
                        SetPageUptodate(page);
        }
@@ -1468,6 +1483,7 @@ static int ext4_journalled_write_end(struct file *file,
                 */
                ext4_orphan_add(handle, inode);
 
+errout:
        ret2 = ext4_journal_stop(handle);
        if (!ret)
                ret = ret2;
@@ -2034,6 +2050,12 @@ static int ext4_writepage(struct page *page,
        struct ext4_io_submit io_submit;
        bool keep_towrite = false;
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb)))) {
+               ext4_invalidatepage(page, 0, PAGE_SIZE);
+               unlock_page(page);
+               return -EIO;
+       }
+
        trace_ext4_writepage(page);
        size = i_size_read(inode);
        if (page->index == size >> PAGE_SHIFT)
@@ -2409,7 +2431,8 @@ static int mpage_map_and_submit_extent(handle_t *handle,
                if (err < 0) {
                        struct super_block *sb = inode->i_sb;
 
-                       if (EXT4_SB(sb)->s_mount_flags & EXT4_MF_FS_ABORTED)
+                       if (ext4_forced_shutdown(EXT4_SB(sb)) ||
+                           EXT4_SB(sb)->s_mount_flags & EXT4_MF_FS_ABORTED)
                                goto invalidate_dirty_pages;
                        /*
                         * Let the uper layers retry transient errors.
@@ -2464,8 +2487,8 @@ update_disksize:
                        disksize = i_size;
                if (disksize > EXT4_I(inode)->i_disksize)
                        EXT4_I(inode)->i_disksize = disksize;
-               err2 = ext4_mark_inode_dirty(handle, inode);
                up_write(&EXT4_I(inode)->i_data_sem);
+               err2 = ext4_mark_inode_dirty(handle, inode);
                if (err2)
                        ext4_error(inode->i_sb,
                                   "Failed to mark inode %lu dirty",
@@ -2631,6 +2654,9 @@ static int ext4_writepages(struct address_space *mapping,
        struct blk_plug plug;
        bool give_up_on_write = false;
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
+               return -EIO;
+
        percpu_down_read(&sbi->s_journal_flag_rwsem);
        trace_ext4_writepages(inode, wbc);
 
@@ -2667,7 +2693,8 @@ static int ext4_writepages(struct address_space *mapping,
         * *never* be called, so if that ever happens, we would want
         * the stack trace.
         */
-       if (unlikely(sbi->s_mount_flags & EXT4_MF_FS_ABORTED)) {
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(mapping->host->i_sb)) ||
+                    sbi->s_mount_flags & EXT4_MF_FS_ABORTED)) {
                ret = -EROFS;
                goto out_writepages;
        }
@@ -2892,6 +2919,9 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping,
        struct inode *inode = mapping->host;
        handle_t *handle;
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
+               return -EIO;
+
        index = pos >> PAGE_SHIFT;
 
        if (ext4_nonda_switch(inode->i_sb) ||
@@ -3914,6 +3944,10 @@ static int ext4_block_truncate_page(handle_t *handle,
        unsigned blocksize;
        struct inode *inode = mapping->host;
 
+       /* If we are processing an encrypted inode during orphan list handling */
+       if (ext4_encrypted_inode(inode) && !fscrypt_has_encryption_key(inode))
+               return 0;
+
        blocksize = inode->i_sb->s_blocksize;
        length = blocksize - (offset & (blocksize - 1));
 
@@ -4222,7 +4256,9 @@ int ext4_truncate(struct inode *inode)
        if (ext4_has_inline_data(inode)) {
                int has_inline = 1;
 
-               ext4_inline_data_truncate(inode, &has_inline);
+               err = ext4_inline_data_truncate(inode, &has_inline);
+               if (err)
+                       return err;
                if (has_inline)
                        return 0;
        }
@@ -5197,6 +5233,9 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
        int orphan = 0;
        const unsigned int ia_valid = attr->ia_valid;
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
+               return -EIO;
+
        error = setattr_prepare(dentry, attr);
        if (error)
                return error;
@@ -5483,6 +5522,9 @@ int ext4_mark_iloc_dirty(handle_t *handle,
 {
        int err = 0;
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
+               return -EIO;
+
        if (IS_I_VERSION(inode))
                inode_inc_iversion(inode);
 
@@ -5506,6 +5548,9 @@ ext4_reserve_inode_write(handle_t *handle, struct inode *inode,
 {
        int err;
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
+               return -EIO;
+
        err = ext4_get_inode_loc(inode, iloc);
        if (!err) {
                BUFFER_TRACE(iloc->bh, "get_write_access");
index d534399cf60785ed42cabe77b5ab41aefcb6ae9b..a4273ddb992232e1587e33fd7f3a23ea926aaa7e 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/quotaops.h>
 #include <linux/uuid.h>
 #include <linux/uaccess.h>
+#include <linux/delay.h>
 #include "ext4_jbd2.h"
 #include "ext4.h"
 
@@ -442,6 +443,52 @@ static inline unsigned long ext4_xflags_to_iflags(__u32 xflags)
        return iflags;
 }
 
+int ext4_shutdown(struct super_block *sb, unsigned long arg)
+{
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+       __u32 flags;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       if (get_user(flags, (__u32 __user *)arg))
+               return -EFAULT;
+
+       if (flags > EXT4_GOING_FLAGS_NOLOGFLUSH)
+               return -EINVAL;
+
+       if (ext4_forced_shutdown(sbi))
+               return 0;
+
+       ext4_msg(sb, KERN_ALERT, "shut down requested (%d)", flags);
+
+       switch (flags) {
+       case EXT4_GOING_FLAGS_DEFAULT:
+               freeze_bdev(sb->s_bdev);
+               set_bit(EXT4_FLAGS_SHUTDOWN, &sbi->s_ext4_flags);
+               thaw_bdev(sb->s_bdev, sb);
+               break;
+       case EXT4_GOING_FLAGS_LOGFLUSH:
+               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);
+               }
+               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);
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+       clear_opt(sb, DISCARD);
+       return 0;
+}
+
 long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
        struct inode *inode = file_inode(filp);
@@ -893,6 +940,8 @@ resizefs_out:
 
                return 0;
        }
+       case EXT4_IOC_SHUTDOWN:
+               return ext4_shutdown(sb, arg);
        default:
                return -ENOTTY;
        }
@@ -959,6 +1008,7 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case EXT4_IOC_SET_ENCRYPTION_POLICY:
        case EXT4_IOC_GET_ENCRYPTION_PWSALT:
        case EXT4_IOC_GET_ENCRYPTION_POLICY:
+       case EXT4_IOC_SHUTDOWN:
                break;
        default:
                return -ENOIOCTLCMD;
index 7ae43c59bc79578ddc2146328ca050ab68212bd2..10c62de642c6f9e24d82e6017f65e436683cb7ad 100644 (file)
@@ -1556,7 +1556,17 @@ static int mb_find_extent(struct ext4_buddy *e4b, int block,
                ex->fe_len += 1 << order;
        }
 
-       BUG_ON(ex->fe_start + ex->fe_len > (1 << (e4b->bd_blkbits + 3)));
+       if (ex->fe_start + ex->fe_len > (1 << (e4b->bd_blkbits + 3))) {
+               /* Should never happen! (but apparently sometimes does?!?) */
+               WARN_ON(1);
+               ext4_error(e4b->bd_sb, "corruption or bug in mb_find_extent "
+                          "block=%d, order=%d needed=%d ex=%u/%d/%d@%u",
+                          block, order, needed, ex->fe_group, ex->fe_start,
+                          ex->fe_len, ex->fe_logical);
+               ex->fe_len = 0;
+               ex->fe_start = 0;
+               ex->fe_group = 0;
+       }
        return ex->fe_len;
 }
 
@@ -2136,8 +2146,10 @@ ext4_mb_regular_allocator(struct ext4_allocation_context *ac)
         * We search using buddy data only if the order of the request
         * is greater than equal to the sbi_s_mb_order2_reqs
         * You can tune it via /sys/fs/ext4/<partition>/mb_order2_req
+        * We also support searching for power-of-two requests only for
+        * requests upto maximum buddy size we have constructed.
         */
-       if (i >= sbi->s_mb_order2_reqs) {
+       if (i >= sbi->s_mb_order2_reqs && i <= sb->s_blocksize_bits + 2) {
                /*
                 * This should tell if fe_len is exactly power of 2
                 */
@@ -2207,7 +2219,7 @@ repeat:
                        }
 
                        ac->ac_groups_scanned++;
-                       if (cr == 0 && ac->ac_2order < sb->s_blocksize_bits+2)
+                       if (cr == 0)
                                ext4_mb_simple_scan_group(ac, &e4b);
                        else if (cr == 1 && sbi->s_stripe &&
                                        !(ac->ac_g_ex.fe_len % sbi->s_stripe))
@@ -3123,6 +3135,13 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac,
        if (ar->pright && start + size - 1 >= ar->lright)
                size -= start + size - ar->lright;
 
+       /*
+        * Trim allocation request for filesystems with artificially small
+        * groups.
+        */
+       if (size > EXT4_BLOCKS_PER_GROUP(ac->ac_sb))
+               size = EXT4_BLOCKS_PER_GROUP(ac->ac_sb);
+
        end = start + size;
 
        /* check we don't cross already preallocated blocks */
index eadba919f26b1484c10125739a0e684fe49b7273..6ad612c576fc733f8a6d95540c20d8e75995e1c6 100644 (file)
@@ -1378,6 +1378,8 @@ static struct buffer_head * ext4_find_entry (struct inode *dir,
                return NULL;
 
        retval = ext4_fname_setup_filename(dir, d_name, 1, &fname);
+       if (retval == -ENOENT)
+               return NULL;
        if (retval)
                return ERR_PTR(retval);
 
@@ -1616,13 +1618,15 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi
                    !fscrypt_has_permitted_context(dir, inode)) {
                        int nokey = ext4_encrypted_inode(inode) &&
                                !fscrypt_has_encryption_key(inode);
-                       iput(inode);
-                       if (nokey)
+                       if (nokey) {
+                               iput(inode);
                                return ERR_PTR(-ENOKEY);
+                       }
                        ext4_warning(inode->i_sb,
                                     "Inconsistent encryption contexts: %lu/%lu",
                                     (unsigned long) dir->i_ino,
                                     (unsigned long) inode->i_ino);
+                       iput(inode);
                        return ERR_PTR(-EPERM);
                }
        }
@@ -2935,6 +2939,9 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry)
        struct ext4_dir_entry_2 *de;
        handle_t *handle = NULL;
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(dir->i_sb))))
+               return -EIO;
+
        /* Initialize quotas before so that eventual writes go in
         * separate transaction */
        retval = dquot_initialize(dir);
@@ -3008,6 +3015,9 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
        struct ext4_dir_entry_2 *de;
        handle_t *handle = NULL;
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(dir->i_sb))))
+               return -EIO;
+
        trace_ext4_unlink_enter(dir, dentry);
        /* Initialize quotas before so that eventual writes go
         * in separate transaction */
@@ -3078,6 +3088,9 @@ static int ext4_symlink(struct inode *dir,
        struct fscrypt_str disk_link;
        struct fscrypt_symlink_data *sd = NULL;
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(dir->i_sb))))
+               return -EIO;
+
        disk_link.len = len + 1;
        disk_link.name = (char *) symname;
 
@@ -3088,7 +3101,7 @@ static int ext4_symlink(struct inode *dir,
                if (err)
                        return err;
                if (!fscrypt_has_encryption_key(dir))
-                       return -EPERM;
+                       return -ENOKEY;
                disk_link.len = (fscrypt_fname_encrypted_size(dir, len) +
                                 sizeof(struct fscrypt_symlink_data));
                sd = kzalloc(disk_link.len, GFP_KERNEL);
@@ -3525,6 +3538,12 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
                        EXT4_I(old_dentry->d_inode)->i_projid)))
                return -EXDEV;
 
+       if ((ext4_encrypted_inode(old_dir) &&
+            !fscrypt_has_encryption_key(old_dir)) ||
+           (ext4_encrypted_inode(new_dir) &&
+            !fscrypt_has_encryption_key(new_dir)))
+               return -ENOKEY;
+
        retval = dquot_initialize(old.dir);
        if (retval)
                return retval;
@@ -3725,6 +3744,12 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
        int retval;
        struct timespec ctime;
 
+       if ((ext4_encrypted_inode(old_dir) &&
+            !fscrypt_has_encryption_key(old_dir)) ||
+           (ext4_encrypted_inode(new_dir) &&
+            !fscrypt_has_encryption_key(new_dir)))
+               return -ENOKEY;
+
        if ((ext4_encrypted_inode(old_dir) ||
             ext4_encrypted_inode(new_dir)) &&
            (old_dir != new_dir) &&
@@ -3858,6 +3883,9 @@ static int ext4_rename2(struct inode *old_dir, struct dentry *old_dentry,
                        struct inode *new_dir, struct dentry *new_dentry,
                        unsigned int flags)
 {
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(old_dir->i_sb))))
+               return -EIO;
+
        if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
                return -EINVAL;
 
index d83b0f3c5fe9eac1390b71bd2c3d43b13a087f51..208241b06662fbccfd741340ba167e68a711418e 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/backing-dev.h>
-#include <linux/fscrypto.h>
 
 #include "ext4_jbd2.h"
 #include "xattr.h"
@@ -158,7 +157,7 @@ static int ext4_end_io(ext4_io_end_t *io)
 
        io->handle = NULL;      /* Following call will use up the handle */
        ret = ext4_convert_unwritten_extents(handle, inode, offset, size);
-       if (ret < 0) {
+       if (ret < 0 && !ext4_forced_shutdown(EXT4_SB(inode->i_sb))) {
                ext4_msg(inode->i_sb, KERN_EMERG,
                         "failed to convert unwritten extents to written "
                         "extents -- potential data loss!  "
index cf681004b1965fba00be6e97ee9a4cbe57eb3654..c3ed9021b781c57cce5d6cff163c216be6c20020 100644 (file)
@@ -45,7 +45,8 @@ int ext4_resize_begin(struct super_block *sb)
                return -EPERM;
        }
 
-       if (test_and_set_bit_lock(EXT4_RESIZING, &EXT4_SB(sb)->s_resize_flags))
+       if (test_and_set_bit_lock(EXT4_FLAGS_RESIZING,
+                                 &EXT4_SB(sb)->s_ext4_flags))
                ret = -EBUSY;
 
        return ret;
@@ -53,7 +54,7 @@ int ext4_resize_begin(struct super_block *sb)
 
 void ext4_resize_end(struct super_block *sb)
 {
-       clear_bit_unlock(EXT4_RESIZING, &EXT4_SB(sb)->s_resize_flags);
+       clear_bit_unlock(EXT4_FLAGS_RESIZING, &EXT4_SB(sb)->s_ext4_flags);
        smp_mb__after_atomic();
 }
 
index 66845a08a87a42bc8a97c7fcab88644c19d6b0f9..2e03a0a88d92f7731346a26cbdc934458549660f 100644 (file)
@@ -438,6 +438,9 @@ void __ext4_error(struct super_block *sb, const char *function,
        struct va_format vaf;
        va_list args;
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(sb))))
+               return;
+
        if (ext4_error_ratelimit(sb)) {
                va_start(args, fmt);
                vaf.fmt = fmt;
@@ -459,6 +462,9 @@ void __ext4_error_inode(struct inode *inode, const char *function,
        struct va_format vaf;
        struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
+               return;
+
        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)) {
@@ -491,6 +497,9 @@ void __ext4_error_file(struct file *file, const char *function,
        struct inode *inode = file_inode(file);
        char pathname[80], *path;
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
+               return;
+
        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)) {
@@ -567,6 +576,9 @@ void __ext4_std_error(struct super_block *sb, const char *function,
        char nbuf[16];
        const char *errstr;
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(sb))))
+               return;
+
        /* Special case: if the error is EROFS, and we're not already
         * inside a transaction, then there's really no point in logging
         * an error. */
@@ -600,6 +612,9 @@ void __ext4_abort(struct super_block *sb, const char *function,
        struct va_format vaf;
        va_list args;
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(sb))))
+               return;
+
        save_error_info(sb, function, line);
        va_start(args, fmt);
        vaf.fmt = fmt;
@@ -695,6 +710,9 @@ __acquires(bitlock)
        va_list args;
        struct ext4_super_block *es = EXT4_SB(sb)->s_es;
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(sb))))
+               return;
+
        es->s_last_error_ino = cpu_to_le32(ino);
        es->s_last_error_block = cpu_to_le64(block);
        __save_error_info(sb, function, line);
@@ -825,6 +843,7 @@ static void ext4_put_super(struct super_block *sb)
 {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        struct ext4_super_block *es = sbi->s_es;
+       int aborted = 0;
        int i, err;
 
        ext4_unregister_li_request(sb);
@@ -834,9 +853,10 @@ static void ext4_put_super(struct super_block *sb)
        destroy_workqueue(sbi->rsv_conversion_wq);
 
        if (sbi->s_journal) {
+               aborted = is_journal_aborted(sbi->s_journal);
                err = jbd2_journal_destroy(sbi->s_journal);
                sbi->s_journal = NULL;
-               if (err < 0)
+               if ((err < 0) && !aborted)
                        ext4_abort(sb, "Couldn't clean up the journal");
        }
 
@@ -847,7 +867,7 @@ static void ext4_put_super(struct super_block *sb)
        ext4_mb_release(sb);
        ext4_ext_release(sb);
 
-       if (!(sb->s_flags & MS_RDONLY)) {
+       if (!(sb->s_flags & MS_RDONLY) && !aborted) {
                ext4_clear_feature_journal_needs_recovery(sb);
                es->s_state = cpu_to_le16(sbi->s_mount_state);
        }
@@ -1100,12 +1120,6 @@ static int ext4_get_context(struct inode *inode, void *ctx, size_t len)
                                 EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, ctx, len);
 }
 
-static int ext4_key_prefix(struct inode *inode, u8 **key)
-{
-       *key = EXT4_SB(inode->i_sb)->key_prefix;
-       return EXT4_SB(inode->i_sb)->key_prefix_size;
-}
-
 static int ext4_prepare_context(struct inode *inode)
 {
        return ext4_convert_inline_data(inode);
@@ -1179,9 +1193,9 @@ static unsigned ext4_max_namelen(struct inode *inode)
                EXT4_NAME_LEN;
 }
 
-static struct fscrypt_operations ext4_cryptops = {
+static const struct fscrypt_operations ext4_cryptops = {
+       .key_prefix             = "ext4:",
        .get_context            = ext4_get_context,
-       .key_prefix             = ext4_key_prefix,
        .prepare_context        = ext4_prepare_context,
        .set_context            = ext4_set_context,
        .dummy_context          = ext4_dummy_context,
@@ -1190,7 +1204,7 @@ static struct fscrypt_operations ext4_cryptops = {
        .max_namelen            = ext4_max_namelen,
 };
 #else
-static struct fscrypt_operations ext4_cryptops = {
+static const struct fscrypt_operations ext4_cryptops = {
        .is_encrypted           = ext4_encrypted_inode,
 };
 #endif
@@ -1290,7 +1304,7 @@ enum {
        Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err,
        Opt_usrquota, Opt_grpquota, Opt_prjquota, Opt_i_version, Opt_dax,
        Opt_stripe, Opt_delalloc, Opt_nodelalloc, Opt_mblk_io_submit,
-       Opt_lazytime, Opt_nolazytime,
+       Opt_lazytime, Opt_nolazytime, Opt_debug_want_extra_isize,
        Opt_nomblk_io_submit, Opt_block_validity, Opt_noblock_validity,
        Opt_inode_readahead_blks, Opt_journal_ioprio,
        Opt_dioread_nolock, Opt_dioread_lock,
@@ -1358,6 +1372,7 @@ static const match_table_t tokens = {
        {Opt_delalloc, "delalloc"},
        {Opt_lazytime, "lazytime"},
        {Opt_nolazytime, "nolazytime"},
+       {Opt_debug_want_extra_isize, "debug_want_extra_isize=%u"},
        {Opt_nodelalloc, "nodelalloc"},
        {Opt_removed, "mblk_io_submit"},
        {Opt_removed, "nomblk_io_submit"},
@@ -1563,6 +1578,7 @@ static const struct mount_opts {
 #endif
        {Opt_nouid32, EXT4_MOUNT_NO_UID32, MOPT_SET},
        {Opt_debug, EXT4_MOUNT_DEBUG, MOPT_SET},
+       {Opt_debug_want_extra_isize, 0, MOPT_GTE0},
        {Opt_quota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA, MOPT_SET | MOPT_Q},
        {Opt_usrquota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA,
                                                        MOPT_SET | MOPT_Q},
@@ -1676,6 +1692,8 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
                if (arg == 0)
                        arg = JBD2_DEFAULT_MAX_COMMIT_AGE;
                sbi->s_commit_interval = HZ * arg;
+       } else if (token == Opt_debug_want_extra_isize) {
+               sbi->s_want_extra_isize = arg;
        } else if (token == Opt_max_batch_time) {
                sbi->s_max_batch_time = arg;
        } else if (token == Opt_min_batch_time) {
@@ -2619,9 +2637,9 @@ static unsigned long ext4_get_stripe_size(struct ext4_sb_info *sbi)
 
        if (sbi->s_stripe && sbi->s_stripe <= sbi->s_blocks_per_group)
                ret = sbi->s_stripe;
-       else if (stripe_width <= sbi->s_blocks_per_group)
+       else if (stripe_width && stripe_width <= sbi->s_blocks_per_group)
                ret = stripe_width;
-       else if (stride <= sbi->s_blocks_per_group)
+       else if (stride && stride <= sbi->s_blocks_per_group)
                ret = stride;
        else
                ret = 0;
@@ -3842,7 +3860,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) /
                   EXT4_DESC_PER_BLOCK(sb);
        if (ext4_has_feature_meta_bg(sb)) {
-               if (le32_to_cpu(es->s_first_meta_bg) >= db_count) {
+               if (le32_to_cpu(es->s_first_meta_bg) > db_count) {
                        ext4_msg(sb, KERN_WARNING,
                                 "first meta block group too large: %u "
                                 "(group descriptor block count %u)",
@@ -3925,7 +3943,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
         * root first: it may be modified in the journal!
         */
        if (!test_opt(sb, NOLOAD) && ext4_has_feature_journal(sb)) {
-               if (ext4_load_journal(sb, es, journal_devnum))
+               err = ext4_load_journal(sb, es, journal_devnum);
+               if (err)
                        goto failed_mount3a;
        } else if (test_opt(sb, NOLOAD) && !(sb->s_flags & MS_RDONLY) &&
                   ext4_has_feature_journal_needs_recovery(sb)) {
@@ -4087,7 +4106,8 @@ no_journal:
                sb->s_flags |= MS_RDONLY;
 
        /* determine the minimum size of new large inodes, if present */
-       if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) {
+       if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE &&
+           sbi->s_want_extra_isize == 0) {
                sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
                                                     EXT4_GOOD_OLD_INODE_SIZE;
                if (ext4_has_feature_extra_isize(sb)) {
@@ -4218,11 +4238,6 @@ no_journal:
        ratelimit_state_init(&sbi->s_msg_ratelimit_state, 5 * HZ, 10);
 
        kfree(orig_data);
-#ifdef CONFIG_EXT4_FS_ENCRYPTION
-       memcpy(sbi->key_prefix, EXT4_KEY_DESC_PREFIX,
-                               EXT4_KEY_DESC_PREFIX_SIZE);
-       sbi->key_prefix_size = EXT4_KEY_DESC_PREFIX_SIZE;
-#endif
        return 0;
 
 cantfind_ext4:
@@ -4720,6 +4735,9 @@ static int ext4_sync_fs(struct super_block *sb, int wait)
        bool needs_barrier = false;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(sb))))
+               return 0;
+
        trace_ext4_sync_fs(sb, wait);
        flush_workqueue(sbi->rsv_conversion_wq);
        /*
@@ -4803,7 +4821,7 @@ out:
  */
 static int ext4_unfreeze(struct super_block *sb)
 {
-       if (sb->s_flags & MS_RDONLY)
+       if ((sb->s_flags & MS_RDONLY) || ext4_forced_shutdown(EXT4_SB(sb)))
                return 0;
 
        if (EXT4_SB(sb)->s_journal) {
index 5a94fa52b74f8d6cfce999d4be4750d74b0ce2b2..67636acf762475e211a641f4720e862ba886a40a 100644 (file)
@@ -411,6 +411,9 @@ ext4_xattr_get(struct inode *inode, int name_index, const char *name,
 {
        int error;
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
+               return -EIO;
+
        if (strlen(name) > 255)
                return -ERANGE;
 
@@ -1188,16 +1191,14 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
        struct ext4_xattr_block_find bs = {
                .s = { .not_found = -ENODATA, },
        };
-       unsigned long no_expand;
+       int no_expand;
        int error;
 
        if (!name)
                return -EINVAL;
        if (strlen(name) > 255)
                return -ERANGE;
-       down_write(&EXT4_I(inode)->xattr_sem);
-       no_expand = ext4_test_inode_state(inode, EXT4_STATE_NO_EXPAND);
-       ext4_set_inode_state(inode, EXT4_STATE_NO_EXPAND);
+       ext4_write_lock_xattr(inode, &no_expand);
 
        error = ext4_reserve_inode_write(handle, inode, &is.iloc);
        if (error)
@@ -1264,7 +1265,7 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
                ext4_xattr_update_super_block(handle, inode->i_sb);
                inode->i_ctime = current_time(inode);
                if (!value)
-                       ext4_clear_inode_state(inode, EXT4_STATE_NO_EXPAND);
+                       no_expand = 0;
                error = ext4_mark_iloc_dirty(handle, inode, &is.iloc);
                /*
                 * The bh is consumed by ext4_mark_iloc_dirty, even with
@@ -1278,9 +1279,7 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
 cleanup:
        brelse(is.iloc.bh);
        brelse(bs.bh);
-       if (no_expand == 0)
-               ext4_clear_inode_state(inode, EXT4_STATE_NO_EXPAND);
-       up_write(&EXT4_I(inode)->xattr_sem);
+       ext4_write_unlock_xattr(inode, &no_expand);
        return error;
 }
 
@@ -1497,12 +1496,11 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
        int error = 0, tried_min_extra_isize = 0;
        int s_min_extra_isize = le16_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_min_extra_isize);
        int isize_diff; /* How much do we need to grow i_extra_isize */
+       int no_expand;
+
+       if (ext4_write_trylock_xattr(inode, &no_expand) == 0)
+               return 0;
 
-       down_write(&EXT4_I(inode)->xattr_sem);
-       /*
-        * Set EXT4_STATE_NO_EXPAND to avoid recursion when marking inode dirty
-        */
-       ext4_set_inode_state(inode, EXT4_STATE_NO_EXPAND);
 retry:
        isize_diff = new_extra_isize - EXT4_I(inode)->i_extra_isize;
        if (EXT4_I(inode)->i_extra_isize >= new_extra_isize)
@@ -1584,17 +1582,16 @@ shift:
        EXT4_I(inode)->i_extra_isize = new_extra_isize;
        brelse(bh);
 out:
-       ext4_clear_inode_state(inode, EXT4_STATE_NO_EXPAND);
-       up_write(&EXT4_I(inode)->xattr_sem);
+       ext4_write_unlock_xattr(inode, &no_expand);
        return 0;
 
 cleanup:
        brelse(bh);
        /*
-        * We deliberately leave EXT4_STATE_NO_EXPAND set here since inode
-        * size expansion failed.
+        * Inode size expansion failed; don't try again
         */
-       up_write(&EXT4_I(inode)->xattr_sem);
+       no_expand = 1;
+       ext4_write_unlock_xattr(inode, &no_expand);
        return error;
 }
 
index a92e783fa057070a2d46ece41089bae6e3a26fe4..099c8b670ef56e2a4ab85266b4c0f112edaa48b9 100644 (file)
@@ -102,6 +102,38 @@ extern const struct xattr_handler ext4_xattr_security_handler;
 
 #define EXT4_XATTR_NAME_ENCRYPTION_CONTEXT "c"
 
+/*
+ * The EXT4_STATE_NO_EXPAND is overloaded and used for two purposes.
+ * The first is to signal that there the inline xattrs and data are
+ * taking up so much space that we might as well not keep trying to
+ * expand it.  The second is that xattr_sem is taken for writing, so
+ * we shouldn't try to recurse into the inode expansion.  For this
+ * second case, we need to make sure that we take save and restore the
+ * NO_EXPAND state flag appropriately.
+ */
+static inline void ext4_write_lock_xattr(struct inode *inode, int *save)
+{
+       down_write(&EXT4_I(inode)->xattr_sem);
+       *save = ext4_test_inode_state(inode, EXT4_STATE_NO_EXPAND);
+       ext4_set_inode_state(inode, EXT4_STATE_NO_EXPAND);
+}
+
+static inline int ext4_write_trylock_xattr(struct inode *inode, int *save)
+{
+       if (down_write_trylock(&EXT4_I(inode)->xattr_sem) == 0)
+               return 0;
+       *save = ext4_test_inode_state(inode, EXT4_STATE_NO_EXPAND);
+       ext4_set_inode_state(inode, EXT4_STATE_NO_EXPAND);
+       return 1;
+}
+
+static inline void ext4_write_unlock_xattr(struct inode *inode, int *save)
+{
+       if (*save == 0)
+               ext4_clear_inode_state(inode, EXT4_STATE_NO_EXPAND);
+       up_write(&EXT4_I(inode)->xattr_sem);
+}
+
 extern ssize_t ext4_listxattr(struct dentry *, char *, size_t);
 
 extern int ext4_xattr_get(struct inode *, int, const char *, void *, size_t);
index 827c5daef4fca7d9168833ccc3388cd2dc6c071c..18607fc5240dafe4977f1e44532d4a33725a7623 100644 (file)
@@ -268,7 +268,10 @@ struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir,
 
        err = fscrypt_setup_filename(dir, child, 1, &fname);
        if (err) {
-               *res_page = ERR_PTR(err);
+               if (err == -ENOENT)
+                       *res_page = NULL;
+               else
+                       *res_page = ERR_PTR(err);
                return NULL;
        }
 
index 2da8c3aa0ce5db222ed1c60aa6d394140d564aae..069fc7277d8df0589ff502475c97b55098de9a92 100644 (file)
 #include <linux/vmalloc.h>
 #include <linux/bio.h>
 #include <linux/blkdev.h>
-#include <linux/fscrypto.h>
+#ifdef CONFIG_F2FS_FS_ENCRYPTION
+#include <linux/fscrypt_supp.h>
+#else
+#include <linux/fscrypt_notsupp.h>
+#endif
 #include <crypto/hash.h>
 
 #ifdef CONFIG_F2FS_CHECK_FS
@@ -760,10 +764,6 @@ enum {
        MAX_TIME,
 };
 
-#ifdef CONFIG_F2FS_FS_ENCRYPTION
-#define F2FS_KEY_DESC_PREFIX "f2fs:"
-#define F2FS_KEY_DESC_PREFIX_SIZE 5
-#endif
 struct f2fs_sb_info {
        struct super_block *sb;                 /* pointer to VFS super block */
        struct proc_dir_entry *s_proc;          /* proc entry */
@@ -771,11 +771,6 @@ struct f2fs_sb_info {
        int valid_super_block;                  /* valid super block no */
        unsigned long s_flag;                           /* flags for sbi */
 
-#ifdef CONFIG_F2FS_FS_ENCRYPTION
-       u8 key_prefix[F2FS_KEY_DESC_PREFIX_SIZE];
-       u8 key_prefix_size;
-#endif
-
 #ifdef CONFIG_BLK_DEV_ZONED
        unsigned int blocks_per_blkz;           /* F2FS blocks per zone */
        unsigned int log_blocks_per_blkz;       /* log2 F2FS blocks per zone */
@@ -2510,28 +2505,4 @@ static inline bool f2fs_may_encrypt(struct inode *inode)
 #endif
 }
 
-#ifndef CONFIG_F2FS_FS_ENCRYPTION
-#define fscrypt_set_d_op(i)
-#define fscrypt_get_ctx                        fscrypt_notsupp_get_ctx
-#define fscrypt_release_ctx            fscrypt_notsupp_release_ctx
-#define fscrypt_encrypt_page           fscrypt_notsupp_encrypt_page
-#define fscrypt_decrypt_page           fscrypt_notsupp_decrypt_page
-#define fscrypt_decrypt_bio_pages      fscrypt_notsupp_decrypt_bio_pages
-#define fscrypt_pullback_bio_page      fscrypt_notsupp_pullback_bio_page
-#define fscrypt_restore_control_page   fscrypt_notsupp_restore_control_page
-#define fscrypt_zeroout_range          fscrypt_notsupp_zeroout_range
-#define fscrypt_ioctl_set_policy       fscrypt_notsupp_ioctl_set_policy
-#define fscrypt_ioctl_get_policy       fscrypt_notsupp_ioctl_get_policy
-#define fscrypt_has_permitted_context  fscrypt_notsupp_has_permitted_context
-#define fscrypt_inherit_context                fscrypt_notsupp_inherit_context
-#define fscrypt_get_encryption_info    fscrypt_notsupp_get_encryption_info
-#define fscrypt_put_encryption_info    fscrypt_notsupp_put_encryption_info
-#define fscrypt_setup_filename         fscrypt_notsupp_setup_filename
-#define fscrypt_free_filename          fscrypt_notsupp_free_filename
-#define fscrypt_fname_encrypted_size   fscrypt_notsupp_fname_encrypted_size
-#define fscrypt_fname_alloc_buffer     fscrypt_notsupp_fname_alloc_buffer
-#define fscrypt_fname_free_buffer      fscrypt_notsupp_fname_free_buffer
-#define fscrypt_fname_disk_to_usr      fscrypt_notsupp_fname_disk_to_usr
-#define fscrypt_fname_usr_to_disk      fscrypt_notsupp_fname_usr_to_disk
-#endif
 #endif
index 56c19b0610a899a6351f72a16e26b788f956e3d5..11cabcadb1a33c5e868ca2115453a108184c215c 100644 (file)
@@ -403,7 +403,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
                        return err;
 
                if (!fscrypt_has_encryption_key(dir))
-                       return -EPERM;
+                       return -ENOKEY;
 
                disk_link.len = (fscrypt_fname_encrypted_size(dir, len) +
                                sizeof(struct fscrypt_symlink_data));
@@ -447,7 +447,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
                        goto err_out;
 
                if (!fscrypt_has_encryption_key(inode)) {
-                       err = -EPERM;
+                       err = -ENOKEY;
                        goto err_out;
                }
 
index 46fd30d8af7763c93244092b6673e3cc2ff5f05f..a831303bb777aecd143217aad078c305a2c00b59 100644 (file)
@@ -1156,12 +1156,6 @@ static int f2fs_get_context(struct inode *inode, void *ctx, size_t len)
                                ctx, len, NULL);
 }
 
-static int f2fs_key_prefix(struct inode *inode, u8 **key)
-{
-       *key = F2FS_I_SB(inode)->key_prefix;
-       return F2FS_I_SB(inode)->key_prefix_size;
-}
-
 static int f2fs_set_context(struct inode *inode, const void *ctx, size_t len,
                                                        void *fs_data)
 {
@@ -1176,16 +1170,16 @@ static unsigned f2fs_max_namelen(struct inode *inode)
                        inode->i_sb->s_blocksize : F2FS_NAME_LEN;
 }
 
-static struct fscrypt_operations f2fs_cryptops = {
+static const struct fscrypt_operations f2fs_cryptops = {
+       .key_prefix     = "f2fs:",
        .get_context    = f2fs_get_context,
-       .key_prefix     = f2fs_key_prefix,
        .set_context    = f2fs_set_context,
        .is_encrypted   = f2fs_encrypted_inode,
        .empty_dir      = f2fs_empty_dir,
        .max_namelen    = f2fs_max_namelen,
 };
 #else
-static struct fscrypt_operations f2fs_cryptops = {
+static const struct fscrypt_operations f2fs_cryptops = {
        .is_encrypted   = f2fs_encrypted_inode,
 };
 #endif
@@ -1518,12 +1512,6 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
        mutex_init(&sbi->wio_mutex[NODE]);
        mutex_init(&sbi->wio_mutex[DATA]);
        spin_lock_init(&sbi->cp_lock);
-
-#ifdef CONFIG_F2FS_FS_ENCRYPTION
-       memcpy(sbi->key_prefix, F2FS_KEY_DESC_PREFIX,
-                               F2FS_KEY_DESC_PREFIX_SIZE);
-       sbi->key_prefix_size = F2FS_KEY_DESC_PREFIX_SIZE;
-#endif
 }
 
 static int init_percpu_info(struct f2fs_sb_info *sbi)
index 6b039d7ce160fce7677c3e5d702cd27a6299bb59..ed7a2e252ad802bf587006b00939696ea2cbe9eb 100644 (file)
@@ -143,8 +143,8 @@ static int gfs2_writepage(struct page *page, struct writeback_control *wbc)
 /* This is the same as calling block_write_full_page, but it also
  * writes pages outside of i_size
  */
-int gfs2_write_full_page(struct page *page, get_block_t *get_block,
-                        struct writeback_control *wbc)
+static int gfs2_write_full_page(struct page *page, get_block_t *get_block,
+                               struct writeback_control *wbc)
 {
        struct inode * const inode = page->mapping->host;
        loff_t i_size = i_size_read(inode);
index fc5da4cbe88c1c67a8c5ffcb512ee7edf877bb6c..01b97c012c6e9635540eaf2126cd5358726c1082 100644 (file)
@@ -720,6 +720,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        struct gfs2_rgrp_list rlist;
+       struct gfs2_trans *tr;
        u64 bn, bstart;
        u32 blen, btotal;
        __be64 *p;
@@ -728,6 +729,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
        unsigned int revokes = 0;
        int x;
        int error;
+       int jblocks_rqsted;
 
        error = gfs2_rindex_update(sdp);
        if (error)
@@ -791,12 +793,17 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
        if (gfs2_rs_active(&ip->i_res)) /* needs to be done with the rgrp glock held */
                gfs2_rs_deltree(&ip->i_res);
 
-       error = gfs2_trans_begin(sdp, rg_blocks + RES_DINODE +
-                                RES_INDIRECT + RES_STATFS + RES_QUOTA,
-                                revokes);
+restart:
+       jblocks_rqsted = rg_blocks + RES_DINODE +
+               RES_INDIRECT + RES_STATFS + RES_QUOTA +
+               gfs2_struct2blk(sdp, revokes, sizeof(u64));
+       if (jblocks_rqsted > atomic_read(&sdp->sd_log_thresh2))
+               jblocks_rqsted = atomic_read(&sdp->sd_log_thresh2);
+       error = gfs2_trans_begin(sdp, jblocks_rqsted, revokes);
        if (error)
                goto out_rg_gunlock;
 
+       tr = current->journal_info;
        down_write(&ip->i_rw_mutex);
 
        gfs2_trans_add_meta(ip->i_gl, dibh);
@@ -810,6 +817,16 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
                if (!*p)
                        continue;
 
+               /* check for max reasonable journal transaction blocks */
+               if (tr->tr_num_buf_new + RES_STATFS +
+                   RES_QUOTA >= atomic_read(&sdp->sd_log_thresh2)) {
+                       if (rg_blocks >= tr->tr_num_buf_new)
+                               rg_blocks -= tr->tr_num_buf_new;
+                       else
+                               rg_blocks = 0;
+                       break;
+               }
+
                bn = be64_to_cpu(*p);
 
                if (bstart + blen == bn)
@@ -827,6 +844,9 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
                *p = 0;
                gfs2_add_inode_blocks(&ip->i_inode, -1);
        }
+       if (p == bottom)
+               rg_blocks = 0;
+
        if (bstart) {
                __gfs2_free_blocks(ip, bstart, blen, metadata);
                btotal += blen;
@@ -844,6 +864,9 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
 
        gfs2_trans_end(sdp);
 
+       if (rg_blocks)
+               goto restart;
+
 out_rg_gunlock:
        gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs);
 out_rlist:
index 94f50cac91c617b03025d4d596d8d9d65d2c185b..a2d45db32cd5f093a8ddac3feaadcf22c0719ef9 100644 (file)
@@ -1802,16 +1802,18 @@ void gfs2_glock_exit(void)
 
 static void gfs2_glock_iter_next(struct gfs2_glock_iter *gi)
 {
-       do {
-               gi->gl = rhashtable_walk_next(&gi->hti);
+       while ((gi->gl = rhashtable_walk_next(&gi->hti))) {
                if (IS_ERR(gi->gl)) {
                        if (PTR_ERR(gi->gl) == -EAGAIN)
                                continue;
                        gi->gl = NULL;
+                       return;
                }
-       /* Skip entries for other sb and dead entries */
-       } while ((gi->gl) && ((gi->sdp != gi->gl->gl_name.ln_sbd) ||
-                             __lockref_is_dead(&gi->gl->gl_lockref)));
+               /* Skip entries for other sb and dead entries */
+               if (gi->sdp == gi->gl->gl_name.ln_sbd &&
+                   !__lockref_is_dead(&gi->gl->gl_lockref))
+                       return;
+       }
 }
 
 static void *gfs2_glock_seq_start(struct seq_file *seq, loff_t *pos)
index a6a3389a07fc67187288e5bb82a3b19d4996bf37..c45084ac642d1929058ea5d903ad796d574a45cc 100644 (file)
@@ -470,15 +470,19 @@ struct gfs2_quota_data {
        struct rcu_head qd_rcu;
 };
 
+enum {
+       TR_TOUCHED = 1,
+       TR_ATTACHED = 2,
+       TR_ALLOCED = 3,
+};
+
 struct gfs2_trans {
        unsigned long tr_ip;
 
        unsigned int tr_blocks;
        unsigned int tr_revokes;
        unsigned int tr_reserved;
-       unsigned int tr_touched:1;
-       unsigned int tr_attached:1;
-       unsigned int tr_alloced:1;
+       unsigned long tr_flags;
 
        unsigned int tr_num_buf_new;
        unsigned int tr_num_databuf_new;
@@ -794,6 +798,7 @@ struct gfs2_sbd {
        atomic_t sd_log_thresh1;
        atomic_t sd_log_thresh2;
        atomic_t sd_log_blks_free;
+       atomic_t sd_log_blks_needed;
        wait_queue_head_t sd_log_waitq;
        wait_queue_head_t sd_logd_waitq;
 
index 27c00a16def0a50fc6fe6b40a94184f862196995..f865b96374df2b5c40ecfb13663154499ec09b31 100644 (file)
@@ -349,6 +349,7 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks)
        if (gfs2_assert_warn(sdp, blks) ||
            gfs2_assert_warn(sdp, blks <= sdp->sd_jdesc->jd_blocks))
                return -EINVAL;
+       atomic_add(blks, &sdp->sd_log_blks_needed);
 retry:
        free_blocks = atomic_read(&sdp->sd_log_blks_free);
        if (unlikely(free_blocks <= wanted)) {
@@ -370,6 +371,7 @@ retry:
                        wake_up(&sdp->sd_reserving_log_wait);
                goto retry;
        }
+       atomic_sub(blks, &sdp->sd_log_blks_needed);
        trace_gfs2_log_blocks(sdp, -blks);
 
        /*
@@ -797,7 +799,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl,
 
 static void gfs2_merge_trans(struct gfs2_trans *old, struct gfs2_trans *new)
 {
-       WARN_ON_ONCE(old->tr_attached != 1);
+       WARN_ON_ONCE(!test_bit(TR_ATTACHED, &old->tr_flags));
 
        old->tr_num_buf_new     += new->tr_num_buf_new;
        old->tr_num_databuf_new += new->tr_num_databuf_new;
@@ -821,9 +823,9 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
        if (sdp->sd_log_tr) {
                gfs2_merge_trans(sdp->sd_log_tr, tr);
        } else if (tr->tr_num_buf_new || tr->tr_num_databuf_new) {
-               gfs2_assert_withdraw(sdp, tr->tr_alloced);
+               gfs2_assert_withdraw(sdp, test_bit(TR_ALLOCED, &tr->tr_flags));
                sdp->sd_log_tr = tr;
-               tr->tr_attached = 1;
+               set_bit(TR_ATTACHED, &tr->tr_flags);
        }
 
        sdp->sd_log_commited_revoke += tr->tr_num_revoke - tr->tr_num_revoke_rm;
@@ -891,13 +893,16 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp)
 
 static inline int gfs2_jrnl_flush_reqd(struct gfs2_sbd *sdp)
 {
-       return (atomic_read(&sdp->sd_log_pinned) >= atomic_read(&sdp->sd_log_thresh1));
+       return (atomic_read(&sdp->sd_log_pinned) +
+               atomic_read(&sdp->sd_log_blks_needed) >=
+               atomic_read(&sdp->sd_log_thresh1));
 }
 
 static inline int gfs2_ail_flush_reqd(struct gfs2_sbd *sdp)
 {
        unsigned int used_blocks = sdp->sd_jdesc->jd_blocks - atomic_read(&sdp->sd_log_blks_free);
-       return used_blocks >= atomic_read(&sdp->sd_log_thresh2);
+       return used_blocks + atomic_read(&sdp->sd_log_blks_needed) >=
+               atomic_read(&sdp->sd_log_thresh2);
 }
 
 /**
@@ -913,12 +918,15 @@ int gfs2_logd(void *data)
        struct gfs2_sbd *sdp = data;
        unsigned long t = 1;
        DEFINE_WAIT(wait);
+       bool did_flush;
 
        while (!kthread_should_stop()) {
 
+               did_flush = false;
                if (gfs2_jrnl_flush_reqd(sdp) || t == 0) {
                        gfs2_ail1_empty(sdp);
                        gfs2_log_flush(sdp, NULL, NORMAL_FLUSH);
+                       did_flush = true;
                }
 
                if (gfs2_ail_flush_reqd(sdp)) {
@@ -926,9 +934,10 @@ int gfs2_logd(void *data)
                        gfs2_ail1_wait(sdp);
                        gfs2_ail1_empty(sdp);
                        gfs2_log_flush(sdp, NULL, NORMAL_FLUSH);
+                       did_flush = true;
                }
 
-               if (!gfs2_ail_flush_reqd(sdp))
+               if (!gfs2_ail_flush_reqd(sdp) || did_flush)
                        wake_up(&sdp->sd_log_waitq);
 
                t = gfs2_tune_get(sdp, gt_logd_secs) * HZ;
index 49db8ef13fdff5308e7e49e5765f91cb58d9ab33..663ffc135ef365a436ae658d3f71965b31cee06e 100644 (file)
@@ -292,7 +292,7 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,
        wait_on_buffer(bh);
        if (unlikely(!buffer_uptodate(bh))) {
                struct gfs2_trans *tr = current->journal_info;
-               if (tr && tr->tr_touched)
+               if (tr && test_bit(TR_TOUCHED, &tr->tr_flags))
                        gfs2_io_error_bh(sdp, bh);
                brelse(bh);
                *bhp = NULL;
@@ -319,7 +319,7 @@ int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh)
 
        if (!buffer_uptodate(bh)) {
                struct gfs2_trans *tr = current->journal_info;
-               if (tr && tr->tr_touched)
+               if (tr && test_bit(TR_TOUCHED, &tr->tr_flags))
                        gfs2_io_error_bh(sdp, bh);
                return -EIO;
        }
@@ -345,7 +345,7 @@ void gfs2_remove_from_journal(struct buffer_head *bh, int meta)
                        tr->tr_num_buf_rm++;
                else
                        tr->tr_num_databuf_rm++;
-               tr->tr_touched = 1;
+               set_bit(TR_TOUCHED, &tr->tr_flags);
                was_pinned = 1;
                brelse(bh);
        }
index a34308df927f4f1395b918f27b30eec5dce60320..b108e7ba81af73568b71ec0b163bf68fbbde8948 100644 (file)
@@ -683,6 +683,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
                goto fail_jindex;
        }
 
+       atomic_set(&sdp->sd_log_blks_needed, 0);
        if (sdp->sd_args.ar_spectator) {
                sdp->sd_jdesc = gfs2_jdesc_find(sdp, 0);
                atomic_set(&sdp->sd_log_blks_free, sdp->sd_jdesc->jd_blocks);
@@ -1226,7 +1227,7 @@ static int set_gfs2_super(struct super_block *s, void *data)
         * We set the bdi here to the queue backing, file systems can
         * overwrite this in ->fill_super()
         */
-       s->s_bdi = &bdev_get_queue(s->s_bdev)->backing_dev_info;
+       s->s_bdi = bdev_get_queue(s->s_bdev)->backing_dev_info;
        return 0;
 }
 
index 0c1bde395062141045f0c857cba624b9f4ee5a1e..affef3c066e098621a244027a08add5902f6ca56 100644 (file)
@@ -48,7 +48,7 @@ int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
        tr->tr_blocks = blocks;
        tr->tr_revokes = revokes;
        tr->tr_reserved = 1;
-       tr->tr_alloced = 1;
+       set_bit(TR_ALLOCED, &tr->tr_flags);
        if (blocks)
                tr->tr_reserved += 6 + blocks;
        if (revokes)
@@ -78,7 +78,8 @@ static void gfs2_print_trans(const struct gfs2_trans *tr)
 {
        pr_warn("Transaction created at: %pSR\n", (void *)tr->tr_ip);
        pr_warn("blocks=%u revokes=%u reserved=%u touched=%u\n",
-               tr->tr_blocks, tr->tr_revokes, tr->tr_reserved, tr->tr_touched);
+               tr->tr_blocks, tr->tr_revokes, tr->tr_reserved,
+               test_bit(TR_TOUCHED, &tr->tr_flags));
        pr_warn("Buf %u/%u Databuf %u/%u Revoke %u/%u\n",
                tr->tr_num_buf_new, tr->tr_num_buf_rm,
                tr->tr_num_databuf_new, tr->tr_num_databuf_rm,
@@ -89,12 +90,12 @@ void gfs2_trans_end(struct gfs2_sbd *sdp)
 {
        struct gfs2_trans *tr = current->journal_info;
        s64 nbuf;
-       int alloced = tr->tr_alloced;
+       int alloced = test_bit(TR_ALLOCED, &tr->tr_flags);
 
        BUG_ON(!tr);
        current->journal_info = NULL;
 
-       if (!tr->tr_touched) {
+       if (!test_bit(TR_TOUCHED, &tr->tr_flags)) {
                gfs2_log_release(sdp, tr->tr_reserved);
                if (alloced) {
                        kfree(tr);
@@ -112,8 +113,8 @@ void gfs2_trans_end(struct gfs2_sbd *sdp)
                gfs2_print_trans(tr);
 
        gfs2_log_commit(sdp, tr);
-       if (alloced && !tr->tr_attached)
-                       kfree(tr);
+       if (alloced && !test_bit(TR_ATTACHED, &tr->tr_flags))
+               kfree(tr);
        up_read(&sdp->sd_log_flush_lock);
 
        if (sdp->sd_vfs->s_flags & MS_SYNCHRONOUS)
@@ -169,6 +170,10 @@ void gfs2_trans_add_data(struct gfs2_glock *gl, struct buffer_head *bh)
        }
 
        lock_buffer(bh);
+       if (buffer_pinned(bh)) {
+               set_bit(TR_TOUCHED, &tr->tr_flags);
+               goto out;
+       }
        gfs2_log_lock(sdp);
        bd = bh->b_private;
        if (bd == NULL) {
@@ -182,7 +187,7 @@ void gfs2_trans_add_data(struct gfs2_glock *gl, struct buffer_head *bh)
                gfs2_log_lock(sdp);
        }
        gfs2_assert(sdp, bd->bd_gl == gl);
-       tr->tr_touched = 1;
+       set_bit(TR_TOUCHED, &tr->tr_flags);
        if (list_empty(&bd->bd_list)) {
                set_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags);
                set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags);
@@ -191,45 +196,24 @@ void gfs2_trans_add_data(struct gfs2_glock *gl, struct buffer_head *bh)
                list_add_tail(&bd->bd_list, &tr->tr_databuf);
        }
        gfs2_log_unlock(sdp);
+out:
        unlock_buffer(bh);
 }
 
-static void meta_lo_add(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd)
-{
-       struct gfs2_meta_header *mh;
-       struct gfs2_trans *tr;
-       enum gfs2_freeze_state state = atomic_read(&sdp->sd_freeze_state);
-
-       tr = current->journal_info;
-       tr->tr_touched = 1;
-       if (!list_empty(&bd->bd_list))
-               return;
-       set_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags);
-       set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags);
-       mh = (struct gfs2_meta_header *)bd->bd_bh->b_data;
-       if (unlikely(mh->mh_magic != cpu_to_be32(GFS2_MAGIC))) {
-               pr_err("Attempting to add uninitialised block to journal (inplace block=%lld)\n",
-                      (unsigned long long)bd->bd_bh->b_blocknr);
-               BUG();
-       }
-       if (unlikely(state == SFS_FROZEN)) {
-               printk(KERN_INFO "GFS2:adding buf while frozen\n");
-               gfs2_assert_withdraw(sdp, 0);
-       }
-       gfs2_pin(sdp, bd->bd_bh);
-       mh->__pad0 = cpu_to_be64(0);
-       mh->mh_jid = cpu_to_be32(sdp->sd_jdesc->jd_jid);
-       list_add(&bd->bd_list, &tr->tr_buf);
-       tr->tr_num_buf_new++;
-}
-
 void gfs2_trans_add_meta(struct gfs2_glock *gl, struct buffer_head *bh)
 {
 
        struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
        struct gfs2_bufdata *bd;
+       struct gfs2_meta_header *mh;
+       struct gfs2_trans *tr = current->journal_info;
+       enum gfs2_freeze_state state = atomic_read(&sdp->sd_freeze_state);
 
        lock_buffer(bh);
+       if (buffer_pinned(bh)) {
+               set_bit(TR_TOUCHED, &tr->tr_flags);
+               goto out;
+       }
        gfs2_log_lock(sdp);
        bd = bh->b_private;
        if (bd == NULL) {
@@ -245,8 +229,29 @@ void gfs2_trans_add_meta(struct gfs2_glock *gl, struct buffer_head *bh)
                gfs2_log_lock(sdp);
        }
        gfs2_assert(sdp, bd->bd_gl == gl);
-       meta_lo_add(sdp, bd);
+       set_bit(TR_TOUCHED, &tr->tr_flags);
+       if (!list_empty(&bd->bd_list))
+               goto out_unlock;
+       set_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags);
+       set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags);
+       mh = (struct gfs2_meta_header *)bd->bd_bh->b_data;
+       if (unlikely(mh->mh_magic != cpu_to_be32(GFS2_MAGIC))) {
+               pr_err("Attempting to add uninitialised block to journal (inplace block=%lld)\n",
+                      (unsigned long long)bd->bd_bh->b_blocknr);
+               BUG();
+       }
+       if (unlikely(state == SFS_FROZEN)) {
+               printk(KERN_INFO "GFS2:adding buf while frozen\n");
+               gfs2_assert_withdraw(sdp, 0);
+       }
+       gfs2_pin(sdp, bd->bd_bh);
+       mh->__pad0 = cpu_to_be64(0);
+       mh->mh_jid = cpu_to_be32(sdp->sd_jdesc->jd_jid);
+       list_add(&bd->bd_list, &tr->tr_buf);
+       tr->tr_num_buf_new++;
+out_unlock:
        gfs2_log_unlock(sdp);
+out:
        unlock_buffer(bh);
 }
 
@@ -256,7 +261,7 @@ void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd)
 
        BUG_ON(!list_empty(&bd->bd_list));
        gfs2_add_revoke(sdp, bd);
-       tr->tr_touched = 1;
+       set_bit(TR_TOUCHED, &tr->tr_flags);
        tr->tr_num_revoke++;
 }
 
index d8a5d0a08f0758c5c3e6e9e4a18a772b706e2646..a1a359bfcc9cd4ff84254e464788ab3031dfe90f 100644 (file)
@@ -276,11 +276,11 @@ loop:
        goto loop;
 
 end_loop:
-       write_unlock(&journal->j_state_lock);
        del_timer_sync(&journal->j_commit_timer);
        journal->j_task = NULL;
        wake_up(&journal->j_wait_done_commit);
        jbd_debug(1, "Journal thread exiting.\n");
+       write_unlock(&journal->j_state_lock);
        return 0;
 }
 
index e1652665bd93d0cf30dece02b5a1b7692fdec811..5e659ee08d6ae84046b9b8d59f41641e9ef28b22 100644 (file)
@@ -1863,7 +1863,9 @@ static void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh)
 
        __blist_del_buffer(list, jh);
        jh->b_jlist = BJ_None;
-       if (test_clear_buffer_jbddirty(bh))
+       if (transaction && is_journal_aborted(transaction->t_journal))
+               clear_buffer_jbddirty(bh);
+       else if (test_clear_buffer_jbddirty(bh))
                mark_buffer_dirty(bh);  /* Expose it to the VM */
 }
 
index 47febcf9918502a2b55b99a571c50b6b1c824cc3..20b1c17320d5283c56ca91e5262c6ccd69129a74 100644 (file)
@@ -104,6 +104,7 @@ config NFSD_SCSILAYOUT
        depends on NFSD_V4 && BLOCK
        select NFSD_PNFS
        select EXPORTFS_BLOCK_OPS
+       select BLK_SCSI_REQUEST
        help
          This option enables support for the exporting pNFS SCSI layouts
          in the kernel's NFS server. The pNFS SCSI layout enables NFS
index 0780ff8645391e83622708159550973290404960..a06115e3161244f37f549b3d83629a620d0a2019 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/nfsd/debug.h>
 #include <scsi/scsi_proto.h>
 #include <scsi/scsi_common.h>
+#include <scsi/scsi_request.h>
 
 #include "blocklayoutxdr.h"
 #include "pnfs.h"
@@ -213,6 +214,7 @@ static int nfsd4_scsi_identify_device(struct block_device *bdev,
 {
        struct request_queue *q = bdev->bd_disk->queue;
        struct request *rq;
+       struct scsi_request *req;
        size_t bufflen = 252, len, id_len;
        u8 *buf, *d, type, assoc;
        int error;
@@ -221,23 +223,24 @@ static int nfsd4_scsi_identify_device(struct block_device *bdev,
        if (!buf)
                return -ENOMEM;
 
-       rq = blk_get_request(q, READ, GFP_KERNEL);
+       rq = blk_get_request(q, REQ_OP_SCSI_IN, GFP_KERNEL);
        if (IS_ERR(rq)) {
                error = -ENOMEM;
                goto out_free_buf;
        }
-       blk_rq_set_block_pc(rq);
+       req = scsi_req(rq);
+       scsi_req_init(rq);
 
        error = blk_rq_map_kern(q, rq, buf, bufflen, GFP_KERNEL);
        if (error)
                goto out_put_request;
 
-       rq->cmd[0] = INQUIRY;
-       rq->cmd[1] = 1;
-       rq->cmd[2] = 0x83;
-       rq->cmd[3] = bufflen >> 8;
-       rq->cmd[4] = bufflen & 0xff;
-       rq->cmd_len = COMMAND_SIZE(INQUIRY);
+       req->cmd[0] = INQUIRY;
+       req->cmd[1] = 1;
+       req->cmd[2] = 0x83;
+       req->cmd[3] = bufflen >> 8;
+       req->cmd[4] = bufflen & 0xff;
+       req->cmd_len = COMMAND_SIZE(INQUIRY);
 
        error = blk_execute_rq(rq->q, NULL, rq, 1);
        if (error) {
index 12eeae62a2b1f7042dcc3054a22920d9b151a036..e1872f36147f590765cf1d7548cce2e0d5243752 100644 (file)
@@ -1068,7 +1068,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_time_gran = 1;
        sb->s_max_links = NILFS_LINK_MAX;
 
-       sb->s_bdi = &bdev_get_queue(sb->s_bdev)->backing_dev_info;
+       sb->s_bdi = bdev_get_queue(sb->s_bdev)->backing_dev_info;
 
        err = load_nilfs(nilfs, sb);
        if (err)
index bbc175d4213d5776e65ee9a438cf4e90f8c0f6c2..a4c46221755ea6e2ed743ac1d060a6ab40b45070 100644 (file)
@@ -31,7 +31,6 @@ static bool should_merge(struct fsnotify_event *old_fsn,
 static int fanotify_merge(struct list_head *list, struct fsnotify_event *event)
 {
        struct fsnotify_event *test_event;
-       bool do_merge = false;
 
        pr_debug("%s: list=%p event=%p\n", __func__, list, event);
 
@@ -47,16 +46,12 @@ static int fanotify_merge(struct list_head *list, struct fsnotify_event *event)
 
        list_for_each_entry_reverse(test_event, list, list) {
                if (should_merge(test_event, event)) {
-                       do_merge = true;
-                       break;
+                       test_event->mask |= event->mask;
+                       return 1;
                }
        }
 
-       if (!do_merge)
-               return 0;
-
-       test_event->mask |= event->mask;
-       return 1;
+       return 0;
 }
 
 #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
index b1f7d30e96c27aa5d3e2a9abe0052e123087a448..3d773eb9e14476fb4035773e6666f84f813f8369 100644 (file)
@@ -2488,6 +2488,12 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
        length = -ESRCH;
        if (!task)
                goto out_no_task;
+
+       /* A task may only write its own attributes. */
+       length = -EACCES;
+       if (current != task)
+               goto out;
+
        if (count > PAGE_SIZE)
                count = PAGE_SIZE;
 
@@ -2503,14 +2509,13 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
        }
 
        /* Guard against adverse ptrace interaction */
-       length = mutex_lock_interruptible(&task->signal->cred_guard_mutex);
+       length = mutex_lock_interruptible(&current->signal->cred_guard_mutex);
        if (length < 0)
                goto out_free;
 
-       length = security_setprocattr(task,
-                                     (char*)file->f_path.dentry->d_name.name,
+       length = security_setprocattr(file->f_path.dentry->d_name.name,
                                      page, count);
-       mutex_unlock(&task->signal->cred_guard_mutex);
+       mutex_unlock(&current->signal->cred_guard_mutex);
 out_free:
        kfree(page);
 out:
index 1709ed029a2cae70c3d4a6cccccca760a0ad003f..ea662b0e5e789f63b018ba6d59f5d946ba0c74ef 100644 (file)
@@ -1047,7 +1047,7 @@ static int set_bdev_super(struct super_block *s, void *data)
         * We set the bdi here to the queue backing, file systems can
         * overwrite this in ->fill_super()
         */
-       s->s_bdi = &bdev_get_queue(s->s_bdev)->backing_dev_info;
+       s->s_bdi = bdev_get_queue(s->s_bdev)->backing_dev_info;
        return 0;
 }
 
index 3402720f2b28280c1012c3d0a02ae1c27569e496..382ed428cfd2167cc8c57c934e06ab29a92ceb6c 100644 (file)
@@ -26,15 +26,6 @@ static unsigned int ubifs_crypt_max_namelen(struct inode *inode)
                return UBIFS_MAX_NLEN;
 }
 
-static int ubifs_key_prefix(struct inode *inode, u8 **key)
-{
-       static char prefix[] = "ubifs:";
-
-       *key = prefix;
-
-       return sizeof(prefix) - 1;
-}
-
 int ubifs_encrypt(const struct inode *inode, struct ubifs_data_node *dn,
                  unsigned int in_len, unsigned int *out_len, int block)
 {
@@ -86,12 +77,12 @@ int ubifs_decrypt(const struct inode *inode, struct ubifs_data_node *dn,
        return 0;
 }
 
-struct fscrypt_operations ubifs_crypt_operations = {
+const struct fscrypt_operations ubifs_crypt_operations = {
        .flags                  = FS_CFLG_OWN_PAGES,
+       .key_prefix             = "ubifs:",
        .get_context            = ubifs_crypt_get_context,
        .set_context            = ubifs_crypt_set_context,
        .is_encrypted           = __ubifs_crypt_is_encrypted,
        .empty_dir              = ubifs_crypt_empty_dir,
        .max_namelen            = ubifs_crypt_max_namelen,
-       .key_prefix             = ubifs_key_prefix,
 };
index e08aa04fc8351ca03db6479f94a33c0fe1ff845b..b73811bd7676d6221243f21d52b06d9efed7cf4a 100644 (file)
@@ -2000,7 +2000,7 @@ static struct ubifs_info *alloc_ubifs_info(struct ubi_volume_desc *ubi)
 }
 
 #ifndef CONFIG_UBIFS_FS_ENCRYPTION
-struct fscrypt_operations ubifs_crypt_operations = {
+const struct fscrypt_operations ubifs_crypt_operations = {
        .is_encrypted           = __ubifs_crypt_is_encrypted,
 };
 #endif
index ca72382ce6cc9e58e955373649bec3b994f9d19f..f0c86f076535a6ab7a8a791ea7be231be3fe44b9 100644 (file)
 #include <linux/backing-dev.h>
 #include <linux/security.h>
 #include <linux/xattr.h>
-#include <linux/fscrypto.h>
+#ifdef CONFIG_UBIFS_FS_ENCRYPTION
+#include <linux/fscrypt_supp.h>
+#else
+#include <linux/fscrypt_notsupp.h>
+#endif
 #include <linux/random.h>
 #include "ubifs-media.h"
 
@@ -1797,28 +1801,6 @@ int ubifs_decompress(const struct ubifs_info *c, const void *buf, int len,
 #include "key.h"
 
 #ifndef CONFIG_UBIFS_FS_ENCRYPTION
-#define fscrypt_set_d_op(i)
-#define fscrypt_get_ctx                 fscrypt_notsupp_get_ctx
-#define fscrypt_release_ctx             fscrypt_notsupp_release_ctx
-#define fscrypt_encrypt_page            fscrypt_notsupp_encrypt_page
-#define fscrypt_decrypt_page            fscrypt_notsupp_decrypt_page
-#define fscrypt_decrypt_bio_pages       fscrypt_notsupp_decrypt_bio_pages
-#define fscrypt_pullback_bio_page       fscrypt_notsupp_pullback_bio_page
-#define fscrypt_restore_control_page    fscrypt_notsupp_restore_control_page
-#define fscrypt_zeroout_range           fscrypt_notsupp_zeroout_range
-#define fscrypt_ioctl_set_policy       fscrypt_notsupp_ioctl_set_policy
-#define fscrypt_ioctl_get_policy       fscrypt_notsupp_ioctl_get_policy
-#define fscrypt_has_permitted_context   fscrypt_notsupp_has_permitted_context
-#define fscrypt_inherit_context         fscrypt_notsupp_inherit_context
-#define fscrypt_get_encryption_info     fscrypt_notsupp_get_encryption_info
-#define fscrypt_put_encryption_info     fscrypt_notsupp_put_encryption_info
-#define fscrypt_setup_filename          fscrypt_notsupp_setup_filename
-#define fscrypt_free_filename           fscrypt_notsupp_free_filename
-#define fscrypt_fname_encrypted_size    fscrypt_notsupp_fname_encrypted_size
-#define fscrypt_fname_alloc_buffer      fscrypt_notsupp_fname_alloc_buffer
-#define fscrypt_fname_free_buffer       fscrypt_notsupp_fname_free_buffer
-#define fscrypt_fname_disk_to_usr       fscrypt_notsupp_fname_disk_to_usr
-#define fscrypt_fname_usr_to_disk       fscrypt_notsupp_fname_usr_to_disk
 static inline int ubifs_encrypt(const struct inode *inode,
                                struct ubifs_data_node *dn,
                                unsigned int in_len, unsigned int *out_len,
@@ -1842,7 +1824,7 @@ int ubifs_decrypt(const struct inode *inode, struct ubifs_data_node *dn,
                  unsigned int *out_len, int block);
 #endif
 
-extern struct fscrypt_operations ubifs_crypt_operations;
+extern const struct fscrypt_operations ubifs_crypt_operations;
 
 static inline bool __ubifs_crypt_is_encrypted(struct inode *inode)
 {
index 4792b771aa8073231ee46116af2bfffe009b92a3..9f24bd1a9f44ef4dde495b7dda82e96a0562e1c2 100644 (file)
@@ -41,7 +41,7 @@
 struct charspec {
        uint8_t         charSetType;
        uint8_t         charSetInfo[63];
-} __attribute__ ((packed));
+} __packed;
 
 /* Character Set Type (ECMA 167r3 1/7.2.1.1) */
 #define CHARSPEC_TYPE_CS0              0x00    /* (1/7.2.2) */
@@ -68,7 +68,7 @@ struct timestamp {
        uint8_t         centiseconds;
        uint8_t         hundredsOfMicroseconds;
        uint8_t         microseconds;
-} __attribute__ ((packed));
+} __packed;
 
 /* Type and Time Zone (ECMA 167r3 1/7.3.1) */
 #define TIMESTAMP_TYPE_MASK            0xF000
@@ -82,7 +82,7 @@ struct regid {
        uint8_t         flags;
        uint8_t         ident[23];
        uint8_t         identSuffix[8];
-} __attribute__ ((packed));
+} __packed;
 
 /* Flags (ECMA 167r3 1/7.4.1) */
 #define ENTITYID_FLAGS_DIRTY           0x00
@@ -95,7 +95,7 @@ struct volStructDesc {
        uint8_t         stdIdent[VSD_STD_ID_LEN];
        uint8_t         structVersion;
        uint8_t         structData[2041];
-} __attribute__ ((packed));
+} __packed;
 
 /* Standard Identifier (EMCA 167r2 2/9.1.2) */
 #define VSD_STD_ID_NSR02               "NSR02" /* (3/9.1) */
@@ -114,7 +114,7 @@ struct beginningExtendedAreaDesc {
        uint8_t         stdIdent[VSD_STD_ID_LEN];
        uint8_t         structVersion;
        uint8_t         structData[2041];
-} __attribute__ ((packed));
+} __packed;
 
 /* Terminating Extended Area Descriptor (ECMA 167r3 2/9.3) */
 struct terminatingExtendedAreaDesc {
@@ -122,7 +122,7 @@ struct terminatingExtendedAreaDesc {
        uint8_t         stdIdent[VSD_STD_ID_LEN];
        uint8_t         structVersion;
        uint8_t         structData[2041];
-} __attribute__ ((packed));
+} __packed;
 
 /* Boot Descriptor (ECMA 167r3 2/9.4) */
 struct bootDesc {
@@ -140,7 +140,7 @@ struct bootDesc {
        __le16                  flags;
        uint8_t                 reserved2[32];
        uint8_t                 bootUse[1906];
-} __attribute__ ((packed));
+} __packed;
 
 /* Flags (ECMA 167r3 2/9.4.12) */
 #define BOOT_FLAGS_ERASE               0x01
@@ -149,7 +149,7 @@ struct bootDesc {
 struct extent_ad {
        __le32          extLength;
        __le32          extLocation;
-} __attribute__ ((packed));
+} __packed;
 
 struct kernel_extent_ad {
        uint32_t        extLength;
@@ -166,7 +166,7 @@ struct tag {
        __le16          descCRC;
        __le16          descCRCLength;
        __le32          tagLocation;
-} __attribute__ ((packed));
+} __packed;
 
 /* Tag Identifier (ECMA 167r3 3/7.2.1) */
 #define TAG_IDENT_PVD                  0x0001
@@ -186,7 +186,7 @@ struct NSRDesc {
        uint8_t         structVersion;
        uint8_t         reserved;
        uint8_t         structData[2040];
-} __attribute__ ((packed));
+} __packed;
 
 /* Primary Volume Descriptor (ECMA 167r3 3/10.1) */
 struct primaryVolDesc {
@@ -212,7 +212,7 @@ struct primaryVolDesc {
        __le32                  predecessorVolDescSeqLocation;
        __le16                  flags;
        uint8_t                 reserved[22];
-} __attribute__ ((packed));
+} __packed;
 
 /* Flags (ECMA 167r3 3/10.1.21) */
 #define PVD_FLAGS_VSID_COMMON          0x0001
@@ -223,7 +223,7 @@ struct anchorVolDescPtr {
        struct extent_ad        mainVolDescSeqExt;
        struct extent_ad        reserveVolDescSeqExt;
        uint8_t                 reserved[480];
-} __attribute__ ((packed));
+} __packed;
 
 /* Volume Descriptor Pointer (ECMA 167r3 3/10.3) */
 struct volDescPtr {
@@ -231,7 +231,7 @@ struct volDescPtr {
        __le32                  volDescSeqNum;
        struct extent_ad        nextVolDescSeqExt;
        uint8_t                 reserved[484];
-} __attribute__ ((packed));
+} __packed;
 
 /* Implementation Use Volume Descriptor (ECMA 167r3 3/10.4) */
 struct impUseVolDesc {
@@ -239,7 +239,7 @@ struct impUseVolDesc {
        __le32          volDescSeqNum;
        struct regid    impIdent;
        uint8_t         impUse[460];
-} __attribute__ ((packed));
+} __packed;
 
 /* Partition Descriptor (ECMA 167r3 3/10.5) */
 struct partitionDesc {
@@ -255,7 +255,7 @@ struct partitionDesc {
        struct regid impIdent;
        uint8_t impUse[128];
        uint8_t reserved[156];
-} __attribute__ ((packed));
+} __packed;
 
 /* Partition Flags (ECMA 167r3 3/10.5.3) */
 #define PD_PARTITION_FLAGS_ALLOC       0x0001
@@ -291,14 +291,14 @@ struct logicalVolDesc {
        uint8_t                 impUse[128];
        struct extent_ad        integritySeqExt;
        uint8_t                 partitionMaps[0];
-} __attribute__ ((packed));
+} __packed;
 
 /* Generic Partition Map (ECMA 167r3 3/10.7.1) */
 struct genericPartitionMap {
        uint8_t         partitionMapType;
        uint8_t         partitionMapLength;
        uint8_t         partitionMapping[0];
-} __attribute__ ((packed));
+} __packed;
 
 /* Partition Map Type (ECMA 167r3 3/10.7.1.1) */
 #define GP_PARTITION_MAP_TYPE_UNDEF    0x00
@@ -311,14 +311,14 @@ struct genericPartitionMap1 {
        uint8_t         partitionMapLength;
        __le16          volSeqNum;
        __le16          partitionNum;
-} __attribute__ ((packed));
+} __packed;
 
 /* Type 2 Partition Map (ECMA 167r3 3/10.7.3) */
 struct genericPartitionMap2 {
        uint8_t         partitionMapType;
        uint8_t         partitionMapLength;
        uint8_t         partitionIdent[62];
-} __attribute__ ((packed));
+} __packed;
 
 /* Unallocated Space Descriptor (ECMA 167r3 3/10.8) */
 struct unallocSpaceDesc {
@@ -326,13 +326,13 @@ struct unallocSpaceDesc {
        __le32                  volDescSeqNum;
        __le32                  numAllocDescs;
        struct extent_ad        allocDescs[0];
-} __attribute__ ((packed));
+} __packed;
 
 /* Terminating Descriptor (ECMA 167r3 3/10.9) */
 struct terminatingDesc {
        struct tag      descTag;
        uint8_t         reserved[496];
-} __attribute__ ((packed));
+} __packed;
 
 /* Logical Volume Integrity Descriptor (ECMA 167r3 3/10.10) */
 struct logicalVolIntegrityDesc {
@@ -346,7 +346,7 @@ struct logicalVolIntegrityDesc {
        __le32                  freeSpaceTable[0];
        __le32                  sizeTable[0];
        uint8_t                 impUse[0];
-} __attribute__ ((packed));
+} __packed;
 
 /* Integrity Type (ECMA 167r3 3/10.10.3) */
 #define LVID_INTEGRITY_TYPE_OPEN       0x00000000
@@ -356,7 +356,7 @@ struct logicalVolIntegrityDesc {
 struct lb_addr {
        __le32          logicalBlockNum;
        __le16          partitionReferenceNum;
-} __attribute__ ((packed));
+} __packed;
 
 /* ... and its in-core analog */
 struct kernel_lb_addr {
@@ -368,14 +368,14 @@ struct kernel_lb_addr {
 struct short_ad {
         __le32         extLength;
         __le32         extPosition;
-} __attribute__ ((packed));
+} __packed;
 
 /* Long Allocation Descriptor (ECMA 167r3 4/14.14.2) */
 struct long_ad {
        __le32          extLength;
        struct lb_addr  extLocation;
        uint8_t         impUse[6];
-} __attribute__ ((packed));
+} __packed;
 
 struct kernel_long_ad {
        uint32_t                extLength;
@@ -389,7 +389,7 @@ struct ext_ad {
        __le32          recordedLength;
        __le32          informationLength;
        struct lb_addr  extLocation;
-} __attribute__ ((packed));
+} __packed;
 
 struct kernel_ext_ad {
        uint32_t                extLength;
@@ -434,7 +434,7 @@ struct fileSetDesc {
        struct long_ad          nextExt;
        struct long_ad          streamDirectoryICB;
        uint8_t                 reserved[32];
-} __attribute__ ((packed));
+} __packed;
 
 /* Partition Header Descriptor (ECMA 167r3 4/14.3) */
 struct partitionHeaderDesc {
@@ -444,7 +444,7 @@ struct partitionHeaderDesc {
        struct short_ad freedSpaceTable;
        struct short_ad freedSpaceBitmap;
        uint8_t         reserved[88];
-} __attribute__ ((packed));
+} __packed;
 
 /* File Identifier Descriptor (ECMA 167r3 4/14.4) */
 struct fileIdentDesc {
@@ -457,7 +457,7 @@ struct fileIdentDesc {
        uint8_t         impUse[0];
        uint8_t         fileIdent[0];
        uint8_t         padding[0];
-} __attribute__ ((packed));
+} __packed;
 
 /* File Characteristics (ECMA 167r3 4/14.4.3) */
 #define FID_FILE_CHAR_HIDDEN           0x01
@@ -471,7 +471,7 @@ struct allocExtDesc {
        struct tag      descTag;
        __le32          previousAllocExtLocation;
        __le32          lengthAllocDescs;
-} __attribute__ ((packed));
+} __packed;
 
 /* ICB Tag (ECMA 167r3 4/14.6) */
 struct icbtag {
@@ -483,7 +483,7 @@ struct icbtag {
        uint8_t         fileType;
        struct lb_addr  parentICBLocation;
        __le16          flags;
-} __attribute__ ((packed));
+} __packed;
 
 /* Strategy Type (ECMA 167r3 4/14.6.2) */
 #define ICBTAG_STRATEGY_TYPE_UNDEF     0x0000
@@ -531,13 +531,13 @@ struct indirectEntry {
        struct tag      descTag;
        struct icbtag   icbTag;
        struct long_ad  indirectICB;
-} __attribute__ ((packed));
+} __packed;
 
 /* Terminal Entry (ECMA 167r3 4/14.8) */
 struct terminalEntry {
        struct tag      descTag;
        struct icbtag   icbTag;
-} __attribute__ ((packed));
+} __packed;
 
 /* File Entry (ECMA 167r3 4/14.9) */
 struct fileEntry {
@@ -563,7 +563,7 @@ struct fileEntry {
        __le32                  lengthAllocDescs;
        uint8_t                 extendedAttr[0];
        uint8_t                 allocDescs[0];
-} __attribute__ ((packed));
+} __packed;
 
 /* Permissions (ECMA 167r3 4/14.9.5) */
 #define FE_PERM_O_EXEC                 0x00000001U
@@ -607,7 +607,7 @@ struct extendedAttrHeaderDesc {
        struct tag      descTag;
        __le32          impAttrLocation;
        __le32          appAttrLocation;
-} __attribute__ ((packed));
+} __packed;
 
 /* Generic Format (ECMA 167r3 4/14.10.2) */
 struct genericFormat {
@@ -616,7 +616,7 @@ struct genericFormat {
        uint8_t         reserved[3];
        __le32          attrLength;
        uint8_t         attrData[0];
-} __attribute__ ((packed));
+} __packed;
 
 /* Character Set Information (ECMA 167r3 4/14.10.3) */
 struct charSetInfo {
@@ -627,7 +627,7 @@ struct charSetInfo {
        __le32          escapeSeqLength;
        uint8_t         charSetType;
        uint8_t         escapeSeq[0];
-} __attribute__ ((packed));
+} __packed;
 
 /* Alternate Permissions (ECMA 167r3 4/14.10.4) */
 struct altPerms {
@@ -638,7 +638,7 @@ struct altPerms {
        __le16          ownerIdent;
        __le16          groupIdent;
        __le16          permission;
-} __attribute__ ((packed));
+} __packed;
 
 /* File Times Extended Attribute (ECMA 167r3 4/14.10.5) */
 struct fileTimesExtAttr {
@@ -649,7 +649,7 @@ struct fileTimesExtAttr {
        __le32          dataLength;
        __le32          fileTimeExistence;
        uint8_t         fileTimes;
-} __attribute__ ((packed));
+} __packed;
 
 /* FileTimeExistence (ECMA 167r3 4/14.10.5.6) */
 #define FTE_CREATION                   0x00000001
@@ -666,7 +666,7 @@ struct infoTimesExtAttr {
        __le32          dataLength;
        __le32          infoTimeExistence;
        uint8_t         infoTimes[0];
-} __attribute__ ((packed));
+} __packed;
 
 /* Device Specification (ECMA 167r3 4/14.10.7) */
 struct deviceSpec {
@@ -678,7 +678,7 @@ struct deviceSpec {
        __le32          majorDeviceIdent;
        __le32          minorDeviceIdent;
        uint8_t         impUse[0];
-} __attribute__ ((packed));
+} __packed;
 
 /* Implementation Use Extended Attr (ECMA 167r3 4/14.10.8) */
 struct impUseExtAttr {
@@ -689,7 +689,7 @@ struct impUseExtAttr {
        __le32          impUseLength;
        struct regid    impIdent;
        uint8_t         impUse[0];
-} __attribute__ ((packed));
+} __packed;
 
 /* Application Use Extended Attribute (ECMA 167r3 4/14.10.9) */
 struct appUseExtAttr {
@@ -700,7 +700,7 @@ struct appUseExtAttr {
        __le32          appUseLength;
        struct regid    appIdent;
        uint8_t         appUse[0];
-} __attribute__ ((packed));
+} __packed;
 
 #define EXTATTR_CHAR_SET               1
 #define EXTATTR_ALT_PERMS              3
@@ -716,7 +716,7 @@ struct unallocSpaceEntry {
        struct icbtag   icbTag;
        __le32          lengthAllocDescs;
        uint8_t         allocDescs[0];
-} __attribute__ ((packed));
+} __packed;
 
 /* Space Bitmap Descriptor (ECMA 167r3 4/14.12) */
 struct spaceBitmapDesc {
@@ -724,7 +724,7 @@ struct spaceBitmapDesc {
        __le32          numOfBits;
        __le32          numOfBytes;
        uint8_t         bitmap[0];
-} __attribute__ ((packed));
+} __packed;
 
 /* Partition Integrity Entry (ECMA 167r3 4/14.13) */
 struct partitionIntegrityEntry {
@@ -735,7 +735,7 @@ struct partitionIntegrityEntry {
        uint8_t                 reserved[175];
        struct regid            impIdent;
        uint8_t                 impUse[256];
-} __attribute__ ((packed));
+} __packed;
 
 /* Short Allocation Descriptor (ECMA 167r3 4/14.14.1) */
 
@@ -753,7 +753,7 @@ struct partitionIntegrityEntry {
 struct logicalVolHeaderDesc {
        __le64          uniqueID;
        uint8_t         reserved[24];
-} __attribute__ ((packed));
+} __packed;
 
 /* Path Component (ECMA 167r3 4/14.16.1) */
 struct pathComponent {
@@ -761,7 +761,7 @@ struct pathComponent {
        uint8_t         lengthComponentIdent;
        __le16          componentFileVersionNum;
        dstring         componentIdent[0];
-} __attribute__ ((packed));
+} __packed;
 
 /* File Entry (ECMA 167r3 4/14.17) */
 struct extendedFileEntry {
@@ -791,6 +791,6 @@ struct extendedFileEntry {
        __le32                  lengthAllocDescs;
        uint8_t                 extendedAttr[0];
        uint8_t                 allocDescs[0];
-} __attribute__ ((packed));
+} __packed;
 
 #endif /* _ECMA_167_H */
index dbcb3a4a0cb99ca261774767230bd2af77233640..e04cc0cdca9d736683c4fc5ac647e7fbdcc872c4 100644 (file)
@@ -176,54 +176,46 @@ long udf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
        struct inode *inode = file_inode(filp);
        long old_block, new_block;
-       int result = -EINVAL;
+       int result;
 
        if (inode_permission(inode, MAY_READ) != 0) {
                udf_debug("no permission to access inode %lu\n", inode->i_ino);
-               result = -EPERM;
-               goto out;
+               return -EPERM;
        }
 
-       if (!arg) {
+       if (!arg && ((cmd == UDF_GETVOLIDENT) || (cmd == UDF_GETEASIZE) ||
+                    (cmd == UDF_RELOCATE_BLOCKS) || (cmd == UDF_GETEABLOCK))) {
                udf_debug("invalid argument to udf_ioctl\n");
-               result = -EINVAL;
-               goto out;
+               return -EINVAL;
        }
 
        switch (cmd) {
        case UDF_GETVOLIDENT:
                if (copy_to_user((char __user *)arg,
                                 UDF_SB(inode->i_sb)->s_volume_ident, 32))
-                       result = -EFAULT;
-               else
-                       result = 0;
-               goto out;
+                       return -EFAULT;
+               return 0;
        case UDF_RELOCATE_BLOCKS:
-               if (!capable(CAP_SYS_ADMIN)) {
-                       result = -EPERM;
-                       goto out;
-               }
-               if (get_user(old_block, (long __user *)arg)) {
-                       result = -EFAULT;
-                       goto out;
-               }
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               if (get_user(old_block, (long __user *)arg))
+                       return -EFAULT;
                result = udf_relocate_blocks(inode->i_sb,
                                                old_block, &new_block);
                if (result == 0)
                        result = put_user(new_block, (long __user *)arg);
-               goto out;
+               return result;
        case UDF_GETEASIZE:
-               result = put_user(UDF_I(inode)->i_lenEAttr, (int __user *)arg);
-               goto out;
+               return put_user(UDF_I(inode)->i_lenEAttr, (int __user *)arg);
        case UDF_GETEABLOCK:
-               result = copy_to_user((char __user *)arg,
-                                     UDF_I(inode)->i_ext.i_data,
-                                     UDF_I(inode)->i_lenEAttr) ? -EFAULT : 0;
-               goto out;
+               return copy_to_user((char __user *)arg,
+                                   UDF_I(inode)->i_ext.i_data,
+                                   UDF_I(inode)->i_lenEAttr) ? -EFAULT : 0;
+       default:
+               return -ENOIOCTLCMD;
        }
 
-out:
-       return result;
+       return 0;
 }
 
 static int udf_release_file(struct inode *inode, struct file *filp)
index 0f3db71753aa262f9281257263f845c857aba0e9..8ec6b3df0bc7f7dc47c3c690259df74023bb6841 100644 (file)
 #include "udf_i.h"
 #include "udf_sb.h"
 
-MODULE_AUTHOR("Ben Fennema");
-MODULE_DESCRIPTION("Universal Disk Format Filesystem");
-MODULE_LICENSE("GPL");
-
 #define EXTENT_MERGE_SIZE 5
 
 static umode_t udf_convert_permissions(struct fileEntry *);
@@ -57,14 +53,12 @@ static sector_t inode_getblk(struct inode *, sector_t, int *, int *);
 static int8_t udf_insert_aext(struct inode *, struct extent_position,
                              struct kernel_lb_addr, uint32_t);
 static void udf_split_extents(struct inode *, int *, int, int,
-                             struct kernel_long_ad[EXTENT_MERGE_SIZE], int *);
+                             struct kernel_long_ad *, int *);
 static void udf_prealloc_extents(struct inode *, int, int,
-                                struct kernel_long_ad[EXTENT_MERGE_SIZE], int *);
-static void udf_merge_extents(struct inode *,
-                             struct kernel_long_ad[EXTENT_MERGE_SIZE], int *);
-static void udf_update_extents(struct inode *,
-                              struct kernel_long_ad[EXTENT_MERGE_SIZE], int, int,
-                              struct extent_position *);
+                                struct kernel_long_ad *, int *);
+static void udf_merge_extents(struct inode *, struct kernel_long_ad *, int *);
+static void udf_update_extents(struct inode *, struct kernel_long_ad *, int,
+                              int, struct extent_position *);
 static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int);
 
 static void __udf_clear_extent_cache(struct inode *inode)
@@ -111,7 +105,7 @@ static int udf_read_extent_cache(struct inode *inode, loff_t bcount,
 
 /* Add extent to extent cache */
 static void udf_update_extent_cache(struct inode *inode, loff_t estart,
-                                   struct extent_position *pos, int next_epos)
+                                   struct extent_position *pos)
 {
        struct udf_inode_info *iinfo = UDF_I(inode);
 
@@ -120,19 +114,16 @@ static void udf_update_extent_cache(struct inode *inode, loff_t estart,
        __udf_clear_extent_cache(inode);
        if (pos->bh)
                get_bh(pos->bh);
-       memcpy(&iinfo->cached_extent.epos, pos,
-              sizeof(struct extent_position));
+       memcpy(&iinfo->cached_extent.epos, pos, sizeof(struct extent_position));
        iinfo->cached_extent.lstart = estart;
-       if (next_epos)
-               switch (iinfo->i_alloc_type) {
-               case ICBTAG_FLAG_AD_SHORT:
-                       iinfo->cached_extent.epos.offset -=
-                       sizeof(struct short_ad);
-                       break;
-               case ICBTAG_FLAG_AD_LONG:
-                       iinfo->cached_extent.epos.offset -=
-                       sizeof(struct long_ad);
-               }
+       switch (iinfo->i_alloc_type) {
+       case ICBTAG_FLAG_AD_SHORT:
+               iinfo->cached_extent.epos.offset -= sizeof(struct short_ad);
+               break;
+       case ICBTAG_FLAG_AD_LONG:
+               iinfo->cached_extent.epos.offset -= sizeof(struct long_ad);
+               break;
+       }
        spin_unlock(&iinfo->i_extent_cache_lock);
 }
 
@@ -747,11 +738,8 @@ static sector_t inode_getblk(struct inode *inode, sector_t block,
                                 ~(inode->i_sb->s_blocksize - 1));
                        udf_write_aext(inode, &cur_epos, &eloc, elen, 1);
                }
-               brelse(prev_epos.bh);
-               brelse(cur_epos.bh);
-               brelse(next_epos.bh);
                newblock = udf_get_lb_pblock(inode->i_sb, &eloc, offset);
-               return newblock;
+               goto out_free;
        }
 
        /* Are we beyond EOF? */
@@ -774,11 +762,9 @@ static sector_t inode_getblk(struct inode *inode, sector_t block,
                /* Create extents for the hole between EOF and offset */
                ret = udf_do_extend_file(inode, &prev_epos, laarr, offset);
                if (ret < 0) {
-                       brelse(prev_epos.bh);
-                       brelse(cur_epos.bh);
-                       brelse(next_epos.bh);
                        *err = ret;
-                       return 0;
+                       newblock = 0;
+                       goto out_free;
                }
                c = 0;
                offset = 0;
@@ -841,11 +827,9 @@ static sector_t inode_getblk(struct inode *inode, sector_t block,
                                iinfo->i_location.partitionReferenceNum,
                                goal, err);
                if (!newblocknum) {
-                       brelse(prev_epos.bh);
-                       brelse(cur_epos.bh);
-                       brelse(next_epos.bh);
                        *err = -ENOSPC;
-                       return 0;
+                       newblock = 0;
+                       goto out_free;
                }
                if (isBeyondEOF)
                        iinfo->i_lenExtents += inode->i_sb->s_blocksize;
@@ -857,14 +841,12 @@ static sector_t inode_getblk(struct inode *inode, sector_t block,
         * block */
        udf_split_extents(inode, &c, offset, newblocknum, laarr, &endnum);
 
-#ifdef UDF_PREALLOCATE
        /* We preallocate blocks only for regular files. It also makes sense
         * for directories but there's a problem when to drop the
         * preallocation. We might use some delayed work for that but I feel
         * it's overengineering for a filesystem like UDF. */
        if (S_ISREG(inode->i_mode))
                udf_prealloc_extents(inode, c, lastblock, laarr, &endnum);
-#endif
 
        /* merge any continuous blocks in laarr */
        udf_merge_extents(inode, laarr, &endnum);
@@ -874,15 +856,11 @@ static sector_t inode_getblk(struct inode *inode, sector_t block,
         * the new number of extents is less than the old number */
        udf_update_extents(inode, laarr, startnum, endnum, &prev_epos);
 
-       brelse(prev_epos.bh);
-       brelse(cur_epos.bh);
-       brelse(next_epos.bh);
-
        newblock = udf_get_pblock(inode->i_sb, newblocknum,
                                iinfo->i_location.partitionReferenceNum, 0);
        if (!newblock) {
                *err = -EIO;
-               return 0;
+               goto out_free;
        }
        *new = 1;
        iinfo->i_next_alloc_block = block;
@@ -893,13 +871,15 @@ static sector_t inode_getblk(struct inode *inode, sector_t block,
                udf_sync_inode(inode);
        else
                mark_inode_dirty(inode);
-
+out_free:
+       brelse(prev_epos.bh);
+       brelse(cur_epos.bh);
+       brelse(next_epos.bh);
        return newblock;
 }
 
 static void udf_split_extents(struct inode *inode, int *c, int offset,
-                             int newblocknum,
-                             struct kernel_long_ad laarr[EXTENT_MERGE_SIZE],
+                             int newblocknum, struct kernel_long_ad *laarr,
                              int *endnum)
 {
        unsigned long blocksize = inode->i_sb->s_blocksize;
@@ -963,7 +943,7 @@ static void udf_split_extents(struct inode *inode, int *c, int offset,
 }
 
 static void udf_prealloc_extents(struct inode *inode, int c, int lastblock,
-                                struct kernel_long_ad laarr[EXTENT_MERGE_SIZE],
+                                struct kernel_long_ad *laarr,
                                 int *endnum)
 {
        int start, length = 0, currlength = 0, i;
@@ -1058,8 +1038,7 @@ static void udf_prealloc_extents(struct inode *inode, int c, int lastblock,
        }
 }
 
-static void udf_merge_extents(struct inode *inode,
-                             struct kernel_long_ad laarr[EXTENT_MERGE_SIZE],
+static void udf_merge_extents(struct inode *inode, struct kernel_long_ad *laarr,
                              int *endnum)
 {
        int i;
@@ -1158,8 +1137,7 @@ static void udf_merge_extents(struct inode *inode,
        }
 }
 
-static void udf_update_extents(struct inode *inode,
-                              struct kernel_long_ad laarr[EXTENT_MERGE_SIZE],
+static void udf_update_extents(struct inode *inode, struct kernel_long_ad *laarr,
                               int startnum, int endnum,
                               struct extent_position *epos)
 {
@@ -1299,6 +1277,12 @@ static int udf_read_inode(struct inode *inode, bool hidden_inode)
        int ret = -EIO;
 
 reread:
+       if (iloc->partitionReferenceNum >= sbi->s_partitions) {
+               udf_debug("partition reference: %d > logical volume partitions: %d\n",
+                         iloc->partitionReferenceNum, sbi->s_partitions);
+               return -EIO;
+       }
+
        if (iloc->logicalBlockNum >=
            sbi->s_partmaps[iloc->partitionReferenceNum].s_partition_len) {
                udf_debug("block=%d, partition=%d out of range\n",
@@ -1549,7 +1533,7 @@ reread:
                break;
        case ICBTAG_FILE_TYPE_SYMLINK:
                inode->i_data.a_ops = &udf_symlink_aops;
-               inode->i_op = &page_symlink_inode_operations;
+               inode->i_op = &udf_symlink_inode_operations;
                inode_nohighmem(inode);
                inode->i_mode = S_IFLNK | S_IRWXUGO;
                break;
@@ -1627,6 +1611,14 @@ static int udf_sync_inode(struct inode *inode)
        return udf_update_inode(inode, 1);
 }
 
+static void udf_adjust_time(struct udf_inode_info *iinfo, struct timespec time)
+{
+       if (iinfo->i_crtime.tv_sec > time.tv_sec ||
+           (iinfo->i_crtime.tv_sec == time.tv_sec &&
+            iinfo->i_crtime.tv_nsec > time.tv_nsec))
+               iinfo->i_crtime = time;
+}
+
 static int udf_update_inode(struct inode *inode, int do_sync)
 {
        struct buffer_head *bh = NULL;
@@ -1753,20 +1745,9 @@ static int udf_update_inode(struct inode *inode, int do_sync)
                efe->objectSize = cpu_to_le64(inode->i_size);
                efe->logicalBlocksRecorded = cpu_to_le64(lb_recorded);
 
-               if (iinfo->i_crtime.tv_sec > inode->i_atime.tv_sec ||
-                   (iinfo->i_crtime.tv_sec == inode->i_atime.tv_sec &&
-                    iinfo->i_crtime.tv_nsec > inode->i_atime.tv_nsec))
-                       iinfo->i_crtime = inode->i_atime;
-
-               if (iinfo->i_crtime.tv_sec > inode->i_mtime.tv_sec ||
-                   (iinfo->i_crtime.tv_sec == inode->i_mtime.tv_sec &&
-                    iinfo->i_crtime.tv_nsec > inode->i_mtime.tv_nsec))
-                       iinfo->i_crtime = inode->i_mtime;
-
-               if (iinfo->i_crtime.tv_sec > inode->i_ctime.tv_sec ||
-                   (iinfo->i_crtime.tv_sec == inode->i_ctime.tv_sec &&
-                    iinfo->i_crtime.tv_nsec > inode->i_ctime.tv_nsec))
-                       iinfo->i_crtime = inode->i_ctime;
+               udf_adjust_time(iinfo, inode->i_atime);
+               udf_adjust_time(iinfo, inode->i_mtime);
+               udf_adjust_time(iinfo, inode->i_ctime);
 
                udf_time_to_disk_stamp(&efe->accessTime, inode->i_atime);
                udf_time_to_disk_stamp(&efe->modificationTime, inode->i_mtime);
@@ -2286,8 +2267,7 @@ int8_t inode_bmap(struct inode *inode, sector_t block,
                  uint32_t *elen, sector_t *offset)
 {
        unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits;
-       loff_t lbcount = 0, bcount =
-           (loff_t) block << blocksize_bits;
+       loff_t lbcount = 0, bcount = (loff_t) block << blocksize_bits;
        int8_t etype;
        struct udf_inode_info *iinfo;
 
@@ -2308,7 +2288,7 @@ int8_t inode_bmap(struct inode *inode, sector_t block,
                lbcount += *elen;
        } while (lbcount <= bcount);
        /* update extent cache */
-       udf_update_extent_cache(inode, lbcount - *elen, pos, 1);
+       udf_update_extent_cache(inode, lbcount - *elen, pos);
        *offset = (bcount + *elen - lbcount) >> blocksize_bits;
 
        return etype;
index 6ad5a453af97a60a9adfd12f38e788e887f8b417..5c7ec121990dac4368ec5cc5109b57d5da4424c1 100644 (file)
@@ -58,7 +58,7 @@ unsigned long udf_get_last_block(struct super_block *sb)
         */
        if (ioctl_by_bdev(bdev, CDROM_LAST_WRITTEN, (unsigned long) &lblock) ||
            lblock == 0)
-               lblock = bdev->bd_inode->i_size >> sb->s_blocksize_bits;
+               lblock = i_size_read(bdev->bd_inode) >> sb->s_blocksize_bits;
 
        if (lblock)
                return lblock - 1;
index 71d1c25f360d170286862382cb4cf0e31cf40508..3949c4bec3a3ff3d13369b8930e1715bd86b196e 100644 (file)
@@ -141,8 +141,6 @@ struct genericFormat *udf_add_extendedattr(struct inode *inode, uint32_t size,
                iinfo->i_lenEAttr += size;
                return (struct genericFormat *)&ea[offset];
        }
-       if (loc & 0x02)
-               ;
 
        return NULL;
 }
index 2d65e280748bb99f2c9e494142c7cf78587148d7..babf48d0e55330ec798460c2a7500878b90eeb06 100644 (file)
@@ -931,7 +931,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
        }
 
        inode->i_data.a_ops = &udf_symlink_aops;
-       inode->i_op = &page_symlink_inode_operations;
+       inode->i_op = &udf_symlink_inode_operations;
        inode_nohighmem(inode);
 
        if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
index fbff74654df2242f0df086237512226923c76429..a4da59e38b7fc07e168bf5d01d03e672678c7576 100644 (file)
@@ -70,17 +70,17 @@ struct UDFIdentSuffix {
        uint8_t         OSClass;
        uint8_t         OSIdentifier;
        uint8_t         reserved[4];
-} __attribute__ ((packed));
+} __packed;
 
 struct impIdentSuffix {
        uint8_t         OSClass;
        uint8_t         OSIdentifier;
        uint8_t         reserved[6];
-} __attribute__ ((packed));
+} __packed;
 
 struct appIdentSuffix {
        uint8_t         impUse[8];
-} __attribute__ ((packed));
+} __packed;
 
 /* Logical Volume Integrity Descriptor (UDF 2.50 2.2.6) */
 /* Implementation Use (UDF 2.50 2.2.6.4) */
@@ -92,7 +92,7 @@ struct logicalVolIntegrityDescImpUse {
        __le16          minUDFWriteRev;
        __le16          maxUDFWriteRev;
        uint8_t         impUse[0];
-} __attribute__ ((packed));
+} __packed;
 
 /* Implementation Use Volume Descriptor (UDF 2.50 2.2.7) */
 /* Implementation Use (UDF 2.50 2.2.7.2) */
@@ -104,7 +104,7 @@ struct impUseVolDescImpUse {
        dstring         LVInfo3[36];
        struct regid    impIdent;
        uint8_t         impUse[128];
-} __attribute__ ((packed));
+} __packed;
 
 struct udfPartitionMap2 {
        uint8_t         partitionMapType;
@@ -113,7 +113,7 @@ struct udfPartitionMap2 {
        struct regid    partIdent;
        __le16          volSeqNum;
        __le16          partitionNum;
-} __attribute__ ((packed));
+} __packed;
 
 /* Virtual Partition Map (UDF 2.50 2.2.8) */
 struct virtualPartitionMap {
@@ -124,7 +124,7 @@ struct virtualPartitionMap {
        __le16          volSeqNum;
        __le16          partitionNum;
        uint8_t         reserved2[24];
-} __attribute__ ((packed));
+} __packed;
 
 /* Sparable Partition Map (UDF 2.50 2.2.9) */
 struct sparablePartitionMap {
@@ -139,7 +139,7 @@ struct sparablePartitionMap {
        uint8_t reserved2[1];
        __le32 sizeSparingTable;
        __le32 locSparingTable[4];
-} __attribute__ ((packed));
+} __packed;
 
 /* Metadata Partition Map (UDF 2.4.0 2.2.10) */
 struct metadataPartitionMap {
@@ -156,14 +156,14 @@ struct metadataPartitionMap {
        __le16          alignUnitSize;
        uint8_t         flags;
        uint8_t         reserved2[5];
-} __attribute__ ((packed));
+} __packed;
 
 /* Virtual Allocation Table (UDF 1.5 2.2.10) */
 struct virtualAllocationTable15 {
        __le32          VirtualSector[0];
        struct regid    vatIdent;
        __le32          previousVATICBLoc;
-} __attribute__ ((packed));
+} __packed;
 
 #define ICBTAG_FILE_TYPE_VAT15         0x00U
 
@@ -181,7 +181,7 @@ struct virtualAllocationTable20 {
        __le16          reserved;
        uint8_t         impUse[0];
        __le32          vatEntry[0];
-} __attribute__ ((packed));
+} __packed;
 
 #define ICBTAG_FILE_TYPE_VAT20         0xF8U
 
@@ -189,7 +189,7 @@ struct virtualAllocationTable20 {
 struct sparingEntry {
        __le32          origLocation;
        __le32          mappedLocation;
-} __attribute__ ((packed));
+} __packed;
 
 struct sparingTable {
        struct tag      descTag;
@@ -199,7 +199,7 @@ struct sparingTable {
        __le32          sequenceNum;
        struct sparingEntry
                        mapEntry[0];
-} __attribute__ ((packed));
+} __packed;
 
 /* Metadata File (and Metadata Mirror File) (UDF 2.50 2.2.13.1) */
 #define ICBTAG_FILE_TYPE_MAIN          0xFA
@@ -210,7 +210,7 @@ struct sparingTable {
 struct allocDescImpUse {
        __le16          flags;
        uint8_t         impUse[4];
-} __attribute__ ((packed));
+} __packed;
 
 #define AD_IU_EXT_ERASED               0x0001
 
@@ -222,7 +222,7 @@ struct allocDescImpUse {
 struct freeEaSpace {
        __le16          headerChecksum;
        uint8_t         freeEASpace[0];
-} __attribute__ ((packed));
+} __packed;
 
 /* DVD Copyright Management Information (UDF 2.50 3.3.4.5.1.2) */
 struct DVDCopyrightImpUse {
@@ -230,14 +230,14 @@ struct DVDCopyrightImpUse {
        uint8_t         CGMSInfo;
        uint8_t         dataType;
        uint8_t         protectionSystemInfo[4];
-} __attribute__ ((packed));
+} __packed;
 
 /* Application Use Extended Attribute (UDF 2.50 3.3.4.6) */
 /* FreeAppEASpace (UDF 2.50 3.3.4.6.1) */
 struct freeAppEASpace {
        __le16          headerChecksum;
        uint8_t         freeEASpace[0];
-} __attribute__ ((packed));
+} __packed;
 
 /* UDF Defined System Stream (UDF 2.50 3.3.7) */
 #define UDF_ID_UNIQUE_ID               "*UDF Unique ID Mapping Data"
index 4942549e7dc8b3758dd8c8fadb99e8fba4265c00..14b4bc1f680131c20b774a75716875f50c5d7418 100644 (file)
@@ -264,9 +264,6 @@ static void __exit exit_udf_fs(void)
        destroy_inodecache();
 }
 
-module_init(init_udf_fs)
-module_exit(exit_udf_fs)
-
 static int udf_sb_alloc_partition_maps(struct super_block *sb, u32 count)
 {
        struct udf_sb_info *sbi = UDF_SB(sb);
@@ -1216,7 +1213,8 @@ static int udf_load_vat(struct super_block *sb, int p_index, int type1_index)
        struct udf_inode_info *vati;
        uint32_t pos;
        struct virtualAllocationTable20 *vat20;
-       sector_t blocks = sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits;
+       sector_t blocks = i_size_read(sb->s_bdev->bd_inode) >>
+                         sb->s_blocksize_bits;
 
        udf_find_vat_block(sb, p_index, type1_index, sbi->s_last_block);
        if (!sbi->s_vat_inode &&
@@ -1806,7 +1804,7 @@ static int udf_check_anchor_block(struct super_block *sb, sector_t block,
 
        if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV) &&
            udf_fixed_to_variable(block) >=
-           sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits)
+           i_size_read(sb->s_bdev->bd_inode) >> sb->s_blocksize_bits)
                return -EAGAIN;
 
        bh = udf_read_tagged(sb, block, block, &ident);
@@ -1868,7 +1866,7 @@ static int udf_scan_anchors(struct super_block *sb, sector_t *lastblock,
                last[last_count++] = *lastblock - 152;
 
        for (i = 0; i < last_count; i++) {
-               if (last[i] >= sb->s_bdev->bd_inode->i_size >>
+               if (last[i] >= i_size_read(sb->s_bdev->bd_inode) >>
                                sb->s_blocksize_bits)
                        continue;
                ret = udf_check_anchor_block(sb, last[i], fileset);
@@ -1957,7 +1955,7 @@ static int udf_load_vrs(struct super_block *sb, struct udf_options *uopt,
                if (!nsr_off) {
                        if (!silent)
                                udf_warn(sb, "No VRS found\n");
-                       return 0;
+                       return -EINVAL;
                }
                if (nsr_off == -1)
                        udf_debug("Failed to read sector at offset %d. "
@@ -1986,6 +1984,7 @@ static void udf_open_lvid(struct super_block *sb)
        struct buffer_head *bh = sbi->s_lvid_bh;
        struct logicalVolIntegrityDesc *lvid;
        struct logicalVolIntegrityDescImpUse *lvidiu;
+       struct timespec ts;
 
        if (!bh)
                return;
@@ -1997,8 +1996,8 @@ static void udf_open_lvid(struct super_block *sb)
        mutex_lock(&sbi->s_alloc_mutex);
        lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
        lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
-       udf_time_to_disk_stamp(&lvid->recordingDateAndTime,
-                               CURRENT_TIME);
+       ktime_get_real_ts(&ts);
+       udf_time_to_disk_stamp(&lvid->recordingDateAndTime, ts);
        lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_OPEN);
 
        lvid->descTag.descCRC = cpu_to_le16(
@@ -2019,6 +2018,7 @@ static void udf_close_lvid(struct super_block *sb)
        struct buffer_head *bh = sbi->s_lvid_bh;
        struct logicalVolIntegrityDesc *lvid;
        struct logicalVolIntegrityDescImpUse *lvidiu;
+       struct timespec ts;
 
        if (!bh)
                return;
@@ -2030,7 +2030,8 @@ static void udf_close_lvid(struct super_block *sb)
        mutex_lock(&sbi->s_alloc_mutex);
        lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
        lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
-       udf_time_to_disk_stamp(&lvid->recordingDateAndTime, CURRENT_TIME);
+       ktime_get_real_ts(&ts);
+       udf_time_to_disk_stamp(&lvid->recordingDateAndTime, ts);
        if (UDF_MAX_WRITE_VERSION > le16_to_cpu(lvidiu->maxUDFWriteRev))
                lvidiu->maxUDFWriteRev = cpu_to_le16(UDF_MAX_WRITE_VERSION);
        if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFReadRev))
@@ -2158,15 +2159,25 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
                ret = udf_load_vrs(sb, &uopt, silent, &fileset);
        } else {
                uopt.blocksize = bdev_logical_block_size(sb->s_bdev);
-               ret = udf_load_vrs(sb, &uopt, silent, &fileset);
-               if (ret == -EAGAIN && uopt.blocksize != UDF_DEFAULT_BLOCKSIZE) {
-                       if (!silent)
-                               pr_notice("Rescanning with blocksize %d\n",
-                                         UDF_DEFAULT_BLOCKSIZE);
-                       brelse(sbi->s_lvid_bh);
-                       sbi->s_lvid_bh = NULL;
-                       uopt.blocksize = UDF_DEFAULT_BLOCKSIZE;
+               while (uopt.blocksize <= 4096) {
                        ret = udf_load_vrs(sb, &uopt, silent, &fileset);
+                       if (ret < 0) {
+                               if (!silent && ret != -EACCES) {
+                                       pr_notice("Scanning with blocksize %d failed\n",
+                                                 uopt.blocksize);
+                               }
+                               brelse(sbi->s_lvid_bh);
+                               sbi->s_lvid_bh = NULL;
+                               /*
+                                * EACCES is special - we want to propagate to
+                                * upper layers that we cannot handle RW mount.
+                                */
+                               if (ret == -EACCES)
+                                       break;
+                       } else
+                               break;
+
+                       uopt.blocksize <<= 1;
                }
        }
        if (ret < 0) {
@@ -2497,3 +2508,9 @@ static unsigned int udf_count_free(struct super_block *sb)
 
        return accum;
 }
+
+MODULE_AUTHOR("Ben Fennema");
+MODULE_DESCRIPTION("Universal Disk Format Filesystem");
+MODULE_LICENSE("GPL");
+module_init(init_udf_fs)
+module_exit(exit_udf_fs)
index 8d619773056b5ef0b0a3f2d7dd27b74a6eb76434..f7dfef53f7396805c93d06c2c814423af6519b8c 100644 (file)
@@ -152,9 +152,39 @@ out_unmap:
        return err;
 }
 
+static int udf_symlink_getattr(struct vfsmount *mnt, struct dentry *dentry,
+                              struct kstat *stat)
+{
+       struct inode *inode = d_backing_inode(dentry);
+       struct page *page;
+
+       generic_fillattr(inode, stat);
+       page = read_mapping_page(inode->i_mapping, 0, NULL);
+       if (IS_ERR(page))
+               return PTR_ERR(page);
+       /*
+        * UDF uses non-trivial encoding of symlinks so i_size does not match
+        * number of characters reported by readlink(2) which apparently some
+        * applications expect. Also POSIX says that "The value returned in the
+        * st_size field shall be the length of the contents of the symbolic
+        * link, and shall not count a trailing null if one is present." So
+        * let's report the length of string returned by readlink(2) for
+        * st_size.
+        */
+       stat->size = strlen(page_address(page));
+       put_page(page);
+
+       return 0;
+}
+
 /*
  * symlinks can't do much...
  */
 const struct address_space_operations udf_symlink_aops = {
        .readpage               = udf_symlink_filler,
 };
+
+const struct inode_operations udf_symlink_inode_operations = {
+       .get_link       = page_get_link,
+       .getattr        = udf_symlink_getattr,
+};
index 263829ef1873644a16ac3340555291a7fc240a4a..63b0349843787a403bdfc25feb1f2d761603de62 100644 (file)
@@ -15,7 +15,6 @@
 #include "udfend.h"
 #include "udf_i.h"
 
-#define UDF_PREALLOCATE
 #define UDF_DEFAULT_PREALLOC_BLOCKS    8
 
 extern __printf(3, 4) void _udf_err(struct super_block *sb,
@@ -85,6 +84,7 @@ extern const struct inode_operations udf_dir_inode_operations;
 extern const struct file_operations udf_dir_operations;
 extern const struct inode_operations udf_file_inode_operations;
 extern const struct file_operations udf_file_operations;
+extern const struct inode_operations udf_symlink_inode_operations;
 extern const struct address_space_operations udf_aops;
 extern const struct address_space_operations udf_adinicb_aops;
 extern const struct address_space_operations udf_symlink_aops;
index ac3b4db519df8ee5c03fc759295028d6316f474e..8c7d01b759221b4c35f43801a00f3f4605da421e 100644 (file)
@@ -758,7 +758,7 @@ xfs_buf_readahead_map(
        int                     nmaps,
        const struct xfs_buf_ops *ops)
 {
-       if (bdi_read_congested(target->bt_bdi))
+       if (bdi_read_congested(target->bt_bdev->bd_bdi))
                return;
 
        xfs_buf_read_map(target, map, nmaps,
@@ -1791,7 +1791,6 @@ xfs_alloc_buftarg(
        btp->bt_mount = mp;
        btp->bt_dev =  bdev->bd_dev;
        btp->bt_bdev = bdev;
-       btp->bt_bdi = blk_get_backing_dev_info(bdev);
 
        if (xfs_setsize_buftarg_early(btp, bdev))
                goto error;
index 8a9d3a9599f00f410fe9b6e922b62242dfd8ab81..3c867e5a63e1d591bd51cc9ba34ef185bbd9e0e7 100644 (file)
@@ -109,7 +109,6 @@ typedef unsigned int xfs_buf_flags_t;
 typedef struct xfs_buftarg {
        dev_t                   bt_dev;
        struct block_device     *bt_bdev;
-       struct backing_dev_info *bt_bdi;
        struct xfs_mount        *bt_mount;
        unsigned int            bt_meta_sectorsize;
        size_t                  bt_meta_sectormask;
index cd20d5586f4bf67c1e4d96e74ce597017206eeff..c77b91ff1149c68cdc9e687c041be6e97fd387b0 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d25da936750e7df39af2c07605b313d636346b91..07740072da55d9bc64794c5f7232be4d5e256bc0 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 2c396344a7a256c7394f40318a52703b5cc27395..ad54610ea6cd4520812357633d8e461c6f49e744 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -91,7 +91,6 @@ struct acpi_exception_info {
 #define ACPI_SUCCESS(a)                 (!(a))
 #define ACPI_FAILURE(a)                 (a)
 
-#define ACPI_SKIP(a)                    (a == AE_CTRL_SKIP)
 #define AE_OK                           (acpi_status) 0x0000
 
 /*
@@ -211,11 +210,10 @@ struct acpi_exception_info {
 #define AE_CTRL_TRANSFER                EXCEP_CTL (0x0008)
 #define AE_CTRL_BREAK                   EXCEP_CTL (0x0009)
 #define AE_CTRL_CONTINUE                EXCEP_CTL (0x000A)
-#define AE_CTRL_SKIP                    EXCEP_CTL (0x000B)
-#define AE_CTRL_PARSE_CONTINUE          EXCEP_CTL (0x000C)
-#define AE_CTRL_PARSE_PENDING           EXCEP_CTL (0x000D)
+#define AE_CTRL_PARSE_CONTINUE          EXCEP_CTL (0x000B)
+#define AE_CTRL_PARSE_PENDING           EXCEP_CTL (0x000C)
 
-#define AE_CODE_CTRL_MAX                0x000D
+#define AE_CODE_CTRL_MAX                0x000C
 
 /* Exception strings for acpi_format_exception */
 
@@ -378,7 +376,6 @@ static const struct acpi_exception_info acpi_gbl_exception_names_ctrl[] = {
        EXCEP_TXT("AE_CTRL_TRANSFER", "Transfer control to called method"),
        EXCEP_TXT("AE_CTRL_BREAK", "A Break has been executed"),
        EXCEP_TXT("AE_CTRL_CONTINUE", "A Continue has been executed"),
-       EXCEP_TXT("AE_CTRL_SKIP", "Not currently used"),
        EXCEP_TXT("AE_CTRL_PARSE_CONTINUE", "Used to skip over bad opcodes"),
        EXCEP_TXT("AE_CTRL_PARSE_PENDING", "Used to implement AML While loops")
 };
index be779db708bd735057582fe9750fdc5016735b15..b421584033a51dcfdce6918c62bdd6b0273c77e4 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 48eb4dd99bb133353b7c0f25baf13f3428876598..c2e664e74075c7a4949c1ba656a7202123973c4b 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 82803ae9713f96f2b900e15cb33785594809f7e3..ca036620703c6be8c726dd1b77c3e7fc89d9de2a 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 4242c31ffaee3386b50d791915a8113423cf041d..ef0ae8aaa56771a3a1c4e00a4712f55cbdda9114 100644 (file)
@@ -522,6 +522,8 @@ void acpi_bus_trim(struct acpi_device *start);
 acpi_status acpi_bus_get_ejd(acpi_handle handle, acpi_handle * ejd);
 int acpi_match_device_ids(struct acpi_device *device,
                          const struct acpi_device_id *ids);
+void acpi_set_modalias(struct acpi_device *adev, const char *default_id,
+                      char *modalias, size_t len);
 int acpi_create_dir(struct acpi_device *);
 void acpi_remove_dir(struct acpi_device *);
 
index f3414c83abb1631197628c737ef8bee42f73c856..c66eb8ffa454b2d19532c9e45867d19f0480851f 100644 (file)
@@ -7,7 +7,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -333,6 +333,10 @@ u64 acpi_os_get_timer(void);
 acpi_status acpi_os_signal(u32 function, void *info);
 #endif
 
+#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_enter_sleep
+acpi_status acpi_os_enter_sleep(u8 sleep_state, u32 rega_value, u32 regb_value);
+#endif
+
 /*
  * Debug print routines
  */
@@ -355,12 +359,12 @@ void acpi_os_redirect_output(void *destination);
 acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read);
 #endif
 
-#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_initialize_command_signals
-acpi_status acpi_os_initialize_command_signals(void);
+#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_initialize_debugger
+acpi_status acpi_os_initialize_debugger(void);
 #endif
 
-#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_terminate_command_signals
-void acpi_os_terminate_command_signals(void);
+#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_terminate_debugger
+void acpi_os_terminate_debugger(void);
 #endif
 
 #ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_wait_command_ready
index f5e10dd8e86b712a4c0e97a206d36ff88fabe02f..3795386ea7068a1e0a77801ee98e9a569c59f3e2 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -46,7 +46,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20160930
+#define ACPI_CA_VERSION                 0x20170119
 
 #include <acpi/acconfig.h>
 #include <acpi/actypes.h>
index 16c189283ea0c4eab8053329daa55ba7287d4dfe..f0f7403d2000da2a16fbf34b6d69ae4c1fe78f0a 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index da5708caf8a12493de0e52376c27b7c0bffd1378..d92543f3bbfdcaaeac47252729af30ba428eb371 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 796d6baae3a34c08c51787bc1b8d562323d2d0f2..b4ce55c008b056822ed10ee1d0775a8b3d2a8934 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c93dbadfc71d34836f085d872c2b625b8bce1ad6..7aee9fb3bd1f06f88c3a83b708ae0b5e452170cb 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ebc1f4f9fe66e3b9b3a8bbc0364c5ca11e8d2809..94414b255a38b905438be32dd9626dd5e37ff431 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1d798abae710b38ba4af4511e7ae654cfdf3151b..d549e31c6d181b220468ce005ed575dc3d20b084 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 0f269e088f7aad327be5bfa8dc5ea889308fe69c..699a1999afe8ae7df1fcda53553d915a7276a403 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 34cce729109cc9d5ad7ac5346627af7da3358cf1..09994b063243c749ddfa424c82c154ee2552cf69 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -75,7 +75,8 @@
        (defined ACPI_NAMES_APP)    || \
        (defined ACPI_SRC_APP)      || \
        (defined ACPI_XTRACT_APP)   || \
-       (defined ACPI_EXAMPLE_APP)
+       (defined ACPI_EXAMPLE_APP)  || \
+       (defined ACPI_EFI_HELLO)
 #define ACPI_APPLICATION
 #define ACPI_SINGLE_THREADED
 #define USE_NATIVE_ALLOCATE_ZEROED
 #include "acmsvc.h"
 
 #elif defined(__INTEL_COMPILER)
-#include "acintel.h"
+#include <acpi/platform/acintel.h>
 
 #endif
 
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
-#ifdef ACPI_APPLICATION
+#if defined (ACPI_APPLICATION) || defined(ACPI_LIBRARY)
 #include <stdio.h>
 #include <fcntl.h>
 #include <errno.h>
index b3171b9d6974984872e520830ecd4d050d9cd35c..127c848a1ba7cd3e0f372afafad193d178f70ebf 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 8f66aaabadf74dc252fde96f30784c4537ed0b03..e877a35ee977aeb020811c88355ac3558b44eb82 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 46ead2caada4d2a36133a5100ccb912b29b57613..4f701b288cece7e2b162b93d09b76ce615264d6d 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/platform/acintel.h b/include/acpi/platform/acintel.h
new file mode 100644 (file)
index 0000000..17bd3b7
--- /dev/null
@@ -0,0 +1,87 @@
+/******************************************************************************
+ *
+ * Name: acintel.h - VC specific defines, etc.
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2017, Intel Corp.
+ * 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 at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may 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.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#ifndef __ACINTEL_H__
+#define __ACINTEL_H__
+
+/*
+ * Use compiler specific <stdarg.h> is a good practice for even when
+ * -nostdinc is specified (i.e., ACPI_USE_STANDARD_HEADERS undefined.
+ */
+#include <stdarg.h>
+
+/* Configuration specific to Intel 64-bit C compiler */
+
+#define COMPILER_DEPENDENT_INT64    __int64
+#define COMPILER_DEPENDENT_UINT64   unsigned __int64
+#define ACPI_INLINE                 __inline
+
+/*
+ * Calling conventions:
+ *
+ * ACPI_SYSTEM_XFACE        - Interfaces to host OS (handlers, threads)
+ * ACPI_EXTERNAL_XFACE      - External ACPI interfaces
+ * ACPI_INTERNAL_XFACE      - Internal ACPI interfaces
+ * ACPI_INTERNAL_VAR_XFACE  - Internal variable-parameter list interfaces
+ */
+#define ACPI_SYSTEM_XFACE
+#define ACPI_EXTERNAL_XFACE
+#define ACPI_INTERNAL_XFACE
+#define ACPI_INTERNAL_VAR_XFACE
+
+/* remark 981 - operands evaluated in no particular order */
+#pragma warning(disable:981)
+
+/* warn C4100: unreferenced formal parameter */
+#pragma warning(disable:4100)
+
+/* warn C4127: conditional expression is constant */
+#pragma warning(disable:4127)
+
+/* warn C4706: assignment within conditional expression */
+#pragma warning(disable:4706)
+
+/* warn C4214: bit field types other than int */
+#pragma warning(disable:4214)
+
+#endif                         /* __ACINTEL_H__ */
index e861a24f06f2aca2bb575a10fa3041fcb32815e3..a39e3f67616fc299c2c98964f3ec28cc064a0202 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  */
 #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_readable
 #define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_writable
-#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_initialize_command_signals
-#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_terminate_command_signals
+#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_initialize_debugger
+#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_terminate_debugger
 
 /*
  * OSL interfaces used by utilities
 #define ACPI_CAST_PTHREAD_T(pthread) ((acpi_thread_id) (pthread))
 
 #if defined(__ia64__)    || defined(__x86_64__) ||\
-       defined(__aarch64__) || defined(__PPC64__)
+       defined(__aarch64__) || defined(__PPC64__) ||\
+       defined(__s390x__)
 #define ACPI_MACHINE_WIDTH          64
 #define COMPILER_DEPENDENT_INT64    long
 #define COMPILER_DEPENDENT_UINT64   unsigned long
index 7dbb1141f546077ceec4c9fe39b077ae8e1ba379..efdff527f8fc75638da41d998a63eb94cc44ead4 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -129,12 +129,12 @@ static inline u8 acpi_os_readable(void *pointer, acpi_size length)
        return TRUE;
 }
 
-static inline acpi_status acpi_os_initialize_command_signals(void)
+static inline acpi_status acpi_os_initialize_debugger(void)
 {
        return AE_OK;
 }
 
-static inline void acpi_os_terminate_command_signals(void)
+static inline void acpi_os_terminate_debugger(void)
 {
        return;
 }
diff --git a/include/dt-bindings/pinctrl/stm32h7-pinfunc.h b/include/dt-bindings/pinctrl/stm32h7-pinfunc.h
new file mode 100644 (file)
index 0000000..cb673b5
--- /dev/null
@@ -0,0 +1,1612 @@
+#ifndef _DT_BINDINGS_STM32H7_PINFUNC_H
+#define _DT_BINDINGS_STM32H7_PINFUNC_H
+
+#define STM32H7_PA0_FUNC_GPIO 0x0
+#define STM32H7_PA0_FUNC_TIM2_CH1_TIM2_ETR 0x2
+#define STM32H7_PA0_FUNC_TIM5_CH1 0x3
+#define STM32H7_PA0_FUNC_TIM8_ETR 0x4
+#define STM32H7_PA0_FUNC_TIM15_BKIN 0x5
+#define STM32H7_PA0_FUNC_USART2_CTS_NSS 0x8
+#define STM32H7_PA0_FUNC_UART4_TX 0x9
+#define STM32H7_PA0_FUNC_SDMMC2_CMD 0xa
+#define STM32H7_PA0_FUNC_SAI2_SD_B 0xb
+#define STM32H7_PA0_FUNC_ETH_MII_CRS 0xc
+#define STM32H7_PA0_FUNC_EVENTOUT 0x10
+#define STM32H7_PA0_FUNC_ANALOG 0x11
+
+#define STM32H7_PA1_FUNC_GPIO 0x100
+#define STM32H7_PA1_FUNC_TIM2_CH2 0x102
+#define STM32H7_PA1_FUNC_TIM5_CH2 0x103
+#define STM32H7_PA1_FUNC_LPTIM3_OUT 0x104
+#define STM32H7_PA1_FUNC_TIM15_CH1N 0x105
+#define STM32H7_PA1_FUNC_USART2_RTS 0x108
+#define STM32H7_PA1_FUNC_UART4_RX 0x109
+#define STM32H7_PA1_FUNC_QUADSPI_BK1_IO3 0x10a
+#define STM32H7_PA1_FUNC_SAI2_MCK_B 0x10b
+#define STM32H7_PA1_FUNC_ETH_MII_RX_CLK_ETH_RMII_REF_CLK 0x10c
+#define STM32H7_PA1_FUNC_LCD_R2 0x10f
+#define STM32H7_PA1_FUNC_EVENTOUT 0x110
+#define STM32H7_PA1_FUNC_ANALOG 0x111
+
+#define STM32H7_PA2_FUNC_GPIO 0x200
+#define STM32H7_PA2_FUNC_TIM2_CH3 0x202
+#define STM32H7_PA2_FUNC_TIM5_CH3 0x203
+#define STM32H7_PA2_FUNC_LPTIM4_OUT 0x204
+#define STM32H7_PA2_FUNC_TIM15_CH1 0x205
+#define STM32H7_PA2_FUNC_USART2_TX 0x208
+#define STM32H7_PA2_FUNC_SAI2_SCK_B 0x209
+#define STM32H7_PA2_FUNC_ETH_MDIO 0x20c
+#define STM32H7_PA2_FUNC_MDIOS_MDIO 0x20d
+#define STM32H7_PA2_FUNC_LCD_R1 0x20f
+#define STM32H7_PA2_FUNC_EVENTOUT 0x210
+#define STM32H7_PA2_FUNC_ANALOG 0x211
+
+#define STM32H7_PA3_FUNC_GPIO 0x300
+#define STM32H7_PA3_FUNC_TIM2_CH4 0x302
+#define STM32H7_PA3_FUNC_TIM5_CH4 0x303
+#define STM32H7_PA3_FUNC_LPTIM5_OUT 0x304
+#define STM32H7_PA3_FUNC_TIM15_CH2 0x305
+#define STM32H7_PA3_FUNC_USART2_RX 0x308
+#define STM32H7_PA3_FUNC_LCD_B2 0x30a
+#define STM32H7_PA3_FUNC_OTG_HS_ULPI_D0 0x30b
+#define STM32H7_PA3_FUNC_ETH_MII_COL 0x30c
+#define STM32H7_PA3_FUNC_LCD_B5 0x30f
+#define STM32H7_PA3_FUNC_EVENTOUT 0x310
+#define STM32H7_PA3_FUNC_ANALOG 0x311
+
+#define STM32H7_PA4_FUNC_GPIO 0x400
+#define STM32H7_PA4_FUNC_TIM5_ETR 0x403
+#define STM32H7_PA4_FUNC_SPI1_NSS_I2S1_WS 0x406
+#define STM32H7_PA4_FUNC_SPI3_NSS_I2S3_WS 0x407
+#define STM32H7_PA4_FUNC_USART2_CK 0x408
+#define STM32H7_PA4_FUNC_SPI6_NSS 0x409
+#define STM32H7_PA4_FUNC_OTG_HS_SOF 0x40d
+#define STM32H7_PA4_FUNC_DCMI_HSYNC 0x40e
+#define STM32H7_PA4_FUNC_LCD_VSYNC 0x40f
+#define STM32H7_PA4_FUNC_EVENTOUT 0x410
+#define STM32H7_PA4_FUNC_ANALOG 0x411
+
+#define STM32H7_PA5_FUNC_GPIO 0x500
+#define STM32H7_PA5_FUNC_TIM2_CH1_TIM2_ETR 0x502
+#define STM32H7_PA5_FUNC_TIM8_CH1N 0x504
+#define STM32H7_PA5_FUNC_SPI1_SCK_I2S1_CK 0x506
+#define STM32H7_PA5_FUNC_SPI6_SCK 0x509
+#define STM32H7_PA5_FUNC_OTG_HS_ULPI_CK 0x50b
+#define STM32H7_PA5_FUNC_LCD_R4 0x50f
+#define STM32H7_PA5_FUNC_EVENTOUT 0x510
+#define STM32H7_PA5_FUNC_ANALOG 0x511
+
+#define STM32H7_PA6_FUNC_GPIO 0x600
+#define STM32H7_PA6_FUNC_TIM1_BKIN 0x602
+#define STM32H7_PA6_FUNC_TIM3_CH1 0x603
+#define STM32H7_PA6_FUNC_TIM8_BKIN 0x604
+#define STM32H7_PA6_FUNC_SPI1_MISO_I2S1_SDI 0x606
+#define STM32H7_PA6_FUNC_SPI6_MISO 0x609
+#define STM32H7_PA6_FUNC_TIM13_CH1 0x60a
+#define STM32H7_PA6_FUNC_TIM8_BKIN_COMP12 0x60b
+#define STM32H7_PA6_FUNC_MDIOS_MDC 0x60c
+#define STM32H7_PA6_FUNC_TIM1_BKIN_COMP12 0x60d
+#define STM32H7_PA6_FUNC_DCMI_PIXCLK 0x60e
+#define STM32H7_PA6_FUNC_LCD_G2 0x60f
+#define STM32H7_PA6_FUNC_EVENTOUT 0x610
+#define STM32H7_PA6_FUNC_ANALOG 0x611
+
+#define STM32H7_PA7_FUNC_GPIO 0x700
+#define STM32H7_PA7_FUNC_TIM1_CH1N 0x702
+#define STM32H7_PA7_FUNC_TIM3_CH2 0x703
+#define STM32H7_PA7_FUNC_TIM8_CH1N 0x704
+#define STM32H7_PA7_FUNC_SPI1_MOSI_I2S1_SDO 0x706
+#define STM32H7_PA7_FUNC_SPI6_MOSI 0x709
+#define STM32H7_PA7_FUNC_TIM14_CH1 0x70a
+#define STM32H7_PA7_FUNC_ETH_MII_RX_DV_ETH_RMII_CRS_DV 0x70c
+#define STM32H7_PA7_FUNC_FMC_SDNWE 0x70d
+#define STM32H7_PA7_FUNC_EVENTOUT 0x710
+#define STM32H7_PA7_FUNC_ANALOG 0x711
+
+#define STM32H7_PA8_FUNC_GPIO 0x800
+#define STM32H7_PA8_FUNC_MCO1 0x801
+#define STM32H7_PA8_FUNC_TIM1_CH1 0x802
+#define STM32H7_PA8_FUNC_HRTIM_CHB2 0x803
+#define STM32H7_PA8_FUNC_TIM8_BKIN2 0x804
+#define STM32H7_PA8_FUNC_I2C3_SCL 0x805
+#define STM32H7_PA8_FUNC_USART1_CK 0x808
+#define STM32H7_PA8_FUNC_OTG_FS_SOF 0x80b
+#define STM32H7_PA8_FUNC_UART7_RX 0x80c
+#define STM32H7_PA8_FUNC_TIM8_BKIN2_COMP12 0x80d
+#define STM32H7_PA8_FUNC_LCD_B3 0x80e
+#define STM32H7_PA8_FUNC_LCD_R6 0x80f
+#define STM32H7_PA8_FUNC_EVENTOUT 0x810
+#define STM32H7_PA8_FUNC_ANALOG 0x811
+
+#define STM32H7_PA9_FUNC_GPIO 0x900
+#define STM32H7_PA9_FUNC_TIM1_CH2 0x902
+#define STM32H7_PA9_FUNC_HRTIM_CHC1 0x903
+#define STM32H7_PA9_FUNC_LPUART1_TX 0x904
+#define STM32H7_PA9_FUNC_I2C3_SMBA 0x905
+#define STM32H7_PA9_FUNC_SPI2_SCK_I2S2_CK 0x906
+#define STM32H7_PA9_FUNC_USART1_TX 0x908
+#define STM32H7_PA9_FUNC_CAN1_RXFD 0x90a
+#define STM32H7_PA9_FUNC_ETH_TX_ER 0x90c
+#define STM32H7_PA9_FUNC_DCMI_D0 0x90e
+#define STM32H7_PA9_FUNC_LCD_R5 0x90f
+#define STM32H7_PA9_FUNC_EVENTOUT 0x910
+#define STM32H7_PA9_FUNC_ANALOG 0x911
+
+#define STM32H7_PA10_FUNC_GPIO 0xa00
+#define STM32H7_PA10_FUNC_TIM1_CH3 0xa02
+#define STM32H7_PA10_FUNC_HRTIM_CHC2 0xa03
+#define STM32H7_PA10_FUNC_LPUART1_RX 0xa04
+#define STM32H7_PA10_FUNC_USART1_RX 0xa08
+#define STM32H7_PA10_FUNC_CAN1_TXFD 0xa0a
+#define STM32H7_PA10_FUNC_OTG_FS_ID 0xa0b
+#define STM32H7_PA10_FUNC_MDIOS_MDIO 0xa0c
+#define STM32H7_PA10_FUNC_LCD_B4 0xa0d
+#define STM32H7_PA10_FUNC_DCMI_D1 0xa0e
+#define STM32H7_PA10_FUNC_LCD_B1 0xa0f
+#define STM32H7_PA10_FUNC_EVENTOUT 0xa10
+#define STM32H7_PA10_FUNC_ANALOG 0xa11
+
+#define STM32H7_PA11_FUNC_GPIO 0xb00
+#define STM32H7_PA11_FUNC_TIM1_CH4 0xb02
+#define STM32H7_PA11_FUNC_HRTIM_CHD1 0xb03
+#define STM32H7_PA11_FUNC_LPUART1_CTS 0xb04
+#define STM32H7_PA11_FUNC_SPI2_NSS_I2S2_WS 0xb06
+#define STM32H7_PA11_FUNC_UART4_RX 0xb07
+#define STM32H7_PA11_FUNC_USART1_CTS_NSS 0xb08
+#define STM32H7_PA11_FUNC_CAN1_RX 0xb0a
+#define STM32H7_PA11_FUNC_OTG_FS_DM 0xb0b
+#define STM32H7_PA11_FUNC_LCD_R4 0xb0f
+#define STM32H7_PA11_FUNC_EVENTOUT 0xb10
+#define STM32H7_PA11_FUNC_ANALOG 0xb11
+
+#define STM32H7_PA12_FUNC_GPIO 0xc00
+#define STM32H7_PA12_FUNC_TIM1_ETR 0xc02
+#define STM32H7_PA12_FUNC_HRTIM_CHD2 0xc03
+#define STM32H7_PA12_FUNC_LPUART1_RTS 0xc04
+#define STM32H7_PA12_FUNC_SPI2_SCK_I2S2_CK 0xc06
+#define STM32H7_PA12_FUNC_UART4_TX 0xc07
+#define STM32H7_PA12_FUNC_USART1_RTS 0xc08
+#define STM32H7_PA12_FUNC_SAI2_FS_B 0xc09
+#define STM32H7_PA12_FUNC_CAN1_TX 0xc0a
+#define STM32H7_PA12_FUNC_OTG_FS_DP 0xc0b
+#define STM32H7_PA12_FUNC_LCD_R5 0xc0f
+#define STM32H7_PA12_FUNC_EVENTOUT 0xc10
+#define STM32H7_PA12_FUNC_ANALOG 0xc11
+
+#define STM32H7_PA13_FUNC_GPIO 0xd00
+#define STM32H7_PA13_FUNC_JTMS_SWDIO 0xd01
+#define STM32H7_PA13_FUNC_EVENTOUT 0xd10
+#define STM32H7_PA13_FUNC_ANALOG 0xd11
+
+#define STM32H7_PA14_FUNC_GPIO 0xe00
+#define STM32H7_PA14_FUNC_JTCK_SWCLK 0xe01
+#define STM32H7_PA14_FUNC_EVENTOUT 0xe10
+#define STM32H7_PA14_FUNC_ANALOG 0xe11
+
+#define STM32H7_PA15_FUNC_GPIO 0xf00
+#define STM32H7_PA15_FUNC_JTDI 0xf01
+#define STM32H7_PA15_FUNC_TIM2_CH1_TIM2_ETR 0xf02
+#define STM32H7_PA15_FUNC_HRTIM_FLT1 0xf03
+#define STM32H7_PA15_FUNC_HDMI_CEC 0xf05
+#define STM32H7_PA15_FUNC_SPI1_NSS_I2S1_WS 0xf06
+#define STM32H7_PA15_FUNC_SPI3_NSS_I2S3_WS 0xf07
+#define STM32H7_PA15_FUNC_SPI6_NSS 0xf08
+#define STM32H7_PA15_FUNC_UART4_RTS 0xf09
+#define STM32H7_PA15_FUNC_UART7_TX 0xf0c
+#define STM32H7_PA15_FUNC_DSI_TE 0xf0e
+#define STM32H7_PA15_FUNC_EVENTOUT 0xf10
+#define STM32H7_PA15_FUNC_ANALOG 0xf11
+
+#define STM32H7_PB0_FUNC_GPIO 0x1000
+#define STM32H7_PB0_FUNC_TIM1_CH2N 0x1002
+#define STM32H7_PB0_FUNC_TIM3_CH3 0x1003
+#define STM32H7_PB0_FUNC_TIM8_CH2N 0x1004
+#define STM32H7_PB0_FUNC_DFSDM_CKOUT 0x1007
+#define STM32H7_PB0_FUNC_UART4_CTS 0x1009
+#define STM32H7_PB0_FUNC_LCD_R3 0x100a
+#define STM32H7_PB0_FUNC_OTG_HS_ULPI_D1 0x100b
+#define STM32H7_PB0_FUNC_ETH_MII_RXD2 0x100c
+#define STM32H7_PB0_FUNC_LCD_G1 0x100f
+#define STM32H7_PB0_FUNC_EVENTOUT 0x1010
+#define STM32H7_PB0_FUNC_ANALOG 0x1011
+
+#define STM32H7_PB1_FUNC_GPIO 0x1100
+#define STM32H7_PB1_FUNC_TIM1_CH3N 0x1102
+#define STM32H7_PB1_FUNC_TIM3_CH4 0x1103
+#define STM32H7_PB1_FUNC_TIM8_CH3N 0x1104
+#define STM32H7_PB1_FUNC_DFSDM_DATIN1 0x1107
+#define STM32H7_PB1_FUNC_LCD_R6 0x110a
+#define STM32H7_PB1_FUNC_OTG_HS_ULPI_D2 0x110b
+#define STM32H7_PB1_FUNC_ETH_MII_RXD3 0x110c
+#define STM32H7_PB1_FUNC_LCD_G0 0x110f
+#define STM32H7_PB1_FUNC_EVENTOUT 0x1110
+#define STM32H7_PB1_FUNC_ANALOG 0x1111
+
+#define STM32H7_PB2_FUNC_GPIO 0x1200
+#define STM32H7_PB2_FUNC_SAI1_D1 0x1203
+#define STM32H7_PB2_FUNC_DFSDM_CKIN1 0x1205
+#define STM32H7_PB2_FUNC_SAI1_SD_A 0x1207
+#define STM32H7_PB2_FUNC_SPI3_MOSI_I2S3_SDO 0x1208
+#define STM32H7_PB2_FUNC_SAI4_SD_A 0x1209
+#define STM32H7_PB2_FUNC_QUADSPI_CLK 0x120a
+#define STM32H7_PB2_FUNC_SAI4_D1 0x120b
+#define STM32H7_PB2_FUNC_ETH_TX_ER 0x120c
+#define STM32H7_PB2_FUNC_EVENTOUT 0x1210
+#define STM32H7_PB2_FUNC_ANALOG 0x1211
+
+#define STM32H7_PB3_FUNC_GPIO 0x1300
+#define STM32H7_PB3_FUNC_JTDO_TRACESWO 0x1301
+#define STM32H7_PB3_FUNC_TIM2_CH2 0x1302
+#define STM32H7_PB3_FUNC_HRTIM_FLT4 0x1303
+#define STM32H7_PB3_FUNC_SPI1_SCK_I2S1_CK 0x1306
+#define STM32H7_PB3_FUNC_SPI3_SCK_I2S3_CK 0x1307
+#define STM32H7_PB3_FUNC_SPI6_SCK 0x1309
+#define STM32H7_PB3_FUNC_SDMMC2_D2 0x130a
+#define STM32H7_PB3_FUNC_UART7_RX 0x130c
+#define STM32H7_PB3_FUNC_EVENTOUT 0x1310
+#define STM32H7_PB3_FUNC_ANALOG 0x1311
+
+#define STM32H7_PB4_FUNC_GPIO 0x1400
+#define STM32H7_PB4_FUNC_NJTRST 0x1401
+#define STM32H7_PB4_FUNC_TIM16_BKIN 0x1402
+#define STM32H7_PB4_FUNC_TIM3_CH1 0x1403
+#define STM32H7_PB4_FUNC_HRTIM_EEV6 0x1404
+#define STM32H7_PB4_FUNC_SPI1_MISO_I2S1_SDI 0x1406
+#define STM32H7_PB4_FUNC_SPI3_MISO_I2S3_SDI 0x1407
+#define STM32H7_PB4_FUNC_SPI2_NSS_I2S2_WS 0x1408
+#define STM32H7_PB4_FUNC_SPI6_MISO 0x1409
+#define STM32H7_PB4_FUNC_SDMMC2_D3 0x140a
+#define STM32H7_PB4_FUNC_UART7_TX 0x140c
+#define STM32H7_PB4_FUNC_EVENTOUT 0x1410
+#define STM32H7_PB4_FUNC_ANALOG 0x1411
+
+#define STM32H7_PB5_FUNC_GPIO 0x1500
+#define STM32H7_PB5_FUNC_TIM17_BKIN 0x1502
+#define STM32H7_PB5_FUNC_TIM3_CH2 0x1503
+#define STM32H7_PB5_FUNC_HRTIM_EEV7 0x1504
+#define STM32H7_PB5_FUNC_I2C1_SMBA 0x1505
+#define STM32H7_PB5_FUNC_SPI1_MOSI_I2S1_SDO 0x1506
+#define STM32H7_PB5_FUNC_I2C4_SMBA 0x1507
+#define STM32H7_PB5_FUNC_SPI3_MOSI_I2S3_SDO 0x1508
+#define STM32H7_PB5_FUNC_SPI6_MOSI 0x1509
+#define STM32H7_PB5_FUNC_CAN2_RX 0x150a
+#define STM32H7_PB5_FUNC_OTG_HS_ULPI_D7 0x150b
+#define STM32H7_PB5_FUNC_ETH_PPS_OUT 0x150c
+#define STM32H7_PB5_FUNC_FMC_SDCKE1 0x150d
+#define STM32H7_PB5_FUNC_DCMI_D10 0x150e
+#define STM32H7_PB5_FUNC_UART5_RX 0x150f
+#define STM32H7_PB5_FUNC_EVENTOUT 0x1510
+#define STM32H7_PB5_FUNC_ANALOG 0x1511
+
+#define STM32H7_PB6_FUNC_GPIO 0x1600
+#define STM32H7_PB6_FUNC_TIM16_CH1N 0x1602
+#define STM32H7_PB6_FUNC_TIM4_CH1 0x1603
+#define STM32H7_PB6_FUNC_HRTIM_EEV8 0x1604
+#define STM32H7_PB6_FUNC_I2C1_SCL 0x1605
+#define STM32H7_PB6_FUNC_HDMI_CEC 0x1606
+#define STM32H7_PB6_FUNC_I2C4_SCL 0x1607
+#define STM32H7_PB6_FUNC_USART1_TX 0x1608
+#define STM32H7_PB6_FUNC_LPUART1_TX 0x1609
+#define STM32H7_PB6_FUNC_CAN2_TX 0x160a
+#define STM32H7_PB6_FUNC_QUADSPI_BK1_NCS 0x160b
+#define STM32H7_PB6_FUNC_DFSDM_DATIN5 0x160c
+#define STM32H7_PB6_FUNC_FMC_SDNE1 0x160d
+#define STM32H7_PB6_FUNC_DCMI_D5 0x160e
+#define STM32H7_PB6_FUNC_UART5_TX 0x160f
+#define STM32H7_PB6_FUNC_EVENTOUT 0x1610
+#define STM32H7_PB6_FUNC_ANALOG 0x1611
+
+#define STM32H7_PB7_FUNC_GPIO 0x1700
+#define STM32H7_PB7_FUNC_TIM17_CH1N 0x1702
+#define STM32H7_PB7_FUNC_TIM4_CH2 0x1703
+#define STM32H7_PB7_FUNC_HRTIM_EEV9 0x1704
+#define STM32H7_PB7_FUNC_I2C1_SDA 0x1705
+#define STM32H7_PB7_FUNC_I2C4_SDA 0x1707
+#define STM32H7_PB7_FUNC_USART1_RX 0x1708
+#define STM32H7_PB7_FUNC_LPUART1_RX 0x1709
+#define STM32H7_PB7_FUNC_CAN2_TXFD 0x170a
+#define STM32H7_PB7_FUNC_DFSDM_CKIN5 0x170c
+#define STM32H7_PB7_FUNC_FMC_NL 0x170d
+#define STM32H7_PB7_FUNC_DCMI_VSYNC 0x170e
+#define STM32H7_PB7_FUNC_EVENTOUT 0x1710
+#define STM32H7_PB7_FUNC_ANALOG 0x1711
+
+#define STM32H7_PB8_FUNC_GPIO 0x1800
+#define STM32H7_PB8_FUNC_TIM16_CH1 0x1802
+#define STM32H7_PB8_FUNC_TIM4_CH3 0x1803
+#define STM32H7_PB8_FUNC_DFSDM_CKIN7 0x1804
+#define STM32H7_PB8_FUNC_I2C1_SCL 0x1805
+#define STM32H7_PB8_FUNC_I2C4_SCL 0x1807
+#define STM32H7_PB8_FUNC_SDMMC1_CKIN 0x1808
+#define STM32H7_PB8_FUNC_UART4_RX 0x1809
+#define STM32H7_PB8_FUNC_CAN1_RX 0x180a
+#define STM32H7_PB8_FUNC_SDMMC2_D4 0x180b
+#define STM32H7_PB8_FUNC_ETH_MII_TXD3 0x180c
+#define STM32H7_PB8_FUNC_SDMMC1_D4 0x180d
+#define STM32H7_PB8_FUNC_DCMI_D6 0x180e
+#define STM32H7_PB8_FUNC_LCD_B6 0x180f
+#define STM32H7_PB8_FUNC_EVENTOUT 0x1810
+#define STM32H7_PB8_FUNC_ANALOG 0x1811
+
+#define STM32H7_PB9_FUNC_GPIO 0x1900
+#define STM32H7_PB9_FUNC_TIM17_CH1 0x1902
+#define STM32H7_PB9_FUNC_TIM4_CH4 0x1903
+#define STM32H7_PB9_FUNC_DFSDM_DATIN7 0x1904
+#define STM32H7_PB9_FUNC_I2C1_SDA 0x1905
+#define STM32H7_PB9_FUNC_SPI2_NSS_I2S2_WS 0x1906
+#define STM32H7_PB9_FUNC_I2C4_SDA 0x1907
+#define STM32H7_PB9_FUNC_SDMMC1_CDIR 0x1908
+#define STM32H7_PB9_FUNC_UART4_TX 0x1909
+#define STM32H7_PB9_FUNC_CAN1_TX 0x190a
+#define STM32H7_PB9_FUNC_SDMMC2_D5 0x190b
+#define STM32H7_PB9_FUNC_I2C4_SMBA 0x190c
+#define STM32H7_PB9_FUNC_SDMMC1_D5 0x190d
+#define STM32H7_PB9_FUNC_DCMI_D7 0x190e
+#define STM32H7_PB9_FUNC_LCD_B7 0x190f
+#define STM32H7_PB9_FUNC_EVENTOUT 0x1910
+#define STM32H7_PB9_FUNC_ANALOG 0x1911
+
+#define STM32H7_PB10_FUNC_GPIO 0x1a00
+#define STM32H7_PB10_FUNC_TIM2_CH3 0x1a02
+#define STM32H7_PB10_FUNC_HRTIM_SCOUT 0x1a03
+#define STM32H7_PB10_FUNC_LPTIM2_IN1 0x1a04
+#define STM32H7_PB10_FUNC_I2C2_SCL 0x1a05
+#define STM32H7_PB10_FUNC_SPI2_SCK_I2S2_CK 0x1a06
+#define STM32H7_PB10_FUNC_DFSDM_DATIN7 0x1a07
+#define STM32H7_PB10_FUNC_USART3_TX 0x1a08
+#define STM32H7_PB10_FUNC_QUADSPI_BK1_NCS 0x1a0a
+#define STM32H7_PB10_FUNC_OTG_HS_ULPI_D3 0x1a0b
+#define STM32H7_PB10_FUNC_ETH_MII_RX_ER 0x1a0c
+#define STM32H7_PB10_FUNC_LCD_G4 0x1a0f
+#define STM32H7_PB10_FUNC_EVENTOUT 0x1a10
+#define STM32H7_PB10_FUNC_ANALOG 0x1a11
+
+#define STM32H7_PB11_FUNC_GPIO 0x1b00
+#define STM32H7_PB11_FUNC_TIM2_CH4 0x1b02
+#define STM32H7_PB11_FUNC_HRTIM_SCIN 0x1b03
+#define STM32H7_PB11_FUNC_LPTIM2_ETR 0x1b04
+#define STM32H7_PB11_FUNC_I2C2_SDA 0x1b05
+#define STM32H7_PB11_FUNC_DFSDM_CKIN7 0x1b07
+#define STM32H7_PB11_FUNC_USART3_RX 0x1b08
+#define STM32H7_PB11_FUNC_OTG_HS_ULPI_D4 0x1b0b
+#define STM32H7_PB11_FUNC_ETH_MII_TX_EN_ETH_RMII_TX_EN 0x1b0c
+#define STM32H7_PB11_FUNC_DSI_TE 0x1b0e
+#define STM32H7_PB11_FUNC_LCD_G5 0x1b0f
+#define STM32H7_PB11_FUNC_EVENTOUT 0x1b10
+#define STM32H7_PB11_FUNC_ANALOG 0x1b11
+
+#define STM32H7_PB12_FUNC_GPIO 0x1c00
+#define STM32H7_PB12_FUNC_TIM1_BKIN 0x1c02
+#define STM32H7_PB12_FUNC_I2C2_SMBA 0x1c05
+#define STM32H7_PB12_FUNC_SPI2_NSS_I2S2_WS 0x1c06
+#define STM32H7_PB12_FUNC_DFSDM_DATIN1 0x1c07
+#define STM32H7_PB12_FUNC_USART3_CK 0x1c08
+#define STM32H7_PB12_FUNC_CAN2_RX 0x1c0a
+#define STM32H7_PB12_FUNC_OTG_HS_ULPI_D5 0x1c0b
+#define STM32H7_PB12_FUNC_ETH_MII_TXD0_ETH_RMII_TXD0 0x1c0c
+#define STM32H7_PB12_FUNC_OTG_HS_ID 0x1c0d
+#define STM32H7_PB12_FUNC_TIM1_BKIN_COMP12 0x1c0e
+#define STM32H7_PB12_FUNC_UART5_RX 0x1c0f
+#define STM32H7_PB12_FUNC_EVENTOUT 0x1c10
+#define STM32H7_PB12_FUNC_ANALOG 0x1c11
+
+#define STM32H7_PB13_FUNC_GPIO 0x1d00
+#define STM32H7_PB13_FUNC_TIM1_CH1N 0x1d02
+#define STM32H7_PB13_FUNC_LPTIM2_OUT 0x1d04
+#define STM32H7_PB13_FUNC_SPI2_SCK_I2S2_CK 0x1d06
+#define STM32H7_PB13_FUNC_DFSDM_CKIN1 0x1d07
+#define STM32H7_PB13_FUNC_USART3_CTS_NSS 0x1d08
+#define STM32H7_PB13_FUNC_CAN2_TX 0x1d0a
+#define STM32H7_PB13_FUNC_OTG_HS_ULPI_D6 0x1d0b
+#define STM32H7_PB13_FUNC_ETH_MII_TXD1_ETH_RMII_TXD1 0x1d0c
+#define STM32H7_PB13_FUNC_UART5_TX 0x1d0f
+#define STM32H7_PB13_FUNC_EVENTOUT 0x1d10
+#define STM32H7_PB13_FUNC_ANALOG 0x1d11
+
+#define STM32H7_PB14_FUNC_GPIO 0x1e00
+#define STM32H7_PB14_FUNC_TIM1_CH2N 0x1e02
+#define STM32H7_PB14_FUNC_TIM8_CH2N 0x1e04
+#define STM32H7_PB14_FUNC_USART1_TX 0x1e05
+#define STM32H7_PB14_FUNC_SPI2_MISO_I2S2_SDI 0x1e06
+#define STM32H7_PB14_FUNC_DFSDM_DATIN2 0x1e07
+#define STM32H7_PB14_FUNC_USART3_RTS 0x1e08
+#define STM32H7_PB14_FUNC_UART4_RTS 0x1e09
+#define STM32H7_PB14_FUNC_SDMMC2_D0 0x1e0a
+#define STM32H7_PB14_FUNC_OTG_HS_DM 0x1e0d
+#define STM32H7_PB14_FUNC_EVENTOUT 0x1e10
+#define STM32H7_PB14_FUNC_ANALOG 0x1e11
+
+#define STM32H7_PB15_FUNC_GPIO 0x1f00
+#define STM32H7_PB15_FUNC_RTC_REFIN 0x1f01
+#define STM32H7_PB15_FUNC_TIM1_CH3N 0x1f02
+#define STM32H7_PB15_FUNC_TIM8_CH3N 0x1f04
+#define STM32H7_PB15_FUNC_USART1_RX 0x1f05
+#define STM32H7_PB15_FUNC_SPI2_MOSI_I2S2_SDO 0x1f06
+#define STM32H7_PB15_FUNC_DFSDM_CKIN2 0x1f07
+#define STM32H7_PB15_FUNC_UART4_CTS 0x1f09
+#define STM32H7_PB15_FUNC_SDMMC2_D1 0x1f0a
+#define STM32H7_PB15_FUNC_OTG_HS_DP 0x1f0d
+#define STM32H7_PB15_FUNC_EVENTOUT 0x1f10
+#define STM32H7_PB15_FUNC_ANALOG 0x1f11
+
+#define STM32H7_PC0_FUNC_GPIO 0x2000
+#define STM32H7_PC0_FUNC_DFSDM_CKIN0 0x2004
+#define STM32H7_PC0_FUNC_DFSDM_DATIN4 0x2007
+#define STM32H7_PC0_FUNC_SAI2_FS_B 0x2009
+#define STM32H7_PC0_FUNC_OTG_HS_ULPI_STP 0x200b
+#define STM32H7_PC0_FUNC_FMC_SDNWE 0x200d
+#define STM32H7_PC0_FUNC_LCD_R5 0x200f
+#define STM32H7_PC0_FUNC_EVENTOUT 0x2010
+#define STM32H7_PC0_FUNC_ANALOG 0x2011
+
+#define STM32H7_PC1_FUNC_GPIO 0x2100
+#define STM32H7_PC1_FUNC_TRACED0 0x2101
+#define STM32H7_PC1_FUNC_SAI1_D1 0x2103
+#define STM32H7_PC1_FUNC_DFSDM_DATIN0 0x2104
+#define STM32H7_PC1_FUNC_DFSDM_CKIN4 0x2105
+#define STM32H7_PC1_FUNC_SPI2_MOSI_I2S2_SDO 0x2106
+#define STM32H7_PC1_FUNC_SAI1_SD_A 0x2107
+#define STM32H7_PC1_FUNC_SAI4_SD_A 0x2109
+#define STM32H7_PC1_FUNC_SDMMC2_CK 0x210a
+#define STM32H7_PC1_FUNC_SAI4_D1 0x210b
+#define STM32H7_PC1_FUNC_ETH_MDC 0x210c
+#define STM32H7_PC1_FUNC_MDIOS_MDC 0x210d
+#define STM32H7_PC1_FUNC_EVENTOUT 0x2110
+#define STM32H7_PC1_FUNC_ANALOG 0x2111
+
+#define STM32H7_PC2_FUNC_GPIO 0x2200
+#define STM32H7_PC2_FUNC_DFSDM_CKIN1 0x2204
+#define STM32H7_PC2_FUNC_SPI2_MISO_I2S2_SDI 0x2206
+#define STM32H7_PC2_FUNC_DFSDM_CKOUT 0x2207
+#define STM32H7_PC2_FUNC_OTG_HS_ULPI_DIR 0x220b
+#define STM32H7_PC2_FUNC_ETH_MII_TXD2 0x220c
+#define STM32H7_PC2_FUNC_FMC_SDNE0 0x220d
+#define STM32H7_PC2_FUNC_EVENTOUT 0x2210
+#define STM32H7_PC2_FUNC_ANALOG 0x2211
+
+#define STM32H7_PC3_FUNC_GPIO 0x2300
+#define STM32H7_PC3_FUNC_DFSDM_DATIN1 0x2304
+#define STM32H7_PC3_FUNC_SPI2_MOSI_I2S2_SDO 0x2306
+#define STM32H7_PC3_FUNC_OTG_HS_ULPI_NXT 0x230b
+#define STM32H7_PC3_FUNC_ETH_MII_TX_CLK 0x230c
+#define STM32H7_PC3_FUNC_FMC_SDCKE0 0x230d
+#define STM32H7_PC3_FUNC_EVENTOUT 0x2310
+#define STM32H7_PC3_FUNC_ANALOG 0x2311
+
+#define STM32H7_PC4_FUNC_GPIO 0x2400
+#define STM32H7_PC4_FUNC_DFSDM_CKIN2 0x2404
+#define STM32H7_PC4_FUNC_I2S1_MCK 0x2406
+#define STM32H7_PC4_FUNC_SPDIFRX_IN2 0x240a
+#define STM32H7_PC4_FUNC_ETH_MII_RXD0_ETH_RMII_RXD0 0x240c
+#define STM32H7_PC4_FUNC_FMC_SDNE0 0x240d
+#define STM32H7_PC4_FUNC_EVENTOUT 0x2410
+#define STM32H7_PC4_FUNC_ANALOG 0x2411
+
+#define STM32H7_PC5_FUNC_GPIO 0x2500
+#define STM32H7_PC5_FUNC_SAI1_D3 0x2503
+#define STM32H7_PC5_FUNC_DFSDM_DATIN2 0x2504
+#define STM32H7_PC5_FUNC_SPDIFRX_IN3 0x250a
+#define STM32H7_PC5_FUNC_SAI4_D3 0x250b
+#define STM32H7_PC5_FUNC_ETH_MII_RXD1_ETH_RMII_RXD1 0x250c
+#define STM32H7_PC5_FUNC_FMC_SDCKE0 0x250d
+#define STM32H7_PC5_FUNC_COMP_1_OUT 0x250e
+#define STM32H7_PC5_FUNC_EVENTOUT 0x2510
+#define STM32H7_PC5_FUNC_ANALOG 0x2511
+
+#define STM32H7_PC6_FUNC_GPIO 0x2600
+#define STM32H7_PC6_FUNC_HRTIM_CHA1 0x2602
+#define STM32H7_PC6_FUNC_TIM3_CH1 0x2603
+#define STM32H7_PC6_FUNC_TIM8_CH1 0x2604
+#define STM32H7_PC6_FUNC_DFSDM_CKIN3 0x2605
+#define STM32H7_PC6_FUNC_I2S2_MCK 0x2606
+#define STM32H7_PC6_FUNC_USART6_TX 0x2608
+#define STM32H7_PC6_FUNC_SDMMC1_D0DIR 0x2609
+#define STM32H7_PC6_FUNC_FMC_NWAIT 0x260a
+#define STM32H7_PC6_FUNC_SDMMC2_D6 0x260b
+#define STM32H7_PC6_FUNC_SDMMC1_D6 0x260d
+#define STM32H7_PC6_FUNC_DCMI_D0 0x260e
+#define STM32H7_PC6_FUNC_LCD_HSYNC 0x260f
+#define STM32H7_PC6_FUNC_EVENTOUT 0x2610
+#define STM32H7_PC6_FUNC_ANALOG 0x2611
+
+#define STM32H7_PC7_FUNC_GPIO 0x2700
+#define STM32H7_PC7_FUNC_TRGIO 0x2701
+#define STM32H7_PC7_FUNC_HRTIM_CHA2 0x2702
+#define STM32H7_PC7_FUNC_TIM3_CH2 0x2703
+#define STM32H7_PC7_FUNC_TIM8_CH2 0x2704
+#define STM32H7_PC7_FUNC_DFSDM_DATIN3 0x2705
+#define STM32H7_PC7_FUNC_I2S3_MCK 0x2707
+#define STM32H7_PC7_FUNC_USART6_RX 0x2708
+#define STM32H7_PC7_FUNC_SDMMC1_D123DIR 0x2709
+#define STM32H7_PC7_FUNC_FMC_NE1 0x270a
+#define STM32H7_PC7_FUNC_SDMMC2_D7 0x270b
+#define STM32H7_PC7_FUNC_SWPMI_TX 0x270c
+#define STM32H7_PC7_FUNC_SDMMC1_D7 0x270d
+#define STM32H7_PC7_FUNC_DCMI_D1 0x270e
+#define STM32H7_PC7_FUNC_LCD_G6 0x270f
+#define STM32H7_PC7_FUNC_EVENTOUT 0x2710
+#define STM32H7_PC7_FUNC_ANALOG 0x2711
+
+#define STM32H7_PC8_FUNC_GPIO 0x2800
+#define STM32H7_PC8_FUNC_TRACED1 0x2801
+#define STM32H7_PC8_FUNC_HRTIM_CHB1 0x2802
+#define STM32H7_PC8_FUNC_TIM3_CH3 0x2803
+#define STM32H7_PC8_FUNC_TIM8_CH3 0x2804
+#define STM32H7_PC8_FUNC_USART6_CK 0x2808
+#define STM32H7_PC8_FUNC_UART5_RTS 0x2809
+#define STM32H7_PC8_FUNC_FMC_NE2_FMC_NCE 0x280a
+#define STM32H7_PC8_FUNC_SWPMI_RX 0x280c
+#define STM32H7_PC8_FUNC_SDMMC1_D0 0x280d
+#define STM32H7_PC8_FUNC_DCMI_D2 0x280e
+#define STM32H7_PC8_FUNC_EVENTOUT 0x2810
+#define STM32H7_PC8_FUNC_ANALOG 0x2811
+
+#define STM32H7_PC9_FUNC_GPIO 0x2900
+#define STM32H7_PC9_FUNC_MCO2 0x2901
+#define STM32H7_PC9_FUNC_TIM3_CH4 0x2903
+#define STM32H7_PC9_FUNC_TIM8_CH4 0x2904
+#define STM32H7_PC9_FUNC_I2C3_SDA 0x2905
+#define STM32H7_PC9_FUNC_I2S_CKIN 0x2906
+#define STM32H7_PC9_FUNC_UART5_CTS 0x2909
+#define STM32H7_PC9_FUNC_QUADSPI_BK1_IO0 0x290a
+#define STM32H7_PC9_FUNC_LCD_G3 0x290b
+#define STM32H7_PC9_FUNC_SWPMI_SUSPEND 0x290c
+#define STM32H7_PC9_FUNC_SDMMC1_D1 0x290d
+#define STM32H7_PC9_FUNC_DCMI_D3 0x290e
+#define STM32H7_PC9_FUNC_LCD_B2 0x290f
+#define STM32H7_PC9_FUNC_EVENTOUT 0x2910
+#define STM32H7_PC9_FUNC_ANALOG 0x2911
+
+#define STM32H7_PC10_FUNC_GPIO 0x2a00
+#define STM32H7_PC10_FUNC_HRTIM_EEV1 0x2a03
+#define STM32H7_PC10_FUNC_DFSDM_CKIN5 0x2a04
+#define STM32H7_PC10_FUNC_SPI3_SCK_I2S3_CK 0x2a07
+#define STM32H7_PC10_FUNC_USART3_TX 0x2a08
+#define STM32H7_PC10_FUNC_UART4_TX 0x2a09
+#define STM32H7_PC10_FUNC_QUADSPI_BK1_IO1 0x2a0a
+#define STM32H7_PC10_FUNC_SDMMC1_D2 0x2a0d
+#define STM32H7_PC10_FUNC_DCMI_D8 0x2a0e
+#define STM32H7_PC10_FUNC_LCD_R2 0x2a0f
+#define STM32H7_PC10_FUNC_EVENTOUT 0x2a10
+#define STM32H7_PC10_FUNC_ANALOG 0x2a11
+
+#define STM32H7_PC11_FUNC_GPIO 0x2b00
+#define STM32H7_PC11_FUNC_HRTIM_FLT2 0x2b03
+#define STM32H7_PC11_FUNC_DFSDM_DATIN5 0x2b04
+#define STM32H7_PC11_FUNC_SPI3_MISO_I2S3_SDI 0x2b07
+#define STM32H7_PC11_FUNC_USART3_RX 0x2b08
+#define STM32H7_PC11_FUNC_UART4_RX 0x2b09
+#define STM32H7_PC11_FUNC_QUADSPI_BK2_NCS 0x2b0a
+#define STM32H7_PC11_FUNC_SDMMC1_D3 0x2b0d
+#define STM32H7_PC11_FUNC_DCMI_D4 0x2b0e
+#define STM32H7_PC11_FUNC_EVENTOUT 0x2b10
+#define STM32H7_PC11_FUNC_ANALOG 0x2b11
+
+#define STM32H7_PC12_FUNC_GPIO 0x2c00
+#define STM32H7_PC12_FUNC_TRACED3 0x2c01
+#define STM32H7_PC12_FUNC_HRTIM_EEV2 0x2c03
+#define STM32H7_PC12_FUNC_SPI3_MOSI_I2S3_SDO 0x2c07
+#define STM32H7_PC12_FUNC_USART3_CK 0x2c08
+#define STM32H7_PC12_FUNC_UART5_TX 0x2c09
+#define STM32H7_PC12_FUNC_SDMMC1_CK 0x2c0d
+#define STM32H7_PC12_FUNC_DCMI_D9 0x2c0e
+#define STM32H7_PC12_FUNC_EVENTOUT 0x2c10
+#define STM32H7_PC12_FUNC_ANALOG 0x2c11
+
+#define STM32H7_PC13_FUNC_GPIO 0x2d00
+#define STM32H7_PC13_FUNC_EVENTOUT 0x2d10
+#define STM32H7_PC13_FUNC_ANALOG 0x2d11
+
+#define STM32H7_PC14_FUNC_GPIO 0x2e00
+#define STM32H7_PC14_FUNC_EVENTOUT 0x2e10
+#define STM32H7_PC14_FUNC_ANALOG 0x2e11
+
+#define STM32H7_PC15_FUNC_GPIO 0x2f00
+#define STM32H7_PC15_FUNC_EVENTOUT 0x2f10
+#define STM32H7_PC15_FUNC_ANALOG 0x2f11
+
+#define STM32H7_PD0_FUNC_GPIO 0x3000
+#define STM32H7_PD0_FUNC_DFSDM_CKIN6 0x3004
+#define STM32H7_PD0_FUNC_SAI3_SCK_A 0x3007
+#define STM32H7_PD0_FUNC_UART4_RX 0x3009
+#define STM32H7_PD0_FUNC_CAN1_RX 0x300a
+#define STM32H7_PD0_FUNC_FMC_D2_FMC_DA2 0x300d
+#define STM32H7_PD0_FUNC_EVENTOUT 0x3010
+#define STM32H7_PD0_FUNC_ANALOG 0x3011
+
+#define STM32H7_PD1_FUNC_GPIO 0x3100
+#define STM32H7_PD1_FUNC_DFSDM_DATIN6 0x3104
+#define STM32H7_PD1_FUNC_SAI3_SD_A 0x3107
+#define STM32H7_PD1_FUNC_UART4_TX 0x3109
+#define STM32H7_PD1_FUNC_CAN1_TX 0x310a
+#define STM32H7_PD1_FUNC_FMC_D3_FMC_DA3 0x310d
+#define STM32H7_PD1_FUNC_EVENTOUT 0x3110
+#define STM32H7_PD1_FUNC_ANALOG 0x3111
+
+#define STM32H7_PD2_FUNC_GPIO 0x3200
+#define STM32H7_PD2_FUNC_TRACED2 0x3201
+#define STM32H7_PD2_FUNC_TIM3_ETR 0x3203
+#define STM32H7_PD2_FUNC_UART5_RX 0x3209
+#define STM32H7_PD2_FUNC_SDMMC1_CMD 0x320d
+#define STM32H7_PD2_FUNC_DCMI_D11 0x320e
+#define STM32H7_PD2_FUNC_EVENTOUT 0x3210
+#define STM32H7_PD2_FUNC_ANALOG 0x3211
+
+#define STM32H7_PD3_FUNC_GPIO 0x3300
+#define STM32H7_PD3_FUNC_DFSDM_CKOUT 0x3304
+#define STM32H7_PD3_FUNC_SPI2_SCK_I2S2_CK 0x3306
+#define STM32H7_PD3_FUNC_USART2_CTS_NSS 0x3308
+#define STM32H7_PD3_FUNC_FMC_CLK 0x330d
+#define STM32H7_PD3_FUNC_DCMI_D5 0x330e
+#define STM32H7_PD3_FUNC_LCD_G7 0x330f
+#define STM32H7_PD3_FUNC_EVENTOUT 0x3310
+#define STM32H7_PD3_FUNC_ANALOG 0x3311
+
+#define STM32H7_PD4_FUNC_GPIO 0x3400
+#define STM32H7_PD4_FUNC_HRTIM_FLT3 0x3403
+#define STM32H7_PD4_FUNC_SAI3_FS_A 0x3407
+#define STM32H7_PD4_FUNC_USART2_RTS 0x3408
+#define STM32H7_PD4_FUNC_CAN1_RXFD 0x340a
+#define STM32H7_PD4_FUNC_FMC_NOE 0x340d
+#define STM32H7_PD4_FUNC_EVENTOUT 0x3410
+#define STM32H7_PD4_FUNC_ANALOG 0x3411
+
+#define STM32H7_PD5_FUNC_GPIO 0x3500
+#define STM32H7_PD5_FUNC_HRTIM_EEV3 0x3503
+#define STM32H7_PD5_FUNC_USART2_TX 0x3508
+#define STM32H7_PD5_FUNC_CAN1_TXFD 0x350a
+#define STM32H7_PD5_FUNC_FMC_NWE 0x350d
+#define STM32H7_PD5_FUNC_EVENTOUT 0x3510
+#define STM32H7_PD5_FUNC_ANALOG 0x3511
+
+#define STM32H7_PD6_FUNC_GPIO 0x3600
+#define STM32H7_PD6_FUNC_SAI1_D1 0x3603
+#define STM32H7_PD6_FUNC_DFSDM_CKIN4 0x3604
+#define STM32H7_PD6_FUNC_DFSDM_DATIN1 0x3605
+#define STM32H7_PD6_FUNC_SPI3_MOSI_I2S3_SDO 0x3606
+#define STM32H7_PD6_FUNC_SAI1_SD_A 0x3607
+#define STM32H7_PD6_FUNC_USART2_RX 0x3608
+#define STM32H7_PD6_FUNC_SAI4_SD_A 0x3609
+#define STM32H7_PD6_FUNC_CAN2_RXFD 0x360a
+#define STM32H7_PD6_FUNC_SAI4_D1 0x360b
+#define STM32H7_PD6_FUNC_SDMMC2_CK 0x360c
+#define STM32H7_PD6_FUNC_FMC_NWAIT 0x360d
+#define STM32H7_PD6_FUNC_DCMI_D10 0x360e
+#define STM32H7_PD6_FUNC_LCD_B2 0x360f
+#define STM32H7_PD6_FUNC_EVENTOUT 0x3610
+#define STM32H7_PD6_FUNC_ANALOG 0x3611
+
+#define STM32H7_PD7_FUNC_GPIO 0x3700
+#define STM32H7_PD7_FUNC_DFSDM_DATIN4 0x3704
+#define STM32H7_PD7_FUNC_SPI1_MOSI_I2S1_SDO 0x3706
+#define STM32H7_PD7_FUNC_DFSDM_CKIN1 0x3707
+#define STM32H7_PD7_FUNC_USART2_CK 0x3708
+#define STM32H7_PD7_FUNC_SPDIFRX_IN0 0x370a
+#define STM32H7_PD7_FUNC_SDMMC2_CMD 0x370c
+#define STM32H7_PD7_FUNC_FMC_NE1 0x370d
+#define STM32H7_PD7_FUNC_EVENTOUT 0x3710
+#define STM32H7_PD7_FUNC_ANALOG 0x3711
+
+#define STM32H7_PD8_FUNC_GPIO 0x3800
+#define STM32H7_PD8_FUNC_DFSDM_CKIN3 0x3804
+#define STM32H7_PD8_FUNC_SAI3_SCK_B 0x3807
+#define STM32H7_PD8_FUNC_USART3_TX 0x3808
+#define STM32H7_PD8_FUNC_SPDIFRX_IN1 0x380a
+#define STM32H7_PD8_FUNC_FMC_D13_FMC_DA13 0x380d
+#define STM32H7_PD8_FUNC_EVENTOUT 0x3810
+#define STM32H7_PD8_FUNC_ANALOG 0x3811
+
+#define STM32H7_PD9_FUNC_GPIO 0x3900
+#define STM32H7_PD9_FUNC_DFSDM_DATIN3 0x3904
+#define STM32H7_PD9_FUNC_SAI3_SD_B 0x3907
+#define STM32H7_PD9_FUNC_USART3_RX 0x3908
+#define STM32H7_PD9_FUNC_CAN2_RXFD 0x390a
+#define STM32H7_PD9_FUNC_FMC_D14_FMC_DA14 0x390d
+#define STM32H7_PD9_FUNC_EVENTOUT 0x3910
+#define STM32H7_PD9_FUNC_ANALOG 0x3911
+
+#define STM32H7_PD10_FUNC_GPIO 0x3a00
+#define STM32H7_PD10_FUNC_DFSDM_CKOUT 0x3a04
+#define STM32H7_PD10_FUNC_SAI3_FS_B 0x3a07
+#define STM32H7_PD10_FUNC_USART3_CK 0x3a08
+#define STM32H7_PD10_FUNC_CAN2_TXFD 0x3a0a
+#define STM32H7_PD10_FUNC_FMC_D15_FMC_DA15 0x3a0d
+#define STM32H7_PD10_FUNC_LCD_B3 0x3a0f
+#define STM32H7_PD10_FUNC_EVENTOUT 0x3a10
+#define STM32H7_PD10_FUNC_ANALOG 0x3a11
+
+#define STM32H7_PD11_FUNC_GPIO 0x3b00
+#define STM32H7_PD11_FUNC_LPTIM2_IN2 0x3b04
+#define STM32H7_PD11_FUNC_I2C4_SMBA 0x3b05
+#define STM32H7_PD11_FUNC_USART3_CTS_NSS 0x3b08
+#define STM32H7_PD11_FUNC_QUADSPI_BK1_IO0 0x3b0a
+#define STM32H7_PD11_FUNC_SAI2_SD_A 0x3b0b
+#define STM32H7_PD11_FUNC_FMC_A16 0x3b0d
+#define STM32H7_PD11_FUNC_EVENTOUT 0x3b10
+#define STM32H7_PD11_FUNC_ANALOG 0x3b11
+
+#define STM32H7_PD12_FUNC_GPIO 0x3c00
+#define STM32H7_PD12_FUNC_LPTIM1_IN1 0x3c02
+#define STM32H7_PD12_FUNC_TIM4_CH1 0x3c03
+#define STM32H7_PD12_FUNC_LPTIM2_IN1 0x3c04
+#define STM32H7_PD12_FUNC_I2C4_SCL 0x3c05
+#define STM32H7_PD12_FUNC_USART3_RTS 0x3c08
+#define STM32H7_PD12_FUNC_QUADSPI_BK1_IO1 0x3c0a
+#define STM32H7_PD12_FUNC_SAI2_FS_A 0x3c0b
+#define STM32H7_PD12_FUNC_FMC_A17 0x3c0d
+#define STM32H7_PD12_FUNC_EVENTOUT 0x3c10
+#define STM32H7_PD12_FUNC_ANALOG 0x3c11
+
+#define STM32H7_PD13_FUNC_GPIO 0x3d00
+#define STM32H7_PD13_FUNC_LPTIM1_OUT 0x3d02
+#define STM32H7_PD13_FUNC_TIM4_CH2 0x3d03
+#define STM32H7_PD13_FUNC_I2C4_SDA 0x3d05
+#define STM32H7_PD13_FUNC_QUADSPI_BK1_IO3 0x3d0a
+#define STM32H7_PD13_FUNC_SAI2_SCK_A 0x3d0b
+#define STM32H7_PD13_FUNC_FMC_A18 0x3d0d
+#define STM32H7_PD13_FUNC_EVENTOUT 0x3d10
+#define STM32H7_PD13_FUNC_ANALOG 0x3d11
+
+#define STM32H7_PD14_FUNC_GPIO 0x3e00
+#define STM32H7_PD14_FUNC_TIM4_CH3 0x3e03
+#define STM32H7_PD14_FUNC_SAI3_MCLK_B 0x3e07
+#define STM32H7_PD14_FUNC_UART8_CTS 0x3e09
+#define STM32H7_PD14_FUNC_FMC_D0_FMC_DA0 0x3e0d
+#define STM32H7_PD14_FUNC_EVENTOUT 0x3e10
+#define STM32H7_PD14_FUNC_ANALOG 0x3e11
+
+#define STM32H7_PD15_FUNC_GPIO 0x3f00
+#define STM32H7_PD15_FUNC_TIM4_CH4 0x3f03
+#define STM32H7_PD15_FUNC_SAI3_MCLK_A 0x3f07
+#define STM32H7_PD15_FUNC_UART8_RTS 0x3f09
+#define STM32H7_PD15_FUNC_FMC_D1_FMC_DA1 0x3f0d
+#define STM32H7_PD15_FUNC_EVENTOUT 0x3f10
+#define STM32H7_PD15_FUNC_ANALOG 0x3f11
+
+#define STM32H7_PE0_FUNC_GPIO 0x4000
+#define STM32H7_PE0_FUNC_LPTIM1_ETR 0x4002
+#define STM32H7_PE0_FUNC_TIM4_ETR 0x4003
+#define STM32H7_PE0_FUNC_HRTIM_SCIN 0x4004
+#define STM32H7_PE0_FUNC_LPTIM2_ETR 0x4005
+#define STM32H7_PE0_FUNC_UART8_RX 0x4009
+#define STM32H7_PE0_FUNC_CAN1_RXFD 0x400a
+#define STM32H7_PE0_FUNC_SAI2_MCK_A 0x400b
+#define STM32H7_PE0_FUNC_FMC_NBL0 0x400d
+#define STM32H7_PE0_FUNC_DCMI_D2 0x400e
+#define STM32H7_PE0_FUNC_EVENTOUT 0x4010
+#define STM32H7_PE0_FUNC_ANALOG 0x4011
+
+#define STM32H7_PE1_FUNC_GPIO 0x4100
+#define STM32H7_PE1_FUNC_LPTIM1_IN2 0x4102
+#define STM32H7_PE1_FUNC_HRTIM_SCOUT 0x4104
+#define STM32H7_PE1_FUNC_UART8_TX 0x4109
+#define STM32H7_PE1_FUNC_CAN1_TXFD 0x410a
+#define STM32H7_PE1_FUNC_FMC_NBL1 0x410d
+#define STM32H7_PE1_FUNC_DCMI_D3 0x410e
+#define STM32H7_PE1_FUNC_EVENTOUT 0x4110
+#define STM32H7_PE1_FUNC_ANALOG 0x4111
+
+#define STM32H7_PE2_FUNC_GPIO 0x4200
+#define STM32H7_PE2_FUNC_TRACECLK 0x4201
+#define STM32H7_PE2_FUNC_SAI1_CK1 0x4203
+#define STM32H7_PE2_FUNC_SPI4_SCK 0x4206
+#define STM32H7_PE2_FUNC_SAI1_MCLK_A 0x4207
+#define STM32H7_PE2_FUNC_SAI4_MCLK_A 0x4209
+#define STM32H7_PE2_FUNC_QUADSPI_BK1_IO2 0x420a
+#define STM32H7_PE2_FUNC_SAI4_CK1 0x420b
+#define STM32H7_PE2_FUNC_ETH_MII_TXD3 0x420c
+#define STM32H7_PE2_FUNC_FMC_A23 0x420d
+#define STM32H7_PE2_FUNC_EVENTOUT 0x4210
+#define STM32H7_PE2_FUNC_ANALOG 0x4211
+
+#define STM32H7_PE3_FUNC_GPIO 0x4300
+#define STM32H7_PE3_FUNC_TRACED0 0x4301
+#define STM32H7_PE3_FUNC_TIM15_BKIN 0x4305
+#define STM32H7_PE3_FUNC_SAI1_SD_B 0x4307
+#define STM32H7_PE3_FUNC_SAI4_SD_B 0x4309
+#define STM32H7_PE3_FUNC_FMC_A19 0x430d
+#define STM32H7_PE3_FUNC_EVENTOUT 0x4310
+#define STM32H7_PE3_FUNC_ANALOG 0x4311
+
+#define STM32H7_PE4_FUNC_GPIO 0x4400
+#define STM32H7_PE4_FUNC_TRACED1 0x4401
+#define STM32H7_PE4_FUNC_SAI1_D2 0x4403
+#define STM32H7_PE4_FUNC_DFSDM_DATIN3 0x4404
+#define STM32H7_PE4_FUNC_TIM15_CH1N 0x4405
+#define STM32H7_PE4_FUNC_SPI4_NSS 0x4406
+#define STM32H7_PE4_FUNC_SAI1_FS_A 0x4407
+#define STM32H7_PE4_FUNC_SAI4_FS_A 0x4409
+#define STM32H7_PE4_FUNC_SAI4_D2 0x440b
+#define STM32H7_PE4_FUNC_FMC_A20 0x440d
+#define STM32H7_PE4_FUNC_DCMI_D4 0x440e
+#define STM32H7_PE4_FUNC_LCD_B0 0x440f
+#define STM32H7_PE4_FUNC_EVENTOUT 0x4410
+#define STM32H7_PE4_FUNC_ANALOG 0x4411
+
+#define STM32H7_PE5_FUNC_GPIO 0x4500
+#define STM32H7_PE5_FUNC_TRACED2 0x4501
+#define STM32H7_PE5_FUNC_SAI1_CK2 0x4503
+#define STM32H7_PE5_FUNC_DFSDM_CKIN3 0x4504
+#define STM32H7_PE5_FUNC_TIM15_CH1 0x4505
+#define STM32H7_PE5_FUNC_SPI4_MISO 0x4506
+#define STM32H7_PE5_FUNC_SAI1_SCK_A 0x4507
+#define STM32H7_PE5_FUNC_SAI4_SCK_A 0x4509
+#define STM32H7_PE5_FUNC_SAI4_CK2 0x450b
+#define STM32H7_PE5_FUNC_FMC_A21 0x450d
+#define STM32H7_PE5_FUNC_DCMI_D6 0x450e
+#define STM32H7_PE5_FUNC_LCD_G0 0x450f
+#define STM32H7_PE5_FUNC_EVENTOUT 0x4510
+#define STM32H7_PE5_FUNC_ANALOG 0x4511
+
+#define STM32H7_PE6_FUNC_GPIO 0x4600
+#define STM32H7_PE6_FUNC_TRACED3 0x4601
+#define STM32H7_PE6_FUNC_TIM1_BKIN2 0x4602
+#define STM32H7_PE6_FUNC_SAI1_D1 0x4603
+#define STM32H7_PE6_FUNC_TIM15_CH2 0x4605
+#define STM32H7_PE6_FUNC_SPI4_MOSI 0x4606
+#define STM32H7_PE6_FUNC_SAI1_SD_A 0x4607
+#define STM32H7_PE6_FUNC_SAI4_SD_A 0x4609
+#define STM32H7_PE6_FUNC_SAI4_D1 0x460a
+#define STM32H7_PE6_FUNC_SAI2_MCK_B 0x460b
+#define STM32H7_PE6_FUNC_TIM1_BKIN2_COMP12 0x460c
+#define STM32H7_PE6_FUNC_FMC_A22 0x460d
+#define STM32H7_PE6_FUNC_DCMI_D7 0x460e
+#define STM32H7_PE6_FUNC_LCD_G1 0x460f
+#define STM32H7_PE6_FUNC_EVENTOUT 0x4610
+#define STM32H7_PE6_FUNC_ANALOG 0x4611
+
+#define STM32H7_PE7_FUNC_GPIO 0x4700
+#define STM32H7_PE7_FUNC_TIM1_ETR 0x4702
+#define STM32H7_PE7_FUNC_DFSDM_DATIN2 0x4704
+#define STM32H7_PE7_FUNC_UART7_RX 0x4708
+#define STM32H7_PE7_FUNC_QUADSPI_BK2_IO0 0x470b
+#define STM32H7_PE7_FUNC_FMC_D4_FMC_DA4 0x470d
+#define STM32H7_PE7_FUNC_EVENTOUT 0x4710
+#define STM32H7_PE7_FUNC_ANALOG 0x4711
+
+#define STM32H7_PE8_FUNC_GPIO 0x4800
+#define STM32H7_PE8_FUNC_TIM1_CH1N 0x4802
+#define STM32H7_PE8_FUNC_DFSDM_CKIN2 0x4804
+#define STM32H7_PE8_FUNC_UART7_TX 0x4808
+#define STM32H7_PE8_FUNC_QUADSPI_BK2_IO1 0x480b
+#define STM32H7_PE8_FUNC_FMC_D5_FMC_DA5 0x480d
+#define STM32H7_PE8_FUNC_COMP_2_OUT 0x480e
+#define STM32H7_PE8_FUNC_EVENTOUT 0x4810
+#define STM32H7_PE8_FUNC_ANALOG 0x4811
+
+#define STM32H7_PE9_FUNC_GPIO 0x4900
+#define STM32H7_PE9_FUNC_TIM1_CH1 0x4902
+#define STM32H7_PE9_FUNC_DFSDM_CKOUT 0x4904
+#define STM32H7_PE9_FUNC_UART7_RTS 0x4908
+#define STM32H7_PE9_FUNC_QUADSPI_BK2_IO2 0x490b
+#define STM32H7_PE9_FUNC_FMC_D6_FMC_DA6 0x490d
+#define STM32H7_PE9_FUNC_EVENTOUT 0x4910
+#define STM32H7_PE9_FUNC_ANALOG 0x4911
+
+#define STM32H7_PE10_FUNC_GPIO 0x4a00
+#define STM32H7_PE10_FUNC_TIM1_CH2N 0x4a02
+#define STM32H7_PE10_FUNC_DFSDM_DATIN4 0x4a04
+#define STM32H7_PE10_FUNC_UART7_CTS 0x4a08
+#define STM32H7_PE10_FUNC_QUADSPI_BK2_IO3 0x4a0b
+#define STM32H7_PE10_FUNC_FMC_D7_FMC_DA7 0x4a0d
+#define STM32H7_PE10_FUNC_EVENTOUT 0x4a10
+#define STM32H7_PE10_FUNC_ANALOG 0x4a11
+
+#define STM32H7_PE11_FUNC_GPIO 0x4b00
+#define STM32H7_PE11_FUNC_TIM1_CH2 0x4b02
+#define STM32H7_PE11_FUNC_DFSDM_CKIN4 0x4b04
+#define STM32H7_PE11_FUNC_SPI4_NSS 0x4b06
+#define STM32H7_PE11_FUNC_SAI2_SD_B 0x4b0b
+#define STM32H7_PE11_FUNC_FMC_D8_FMC_DA8 0x4b0d
+#define STM32H7_PE11_FUNC_LCD_G3 0x4b0f
+#define STM32H7_PE11_FUNC_EVENTOUT 0x4b10
+#define STM32H7_PE11_FUNC_ANALOG 0x4b11
+
+#define STM32H7_PE12_FUNC_GPIO 0x4c00
+#define STM32H7_PE12_FUNC_TIM1_CH3N 0x4c02
+#define STM32H7_PE12_FUNC_DFSDM_DATIN5 0x4c04
+#define STM32H7_PE12_FUNC_SPI4_SCK 0x4c06
+#define STM32H7_PE12_FUNC_SAI2_SCK_B 0x4c0b
+#define STM32H7_PE12_FUNC_FMC_D9_FMC_DA9 0x4c0d
+#define STM32H7_PE12_FUNC_COMP_1_OUT 0x4c0e
+#define STM32H7_PE12_FUNC_LCD_B4 0x4c0f
+#define STM32H7_PE12_FUNC_EVENTOUT 0x4c10
+#define STM32H7_PE12_FUNC_ANALOG 0x4c11
+
+#define STM32H7_PE13_FUNC_GPIO 0x4d00
+#define STM32H7_PE13_FUNC_TIM1_CH3 0x4d02
+#define STM32H7_PE13_FUNC_DFSDM_CKIN5 0x4d04
+#define STM32H7_PE13_FUNC_SPI4_MISO 0x4d06
+#define STM32H7_PE13_FUNC_SAI2_FS_B 0x4d0b
+#define STM32H7_PE13_FUNC_FMC_D10_FMC_DA10 0x4d0d
+#define STM32H7_PE13_FUNC_COMP_2_OUT 0x4d0e
+#define STM32H7_PE13_FUNC_LCD_DE 0x4d0f
+#define STM32H7_PE13_FUNC_EVENTOUT 0x4d10
+#define STM32H7_PE13_FUNC_ANALOG 0x4d11
+
+#define STM32H7_PE14_FUNC_GPIO 0x4e00
+#define STM32H7_PE14_FUNC_TIM1_CH4 0x4e02
+#define STM32H7_PE14_FUNC_SPI4_MOSI 0x4e06
+#define STM32H7_PE14_FUNC_SAI2_MCK_B 0x4e0b
+#define STM32H7_PE14_FUNC_FMC_D11_FMC_DA11 0x4e0d
+#define STM32H7_PE14_FUNC_LCD_CLK 0x4e0f
+#define STM32H7_PE14_FUNC_EVENTOUT 0x4e10
+#define STM32H7_PE14_FUNC_ANALOG 0x4e11
+
+#define STM32H7_PE15_FUNC_GPIO 0x4f00
+#define STM32H7_PE15_FUNC_TIM1_BKIN 0x4f02
+#define STM32H7_PE15_FUNC_HDMI__TIM1_BKIN 0x4f06
+#define STM32H7_PE15_FUNC_FMC_D12_FMC_DA12 0x4f0d
+#define STM32H7_PE15_FUNC_TIM1_BKIN_COMP12 0x4f0e
+#define STM32H7_PE15_FUNC_LCD_R7 0x4f0f
+#define STM32H7_PE15_FUNC_EVENTOUT 0x4f10
+#define STM32H7_PE15_FUNC_ANALOG 0x4f11
+
+#define STM32H7_PF0_FUNC_GPIO 0x5000
+#define STM32H7_PF0_FUNC_I2C2_SDA 0x5005
+#define STM32H7_PF0_FUNC_FMC_A0 0x500d
+#define STM32H7_PF0_FUNC_EVENTOUT 0x5010
+#define STM32H7_PF0_FUNC_ANALOG 0x5011
+
+#define STM32H7_PF1_FUNC_GPIO 0x5100
+#define STM32H7_PF1_FUNC_I2C2_SCL 0x5105
+#define STM32H7_PF1_FUNC_FMC_A1 0x510d
+#define STM32H7_PF1_FUNC_EVENTOUT 0x5110
+#define STM32H7_PF1_FUNC_ANALOG 0x5111
+
+#define STM32H7_PF2_FUNC_GPIO 0x5200
+#define STM32H7_PF2_FUNC_I2C2_SMBA 0x5205
+#define STM32H7_PF2_FUNC_FMC_A2 0x520d
+#define STM32H7_PF2_FUNC_EVENTOUT 0x5210
+#define STM32H7_PF2_FUNC_ANALOG 0x5211
+
+#define STM32H7_PF3_FUNC_GPIO 0x5300
+#define STM32H7_PF3_FUNC_FMC_A3 0x530d
+#define STM32H7_PF3_FUNC_EVENTOUT 0x5310
+#define STM32H7_PF3_FUNC_ANALOG 0x5311
+
+#define STM32H7_PF4_FUNC_GPIO 0x5400
+#define STM32H7_PF4_FUNC_FMC_A4 0x540d
+#define STM32H7_PF4_FUNC_EVENTOUT 0x5410
+#define STM32H7_PF4_FUNC_ANALOG 0x5411
+
+#define STM32H7_PF5_FUNC_GPIO 0x5500
+#define STM32H7_PF5_FUNC_FMC_A5 0x550d
+#define STM32H7_PF5_FUNC_EVENTOUT 0x5510
+#define STM32H7_PF5_FUNC_ANALOG 0x5511
+
+#define STM32H7_PF6_FUNC_GPIO 0x5600
+#define STM32H7_PF6_FUNC_TIM16_CH1 0x5602
+#define STM32H7_PF6_FUNC_SPI5_NSS 0x5606
+#define STM32H7_PF6_FUNC_SAI1_SD_B 0x5607
+#define STM32H7_PF6_FUNC_UART7_RX 0x5608
+#define STM32H7_PF6_FUNC_SAI4_SD_B 0x5609
+#define STM32H7_PF6_FUNC_QUADSPI_BK1_IO3 0x560a
+#define STM32H7_PF6_FUNC_EVENTOUT 0x5610
+#define STM32H7_PF6_FUNC_ANALOG 0x5611
+
+#define STM32H7_PF7_FUNC_GPIO 0x5700
+#define STM32H7_PF7_FUNC_TIM17_CH1 0x5702
+#define STM32H7_PF7_FUNC_SPI5_SCK 0x5706
+#define STM32H7_PF7_FUNC_SAI1_MCLK_B 0x5707
+#define STM32H7_PF7_FUNC_UART7_TX 0x5708
+#define STM32H7_PF7_FUNC_SAI4_MCLK_B 0x5709
+#define STM32H7_PF7_FUNC_QUADSPI_BK1_IO2 0x570a
+#define STM32H7_PF7_FUNC_EVENTOUT 0x5710
+#define STM32H7_PF7_FUNC_ANALOG 0x5711
+
+#define STM32H7_PF8_FUNC_GPIO 0x5800
+#define STM32H7_PF8_FUNC_TIM16_CH1N 0x5802
+#define STM32H7_PF8_FUNC_SPI5_MISO 0x5806
+#define STM32H7_PF8_FUNC_SAI1_SCK_B 0x5807
+#define STM32H7_PF8_FUNC_UART7_RTS 0x5808
+#define STM32H7_PF8_FUNC_SAI4_SCK_B 0x5809
+#define STM32H7_PF8_FUNC_TIM13_CH1 0x580a
+#define STM32H7_PF8_FUNC_QUADSPI_BK1_IO0 0x580b
+#define STM32H7_PF8_FUNC_EVENTOUT 0x5810
+#define STM32H7_PF8_FUNC_ANALOG 0x5811
+
+#define STM32H7_PF9_FUNC_GPIO 0x5900
+#define STM32H7_PF9_FUNC_TIM17_CH1N 0x5902
+#define STM32H7_PF9_FUNC_SPI5_MOSI 0x5906
+#define STM32H7_PF9_FUNC_SAI1_FS_B 0x5907
+#define STM32H7_PF9_FUNC_UART7_CTS 0x5908
+#define STM32H7_PF9_FUNC_SAI4_FS_B 0x5909
+#define STM32H7_PF9_FUNC_TIM14_CH1 0x590a
+#define STM32H7_PF9_FUNC_QUADSPI_BK1_IO1 0x590b
+#define STM32H7_PF9_FUNC_EVENTOUT 0x5910
+#define STM32H7_PF9_FUNC_ANALOG 0x5911
+
+#define STM32H7_PF10_FUNC_GPIO 0x5a00
+#define STM32H7_PF10_FUNC_TIM16_BKIN 0x5a02
+#define STM32H7_PF10_FUNC_SAI1_D3 0x5a03
+#define STM32H7_PF10_FUNC_QUADSPI_CLK 0x5a0a
+#define STM32H7_PF10_FUNC_SAI4_D3 0x5a0b
+#define STM32H7_PF10_FUNC_DCMI_D11 0x5a0e
+#define STM32H7_PF10_FUNC_LCD_DE 0x5a0f
+#define STM32H7_PF10_FUNC_EVENTOUT 0x5a10
+#define STM32H7_PF10_FUNC_ANALOG 0x5a11
+
+#define STM32H7_PF11_FUNC_GPIO 0x5b00
+#define STM32H7_PF11_FUNC_SPI5_MOSI 0x5b06
+#define STM32H7_PF11_FUNC_SAI2_SD_B 0x5b0b
+#define STM32H7_PF11_FUNC_FMC_SDNRAS 0x5b0d
+#define STM32H7_PF11_FUNC_DCMI_D12 0x5b0e
+#define STM32H7_PF11_FUNC_EVENTOUT 0x5b10
+#define STM32H7_PF11_FUNC_ANALOG 0x5b11
+
+#define STM32H7_PF12_FUNC_GPIO 0x5c00
+#define STM32H7_PF12_FUNC_FMC_A6 0x5c0d
+#define STM32H7_PF12_FUNC_EVENTOUT 0x5c10
+#define STM32H7_PF12_FUNC_ANALOG 0x5c11
+
+#define STM32H7_PF13_FUNC_GPIO 0x5d00
+#define STM32H7_PF13_FUNC_DFSDM_DATIN6 0x5d04
+#define STM32H7_PF13_FUNC_I2C4_SMBA 0x5d05
+#define STM32H7_PF13_FUNC_FMC_A7 0x5d0d
+#define STM32H7_PF13_FUNC_EVENTOUT 0x5d10
+#define STM32H7_PF13_FUNC_ANALOG 0x5d11
+
+#define STM32H7_PF14_FUNC_GPIO 0x5e00
+#define STM32H7_PF14_FUNC_DFSDM_CKIN6 0x5e04
+#define STM32H7_PF14_FUNC_I2C4_SCL 0x5e05
+#define STM32H7_PF14_FUNC_FMC_A8 0x5e0d
+#define STM32H7_PF14_FUNC_EVENTOUT 0x5e10
+#define STM32H7_PF14_FUNC_ANALOG 0x5e11
+
+#define STM32H7_PF15_FUNC_GPIO 0x5f00
+#define STM32H7_PF15_FUNC_I2C4_SDA 0x5f05
+#define STM32H7_PF15_FUNC_FMC_A9 0x5f0d
+#define STM32H7_PF15_FUNC_EVENTOUT 0x5f10
+#define STM32H7_PF15_FUNC_ANALOG 0x5f11
+
+#define STM32H7_PG0_FUNC_GPIO 0x6000
+#define STM32H7_PG0_FUNC_FMC_A10 0x600d
+#define STM32H7_PG0_FUNC_EVENTOUT 0x6010
+#define STM32H7_PG0_FUNC_ANALOG 0x6011
+
+#define STM32H7_PG1_FUNC_GPIO 0x6100
+#define STM32H7_PG1_FUNC_FMC_A11 0x610d
+#define STM32H7_PG1_FUNC_EVENTOUT 0x6110
+#define STM32H7_PG1_FUNC_ANALOG 0x6111
+
+#define STM32H7_PG2_FUNC_GPIO 0x6200
+#define STM32H7_PG2_FUNC_TIM8_BKIN 0x6204
+#define STM32H7_PG2_FUNC_TIM8_BKIN_COMP12 0x620c
+#define STM32H7_PG2_FUNC_FMC_A12 0x620d
+#define STM32H7_PG2_FUNC_EVENTOUT 0x6210
+#define STM32H7_PG2_FUNC_ANALOG 0x6211
+
+#define STM32H7_PG3_FUNC_GPIO 0x6300
+#define STM32H7_PG3_FUNC_TIM8_BKIN2 0x6304
+#define STM32H7_PG3_FUNC_TIM8_BKIN2_COMP12 0x630c
+#define STM32H7_PG3_FUNC_FMC_A13 0x630d
+#define STM32H7_PG3_FUNC_EVENTOUT 0x6310
+#define STM32H7_PG3_FUNC_ANALOG 0x6311
+
+#define STM32H7_PG4_FUNC_GPIO 0x6400
+#define STM32H7_PG4_FUNC_TIM1_BKIN2 0x6402
+#define STM32H7_PG4_FUNC_TIM1_BKIN2_COMP12 0x640c
+#define STM32H7_PG4_FUNC_FMC_A14_FMC_BA0 0x640d
+#define STM32H7_PG4_FUNC_EVENTOUT 0x6410
+#define STM32H7_PG4_FUNC_ANALOG 0x6411
+
+#define STM32H7_PG5_FUNC_GPIO 0x6500
+#define STM32H7_PG5_FUNC_TIM1_ETR 0x6502
+#define STM32H7_PG5_FUNC_FMC_A15_FMC_BA1 0x650d
+#define STM32H7_PG5_FUNC_EVENTOUT 0x6510
+#define STM32H7_PG5_FUNC_ANALOG 0x6511
+
+#define STM32H7_PG6_FUNC_GPIO 0x6600
+#define STM32H7_PG6_FUNC_TIM17_BKIN 0x6602
+#define STM32H7_PG6_FUNC_HRTIM_CHE1 0x6603
+#define STM32H7_PG6_FUNC_QUADSPI_BK1_NCS 0x660b
+#define STM32H7_PG6_FUNC_FMC_NE3 0x660d
+#define STM32H7_PG6_FUNC_DCMI_D12 0x660e
+#define STM32H7_PG6_FUNC_LCD_R7 0x660f
+#define STM32H7_PG6_FUNC_EVENTOUT 0x6610
+#define STM32H7_PG6_FUNC_ANALOG 0x6611
+
+#define STM32H7_PG7_FUNC_GPIO 0x6700
+#define STM32H7_PG7_FUNC_HRTIM_CHE2 0x6703
+#define STM32H7_PG7_FUNC_SAI1_MCLK_A 0x6707
+#define STM32H7_PG7_FUNC_USART6_CK 0x6708
+#define STM32H7_PG7_FUNC_FMC_INT 0x670d
+#define STM32H7_PG7_FUNC_DCMI_D13 0x670e
+#define STM32H7_PG7_FUNC_LCD_CLK 0x670f
+#define STM32H7_PG7_FUNC_EVENTOUT 0x6710
+#define STM32H7_PG7_FUNC_ANALOG 0x6711
+
+#define STM32H7_PG8_FUNC_GPIO 0x6800
+#define STM32H7_PG8_FUNC_TIM8_ETR 0x6804
+#define STM32H7_PG8_FUNC_SPI6_NSS 0x6806
+#define STM32H7_PG8_FUNC_USART6_RTS 0x6808
+#define STM32H7_PG8_FUNC_SPDIFRX_IN2 0x6809
+#define STM32H7_PG8_FUNC_ETH_PPS_OUT 0x680c
+#define STM32H7_PG8_FUNC_FMC_SDCLK 0x680d
+#define STM32H7_PG8_FUNC_LCD_G7 0x680f
+#define STM32H7_PG8_FUNC_EVENTOUT 0x6810
+#define STM32H7_PG8_FUNC_ANALOG 0x6811
+
+#define STM32H7_PG9_FUNC_GPIO 0x6900
+#define STM32H7_PG9_FUNC_SPI1_MISO_I2S1_SDI 0x6906
+#define STM32H7_PG9_FUNC_USART6_RX 0x6908
+#define STM32H7_PG9_FUNC_SPDIFRX_IN3 0x6909
+#define STM32H7_PG9_FUNC_QUADSPI_BK2_IO2 0x690a
+#define STM32H7_PG9_FUNC_SAI2_FS_B 0x690b
+#define STM32H7_PG9_FUNC_FMC_NE2_FMC_NCE 0x690d
+#define STM32H7_PG9_FUNC_DCMI_VSYNC 0x690e
+#define STM32H7_PG9_FUNC_EVENTOUT 0x6910
+#define STM32H7_PG9_FUNC_ANALOG 0x6911
+
+#define STM32H7_PG10_FUNC_GPIO 0x6a00
+#define STM32H7_PG10_FUNC_HRTIM_FLT5 0x6a03
+#define STM32H7_PG10_FUNC_SPI1_NSS_I2S1_WS 0x6a06
+#define STM32H7_PG10_FUNC_LCD_G3 0x6a0a
+#define STM32H7_PG10_FUNC_SAI2_SD_B 0x6a0b
+#define STM32H7_PG10_FUNC_FMC_NE3 0x6a0d
+#define STM32H7_PG10_FUNC_DCMI_D2 0x6a0e
+#define STM32H7_PG10_FUNC_LCD_B2 0x6a0f
+#define STM32H7_PG10_FUNC_EVENTOUT 0x6a10
+#define STM32H7_PG10_FUNC_ANALOG 0x6a11
+
+#define STM32H7_PG11_FUNC_GPIO 0x6b00
+#define STM32H7_PG11_FUNC_HRTIM_EEV4 0x6b03
+#define STM32H7_PG11_FUNC_SPI1_SCK_I2S1_CK 0x6b06
+#define STM32H7_PG11_FUNC_SPDIFRX_IN0 0x6b09
+#define STM32H7_PG11_FUNC_SDMMC2_D2 0x6b0b
+#define STM32H7_PG11_FUNC_ETH_MII_TX_EN_ETH_RMII_TX_EN 0x6b0c
+#define STM32H7_PG11_FUNC_DCMI_D3 0x6b0e
+#define STM32H7_PG11_FUNC_LCD_B3 0x6b0f
+#define STM32H7_PG11_FUNC_EVENTOUT 0x6b10
+#define STM32H7_PG11_FUNC_ANALOG 0x6b11
+
+#define STM32H7_PG12_FUNC_GPIO 0x6c00
+#define STM32H7_PG12_FUNC_LPTIM1_IN1 0x6c02
+#define STM32H7_PG12_FUNC_HRTIM_EEV5 0x6c03
+#define STM32H7_PG12_FUNC_SPI6_MISO 0x6c06
+#define STM32H7_PG12_FUNC_USART6_RTS 0x6c08
+#define STM32H7_PG12_FUNC_SPDIFRX_IN1 0x6c09
+#define STM32H7_PG12_FUNC_LCD_B4 0x6c0a
+#define STM32H7_PG12_FUNC_ETH_MII_TXD1_ETH_RMII_TXD1 0x6c0c
+#define STM32H7_PG12_FUNC_FMC_NE4 0x6c0d
+#define STM32H7_PG12_FUNC_LCD_B1 0x6c0f
+#define STM32H7_PG12_FUNC_EVENTOUT 0x6c10
+#define STM32H7_PG12_FUNC_ANALOG 0x6c11
+
+#define STM32H7_PG13_FUNC_GPIO 0x6d00
+#define STM32H7_PG13_FUNC_TRACED0 0x6d01
+#define STM32H7_PG13_FUNC_LPTIM1_OUT 0x6d02
+#define STM32H7_PG13_FUNC_HRTIM_EEV10 0x6d03
+#define STM32H7_PG13_FUNC_SPI6_SCK 0x6d06
+#define STM32H7_PG13_FUNC_USART6_CTS_NSS 0x6d08
+#define STM32H7_PG13_FUNC_ETH_MII_TXD0_ETH_RMII_TXD0 0x6d0c
+#define STM32H7_PG13_FUNC_FMC_A24 0x6d0d
+#define STM32H7_PG13_FUNC_LCD_R0 0x6d0f
+#define STM32H7_PG13_FUNC_EVENTOUT 0x6d10
+#define STM32H7_PG13_FUNC_ANALOG 0x6d11
+
+#define STM32H7_PG14_FUNC_GPIO 0x6e00
+#define STM32H7_PG14_FUNC_TRACED1 0x6e01
+#define STM32H7_PG14_FUNC_LPTIM1_ETR 0x6e02
+#define STM32H7_PG14_FUNC_SPI6_MOSI 0x6e06
+#define STM32H7_PG14_FUNC_USART6_TX 0x6e08
+#define STM32H7_PG14_FUNC_QUADSPI_BK2_IO3 0x6e0a
+#define STM32H7_PG14_FUNC_ETH_MII_TXD1_ETH_RMII_TXD1 0x6e0c
+#define STM32H7_PG14_FUNC_FMC_A25 0x6e0d
+#define STM32H7_PG14_FUNC_LCD_B0 0x6e0f
+#define STM32H7_PG14_FUNC_EVENTOUT 0x6e10
+#define STM32H7_PG14_FUNC_ANALOG 0x6e11
+
+#define STM32H7_PG15_FUNC_GPIO 0x6f00
+#define STM32H7_PG15_FUNC_USART6_CTS_NSS 0x6f08
+#define STM32H7_PG15_FUNC_FMC_SDNCAS 0x6f0d
+#define STM32H7_PG15_FUNC_DCMI_D13 0x6f0e
+#define STM32H7_PG15_FUNC_EVENTOUT 0x6f10
+#define STM32H7_PG15_FUNC_ANALOG 0x6f11
+
+#define STM32H7_PH0_FUNC_GPIO 0x7000
+#define STM32H7_PH0_FUNC_EVENTOUT 0x7010
+#define STM32H7_PH0_FUNC_ANALOG 0x7011
+
+#define STM32H7_PH1_FUNC_GPIO 0x7100
+#define STM32H7_PH1_FUNC_EVENTOUT 0x7110
+#define STM32H7_PH1_FUNC_ANALOG 0x7111
+
+#define STM32H7_PH2_FUNC_GPIO 0x7200
+#define STM32H7_PH2_FUNC_LPTIM1_IN2 0x7202
+#define STM32H7_PH2_FUNC_QUADSPI_BK2_IO0 0x720a
+#define STM32H7_PH2_FUNC_SAI2_SCK_B 0x720b
+#define STM32H7_PH2_FUNC_ETH_MII_CRS 0x720c
+#define STM32H7_PH2_FUNC_FMC_SDCKE0 0x720d
+#define STM32H7_PH2_FUNC_LCD_R0 0x720f
+#define STM32H7_PH2_FUNC_EVENTOUT 0x7210
+#define STM32H7_PH2_FUNC_ANALOG 0x7211
+
+#define STM32H7_PH3_FUNC_GPIO 0x7300
+#define STM32H7_PH3_FUNC_QUADSPI_BK2_IO1 0x730a
+#define STM32H7_PH3_FUNC_SAI2_MCK_B 0x730b
+#define STM32H7_PH3_FUNC_ETH_MII_COL 0x730c
+#define STM32H7_PH3_FUNC_FMC_SDNE0 0x730d
+#define STM32H7_PH3_FUNC_LCD_R1 0x730f
+#define STM32H7_PH3_FUNC_EVENTOUT 0x7310
+#define STM32H7_PH3_FUNC_ANALOG 0x7311
+
+#define STM32H7_PH4_FUNC_GPIO 0x7400
+#define STM32H7_PH4_FUNC_I2C2_SCL 0x7405
+#define STM32H7_PH4_FUNC_LCD_G5 0x740a
+#define STM32H7_PH4_FUNC_OTG_HS_ULPI_NXT 0x740b
+#define STM32H7_PH4_FUNC_LCD_G4 0x740f
+#define STM32H7_PH4_FUNC_EVENTOUT 0x7410
+#define STM32H7_PH4_FUNC_ANALOG 0x7411
+
+#define STM32H7_PH5_FUNC_GPIO 0x7500
+#define STM32H7_PH5_FUNC_I2C2_SDA 0x7505
+#define STM32H7_PH5_FUNC_SPI5_NSS 0x7506
+#define STM32H7_PH5_FUNC_FMC_SDNWE 0x750d
+#define STM32H7_PH5_FUNC_EVENTOUT 0x7510
+#define STM32H7_PH5_FUNC_ANALOG 0x7511
+
+#define STM32H7_PH6_FUNC_GPIO 0x7600
+#define STM32H7_PH6_FUNC_I2C2_SMBA 0x7605
+#define STM32H7_PH6_FUNC_SPI5_SCK 0x7606
+#define STM32H7_PH6_FUNC_ETH_MII_RXD2 0x760c
+#define STM32H7_PH6_FUNC_FMC_SDNE1 0x760d
+#define STM32H7_PH6_FUNC_DCMI_D8 0x760e
+#define STM32H7_PH6_FUNC_EVENTOUT 0x7610
+#define STM32H7_PH6_FUNC_ANALOG 0x7611
+
+#define STM32H7_PH7_FUNC_GPIO 0x7700
+#define STM32H7_PH7_FUNC_I2C3_SCL 0x7705
+#define STM32H7_PH7_FUNC_SPI5_MISO 0x7706
+#define STM32H7_PH7_FUNC_ETH_MII_RXD3 0x770c
+#define STM32H7_PH7_FUNC_FMC_SDCKE1 0x770d
+#define STM32H7_PH7_FUNC_DCMI_D9 0x770e
+#define STM32H7_PH7_FUNC_EVENTOUT 0x7710
+#define STM32H7_PH7_FUNC_ANALOG 0x7711
+
+#define STM32H7_PH8_FUNC_GPIO 0x7800
+#define STM32H7_PH8_FUNC_TIM5_ETR 0x7803
+#define STM32H7_PH8_FUNC_I2C3_SDA 0x7805
+#define STM32H7_PH8_FUNC_FMC_D16 0x780d
+#define STM32H7_PH8_FUNC_DCMI_HSYNC 0x780e
+#define STM32H7_PH8_FUNC_LCD_R2 0x780f
+#define STM32H7_PH8_FUNC_EVENTOUT 0x7810
+#define STM32H7_PH8_FUNC_ANALOG 0x7811
+
+#define STM32H7_PH9_FUNC_GPIO 0x7900
+#define STM32H7_PH9_FUNC_I2C3_SMBA 0x7905
+#define STM32H7_PH9_FUNC_FMC_D17 0x790d
+#define STM32H7_PH9_FUNC_DCMI_D0 0x790e
+#define STM32H7_PH9_FUNC_LCD_R3 0x790f
+#define STM32H7_PH9_FUNC_EVENTOUT 0x7910
+#define STM32H7_PH9_FUNC_ANALOG 0x7911
+
+#define STM32H7_PH10_FUNC_GPIO 0x7a00
+#define STM32H7_PH10_FUNC_TIM5_CH1 0x7a03
+#define STM32H7_PH10_FUNC_I2C4_SMBA 0x7a05
+#define STM32H7_PH10_FUNC_FMC_D18 0x7a0d
+#define STM32H7_PH10_FUNC_DCMI_D1 0x7a0e
+#define STM32H7_PH10_FUNC_LCD_R4 0x7a0f
+#define STM32H7_PH10_FUNC_EVENTOUT 0x7a10
+#define STM32H7_PH10_FUNC_ANALOG 0x7a11
+
+#define STM32H7_PH11_FUNC_GPIO 0x7b00
+#define STM32H7_PH11_FUNC_TIM5_CH2 0x7b03
+#define STM32H7_PH11_FUNC_I2C4_SCL 0x7b05
+#define STM32H7_PH11_FUNC_FMC_D19 0x7b0d
+#define STM32H7_PH11_FUNC_DCMI_D2 0x7b0e
+#define STM32H7_PH11_FUNC_LCD_R5 0x7b0f
+#define STM32H7_PH11_FUNC_EVENTOUT 0x7b10
+#define STM32H7_PH11_FUNC_ANALOG 0x7b11
+
+#define STM32H7_PH12_FUNC_GPIO 0x7c00
+#define STM32H7_PH12_FUNC_TIM5_CH3 0x7c03
+#define STM32H7_PH12_FUNC_I2C4_SDA 0x7c05
+#define STM32H7_PH12_FUNC_FMC_D20 0x7c0d
+#define STM32H7_PH12_FUNC_DCMI_D3 0x7c0e
+#define STM32H7_PH12_FUNC_LCD_R6 0x7c0f
+#define STM32H7_PH12_FUNC_EVENTOUT 0x7c10
+#define STM32H7_PH12_FUNC_ANALOG 0x7c11
+
+#define STM32H7_PH13_FUNC_GPIO 0x7d00
+#define STM32H7_PH13_FUNC_TIM8_CH1N 0x7d04
+#define STM32H7_PH13_FUNC_UART4_TX 0x7d09
+#define STM32H7_PH13_FUNC_CAN1_TX 0x7d0a
+#define STM32H7_PH13_FUNC_FMC_D21 0x7d0d
+#define STM32H7_PH13_FUNC_LCD_G2 0x7d0f
+#define STM32H7_PH13_FUNC_EVENTOUT 0x7d10
+#define STM32H7_PH13_FUNC_ANALOG 0x7d11
+
+#define STM32H7_PH14_FUNC_GPIO 0x7e00
+#define STM32H7_PH14_FUNC_TIM8_CH2N 0x7e04
+#define STM32H7_PH14_FUNC_UART4_RX 0x7e09
+#define STM32H7_PH14_FUNC_CAN1_RX 0x7e0a
+#define STM32H7_PH14_FUNC_FMC_D22 0x7e0d
+#define STM32H7_PH14_FUNC_DCMI_D4 0x7e0e
+#define STM32H7_PH14_FUNC_LCD_G3 0x7e0f
+#define STM32H7_PH14_FUNC_EVENTOUT 0x7e10
+#define STM32H7_PH14_FUNC_ANALOG 0x7e11
+
+#define STM32H7_PH15_FUNC_GPIO 0x7f00
+#define STM32H7_PH15_FUNC_TIM8_CH3N 0x7f04
+#define STM32H7_PH15_FUNC_CAN1_TXFD 0x7f0a
+#define STM32H7_PH15_FUNC_FMC_D23 0x7f0d
+#define STM32H7_PH15_FUNC_DCMI_D11 0x7f0e
+#define STM32H7_PH15_FUNC_LCD_G4 0x7f0f
+#define STM32H7_PH15_FUNC_EVENTOUT 0x7f10
+#define STM32H7_PH15_FUNC_ANALOG 0x7f11
+
+#define STM32H7_PI0_FUNC_GPIO 0x8000
+#define STM32H7_PI0_FUNC_TIM5_CH4 0x8003
+#define STM32H7_PI0_FUNC_SPI2_NSS_I2S2_WS 0x8006
+#define STM32H7_PI0_FUNC_CAN1_RXFD 0x800a
+#define STM32H7_PI0_FUNC_FMC_D24 0x800d
+#define STM32H7_PI0_FUNC_DCMI_D13 0x800e
+#define STM32H7_PI0_FUNC_LCD_G5 0x800f
+#define STM32H7_PI0_FUNC_EVENTOUT 0x8010
+#define STM32H7_PI0_FUNC_ANALOG 0x8011
+
+#define STM32H7_PI1_FUNC_GPIO 0x8100
+#define STM32H7_PI1_FUNC_TIM8_BKIN2 0x8104
+#define STM32H7_PI1_FUNC_SPI2_SCK_I2S2_CK 0x8106
+#define STM32H7_PI1_FUNC_TIM8_BKIN2_COMP12 0x810c
+#define STM32H7_PI1_FUNC_FMC_D25 0x810d
+#define STM32H7_PI1_FUNC_DCMI_D8 0x810e
+#define STM32H7_PI1_FUNC_LCD_G6 0x810f
+#define STM32H7_PI1_FUNC_EVENTOUT 0x8110
+#define STM32H7_PI1_FUNC_ANALOG 0x8111
+
+#define STM32H7_PI2_FUNC_GPIO 0x8200
+#define STM32H7_PI2_FUNC_TIM8_CH4 0x8204
+#define STM32H7_PI2_FUNC_SPI2_MISO_I2S2_SDI 0x8206
+#define STM32H7_PI2_FUNC_FMC_D26 0x820d
+#define STM32H7_PI2_FUNC_DCMI_D9 0x820e
+#define STM32H7_PI2_FUNC_LCD_G7 0x820f
+#define STM32H7_PI2_FUNC_EVENTOUT 0x8210
+#define STM32H7_PI2_FUNC_ANALOG 0x8211
+
+#define STM32H7_PI3_FUNC_GPIO 0x8300
+#define STM32H7_PI3_FUNC_TIM8_ETR 0x8304
+#define STM32H7_PI3_FUNC_SPI2_MOSI_I2S2_SDO 0x8306
+#define STM32H7_PI3_FUNC_FMC_D27 0x830d
+#define STM32H7_PI3_FUNC_DCMI_D10 0x830e
+#define STM32H7_PI3_FUNC_EVENTOUT 0x8310
+#define STM32H7_PI3_FUNC_ANALOG 0x8311
+
+#define STM32H7_PI4_FUNC_GPIO 0x8400
+#define STM32H7_PI4_FUNC_TIM8_BKIN 0x8404
+#define STM32H7_PI4_FUNC_SAI2_MCK_A 0x840b
+#define STM32H7_PI4_FUNC_TIM8_BKIN_COMP12 0x840c
+#define STM32H7_PI4_FUNC_FMC_NBL2 0x840d
+#define STM32H7_PI4_FUNC_DCMI_D5 0x840e
+#define STM32H7_PI4_FUNC_LCD_B4 0x840f
+#define STM32H7_PI4_FUNC_EVENTOUT 0x8410
+#define STM32H7_PI4_FUNC_ANALOG 0x8411
+
+#define STM32H7_PI5_FUNC_GPIO 0x8500
+#define STM32H7_PI5_FUNC_TIM8_CH1 0x8504
+#define STM32H7_PI5_FUNC_SAI2_SCK_A 0x850b
+#define STM32H7_PI5_FUNC_FMC_NBL3 0x850d
+#define STM32H7_PI5_FUNC_DCMI_VSYNC 0x850e
+#define STM32H7_PI5_FUNC_LCD_B5 0x850f
+#define STM32H7_PI5_FUNC_EVENTOUT 0x8510
+#define STM32H7_PI5_FUNC_ANALOG 0x8511
+
+#define STM32H7_PI6_FUNC_GPIO 0x8600
+#define STM32H7_PI6_FUNC_TIM8_CH2 0x8604
+#define STM32H7_PI6_FUNC_SAI2_SD_A 0x860b
+#define STM32H7_PI6_FUNC_FMC_D28 0x860d
+#define STM32H7_PI6_FUNC_DCMI_D6 0x860e
+#define STM32H7_PI6_FUNC_LCD_B6 0x860f
+#define STM32H7_PI6_FUNC_EVENTOUT 0x8610
+#define STM32H7_PI6_FUNC_ANALOG 0x8611
+
+#define STM32H7_PI7_FUNC_GPIO 0x8700
+#define STM32H7_PI7_FUNC_TIM8_CH3 0x8704
+#define STM32H7_PI7_FUNC_SAI2_FS_A 0x870b
+#define STM32H7_PI7_FUNC_FMC_D29 0x870d
+#define STM32H7_PI7_FUNC_DCMI_D7 0x870e
+#define STM32H7_PI7_FUNC_LCD_B7 0x870f
+#define STM32H7_PI7_FUNC_EVENTOUT 0x8710
+#define STM32H7_PI7_FUNC_ANALOG 0x8711
+
+#define STM32H7_PI8_FUNC_GPIO 0x8800
+#define STM32H7_PI8_FUNC_EVENTOUT 0x8810
+#define STM32H7_PI8_FUNC_ANALOG 0x8811
+
+#define STM32H7_PI9_FUNC_GPIO 0x8900
+#define STM32H7_PI9_FUNC_UART4_RX 0x8909
+#define STM32H7_PI9_FUNC_CAN1_RX 0x890a
+#define STM32H7_PI9_FUNC_FMC_D30 0x890d
+#define STM32H7_PI9_FUNC_LCD_VSYNC 0x890f
+#define STM32H7_PI9_FUNC_EVENTOUT 0x8910
+#define STM32H7_PI9_FUNC_ANALOG 0x8911
+
+#define STM32H7_PI10_FUNC_GPIO 0x8a00
+#define STM32H7_PI10_FUNC_CAN1_RXFD 0x8a0a
+#define STM32H7_PI10_FUNC_ETH_MII_RX_ER 0x8a0c
+#define STM32H7_PI10_FUNC_FMC_D31 0x8a0d
+#define STM32H7_PI10_FUNC_LCD_HSYNC 0x8a0f
+#define STM32H7_PI10_FUNC_EVENTOUT 0x8a10
+#define STM32H7_PI10_FUNC_ANALOG 0x8a11
+
+#define STM32H7_PI11_FUNC_GPIO 0x8b00
+#define STM32H7_PI11_FUNC_LCD_G6 0x8b0a
+#define STM32H7_PI11_FUNC_OTG_HS_ULPI_DIR 0x8b0b
+#define STM32H7_PI11_FUNC_EVENTOUT 0x8b10
+#define STM32H7_PI11_FUNC_ANALOG 0x8b11
+
+#define STM32H7_PI12_FUNC_GPIO 0x8c00
+#define STM32H7_PI12_FUNC_ETH_TX_ER 0x8c0c
+#define STM32H7_PI12_FUNC_LCD_HSYNC 0x8c0f
+#define STM32H7_PI12_FUNC_EVENTOUT 0x8c10
+#define STM32H7_PI12_FUNC_ANALOG 0x8c11
+
+#define STM32H7_PI13_FUNC_GPIO 0x8d00
+#define STM32H7_PI13_FUNC_LCD_VSYNC 0x8d0f
+#define STM32H7_PI13_FUNC_EVENTOUT 0x8d10
+#define STM32H7_PI13_FUNC_ANALOG 0x8d11
+
+#define STM32H7_PI14_FUNC_GPIO 0x8e00
+#define STM32H7_PI14_FUNC_LCD_CLK 0x8e0f
+#define STM32H7_PI14_FUNC_EVENTOUT 0x8e10
+#define STM32H7_PI14_FUNC_ANALOG 0x8e11
+
+#define STM32H7_PI15_FUNC_GPIO 0x8f00
+#define STM32H7_PI15_FUNC_LCD_G2 0x8f0a
+#define STM32H7_PI15_FUNC_LCD_R0 0x8f0f
+#define STM32H7_PI15_FUNC_EVENTOUT 0x8f10
+#define STM32H7_PI15_FUNC_ANALOG 0x8f11
+
+#define STM32H7_PJ0_FUNC_GPIO 0x9000
+#define STM32H7_PJ0_FUNC_LCD_R7 0x900a
+#define STM32H7_PJ0_FUNC_LCD_R1 0x900f
+#define STM32H7_PJ0_FUNC_EVENTOUT 0x9010
+#define STM32H7_PJ0_FUNC_ANALOG 0x9011
+
+#define STM32H7_PJ1_FUNC_GPIO 0x9100
+#define STM32H7_PJ1_FUNC_LCD_R2 0x910f
+#define STM32H7_PJ1_FUNC_EVENTOUT 0x9110
+#define STM32H7_PJ1_FUNC_ANALOG 0x9111
+
+#define STM32H7_PJ2_FUNC_GPIO 0x9200
+#define STM32H7_PJ2_FUNC_DSI_TE 0x920e
+#define STM32H7_PJ2_FUNC_LCD_R3 0x920f
+#define STM32H7_PJ2_FUNC_EVENTOUT 0x9210
+#define STM32H7_PJ2_FUNC_ANALOG 0x9211
+
+#define STM32H7_PJ3_FUNC_GPIO 0x9300
+#define STM32H7_PJ3_FUNC_LCD_R4 0x930f
+#define STM32H7_PJ3_FUNC_EVENTOUT 0x9310
+#define STM32H7_PJ3_FUNC_ANALOG 0x9311
+
+#define STM32H7_PJ4_FUNC_GPIO 0x9400
+#define STM32H7_PJ4_FUNC_LCD_R5 0x940f
+#define STM32H7_PJ4_FUNC_EVENTOUT 0x9410
+#define STM32H7_PJ4_FUNC_ANALOG 0x9411
+
+#define STM32H7_PJ5_FUNC_GPIO 0x9500
+#define STM32H7_PJ5_FUNC_LCD_R6 0x950f
+#define STM32H7_PJ5_FUNC_EVENTOUT 0x9510
+#define STM32H7_PJ5_FUNC_ANALOG 0x9511
+
+#define STM32H7_PJ6_FUNC_GPIO 0x9600
+#define STM32H7_PJ6_FUNC_TIM8_CH2 0x9604
+#define STM32H7_PJ6_FUNC_LCD_R7 0x960f
+#define STM32H7_PJ6_FUNC_EVENTOUT 0x9610
+#define STM32H7_PJ6_FUNC_ANALOG 0x9611
+
+#define STM32H7_PJ7_FUNC_GPIO 0x9700
+#define STM32H7_PJ7_FUNC_TRGIN 0x9701
+#define STM32H7_PJ7_FUNC_TIM8_CH2N 0x9704
+#define STM32H7_PJ7_FUNC_LCD_G0 0x970f
+#define STM32H7_PJ7_FUNC_EVENTOUT 0x9710
+#define STM32H7_PJ7_FUNC_ANALOG 0x9711
+
+#define STM32H7_PJ8_FUNC_GPIO 0x9800
+#define STM32H7_PJ8_FUNC_TIM1_CH3N 0x9802
+#define STM32H7_PJ8_FUNC_TIM8_CH1 0x9804
+#define STM32H7_PJ8_FUNC_UART8_TX 0x9809
+#define STM32H7_PJ8_FUNC_LCD_G1 0x980f
+#define STM32H7_PJ8_FUNC_EVENTOUT 0x9810
+#define STM32H7_PJ8_FUNC_ANALOG 0x9811
+
+#define STM32H7_PJ9_FUNC_GPIO 0x9900
+#define STM32H7_PJ9_FUNC_TIM1_CH3 0x9902
+#define STM32H7_PJ9_FUNC_TIM8_CH1N 0x9904
+#define STM32H7_PJ9_FUNC_UART8_RX 0x9909
+#define STM32H7_PJ9_FUNC_LCD_G2 0x990f
+#define STM32H7_PJ9_FUNC_EVENTOUT 0x9910
+#define STM32H7_PJ9_FUNC_ANALOG 0x9911
+
+#define STM32H7_PJ10_FUNC_GPIO 0x9a00
+#define STM32H7_PJ10_FUNC_TIM1_CH2N 0x9a02
+#define STM32H7_PJ10_FUNC_TIM8_CH2 0x9a04
+#define STM32H7_PJ10_FUNC_SPI5_MOSI 0x9a06
+#define STM32H7_PJ10_FUNC_LCD_G3 0x9a0f
+#define STM32H7_PJ10_FUNC_EVENTOUT 0x9a10
+#define STM32H7_PJ10_FUNC_ANALOG 0x9a11
+
+#define STM32H7_PJ11_FUNC_GPIO 0x9b00
+#define STM32H7_PJ11_FUNC_TIM1_CH2 0x9b02
+#define STM32H7_PJ11_FUNC_TIM8_CH2N 0x9b04
+#define STM32H7_PJ11_FUNC_SPI5_MISO 0x9b06
+#define STM32H7_PJ11_FUNC_LCD_G4 0x9b0f
+#define STM32H7_PJ11_FUNC_EVENTOUT 0x9b10
+#define STM32H7_PJ11_FUNC_ANALOG 0x9b11
+
+#define STM32H7_PJ12_FUNC_GPIO 0x9c00
+#define STM32H7_PJ12_FUNC_TRGOUT 0x9c01
+#define STM32H7_PJ12_FUNC_LCD_G3 0x9c0a
+#define STM32H7_PJ12_FUNC_LCD_B0 0x9c0f
+#define STM32H7_PJ12_FUNC_EVENTOUT 0x9c10
+#define STM32H7_PJ12_FUNC_ANALOG 0x9c11
+
+#define STM32H7_PJ13_FUNC_GPIO 0x9d00
+#define STM32H7_PJ13_FUNC_LCD_B4 0x9d0a
+#define STM32H7_PJ13_FUNC_LCD_B1 0x9d0f
+#define STM32H7_PJ13_FUNC_EVENTOUT 0x9d10
+#define STM32H7_PJ13_FUNC_ANALOG 0x9d11
+
+#define STM32H7_PJ14_FUNC_GPIO 0x9e00
+#define STM32H7_PJ14_FUNC_LCD_B2 0x9e0f
+#define STM32H7_PJ14_FUNC_EVENTOUT 0x9e10
+#define STM32H7_PJ14_FUNC_ANALOG 0x9e11
+
+#define STM32H7_PJ15_FUNC_GPIO 0x9f00
+#define STM32H7_PJ15_FUNC_LCD_B3 0x9f0f
+#define STM32H7_PJ15_FUNC_EVENTOUT 0x9f10
+#define STM32H7_PJ15_FUNC_ANALOG 0x9f11
+
+#define STM32H7_PK0_FUNC_GPIO 0xa000
+#define STM32H7_PK0_FUNC_TIM1_CH1N 0xa002
+#define STM32H7_PK0_FUNC_TIM8_CH3 0xa004
+#define STM32H7_PK0_FUNC_SPI5_SCK 0xa006
+#define STM32H7_PK0_FUNC_LCD_G5 0xa00f
+#define STM32H7_PK0_FUNC_EVENTOUT 0xa010
+#define STM32H7_PK0_FUNC_ANALOG 0xa011
+
+#define STM32H7_PK1_FUNC_GPIO 0xa100
+#define STM32H7_PK1_FUNC_TIM1_CH1 0xa102
+#define STM32H7_PK1_FUNC_TIM8_CH3N 0xa104
+#define STM32H7_PK1_FUNC_SPI5_NSS 0xa106
+#define STM32H7_PK1_FUNC_LCD_G6 0xa10f
+#define STM32H7_PK1_FUNC_EVENTOUT 0xa110
+#define STM32H7_PK1_FUNC_ANALOG 0xa111
+
+#define STM32H7_PK2_FUNC_GPIO 0xa200
+#define STM32H7_PK2_FUNC_TIM1_BKIN 0xa202
+#define STM32H7_PK2_FUNC_TIM8_BKIN 0xa204
+#define STM32H7_PK2_FUNC_TIM8_BKIN_COMP12 0xa20b
+#define STM32H7_PK2_FUNC_TIM1_BKIN_COMP12 0xa20c
+#define STM32H7_PK2_FUNC_LCD_G7 0xa20f
+#define STM32H7_PK2_FUNC_EVENTOUT 0xa210
+#define STM32H7_PK2_FUNC_ANALOG 0xa211
+
+#define STM32H7_PK3_FUNC_GPIO 0xa300
+#define STM32H7_PK3_FUNC_LCD_B4 0xa30f
+#define STM32H7_PK3_FUNC_EVENTOUT 0xa310
+#define STM32H7_PK3_FUNC_ANALOG 0xa311
+
+#define STM32H7_PK4_FUNC_GPIO 0xa400
+#define STM32H7_PK4_FUNC_LCD_B5 0xa40f
+#define STM32H7_PK4_FUNC_EVENTOUT 0xa410
+#define STM32H7_PK4_FUNC_ANALOG 0xa411
+
+#define STM32H7_PK5_FUNC_GPIO 0xa500
+#define STM32H7_PK5_FUNC_LCD_B6 0xa50f
+#define STM32H7_PK5_FUNC_EVENTOUT 0xa510
+#define STM32H7_PK5_FUNC_ANALOG 0xa511
+
+#define STM32H7_PK6_FUNC_GPIO 0xa600
+#define STM32H7_PK6_FUNC_LCD_B7 0xa60f
+#define STM32H7_PK6_FUNC_EVENTOUT 0xa610
+#define STM32H7_PK6_FUNC_ANALOG 0xa611
+
+#define STM32H7_PK7_FUNC_GPIO 0xa700
+#define STM32H7_PK7_FUNC_LCD_DE 0xa70f
+#define STM32H7_PK7_FUNC_EVENTOUT 0xa710
+#define STM32H7_PK7_FUNC_ANALOG 0xa711
+
+#endif /* _DT_BINDINGS_STM32H7_PINFUNC_H */
index 8e577c2cb0ced43e058201cd32ebdf9d2750e9b2..673acda012af44efe4fb5a7fc5279d08e416cc86 100644 (file)
@@ -291,7 +291,8 @@ bool acpi_processor_validate_proc_id(int proc_id);
 
 #ifdef CONFIG_ACPI_HOTPLUG_CPU
 /* Arch dependent functions for cpu hotplug support */
-int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, int *pcpu);
+int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 acpi_id,
+                int *pcpu);
 int acpi_unmap_cpu(int cpu);
 int acpi_map_cpu2node(acpi_handle handle, int cpu, int physid);
 #endif /* CONFIG_ACPI_HOTPLUG_CPU */
index 388574ea38ed9d4aa1d644442672ad883feaaef3..28e3cf1465ab6d3034929c0e255be9f3830a49ee 100644 (file)
@@ -87,7 +87,7 @@ struct async_submit_ctl {
        void *scribble;
 };
 
-#ifdef CONFIG_DMA_ENGINE
+#if defined(CONFIG_DMA_ENGINE) && !defined(CONFIG_ASYNC_TX_CHANNEL_SWITCH)
 #define async_tx_issue_pending_all dma_issue_pending_all
 
 /**
index f51fca8d0b6f86f4229a3ff487c39c18ad1a92c4..504e784b7ffa6da23212a0a0d110efe91774eb27 100644 (file)
@@ -360,6 +360,7 @@ extern int __audit_log_bprm_fcaps(struct linux_binprm *bprm,
                                  const struct cred *old);
 extern void __audit_log_capset(const struct cred *new, const struct cred *old);
 extern void __audit_mmap_fd(int fd, int flags);
+extern void __audit_log_kern_module(char *name);
 
 static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp)
 {
@@ -387,6 +388,20 @@ static inline int audit_socketcall(int nargs, unsigned long *args)
                return __audit_socketcall(nargs, args);
        return 0;
 }
+
+static inline int audit_socketcall_compat(int nargs, u32 *args)
+{
+       unsigned long a[AUDITSC_ARGS];
+       int i;
+
+       if (audit_dummy_context())
+               return 0;
+
+       for (i = 0; i < nargs; i++)
+               a[i] = (unsigned long)args[i];
+       return __audit_socketcall(nargs, a);
+}
+
 static inline int audit_sockaddr(int len, void *addr)
 {
        if (unlikely(!audit_dummy_context()))
@@ -436,6 +451,12 @@ static inline void audit_mmap_fd(int fd, int flags)
                __audit_mmap_fd(fd, flags);
 }
 
+static inline void audit_log_kern_module(char *name)
+{
+       if (!audit_dummy_context())
+               __audit_log_kern_module(name);
+}
+
 extern int audit_n_rules;
 extern int audit_signals;
 #else /* CONFIG_AUDITSYSCALL */
@@ -513,6 +534,12 @@ static inline int audit_socketcall(int nargs, unsigned long *args)
 {
        return 0;
 }
+
+static inline int audit_socketcall_compat(int nargs, u32 *args)
+{
+       return 0;
+}
+
 static inline void audit_fd_pair(int fd1, int fd2)
 { }
 static inline int audit_sockaddr(int len, void *addr)
@@ -541,6 +568,11 @@ static inline void audit_log_capset(const struct cred *new,
 { }
 static inline void audit_mmap_fd(int fd, int flags)
 { }
+
+static inline void audit_log_kern_module(char *name)
+{
+}
+
 static inline void audit_ptrace(struct task_struct *t)
 { }
 #define audit_n_rules 0
index e850e76acaaf17dea16069faee5d9d12f179ff32..ad955817916d00c35b6b41d204ec61013c88a10f 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/flex_proportions.h>
 #include <linux/timer.h>
 #include <linux/workqueue.h>
+#include <linux/kref.h>
 
 struct page;
 struct device;
@@ -144,6 +145,7 @@ struct backing_dev_info {
 
        char *name;
 
+       struct kref refcnt;     /* Reference counter for the structure */
        unsigned int capabilities; /* Device capabilities */
        unsigned int min_ratio;
        unsigned int max_ratio, max_prop_frac;
index 43b93a947e61b286ac63ef75ac82b14954aa8bdb..c52a48cb9a66379971be13008bd8cdfba087807e 100644 (file)
 #include <linux/slab.h>
 
 int __must_check bdi_init(struct backing_dev_info *bdi);
-void bdi_exit(struct backing_dev_info *bdi);
+
+static inline struct backing_dev_info *bdi_get(struct backing_dev_info *bdi)
+{
+       kref_get(&bdi->refcnt);
+       return bdi;
+}
+
+void bdi_put(struct backing_dev_info *bdi);
 
 __printf(3, 4)
 int bdi_register(struct backing_dev_info *bdi, struct device *parent,
@@ -29,6 +36,7 @@ void bdi_unregister(struct backing_dev_info *bdi);
 
 int __must_check bdi_setup_and_register(struct backing_dev_info *, char *);
 void bdi_destroy(struct backing_dev_info *bdi);
+struct backing_dev_info *bdi_alloc_node(gfp_t gfp_mask, int node_id);
 
 void wb_start_writeback(struct bdi_writeback *wb, long nr_pages,
                        bool range_cyclic, enum wb_reason reason);
@@ -183,7 +191,7 @@ static inline struct backing_dev_info *inode_to_bdi(struct inode *inode)
        sb = inode->i_sb;
 #ifdef CONFIG_BLOCK
        if (sb_is_blkdev_sb(sb))
-               return blk_get_backing_dev_info(I_BDEV(inode));
+               return I_BDEV(inode)->bd_bdi;
 #endif
        return sb->s_bdi;
 }
index 4a2ab5d99ff7ed8a64baa99ae708b30edca00e4d..8e4df3d6c8cd9dbd1ddd96e25e1abae9a4aa4b6f 100644 (file)
@@ -22,6 +22,7 @@ struct blk_mq_hw_ctx {
 
        unsigned long           flags;          /* BLK_MQ_F_* flags */
 
+       void                    *sched_data;
        struct request_queue    *queue;
        struct blk_flush_queue  *fq;
 
@@ -35,6 +36,7 @@ struct blk_mq_hw_ctx {
        atomic_t                wait_index;
 
        struct blk_mq_tags      *tags;
+       struct blk_mq_tags      *sched_tags;
 
        struct srcu_struct      queue_rq_srcu;
 
@@ -60,7 +62,7 @@ struct blk_mq_hw_ctx {
 
 struct blk_mq_tag_set {
        unsigned int            *mq_map;
-       struct blk_mq_ops       *ops;
+       const struct blk_mq_ops *ops;
        unsigned int            nr_hw_queues;
        unsigned int            queue_depth;    /* max hw supported */
        unsigned int            reserved_tags;
@@ -151,11 +153,13 @@ enum {
        BLK_MQ_F_SG_MERGE       = 1 << 2,
        BLK_MQ_F_DEFER_ISSUE    = 1 << 4,
        BLK_MQ_F_BLOCKING       = 1 << 5,
+       BLK_MQ_F_NO_SCHED       = 1 << 6,
        BLK_MQ_F_ALLOC_POLICY_START_BIT = 8,
        BLK_MQ_F_ALLOC_POLICY_BITS = 1,
 
        BLK_MQ_S_STOPPED        = 0,
        BLK_MQ_S_TAG_ACTIVE     = 1,
+       BLK_MQ_S_SCHED_RESTART  = 2,
 
        BLK_MQ_MAX_DEPTH        = 10240,
 
@@ -179,14 +183,13 @@ void blk_mq_free_tag_set(struct blk_mq_tag_set *set);
 
 void blk_mq_flush_plug_list(struct blk_plug *plug, bool from_schedule);
 
-void blk_mq_insert_request(struct request *, bool, bool, bool);
 void blk_mq_free_request(struct request *rq);
-void blk_mq_free_hctx_request(struct blk_mq_hw_ctx *, struct request *rq);
 bool blk_mq_can_queue(struct blk_mq_hw_ctx *);
 
 enum {
        BLK_MQ_REQ_NOWAIT       = (1 << 0), /* return when out of requests */
        BLK_MQ_REQ_RESERVED     = (1 << 1), /* allocate from reserved pool */
+       BLK_MQ_REQ_INTERNAL     = (1 << 2), /* allocate internal/sched tag */
 };
 
 struct request *blk_mq_alloc_request(struct request_queue *q, int rw,
index 519ea2c9df612becf997cf8fafbc1411ce6cd4be..d703acb55d0f0d196296ef4d82f4e97a5efd9c3a 100644 (file)
@@ -162,6 +162,13 @@ enum req_opf {
        /* write the zero filled sector many times */
        REQ_OP_WRITE_ZEROES     = 8,
 
+       /* SCSI passthrough using struct scsi_request */
+       REQ_OP_SCSI_IN          = 32,
+       REQ_OP_SCSI_OUT         = 33,
+       /* Driver private requests */
+       REQ_OP_DRV_IN           = 34,
+       REQ_OP_DRV_OUT          = 35,
+
        REQ_OP_LAST,
 };
 
@@ -220,6 +227,15 @@ static inline bool op_is_write(unsigned int op)
        return (op & 1);
 }
 
+/*
+ * Check if the bio or request is one that needs special treatment in the
+ * flush state machine.
+ */
+static inline bool op_is_flush(unsigned int op)
+{
+       return op & (REQ_FUA | REQ_PREFLUSH);
+}
+
 /*
  * Reads are always treated as synchronous, as are requests with the FUA or
  * PREFLUSH flag.  Other operations may be marked as synchronous using the
@@ -232,22 +248,29 @@ static inline bool op_is_sync(unsigned int op)
 }
 
 typedef unsigned int blk_qc_t;
-#define BLK_QC_T_NONE  -1U
-#define BLK_QC_T_SHIFT 16
+#define BLK_QC_T_NONE          -1U
+#define BLK_QC_T_SHIFT         16
+#define BLK_QC_T_INTERNAL      (1U << 31)
 
 static inline bool blk_qc_t_valid(blk_qc_t cookie)
 {
        return cookie != BLK_QC_T_NONE;
 }
 
-static inline blk_qc_t blk_tag_to_qc_t(unsigned int tag, unsigned int queue_num)
+static inline blk_qc_t blk_tag_to_qc_t(unsigned int tag, unsigned int queue_num,
+                                      bool internal)
 {
-       return tag | (queue_num << BLK_QC_T_SHIFT);
+       blk_qc_t ret = tag | (queue_num << BLK_QC_T_SHIFT);
+
+       if (internal)
+               ret |= BLK_QC_T_INTERNAL;
+
+       return ret;
 }
 
 static inline unsigned int blk_qc_t_to_queue_num(blk_qc_t cookie)
 {
-       return cookie >> BLK_QC_T_SHIFT;
+       return (cookie & ~BLK_QC_T_INTERNAL) >> BLK_QC_T_SHIFT;
 }
 
 static inline unsigned int blk_qc_t_to_tag(blk_qc_t cookie)
@@ -255,6 +278,11 @@ static inline unsigned int blk_qc_t_to_tag(blk_qc_t cookie)
        return cookie & ((1u << BLK_QC_T_SHIFT) - 1);
 }
 
+static inline bool blk_qc_t_is_internal(blk_qc_t cookie)
+{
+       return (cookie & BLK_QC_T_INTERNAL) != 0;
+}
+
 struct blk_issue_stat {
        u64 time;
 };
index 1ca8e8fd10789d0fff1aa0b21ede64b72075e094..aecca0e7d9cadb04c368fbac010ae7dacc831c90 100644 (file)
@@ -70,15 +70,6 @@ struct request_list {
        unsigned int            flags;
 };
 
-/*
- * request command types
- */
-enum rq_cmd_type_bits {
-       REQ_TYPE_FS             = 1,    /* fs request */
-       REQ_TYPE_BLOCK_PC,              /* scsi command */
-       REQ_TYPE_DRV_PRIV,              /* driver defined types from here */
-};
-
 /*
  * request flags */
 typedef __u32 __bitwise req_flags_t;
@@ -128,8 +119,6 @@ typedef __u32 __bitwise req_flags_t;
 #define RQF_NOMERGE_FLAGS \
        (RQF_STARTED | RQF_SOFTBARRIER | RQF_FLUSH_SEQ | RQF_SPECIAL_PAYLOAD)
 
-#define BLK_MAX_CDB    16
-
 /*
  * Try to put the fields that are referenced together in the same cacheline.
  *
@@ -147,13 +136,16 @@ struct request {
        struct blk_mq_ctx *mq_ctx;
 
        int cpu;
-       unsigned cmd_type;
        unsigned int cmd_flags;         /* op and common flags */
        req_flags_t rq_flags;
+
+       int internal_tag;
+
        unsigned long atomic_flags;
 
        /* the following two fields are internal, NEVER access directly */
        unsigned int __data_len;        /* total data len */
+       int tag;
        sector_t __sector;              /* sector cursor */
 
        struct bio *bio;
@@ -222,20 +214,9 @@ struct request {
 
        void *special;          /* opaque pointer available for LLD use */
 
-       int tag;
        int errors;
 
-       /*
-        * when request is used as a packet command carrier
-        */
-       unsigned char __cmd[BLK_MAX_CDB];
-       unsigned char *cmd;
-       unsigned short cmd_len;
-
        unsigned int extra_len; /* length of alignment and padding */
-       unsigned int sense_len;
-       unsigned int resid_len; /* residual count */
-       void *sense;
 
        unsigned long deadline;
        struct list_head timeout_list;
@@ -252,6 +233,21 @@ struct request {
        struct request *next_rq;
 };
 
+static inline bool blk_rq_is_scsi(struct request *rq)
+{
+       return req_op(rq) == REQ_OP_SCSI_IN || req_op(rq) == REQ_OP_SCSI_OUT;
+}
+
+static inline bool blk_rq_is_private(struct request *rq)
+{
+       return req_op(rq) == REQ_OP_DRV_IN || req_op(rq) == REQ_OP_DRV_OUT;
+}
+
+static inline bool blk_rq_is_passthrough(struct request *rq)
+{
+       return blk_rq_is_scsi(rq) || blk_rq_is_private(rq);
+}
+
 static inline unsigned short req_get_ioprio(struct request *req)
 {
        return req->ioprio;
@@ -271,6 +267,8 @@ typedef void (softirq_done_fn)(struct request *);
 typedef int (dma_drain_needed_fn)(struct request *);
 typedef int (lld_busy_fn) (struct request_queue *q);
 typedef int (bsg_job_fn) (struct bsg_job *);
+typedef int (init_rq_fn)(struct request_queue *, struct request *, gfp_t);
+typedef void (exit_rq_fn)(struct request_queue *, struct request *);
 
 enum blk_eh_timer_return {
        BLK_EH_NOT_HANDLED,
@@ -333,6 +331,7 @@ struct queue_limits {
        unsigned short          logical_block_size;
        unsigned short          max_segments;
        unsigned short          max_integrity_segments;
+       unsigned short          max_discard_segments;
 
        unsigned char           misaligned;
        unsigned char           discard_misaligned;
@@ -406,8 +405,10 @@ struct request_queue {
        rq_timed_out_fn         *rq_timed_out_fn;
        dma_drain_needed_fn     *dma_drain_needed;
        lld_busy_fn             *lld_busy_fn;
+       init_rq_fn              *init_rq_fn;
+       exit_rq_fn              *exit_rq_fn;
 
-       struct blk_mq_ops       *mq_ops;
+       const struct blk_mq_ops *mq_ops;
 
        unsigned int            *mq_map;
 
@@ -432,7 +433,8 @@ struct request_queue {
         */
        struct delayed_work     delay_work;
 
-       struct backing_dev_info backing_dev_info;
+       struct backing_dev_info *backing_dev_info;
+       struct disk_devt        *disk_devt;
 
        /*
         * The queue owner gets to use this for whatever they like.
@@ -569,7 +571,15 @@ struct request_queue {
        struct list_head        tag_set_list;
        struct bio_set          *bio_split;
 
+#ifdef CONFIG_BLK_DEBUG_FS
+       struct dentry           *debugfs_dir;
+       struct dentry           *mq_debugfs_dir;
+#endif
+
        bool                    mq_sysfs_init_done;
+
+       size_t                  cmd_size;
+       void                    *rq_alloc_data;
 };
 
 #define QUEUE_FLAG_QUEUED      1       /* uses generic tag queueing */
@@ -600,6 +610,7 @@ struct request_queue {
 #define QUEUE_FLAG_FLUSH_NQ    25      /* flush not queueuable */
 #define QUEUE_FLAG_DAX         26      /* device supports DAX */
 #define QUEUE_FLAG_STATS       27      /* track rq completion times */
+#define QUEUE_FLAG_RESTART     28      /* queue needs restart at completion */
 
 #define QUEUE_FLAG_DEFAULT     ((1 << QUEUE_FLAG_IO_STAT) |            \
                                 (1 << QUEUE_FLAG_STACKABLE)    |       \
@@ -695,9 +706,10 @@ static inline void queue_flag_clear(unsigned int flag, struct request_queue *q)
        ((rq)->cmd_flags & (REQ_FAILFAST_DEV|REQ_FAILFAST_TRANSPORT| \
                             REQ_FAILFAST_DRIVER))
 
-#define blk_account_rq(rq) \
-       (((rq)->rq_flags & RQF_STARTED) && \
-        ((rq)->cmd_type == REQ_TYPE_FS))
+static inline bool blk_account_rq(struct request *rq)
+{
+       return (rq->rq_flags & RQF_STARTED) && !blk_rq_is_passthrough(rq);
+}
 
 #define blk_rq_cpu_valid(rq)   ((rq)->cpu != -1)
 #define blk_bidi_rq(rq)                ((rq)->next_rq != NULL)
@@ -772,7 +784,7 @@ static inline void blk_clear_rl_full(struct request_list *rl, bool sync)
 
 static inline bool rq_mergeable(struct request *rq)
 {
-       if (rq->cmd_type != REQ_TYPE_FS)
+       if (blk_rq_is_passthrough(rq))
                return false;
 
        if (req_op(rq) == REQ_OP_FLUSH)
@@ -910,7 +922,6 @@ extern void blk_rq_init(struct request_queue *q, struct request *rq);
 extern void blk_put_request(struct request *);
 extern void __blk_put_request(struct request_queue *, struct request *);
 extern struct request *blk_get_request(struct request_queue *, int, gfp_t);
-extern void blk_rq_set_block_pc(struct request *);
 extern void blk_requeue_request(struct request_queue *, struct request *);
 extern int blk_lld_busy(struct request_queue *q);
 extern int blk_rq_prep_clone(struct request *rq, struct request *rq_src,
@@ -1047,7 +1058,7 @@ static inline unsigned int blk_rq_get_max_sectors(struct request *rq,
 {
        struct request_queue *q = rq->q;
 
-       if (unlikely(rq->cmd_type != REQ_TYPE_FS))
+       if (blk_rq_is_passthrough(rq))
                return q->limits.max_hw_sectors;
 
        if (!q->limits.chunk_sectors ||
@@ -1129,14 +1140,15 @@ extern void blk_unprep_request(struct request *);
 extern struct request_queue *blk_init_queue_node(request_fn_proc *rfn,
                                        spinlock_t *lock, int node_id);
 extern struct request_queue *blk_init_queue(request_fn_proc *, spinlock_t *);
-extern struct request_queue *blk_init_allocated_queue(struct request_queue *,
-                                                     request_fn_proc *, spinlock_t *);
+extern int blk_init_allocated_queue(struct request_queue *);
 extern void blk_cleanup_queue(struct request_queue *);
 extern void blk_queue_make_request(struct request_queue *, make_request_fn *);
 extern void blk_queue_bounce_limit(struct request_queue *, u64);
 extern void blk_queue_max_hw_sectors(struct request_queue *, unsigned int);
 extern void blk_queue_chunk_sectors(struct request_queue *, unsigned int);
 extern void blk_queue_max_segments(struct request_queue *, unsigned short);
+extern void blk_queue_max_discard_segments(struct request_queue *,
+               unsigned short);
 extern void blk_queue_max_segment_size(struct request_queue *, unsigned int);
 extern void blk_queue_max_discard_sectors(struct request_queue *q,
                unsigned int max_discard_sectors);
@@ -1179,8 +1191,16 @@ extern void blk_queue_rq_timed_out(struct request_queue *, rq_timed_out_fn *);
 extern void blk_queue_rq_timeout(struct request_queue *, unsigned int);
 extern void blk_queue_flush_queueable(struct request_queue *q, bool queueable);
 extern void blk_queue_write_cache(struct request_queue *q, bool enabled, bool fua);
-extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
 
+/*
+ * Number of physical segments as sent to the device.
+ *
+ * Normally this is the number of discontiguous data segments sent by the
+ * submitter.  But for data-less command like discard we might have no
+ * actual data segments submitted, but the driver might have to add it's
+ * own special payload.  In that case we still return 1 here so that this
+ * special payload will be mapped.
+ */
 static inline unsigned short blk_rq_nr_phys_segments(struct request *rq)
 {
        if (rq->rq_flags & RQF_SPECIAL_PAYLOAD)
@@ -1188,6 +1208,15 @@ static inline unsigned short blk_rq_nr_phys_segments(struct request *rq)
        return rq->nr_phys_segments;
 }
 
+/*
+ * Number of discard segments (or ranges) the driver needs to fill in.
+ * Each discard bio merged into a request is counted as one segment.
+ */
+static inline unsigned short blk_rq_nr_discard_segments(struct request *rq)
+{
+       return max_t(unsigned short, rq->nr_phys_segments, 1);
+}
+
 extern int blk_rq_map_sg(struct request_queue *, struct request *, struct scatterlist *);
 extern void blk_dump_rq_flags(struct request *, char *);
 extern long nr_blockdev_pages(void);
@@ -1376,6 +1405,11 @@ static inline unsigned short queue_max_segments(struct request_queue *q)
        return q->limits.max_segments;
 }
 
+static inline unsigned short queue_max_discard_segments(struct request_queue *q)
+{
+       return q->limits.max_discard_segments;
+}
+
 static inline unsigned int queue_max_segment_size(struct request_queue *q)
 {
        return q->limits.max_segment_size;
@@ -1620,6 +1654,25 @@ static inline bool bvec_gap_to_prev(struct request_queue *q,
        return __bvec_gap_to_prev(q, bprv, offset);
 }
 
+/*
+ * Check if the two bvecs from two bios can be merged to one segment.
+ * If yes, no need to check gap between the two bios since the 1st bio
+ * and the 1st bvec in the 2nd bio can be handled in one segment.
+ */
+static inline bool bios_segs_mergeable(struct request_queue *q,
+               struct bio *prev, struct bio_vec *prev_last_bv,
+               struct bio_vec *next_first_bv)
+{
+       if (!BIOVEC_PHYS_MERGEABLE(prev_last_bv, next_first_bv))
+               return false;
+       if (!BIOVEC_SEG_BOUNDARY(q, prev_last_bv, next_first_bv))
+               return false;
+       if (prev->bi_seg_back_size + next_first_bv->bv_len >
+                       queue_max_segment_size(q))
+               return false;
+       return true;
+}
+
 static inline bool bio_will_gap(struct request_queue *q, struct bio *prev,
                         struct bio *next)
 {
@@ -1629,7 +1682,8 @@ static inline bool bio_will_gap(struct request_queue *q, struct bio *prev,
                bio_get_last_bvec(prev, &pb);
                bio_get_first_bvec(next, &nb);
 
-               return __bvec_gap_to_prev(q, &pb, nb.bv_offset);
+               if (!bios_segs_mergeable(q, prev, &pb, &nb))
+                       return __bvec_gap_to_prev(q, &pb, nb.bv_offset);
        }
 
        return false;
index e417f080219a68a90e2b0f795dc8e47c002cc58a..d2e908586e3d50322025806a61816d1ec1b56ece 100644 (file)
@@ -30,9 +30,6 @@ struct blk_trace {
 
 extern int blk_trace_ioctl(struct block_device *, unsigned, char __user *);
 extern void blk_trace_shutdown(struct request_queue *);
-extern int do_blk_trace_setup(struct request_queue *q, char *name,
-                             dev_t dev, struct block_device *bdev,
-                             struct blk_user_trace_setup *buts);
 extern __printf(2, 3)
 void __trace_note_message(struct blk_trace *, const char *fmt, ...);
 
@@ -80,7 +77,6 @@ extern struct attribute_group blk_trace_attr_group;
 #else /* !CONFIG_BLK_DEV_IO_TRACE */
 # define blk_trace_ioctl(bdev, cmd, arg)               (-ENOTTY)
 # define blk_trace_shutdown(q)                         do { } while (0)
-# define do_blk_trace_setup(q, name, dev, bdev, buts)  (-ENOTTY)
 # define blk_add_driver_data(q, rq, data, len)         do {} while (0)
 # define blk_trace_setup(q, name, dev, bdev, arg)      (-ENOTTY)
 # define blk_trace_startstop(q, start)                 (-ENOTTY)
@@ -110,16 +106,16 @@ struct compat_blk_user_trace_setup {
 
 #endif
 
-#if defined(CONFIG_EVENT_TRACING) && defined(CONFIG_BLOCK)
+extern void blk_fill_rwbs(char *rwbs, unsigned int op, int bytes);
 
-static inline int blk_cmd_buf_len(struct request *rq)
+static inline sector_t blk_rq_trace_sector(struct request *rq)
 {
-       return (rq->cmd_type == REQ_TYPE_BLOCK_PC) ? rq->cmd_len * 3 : 1;
+       return blk_rq_is_passthrough(rq) ? 0 : blk_rq_pos(rq);
 }
 
-extern void blk_dump_cmd(char *buf, struct request *rq);
-extern void blk_fill_rwbs(char *rwbs, unsigned int op, int bytes);
-
-#endif /* CONFIG_EVENT_TRACING && CONFIG_BLOCK */
+static inline unsigned int blk_rq_trace_nr_sectors(struct request *rq)
+{
+       return blk_rq_is_passthrough(rq) ? 0 : blk_rq_sectors(rq);
+}
 
 #endif
index 657a718c27d2e9d172e39f2e1f4c2dc33246ed26..e34dde2da0ef57c3692ce7001fa66fe37c4dc578 100644 (file)
@@ -66,9 +66,8 @@ struct bsg_job {
 
 void bsg_job_done(struct bsg_job *job, int result,
                  unsigned int reply_payload_rcv_len);
-int bsg_setup_queue(struct device *dev, struct request_queue *q, char *name,
-                   bsg_job_fn *job_fn, int dd_job_size);
-void bsg_request_fn(struct request_queue *q);
+struct request_queue *bsg_setup_queue(struct device *dev, char *name,
+               bsg_job_fn *job_fn, int dd_job_size);
 void bsg_job_put(struct bsg_job *job);
 int __must_check bsg_job_get(struct bsg_job *job);
 
index 8609d577bb66df1a50c92fc6ef2873f30b6f3e30..6e8f209a6dff05156c2c56aee33b309b61bb91ee 100644 (file)
@@ -36,7 +36,7 @@ struct packet_command
 
 /* Uniform cdrom data structures for cdrom.c */
 struct cdrom_device_info {
-       struct cdrom_device_ops  *ops;  /* link to device_ops */
+       const struct cdrom_device_ops *ops; /* link to device_ops */
        struct list_head list;          /* linked list of all device_info */
        struct gendisk *disk;           /* matching block layer disk */
        void *handle;                   /* driver-dependent data */
@@ -87,7 +87,6 @@ struct cdrom_device_ops {
 
 /* driver specifications */
        const int capability;   /* capability flags */
-       int n_minors;           /* number of active minor devices */
        /* handle uniform packets for scsi type devices (scsi,atapi) */
        int (*generic_packet) (struct cdrom_device_info *,
                               struct packet_command *);
@@ -123,6 +122,8 @@ extern int cdrom_mode_sense(struct cdrom_device_info *cdi,
                            int page_code, int page_control);
 extern void init_cdrom_command(struct packet_command *cgc,
                               void *buffer, int len, int type);
+extern int cdrom_dummy_generic_packet(struct cdrom_device_info *cdi,
+                                     struct packet_command *cgc);
 
 /* The SCSI spec says there could be 256 slots. */
 #define CDROM_MAX_SLOTS        256
index 7e05c5e4e45cd49a82c8669089f307f9ac7e01b5..87165f06a3079dcfe507674e495859c5627f74ca 100644 (file)
@@ -31,7 +31,7 @@
 
 #define CPUFREQ_ETERNAL                        (-1)
 #define CPUFREQ_NAME_LEN               16
-/* Print length for names. Extra 1 space for accomodating '\n' in prints */
+/* Print length for names. Extra 1 space for accommodating '\n' in prints */
 #define CPUFREQ_NAME_PLEN              (CPUFREQ_NAME_LEN + 1)
 
 struct cpufreq_governor;
@@ -115,7 +115,7 @@ struct cpufreq_policy {
         *   guarantee that frequency can be changed on any CPU sharing the
         *   policy and that the change will affect all of the policy CPUs then.
         * - fast_switch_enabled is to be set by governors that support fast
-        *   freqnency switching with the help of cpufreq_enable_fast_switch().
+        *   frequency switching with the help of cpufreq_enable_fast_switch().
         */
        bool                    fast_switch_possible;
        bool                    fast_switch_enabled;
@@ -415,9 +415,6 @@ static inline void cpufreq_resume(void) {}
 /* Policy Notifiers  */
 #define CPUFREQ_ADJUST                 (0)
 #define CPUFREQ_NOTIFY                 (1)
-#define CPUFREQ_START                  (2)
-#define CPUFREQ_CREATE_POLICY          (3)
-#define CPUFREQ_REMOVE_POLICY          (4)
 
 #ifdef CONFIG_CPU_FREQ
 int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list);
index f4754282c9c2a11dbfdd1a3865fcdeb5666abdf6..3252799832cf933cba189710fb443cdf89061902 100644 (file)
@@ -15,6 +15,4 @@ void sha_transform(__u32 *digest, const char *data, __u32 *W);
 
 void md5_transform(__u32 *hash, __u32 const *in);
 
-__u32 half_md4_transform(__u32 buf[4], __u32 const in[8]);
-
 #endif
index 014cc564d1c437f34d1cbe259f087156f1d148c9..c0befcf41b585b7f0e8702a3599eb1c3435cb69b 100644 (file)
@@ -80,6 +80,8 @@ static const struct file_operations __fops = {                                \
 
 #if defined(CONFIG_DEBUG_FS)
 
+struct dentry *debugfs_lookup(const char *name, struct dentry *parent);
+
 struct dentry *debugfs_create_file(const char *name, umode_t mode,
                                   struct dentry *parent, void *data,
                                   const struct file_operations *fops);
@@ -181,6 +183,12 @@ ssize_t debugfs_write_file_bool(struct file *file, const char __user *user_buf,
  * want to duplicate the design decision mistakes of procfs and devfs again.
  */
 
+static inline struct dentry *debugfs_lookup(const char *name,
+                                           struct dentry *parent)
+{
+       return ERR_PTR(-ENODEV);
+}
+
 static inline struct dentry *debugfs_create_file(const char *name, umode_t mode,
                                        struct dentry *parent, void *data,
                                        const struct file_operations *fops)
index 2de4e2eea180d133898980f87c659f86a7fb922b..e0acb0e5243b49552480ed8cfac2d037226f4304 100644 (file)
@@ -104,6 +104,8 @@ struct devfreq_dev_profile {
  * struct devfreq_governor - Devfreq policy governor
  * @node:              list node - contains registered devfreq governors
  * @name:              Governor's name
+ * @immutable:         Immutable flag for governor. If the value is 1,
+ *                     this govenror is never changeable to other governor.
  * @get_target_freq:   Returns desired operating frequency for the device.
  *                     Basically, get_target_freq will run
  *                     devfreq_dev_profile.get_dev_status() to get the
@@ -121,6 +123,7 @@ struct devfreq_governor {
        struct list_head node;
 
        const char name[DEVFREQ_NAME_LEN];
+       const unsigned int immutable;
        int (*get_target_freq)(struct devfreq *this, unsigned long *freq);
        int (*event_handler)(struct devfreq *devfreq,
                                unsigned int event, void *data);
index ef7962e84444d90429afbb0d5e53fd7eaf7d7668..a7e6903866fdc98689bb5189cffd4b8cb7a715fa 100644 (file)
@@ -55,8 +55,6 @@ typedef void (*dm_dtr_fn) (struct dm_target *ti);
  * = 2: The target wants to push back the io
  */
 typedef int (*dm_map_fn) (struct dm_target *ti, struct bio *bio);
-typedef int (*dm_map_request_fn) (struct dm_target *ti, struct request *clone,
-                                 union map_info *map_context);
 typedef int (*dm_clone_and_map_request_fn) (struct dm_target *ti,
                                            struct request *rq,
                                            union map_info *map_context,
@@ -163,7 +161,6 @@ struct target_type {
        dm_ctr_fn ctr;
        dm_dtr_fn dtr;
        dm_map_fn map;
-       dm_map_request_fn map_rq;
        dm_clone_and_map_request_fn clone_and_map_rq;
        dm_release_clone_request_fn release_clone_rq;
        dm_endio_fn end_io;
index ccfd0c3777df20d2bd9c6cd1518673643369c1ad..b63b25814d77df827131c608574fa86821040b8a 100644 (file)
@@ -23,6 +23,7 @@ struct dw_dma;
 /**
  * struct dw_dma_chip - representation of DesignWare DMA controller hardware
  * @dev:               struct device of the DMA controller
+ * @id:                        instance ID
  * @irq:               irq line
  * @regs:              memory mapped I/O space
  * @clk:               hclk clock
@@ -31,6 +32,7 @@ struct dw_dma;
  */
 struct dw_dma_chip {
        struct device   *dev;
+       int             id;
        int             irq;
        void __iomem    *regs;
        struct clk      *clk;
index feee6ec6a13bbba6762618c21812754e3320684d..533680860865a2f6b64d0f73d3fb9040e097657b 100644 (file)
@@ -894,6 +894,17 @@ static inline struct dma_async_tx_descriptor *dmaengine_prep_dma_memset(
                                                    len, flags);
 }
 
+static inline struct dma_async_tx_descriptor *dmaengine_prep_dma_memcpy(
+               struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
+               size_t len, unsigned long flags)
+{
+       if (!chan || !chan->device || !chan->device->device_prep_dma_memcpy)
+               return NULL;
+
+       return chan->device->device_prep_dma_memcpy(chan, dest, src,
+                                                   len, flags);
+}
+
 static inline struct dma_async_tx_descriptor *dmaengine_prep_dma_sg(
                struct dma_chan *chan,
                struct scatterlist *dst_sg, unsigned int dst_nents,
index b276e9ef0e0b4d482312217a31d9c4a4f2416f84..aebecc4ed088f45c189162e560095363ac0e6d2a 100644 (file)
@@ -9,12 +9,22 @@
 struct io_cq;
 struct elevator_type;
 
-typedef int (elevator_merge_fn) (struct request_queue *, struct request **,
+/*
+ * Return values from elevator merger
+ */
+enum elv_merge {
+       ELEVATOR_NO_MERGE       = 0,
+       ELEVATOR_FRONT_MERGE    = 1,
+       ELEVATOR_BACK_MERGE     = 2,
+       ELEVATOR_DISCARD_MERGE  = 3,
+};
+
+typedef enum elv_merge (elevator_merge_fn) (struct request_queue *, struct request **,
                                 struct bio *);
 
 typedef void (elevator_merge_req_fn) (struct request_queue *, struct request *, struct request *);
 
-typedef void (elevator_merged_fn) (struct request_queue *, struct request *, int);
+typedef void (elevator_merged_fn) (struct request_queue *, struct request *, enum elv_merge);
 
 typedef int (elevator_allow_bio_merge_fn) (struct request_queue *,
                                           struct request *, struct bio *);
@@ -77,6 +87,34 @@ struct elevator_ops
        elevator_registered_fn *elevator_registered_fn;
 };
 
+struct blk_mq_alloc_data;
+struct blk_mq_hw_ctx;
+
+struct elevator_mq_ops {
+       int (*init_sched)(struct request_queue *, struct elevator_type *);
+       void (*exit_sched)(struct elevator_queue *);
+
+       bool (*allow_merge)(struct request_queue *, struct request *, struct bio *);
+       bool (*bio_merge)(struct blk_mq_hw_ctx *, struct bio *);
+       int (*request_merge)(struct request_queue *q, struct request **, struct bio *);
+       void (*request_merged)(struct request_queue *, struct request *, enum elv_merge);
+       void (*requests_merged)(struct request_queue *, struct request *, struct request *);
+       struct request *(*get_request)(struct request_queue *, unsigned int, struct blk_mq_alloc_data *);
+       void (*put_request)(struct request *);
+       void (*insert_requests)(struct blk_mq_hw_ctx *, struct list_head *, bool);
+       struct request *(*dispatch_request)(struct blk_mq_hw_ctx *);
+       bool (*has_work)(struct blk_mq_hw_ctx *);
+       void (*completed_request)(struct blk_mq_hw_ctx *, struct request *);
+       void (*started_request)(struct request *);
+       void (*requeue_request)(struct request *);
+       struct request *(*former_request)(struct request_queue *, struct request *);
+       struct request *(*next_request)(struct request_queue *, struct request *);
+       int (*get_rq_priv)(struct request_queue *, struct request *, struct bio *);
+       void (*put_rq_priv)(struct request_queue *, struct request *);
+       void (*init_icq)(struct io_cq *);
+       void (*exit_icq)(struct io_cq *);
+};
+
 #define ELV_NAME_MAX   (16)
 
 struct elv_fs_entry {
@@ -94,12 +132,16 @@ struct elevator_type
        struct kmem_cache *icq_cache;
 
        /* fields provided by elevator implementation */
-       struct elevator_ops ops;
+       union {
+               struct elevator_ops sq;
+               struct elevator_mq_ops mq;
+       } ops;
        size_t icq_size;        /* see iocontext.h */
        size_t icq_align;       /* ditto */
        struct elv_fs_entry *elevator_attrs;
        char elevator_name[ELV_NAME_MAX];
        struct module *elevator_owner;
+       bool uses_mq;
 
        /* managed by elevator core */
        char icq_cache_name[ELV_NAME_MAX + 5];  /* elvname + "_io_cq" */
@@ -123,6 +165,7 @@ struct elevator_queue
        struct kobject kobj;
        struct mutex sysfs_lock;
        unsigned int registered:1;
+       unsigned int uses_mq:1;
        DECLARE_HASHTABLE(hash, ELV_HASH_BITS);
 };
 
@@ -133,12 +176,15 @@ extern void elv_dispatch_sort(struct request_queue *, struct request *);
 extern void elv_dispatch_add_tail(struct request_queue *, struct request *);
 extern void elv_add_request(struct request_queue *, struct request *, int);
 extern void __elv_add_request(struct request_queue *, struct request *, int);
-extern int elv_merge(struct request_queue *, struct request **, struct bio *);
+extern enum elv_merge elv_merge(struct request_queue *, struct request **,
+               struct bio *);
 extern void elv_merge_requests(struct request_queue *, struct request *,
                               struct request *);
-extern void elv_merged_request(struct request_queue *, struct request *, int);
+extern void elv_merged_request(struct request_queue *, struct request *,
+               enum elv_merge);
 extern void elv_bio_merged(struct request_queue *q, struct request *,
                                struct bio *);
+extern bool elv_attempt_insert_merge(struct request_queue *, struct request *);
 extern void elv_requeue_request(struct request_queue *, struct request *);
 extern struct request *elv_former_request(struct request_queue *, struct request *);
 extern struct request *elv_latter_request(struct request_queue *, struct request *);
@@ -184,13 +230,6 @@ extern void elv_rb_add(struct rb_root *, struct request *);
 extern void elv_rb_del(struct rb_root *, struct request *);
 extern struct request *elv_rb_find(struct rb_root *, sector_t);
 
-/*
- * Return values from elevator merger
- */
-#define ELEVATOR_NO_MERGE      0
-#define ELEVATOR_FRONT_MERGE   1
-#define ELEVATOR_BACK_MERGE    2
-
 /*
  * Insertion selection
  */
index 2ba074328894cea30d6273a574417d789fae271d..c930cbc193420978dc20b8310abc4f3a445fd69c 100644 (file)
@@ -423,6 +423,7 @@ struct block_device {
        int                     bd_invalidated;
        struct gendisk *        bd_disk;
        struct request_queue *  bd_queue;
+       struct backing_dev_info *bd_bdi;
        struct list_head        bd_list;
        /*
         * Private data.  You must have bd_claim'ed the block_device
@@ -2342,6 +2343,7 @@ extern struct kmem_cache *names_cachep;
 #ifdef CONFIG_BLOCK
 extern int register_blkdev(unsigned int, const char *);
 extern void unregister_blkdev(unsigned int, const char *);
+extern void bdev_unhash_inode(dev_t dev);
 extern struct block_device *bdget(dev_t);
 extern struct block_device *bdgrab(struct block_device *bdev);
 extern void bd_set_size(struct block_device *, loff_t size);
diff --git a/include/linux/fscrypt_common.h b/include/linux/fscrypt_common.h
new file mode 100644 (file)
index 0000000..547f815
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * fscrypt_common.h: common declarations for per-file encryption
+ *
+ * Copyright (C) 2015, Google, Inc.
+ *
+ * Written by Michael Halcrow, 2015.
+ * Modified by Jaegeuk Kim, 2015.
+ */
+
+#ifndef _LINUX_FSCRYPT_COMMON_H
+#define _LINUX_FSCRYPT_COMMON_H
+
+#include <linux/key.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/bio.h>
+#include <linux/dcache.h>
+#include <crypto/skcipher.h>
+#include <uapi/linux/fs.h>
+
+#define FS_CRYPTO_BLOCK_SIZE           16
+
+struct fscrypt_info;
+
+struct fscrypt_ctx {
+       union {
+               struct {
+                       struct page *bounce_page;       /* Ciphertext page */
+                       struct page *control_page;      /* Original page  */
+               } w;
+               struct {
+                       struct bio *bio;
+                       struct work_struct work;
+               } r;
+               struct list_head free_list;     /* Free list */
+       };
+       u8 flags;                               /* Flags */
+};
+
+/**
+ * For encrypted symlinks, the ciphertext length is stored at the beginning
+ * of the string in little-endian format.
+ */
+struct fscrypt_symlink_data {
+       __le16 len;
+       char encrypted_path[1];
+} __packed;
+
+/**
+ * This function is used to calculate the disk space required to
+ * store a filename of length l in encrypted symlink format.
+ */
+static inline u32 fscrypt_symlink_data_len(u32 l)
+{
+       if (l < FS_CRYPTO_BLOCK_SIZE)
+               l = FS_CRYPTO_BLOCK_SIZE;
+       return (l + sizeof(struct fscrypt_symlink_data) - 1);
+}
+
+struct fscrypt_str {
+       unsigned char *name;
+       u32 len;
+};
+
+struct fscrypt_name {
+       const struct qstr *usr_fname;
+       struct fscrypt_str disk_name;
+       u32 hash;
+       u32 minor_hash;
+       struct fscrypt_str crypto_buf;
+};
+
+#define FSTR_INIT(n, l)                { .name = n, .len = l }
+#define FSTR_TO_QSTR(f)                QSTR_INIT((f)->name, (f)->len)
+#define fname_name(p)          ((p)->disk_name.name)
+#define fname_len(p)           ((p)->disk_name.len)
+
+/*
+ * fscrypt superblock flags
+ */
+#define FS_CFLG_OWN_PAGES (1U << 1)
+
+/*
+ * crypto opertions for filesystems
+ */
+struct fscrypt_operations {
+       unsigned int flags;
+       const char *key_prefix;
+       int (*get_context)(struct inode *, void *, size_t);
+       int (*prepare_context)(struct inode *);
+       int (*set_context)(struct inode *, const void *, size_t, void *);
+       int (*dummy_context)(struct inode *);
+       bool (*is_encrypted)(struct inode *);
+       bool (*empty_dir)(struct inode *);
+       unsigned (*max_namelen)(struct inode *);
+};
+
+static inline bool fscrypt_dummy_context_enabled(struct inode *inode)
+{
+       if (inode->i_sb->s_cop->dummy_context &&
+                               inode->i_sb->s_cop->dummy_context(inode))
+               return true;
+       return false;
+}
+
+static inline bool fscrypt_valid_contents_enc_mode(u32 mode)
+{
+       return (mode == FS_ENCRYPTION_MODE_AES_256_XTS);
+}
+
+static inline bool fscrypt_valid_filenames_enc_mode(u32 mode)
+{
+       return (mode == FS_ENCRYPTION_MODE_AES_256_CTS);
+}
+
+static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
+{
+       if (str->len == 1 && str->name[0] == '.')
+               return true;
+
+       if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.')
+               return true;
+
+       return false;
+}
+
+static inline struct page *fscrypt_control_page(struct page *page)
+{
+#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
+       return ((struct fscrypt_ctx *)page_private(page))->w.control_page;
+#else
+       WARN_ON_ONCE(1);
+       return ERR_PTR(-EINVAL);
+#endif
+}
+
+static inline int fscrypt_has_encryption_key(const struct inode *inode)
+{
+#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
+       return (inode->i_crypt_info != NULL);
+#else
+       return 0;
+#endif
+}
+
+#endif /* _LINUX_FSCRYPT_COMMON_H */
diff --git a/include/linux/fscrypt_notsupp.h b/include/linux/fscrypt_notsupp.h
new file mode 100644 (file)
index 0000000..3511ca7
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * fscrypt_notsupp.h
+ *
+ * This stubs out the fscrypt functions for filesystems configured without
+ * encryption support.
+ */
+
+#ifndef _LINUX_FSCRYPT_NOTSUPP_H
+#define _LINUX_FSCRYPT_NOTSUPP_H
+
+#include <linux/fscrypt_common.h>
+
+/* crypto.c */
+static inline struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *inode,
+                                                 gfp_t gfp_flags)
+{
+       return ERR_PTR(-EOPNOTSUPP);
+}
+
+static inline void fscrypt_release_ctx(struct fscrypt_ctx *ctx)
+{
+       return;
+}
+
+static inline struct page *fscrypt_encrypt_page(const struct inode *inode,
+                                               struct page *page,
+                                               unsigned int len,
+                                               unsigned int offs,
+                                               u64 lblk_num, gfp_t gfp_flags)
+{
+       return ERR_PTR(-EOPNOTSUPP);
+}
+
+static inline int fscrypt_decrypt_page(const struct inode *inode,
+                                      struct page *page,
+                                      unsigned int len, unsigned int offs,
+                                      u64 lblk_num)
+{
+       return -EOPNOTSUPP;
+}
+
+
+static inline void fscrypt_restore_control_page(struct page *page)
+{
+       return;
+}
+
+static inline void fscrypt_set_d_op(struct dentry *dentry)
+{
+       return;
+}
+
+static inline void fscrypt_set_encrypted_dentry(struct dentry *dentry)
+{
+       return;
+}
+
+/* policy.c */
+static inline int fscrypt_ioctl_set_policy(struct file *filp,
+                                          const void __user *arg)
+{
+       return -EOPNOTSUPP;
+}
+
+static inline int fscrypt_ioctl_get_policy(struct file *filp, void __user *arg)
+{
+       return -EOPNOTSUPP;
+}
+
+static inline int fscrypt_has_permitted_context(struct inode *parent,
+                                               struct inode *child)
+{
+       return 0;
+}
+
+static inline int fscrypt_inherit_context(struct inode *parent,
+                                         struct inode *child,
+                                         void *fs_data, bool preload)
+{
+       return -EOPNOTSUPP;
+}
+
+/* keyinfo.c */
+static inline int fscrypt_get_encryption_info(struct inode *inode)
+{
+       return -EOPNOTSUPP;
+}
+
+static inline void fscrypt_put_encryption_info(struct inode *inode,
+                                              struct fscrypt_info *ci)
+{
+       return;
+}
+
+ /* fname.c */
+static inline int fscrypt_setup_filename(struct inode *dir,
+                                        const struct qstr *iname,
+                                        int lookup, struct fscrypt_name *fname)
+{
+       if (dir->i_sb->s_cop->is_encrypted(dir))
+               return -EOPNOTSUPP;
+
+       memset(fname, 0, sizeof(struct fscrypt_name));
+       fname->usr_fname = iname;
+       fname->disk_name.name = (unsigned char *)iname->name;
+       fname->disk_name.len = iname->len;
+       return 0;
+}
+
+static inline void fscrypt_free_filename(struct fscrypt_name *fname)
+{
+       return;
+}
+
+static inline u32 fscrypt_fname_encrypted_size(const struct inode *inode,
+                                              u32 ilen)
+{
+       /* never happens */
+       WARN_ON(1);
+       return 0;
+}
+
+static inline int fscrypt_fname_alloc_buffer(const struct inode *inode,
+                                            u32 ilen,
+                                            struct fscrypt_str *crypto_str)
+{
+       return -EOPNOTSUPP;
+}
+
+static inline void fscrypt_fname_free_buffer(struct fscrypt_str *crypto_str)
+{
+       return;
+}
+
+static inline int fscrypt_fname_disk_to_usr(struct inode *inode,
+                                           u32 hash, u32 minor_hash,
+                                           const struct fscrypt_str *iname,
+                                           struct fscrypt_str *oname)
+{
+       return -EOPNOTSUPP;
+}
+
+static inline int fscrypt_fname_usr_to_disk(struct inode *inode,
+                                           const struct qstr *iname,
+                                           struct fscrypt_str *oname)
+{
+       return -EOPNOTSUPP;
+}
+
+/* bio.c */
+static inline void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *ctx,
+                                            struct bio *bio)
+{
+       return;
+}
+
+static inline void fscrypt_pullback_bio_page(struct page **page, bool restore)
+{
+       return;
+}
+
+static inline int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,
+                                       sector_t pblk, unsigned int len)
+{
+       return -EOPNOTSUPP;
+}
+
+#endif /* _LINUX_FSCRYPT_NOTSUPP_H */
diff --git a/include/linux/fscrypt_supp.h b/include/linux/fscrypt_supp.h
new file mode 100644 (file)
index 0000000..a140f47
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * fscrypt_supp.h
+ *
+ * This is included by filesystems configured with encryption support.
+ */
+
+#ifndef _LINUX_FSCRYPT_SUPP_H
+#define _LINUX_FSCRYPT_SUPP_H
+
+#include <linux/fscrypt_common.h>
+
+/* crypto.c */
+extern struct kmem_cache *fscrypt_info_cachep;
+extern struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *, gfp_t);
+extern void fscrypt_release_ctx(struct fscrypt_ctx *);
+extern struct page *fscrypt_encrypt_page(const struct inode *, struct page *,
+                                               unsigned int, unsigned int,
+                                               u64, gfp_t);
+extern int fscrypt_decrypt_page(const struct inode *, struct page *, unsigned int,
+                               unsigned int, u64);
+extern void fscrypt_restore_control_page(struct page *);
+
+extern const struct dentry_operations fscrypt_d_ops;
+
+static inline void fscrypt_set_d_op(struct dentry *dentry)
+{
+       d_set_d_op(dentry, &fscrypt_d_ops);
+}
+
+static inline void fscrypt_set_encrypted_dentry(struct dentry *dentry)
+{
+       spin_lock(&dentry->d_lock);
+       dentry->d_flags |= DCACHE_ENCRYPTED_WITH_KEY;
+       spin_unlock(&dentry->d_lock);
+}
+
+/* policy.c */
+extern int fscrypt_ioctl_set_policy(struct file *, const void __user *);
+extern int fscrypt_ioctl_get_policy(struct file *, void __user *);
+extern int fscrypt_has_permitted_context(struct inode *, struct inode *);
+extern int fscrypt_inherit_context(struct inode *, struct inode *,
+                                       void *, bool);
+/* keyinfo.c */
+extern int fscrypt_get_encryption_info(struct inode *);
+extern void fscrypt_put_encryption_info(struct inode *, struct fscrypt_info *);
+
+/* fname.c */
+extern int fscrypt_setup_filename(struct inode *, const struct qstr *,
+                               int lookup, struct fscrypt_name *);
+extern void fscrypt_free_filename(struct fscrypt_name *);
+extern u32 fscrypt_fname_encrypted_size(const struct inode *, u32);
+extern int fscrypt_fname_alloc_buffer(const struct inode *, u32,
+                               struct fscrypt_str *);
+extern void fscrypt_fname_free_buffer(struct fscrypt_str *);
+extern int fscrypt_fname_disk_to_usr(struct inode *, u32, u32,
+                       const struct fscrypt_str *, struct fscrypt_str *);
+extern int fscrypt_fname_usr_to_disk(struct inode *, const struct qstr *,
+                       struct fscrypt_str *);
+
+/* bio.c */
+extern void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *, struct bio *);
+extern void fscrypt_pullback_bio_page(struct page **, bool);
+extern int fscrypt_zeroout_range(const struct inode *, pgoff_t, sector_t,
+                                unsigned int);
+
+#endif /* _LINUX_FSCRYPT_SUPP_H */
diff --git a/include/linux/fscrypto.h b/include/linux/fscrypto.h
deleted file mode 100644 (file)
index c074b67..0000000
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * General per-file encryption definition
- *
- * Copyright (C) 2015, Google, Inc.
- *
- * Written by Michael Halcrow, 2015.
- * Modified by Jaegeuk Kim, 2015.
- */
-
-#ifndef _LINUX_FSCRYPTO_H
-#define _LINUX_FSCRYPTO_H
-
-#include <linux/key.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/bio.h>
-#include <linux/dcache.h>
-#include <crypto/skcipher.h>
-#include <uapi/linux/fs.h>
-
-#define FS_CRYPTO_BLOCK_SIZE           16
-
-struct fscrypt_info;
-
-struct fscrypt_ctx {
-       union {
-               struct {
-                       struct page *bounce_page;       /* Ciphertext page */
-                       struct page *control_page;      /* Original page  */
-               } w;
-               struct {
-                       struct bio *bio;
-                       struct work_struct work;
-               } r;
-               struct list_head free_list;     /* Free list */
-       };
-       u8 flags;                               /* Flags */
-       u8 mode;                                /* Encryption mode for tfm */
-};
-
-/**
- * For encrypted symlinks, the ciphertext length is stored at the beginning
- * of the string in little-endian format.
- */
-struct fscrypt_symlink_data {
-       __le16 len;
-       char encrypted_path[1];
-} __packed;
-
-/**
- * This function is used to calculate the disk space required to
- * store a filename of length l in encrypted symlink format.
- */
-static inline u32 fscrypt_symlink_data_len(u32 l)
-{
-       if (l < FS_CRYPTO_BLOCK_SIZE)
-               l = FS_CRYPTO_BLOCK_SIZE;
-       return (l + sizeof(struct fscrypt_symlink_data) - 1);
-}
-
-struct fscrypt_str {
-       unsigned char *name;
-       u32 len;
-};
-
-struct fscrypt_name {
-       const struct qstr *usr_fname;
-       struct fscrypt_str disk_name;
-       u32 hash;
-       u32 minor_hash;
-       struct fscrypt_str crypto_buf;
-};
-
-#define FSTR_INIT(n, l)                { .name = n, .len = l }
-#define FSTR_TO_QSTR(f)                QSTR_INIT((f)->name, (f)->len)
-#define fname_name(p)          ((p)->disk_name.name)
-#define fname_len(p)           ((p)->disk_name.len)
-
-/*
- * fscrypt superblock flags
- */
-#define FS_CFLG_OWN_PAGES (1U << 1)
-
-/*
- * crypto opertions for filesystems
- */
-struct fscrypt_operations {
-       unsigned int flags;
-       int (*get_context)(struct inode *, void *, size_t);
-       int (*key_prefix)(struct inode *, u8 **);
-       int (*prepare_context)(struct inode *);
-       int (*set_context)(struct inode *, const void *, size_t, void *);
-       int (*dummy_context)(struct inode *);
-       bool (*is_encrypted)(struct inode *);
-       bool (*empty_dir)(struct inode *);
-       unsigned (*max_namelen)(struct inode *);
-};
-
-static inline bool fscrypt_dummy_context_enabled(struct inode *inode)
-{
-       if (inode->i_sb->s_cop->dummy_context &&
-                               inode->i_sb->s_cop->dummy_context(inode))
-               return true;
-       return false;
-}
-
-static inline bool fscrypt_valid_contents_enc_mode(u32 mode)
-{
-       return (mode == FS_ENCRYPTION_MODE_AES_256_XTS);
-}
-
-static inline bool fscrypt_valid_filenames_enc_mode(u32 mode)
-{
-       return (mode == FS_ENCRYPTION_MODE_AES_256_CTS);
-}
-
-static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
-{
-       if (str->len == 1 && str->name[0] == '.')
-               return true;
-
-       if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.')
-               return true;
-
-       return false;
-}
-
-static inline struct page *fscrypt_control_page(struct page *page)
-{
-#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
-       return ((struct fscrypt_ctx *)page_private(page))->w.control_page;
-#else
-       WARN_ON_ONCE(1);
-       return ERR_PTR(-EINVAL);
-#endif
-}
-
-static inline int fscrypt_has_encryption_key(const struct inode *inode)
-{
-#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
-       return (inode->i_crypt_info != NULL);
-#else
-       return 0;
-#endif
-}
-
-static inline void fscrypt_set_encrypted_dentry(struct dentry *dentry)
-{
-#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
-       spin_lock(&dentry->d_lock);
-       dentry->d_flags |= DCACHE_ENCRYPTED_WITH_KEY;
-       spin_unlock(&dentry->d_lock);
-#endif
-}
-
-#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
-extern const struct dentry_operations fscrypt_d_ops;
-#endif
-
-static inline void fscrypt_set_d_op(struct dentry *dentry)
-{
-#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
-       d_set_d_op(dentry, &fscrypt_d_ops);
-#endif
-}
-
-#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
-/* crypto.c */
-extern struct kmem_cache *fscrypt_info_cachep;
-extern struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *, gfp_t);
-extern void fscrypt_release_ctx(struct fscrypt_ctx *);
-extern struct page *fscrypt_encrypt_page(const struct inode *, struct page *,
-                                               unsigned int, unsigned int,
-                                               u64, gfp_t);
-extern int fscrypt_decrypt_page(const struct inode *, struct page *, unsigned int,
-                               unsigned int, u64);
-extern void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *, struct bio *);
-extern void fscrypt_pullback_bio_page(struct page **, bool);
-extern void fscrypt_restore_control_page(struct page *);
-extern int fscrypt_zeroout_range(const struct inode *, pgoff_t, sector_t,
-                                               unsigned int);
-/* policy.c */
-extern int fscrypt_ioctl_set_policy(struct file *, const void __user *);
-extern int fscrypt_ioctl_get_policy(struct file *, void __user *);
-extern int fscrypt_has_permitted_context(struct inode *, struct inode *);
-extern int fscrypt_inherit_context(struct inode *, struct inode *,
-                                       void *, bool);
-/* keyinfo.c */
-extern int fscrypt_get_encryption_info(struct inode *);
-extern void fscrypt_put_encryption_info(struct inode *, struct fscrypt_info *);
-
-/* fname.c */
-extern int fscrypt_setup_filename(struct inode *, const struct qstr *,
-                               int lookup, struct fscrypt_name *);
-extern void fscrypt_free_filename(struct fscrypt_name *);
-extern u32 fscrypt_fname_encrypted_size(const struct inode *, u32);
-extern int fscrypt_fname_alloc_buffer(const struct inode *, u32,
-                               struct fscrypt_str *);
-extern void fscrypt_fname_free_buffer(struct fscrypt_str *);
-extern int fscrypt_fname_disk_to_usr(struct inode *, u32, u32,
-                       const struct fscrypt_str *, struct fscrypt_str *);
-extern int fscrypt_fname_usr_to_disk(struct inode *, const struct qstr *,
-                       struct fscrypt_str *);
-#endif
-
-/* crypto.c */
-static inline struct fscrypt_ctx *fscrypt_notsupp_get_ctx(const struct inode *i,
-                                                       gfp_t f)
-{
-       return ERR_PTR(-EOPNOTSUPP);
-}
-
-static inline void fscrypt_notsupp_release_ctx(struct fscrypt_ctx *c)
-{
-       return;
-}
-
-static inline struct page *fscrypt_notsupp_encrypt_page(const struct inode *i,
-                                               struct page *p,
-                                               unsigned int len,
-                                               unsigned int offs,
-                                               u64 lblk_num, gfp_t f)
-{
-       return ERR_PTR(-EOPNOTSUPP);
-}
-
-static inline int fscrypt_notsupp_decrypt_page(const struct inode *i, struct page *p,
-                                               unsigned int len, unsigned int offs,
-                                               u64 lblk_num)
-{
-       return -EOPNOTSUPP;
-}
-
-static inline void fscrypt_notsupp_decrypt_bio_pages(struct fscrypt_ctx *c,
-                                               struct bio *b)
-{
-       return;
-}
-
-static inline void fscrypt_notsupp_pullback_bio_page(struct page **p, bool b)
-{
-       return;
-}
-
-static inline void fscrypt_notsupp_restore_control_page(struct page *p)
-{
-       return;
-}
-
-static inline int fscrypt_notsupp_zeroout_range(const struct inode *i, pgoff_t p,
-                                       sector_t s, unsigned int f)
-{
-       return -EOPNOTSUPP;
-}
-
-/* policy.c */
-static inline int fscrypt_notsupp_ioctl_set_policy(struct file *f,
-                               const void __user *arg)
-{
-       return -EOPNOTSUPP;
-}
-
-static inline int fscrypt_notsupp_ioctl_get_policy(struct file *f,
-                               void __user *arg)
-{
-       return -EOPNOTSUPP;
-}
-
-static inline int fscrypt_notsupp_has_permitted_context(struct inode *p,
-                               struct inode *i)
-{
-       return 0;
-}
-
-static inline int fscrypt_notsupp_inherit_context(struct inode *p,
-                               struct inode *i, void *v, bool b)
-{
-       return -EOPNOTSUPP;
-}
-
-/* keyinfo.c */
-static inline int fscrypt_notsupp_get_encryption_info(struct inode *i)
-{
-       return -EOPNOTSUPP;
-}
-
-static inline void fscrypt_notsupp_put_encryption_info(struct inode *i,
-                                       struct fscrypt_info *f)
-{
-       return;
-}
-
- /* fname.c */
-static inline int fscrypt_notsupp_setup_filename(struct inode *dir,
-                       const struct qstr *iname,
-                       int lookup, struct fscrypt_name *fname)
-{
-       if (dir->i_sb->s_cop->is_encrypted(dir))
-               return -EOPNOTSUPP;
-
-       memset(fname, 0, sizeof(struct fscrypt_name));
-       fname->usr_fname = iname;
-       fname->disk_name.name = (unsigned char *)iname->name;
-       fname->disk_name.len = iname->len;
-       return 0;
-}
-
-static inline void fscrypt_notsupp_free_filename(struct fscrypt_name *fname)
-{
-       return;
-}
-
-static inline u32 fscrypt_notsupp_fname_encrypted_size(struct inode *i, u32 s)
-{
-       /* never happens */
-       WARN_ON(1);
-       return 0;
-}
-
-static inline int fscrypt_notsupp_fname_alloc_buffer(struct inode *inode,
-                               u32 ilen, struct fscrypt_str *crypto_str)
-{
-       return -EOPNOTSUPP;
-}
-
-static inline void fscrypt_notsupp_fname_free_buffer(struct fscrypt_str *c)
-{
-       return;
-}
-
-static inline int fscrypt_notsupp_fname_disk_to_usr(struct inode *inode,
-                       u32 hash, u32 minor_hash,
-                       const struct fscrypt_str *iname,
-                       struct fscrypt_str *oname)
-{
-       return -EOPNOTSUPP;
-}
-
-static inline int fscrypt_notsupp_fname_usr_to_disk(struct inode *inode,
-                       const struct qstr *iname,
-                       struct fscrypt_str *oname)
-{
-       return -EOPNOTSUPP;
-}
-#endif /* _LINUX_FSCRYPTO_H */
index 76f39754e7b0299df616bc3cb909f9a35fce9ea1..a999d281a2f1e41ce6cb7613dc5ecd8e0d4797c8 100644 (file)
@@ -167,6 +167,13 @@ struct blk_integrity {
 };
 
 #endif /* CONFIG_BLK_DEV_INTEGRITY */
+struct disk_devt {
+       atomic_t count;
+       void (*release)(struct disk_devt *disk_devt);
+};
+
+void put_disk_devt(struct disk_devt *disk_devt);
+void get_disk_devt(struct disk_devt *disk_devt);
 
 struct gendisk {
        /* major, first_minor and minors are input parameters only,
@@ -176,6 +183,7 @@ struct gendisk {
        int first_minor;
        int minors;                     /* maximum number of minors, =1 for
                                          * disks that can't be partitioned. */
+       struct disk_devt *disk_devt;
 
        char disk_name[DISK_NAME_LEN];  /* name of major driver */
        char *(*devnode)(struct gendisk *gd, umode_t *mode);
index e973faba69dc5c90586aa97511d860178f31ff2e..846f3b9894805c482242c8b0117fe2537842e5bb 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/irqdomain.h>
 #include <linux/lockdep.h>
 #include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinconf-generic.h>
 
 struct gpio_desc;
 struct of_phandle_args;
@@ -18,18 +19,6 @@ struct module;
 
 #ifdef CONFIG_GPIOLIB
 
-/**
- * enum single_ended_mode - mode for single ended operation
- * @LINE_MODE_PUSH_PULL: normal mode for a GPIO line, drive actively high/low
- * @LINE_MODE_OPEN_DRAIN: set line to be open drain
- * @LINE_MODE_OPEN_SOURCE: set line to be open source
- */
-enum single_ended_mode {
-       LINE_MODE_PUSH_PULL,
-       LINE_MODE_OPEN_DRAIN,
-       LINE_MODE_OPEN_SOURCE,
-};
-
 /**
  * struct gpio_chip - abstract a GPIO controller
  * @label: a functional name for the GPIO device, such as a part
@@ -48,16 +37,8 @@ enum single_ended_mode {
  * @get: returns value for signal "offset", 0=low, 1=high, or negative error
  * @set: assigns output value for signal "offset"
  * @set_multiple: assigns output values for multiple signals defined by "mask"
- * @set_debounce: optional hook for setting debounce time for specified gpio in
- *     interrupt triggered gpio chips
- * @set_single_ended: optional hook for setting a line as open drain, open
- *     source, or non-single ended (restore from open drain/source to normal
- *     push-pull mode) this should be implemented if the hardware supports
- *     open drain or open source settings. The GPIOlib will otherwise try
- *     to emulate open drain/source by not actively driving lines high/low
- *     if a consumer request this. The driver may return -ENOTSUPP if e.g.
- *     it supports just open drain but not open source and is called
- *     with LINE_MODE_OPEN_SOURCE as mode argument.
+ * @set_config: optional hook for all kinds of settings. Uses the same
+ *     packed config format as generic pinconf.
  * @to_irq: optional hook supporting non-static gpio_to_irq() mappings;
  *     implementation may not sleep
  * @dbg_show: optional routine to show contents in debugfs; default code
@@ -150,13 +131,9 @@ struct gpio_chip {
        void                    (*set_multiple)(struct gpio_chip *chip,
                                                unsigned long *mask,
                                                unsigned long *bits);
-       int                     (*set_debounce)(struct gpio_chip *chip,
-                                               unsigned offset,
-                                               unsigned debounce);
-       int                     (*set_single_ended)(struct gpio_chip *chip,
-                                               unsigned offset,
-                                               enum single_ended_mode mode);
-
+       int                     (*set_config)(struct gpio_chip *chip,
+                                             unsigned offset,
+                                             unsigned long config);
        int                     (*to_irq)(struct gpio_chip *chip,
                                                unsigned offset);
 
@@ -340,6 +317,8 @@ static inline int gpiochip_irqchip_add_nested(struct gpio_chip *gpiochip,
 
 int gpiochip_generic_request(struct gpio_chip *chip, unsigned offset);
 void gpiochip_generic_free(struct gpio_chip *chip, unsigned offset);
+int gpiochip_generic_config(struct gpio_chip *chip, unsigned offset,
+                           unsigned long config);
 
 #ifdef CONFIG_PINCTRL
 
index 28f38e2b8f309387b7a983937b50908c3095f7d9..5be325d890d96f9d823753e92296c379e3751076 100644 (file)
@@ -268,6 +268,8 @@ struct hid_item {
 #define HID_CP_APPLICATIONLAUNCHBUTTONS        0x000c0180
 #define HID_CP_GENERICGUIAPPLICATIONCONTROLS   0x000c0200
 
+#define HID_DG_DEVICECONFIG    0x000d000e
+#define HID_DG_DEVICESETTINGS  0x000d0023
 #define HID_DG_CONFIDENCE      0x000d0047
 #define HID_DG_WIDTH           0x000d0048
 #define HID_DG_HEIGHT          0x000d0049
@@ -322,7 +324,7 @@ struct hid_item {
 #define HID_QUIRK_MULTI_INPUT                  0x00000040
 #define HID_QUIRK_HIDINPUT_FORCE               0x00000080
 #define HID_QUIRK_NO_EMPTY_INPUT               0x00000100
-#define HID_QUIRK_NO_INIT_INPUT_REPORTS                0x00000200
+/* 0x00000200 reserved for backward compatibility, was NO_INIT_INPUT_REPORTS */
 #define HID_QUIRK_ALWAYS_POLL                  0x00000400
 #define HID_QUIRK_SKIP_OUTPUT_REPORTS          0x00010000
 #define HID_QUIRK_SKIP_OUTPUT_REPORT_ID                0x00020000
@@ -541,7 +543,6 @@ struct hid_device {                                                 /* device report descriptor */
        struct list_head inputs;                                        /* The list of inputs */
        void *hiddev;                                                   /* The hiddev structure */
        void *hidraw;
-       int minor;                                                      /* Hiddev minor number */
 
        int open;                                                       /* is the device open by anyone? */
        char name[128];                                                 /* Device name */
index a5dd8148660b7eb15482c99b1a602226007ec840..9216222229578075168262ac1c0cec5f88619f57 100644 (file)
  * In-kernel definitions.
  */
 
+struct hiddev {
+       int minor;
+       int exist;
+       int open;
+       struct mutex existancelock;
+       wait_queue_head_t wait;
+       struct hid_device *hid;
+       struct list_head list;
+       spinlock_t list_lock;
+       bool initialized;
+};
+
 struct hid_device;
 struct hid_usage;
 struct hid_field;
index 4b45ec46161fd66d6e7fd32f53dd71b8ac1cab42..7b23a3316dcb1f24694d759a7b5ddaf149ce5376 100644 (file)
@@ -51,6 +51,7 @@ enum i2c_slave_event;
 typedef int (*i2c_slave_cb_t)(struct i2c_client *, enum i2c_slave_event, u8 *);
 
 struct module;
+struct property_entry;
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 /*
@@ -299,6 +300,7 @@ static inline int i2c_slave_event(struct i2c_client *client,
  * @archdata: copied into i2c_client.dev.archdata
  * @of_node: pointer to OpenFirmware device node
  * @fwnode: device node supplied by the platform firmware
+ * @properties: additional device properties for the device
  * @irq: stored in i2c_client.irq
  *
  * I2C doesn't actually support hardware probing, although controllers and
@@ -320,6 +322,7 @@ struct i2c_board_info {
        struct dev_archdata     *archdata;
        struct device_node *of_node;
        struct fwnode_handle *fwnode;
+       const struct property_entry *properties;
        int             irq;
 };
 
index 7aa901d920585949b2ecf6c546d65cb004daceea..1fb088239d12b9f4a5a849a2ce662343743c8bd9 100644 (file)
 
 #include <linux/types.h>
 
+struct regulator;
+
 /**
  * struct i2chid_platform_data - used by hid over i2c implementation.
  * @hid_descriptor_address: i2c register where the HID descriptor is stored.
+ * @supply: regulator for powering on the device.
+ * @post_power_delay_ms: delay after powering on before device is usable.
  *
  * Note that it is the responsibility of the platform driver (or the acpi 5.0
  * driver, or the flattened device tree) to setup the irq related to the gpio in
@@ -31,6 +35,8 @@
  */
 struct i2c_hid_platform_data {
        u16 hid_descriptor_address;
+       struct regulator *supply;
+       int post_power_delay_ms;
 };
 
 #endif /* __LINUX_I2C_HID_H */
index a633898f36ac83f387f6de86350f7768a3d73b6e..2f51c1724b5af647423770dfadafaa7a8837b600 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/mutex.h>
 /* for request_sense */
 #include <linux/cdrom.h>
+#include <scsi/scsi_cmnd.h>
 #include <asm/byteorder.h>
 #include <asm/io.h>
 
 
 struct device;
 
-/* IDE-specific values for req->cmd_type */
-enum ata_cmd_type_bits {
-       REQ_TYPE_ATA_TASKFILE = REQ_TYPE_DRV_PRIV + 1,
-       REQ_TYPE_ATA_PC,
-       REQ_TYPE_ATA_SENSE,     /* sense request */
-       REQ_TYPE_ATA_PM_SUSPEND,/* suspend request */
-       REQ_TYPE_ATA_PM_RESUME, /* resume request */
+/* values for ide_request.type */
+enum ata_priv_type {
+       ATA_PRIV_MISC,
+       ATA_PRIV_TASKFILE,
+       ATA_PRIV_PC,
+       ATA_PRIV_SENSE,         /* sense request */
+       ATA_PRIV_PM_SUSPEND,    /* suspend request */
+       ATA_PRIV_PM_RESUME,     /* resume request */
 };
 
-#define ata_pm_request(rq)     \
-       ((rq)->cmd_type == REQ_TYPE_ATA_PM_SUSPEND || \
-        (rq)->cmd_type == REQ_TYPE_ATA_PM_RESUME)
+struct ide_request {
+       struct scsi_request sreq;
+       u8 sense[SCSI_SENSE_BUFFERSIZE];
+       u8 type;
+};
+
+static inline struct ide_request *ide_req(struct request *rq)
+{
+       return blk_mq_rq_to_pdu(rq);
+}
+
+static inline bool ata_misc_request(struct request *rq)
+{
+       return blk_rq_is_private(rq) && ide_req(rq)->type == ATA_PRIV_MISC;
+}
+
+static inline bool ata_taskfile_request(struct request *rq)
+{
+       return blk_rq_is_private(rq) && ide_req(rq)->type == ATA_PRIV_TASKFILE;
+}
+
+static inline bool ata_pc_request(struct request *rq)
+{
+       return blk_rq_is_private(rq) && ide_req(rq)->type == ATA_PRIV_PC;
+}
+
+static inline bool ata_sense_request(struct request *rq)
+{
+       return blk_rq_is_private(rq) && ide_req(rq)->type == ATA_PRIV_SENSE;
+}
+
+static inline bool ata_pm_request(struct request *rq)
+{
+       return blk_rq_is_private(rq) &&
+               (ide_req(rq)->type == ATA_PRIV_PM_SUSPEND ||
+                ide_req(rq)->type == ATA_PRIV_PM_RESUME);
+}
 
 /* Error codes returned in rq->errors to the higher part of the driver. */
 enum {
@@ -579,7 +615,7 @@ struct ide_drive_s {
 
        /* current sense rq and buffer */
        bool sense_rq_armed;
-       struct request sense_rq;
+       struct request *sense_rq;
        struct request_sense sense_data;
 };
 
index 569cb531094c20a9aa2db478aaa6f348d2afd7f4..38c0bd7ca1074af234d516275791d05f945ce1f0 100644 (file)
@@ -13,6 +13,7 @@
 #define __LINUX_LEDS_H_INCLUDED
 
 #include <linux/device.h>
+#include <linux/kernfs.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
 #include <linux/rwsem.h>
@@ -27,6 +28,7 @@ struct device;
 
 enum led_brightness {
        LED_OFF         = 0,
+       LED_ON          = 1,
        LED_HALF        = 127,
        LED_FULL        = 255,
 };
@@ -46,6 +48,7 @@ struct led_classdev {
 #define LED_DEV_CAP_FLASH      (1 << 18)
 #define LED_HW_PLUGGABLE       (1 << 19)
 #define LED_PANIC_INDICATOR    (1 << 20)
+#define LED_BRIGHT_HW_CHANGED  (1 << 21)
 
        /* set_brightness_work / blink_timer flags, atomic, private. */
        unsigned long           work_flags;
@@ -110,6 +113,11 @@ struct led_classdev {
        bool                    activated;
 #endif
 
+#ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED
+       int                      brightness_hw_changed;
+       struct kernfs_node      *brightness_hw_changed_kn;
+#endif
+
        /* Ensures consistent access to the LED Flash Class device */
        struct mutex            led_access;
 };
@@ -422,4 +430,12 @@ static inline void ledtrig_cpu(enum cpu_led_event evt)
 }
 #endif
 
+#ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED
+extern void led_classdev_notify_brightness_hw_changed(
+       struct led_classdev *led_cdev, enum led_brightness brightness);
+#else
+static inline void led_classdev_notify_brightness_hw_changed(
+       struct led_classdev *led_cdev, enum led_brightness brightness) { }
+#endif
+
 #endif         /* __LINUX_LEDS_H_INCLUDED */
index c170be548b7f1626c7c3a3eb27acd083ee54a5e7..c9a69fc8821ee16e3f479b02db6291c66630afbb 100644 (file)
@@ -968,7 +968,7 @@ struct ata_port_operations {
        void (*sff_tf_read)(struct ata_port *ap, struct ata_taskfile *tf);
        void (*sff_exec_command)(struct ata_port *ap,
                                 const struct ata_taskfile *tf);
-       unsigned int (*sff_data_xfer)(struct ata_device *dev,
+       unsigned int (*sff_data_xfer)(struct ata_queued_cmd *qc,
                        unsigned char *buf, unsigned int buflen, int rw);
        void (*sff_irq_on)(struct ata_port *);
        bool (*sff_irq_check)(struct ata_port *);
@@ -1130,6 +1130,7 @@ extern int ata_sas_port_start(struct ata_port *ap);
 extern void ata_sas_port_stop(struct ata_port *ap);
 extern int ata_sas_slave_configure(struct scsi_device *, struct ata_port *);
 extern int ata_sas_queuecmd(struct scsi_cmnd *cmd, struct ata_port *ap);
+extern enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
 extern int sata_scr_valid(struct ata_link *link);
 extern int sata_scr_read(struct ata_link *link, int reg, u32 *val);
 extern int sata_scr_write(struct ata_link *link, int reg, u32 val);
@@ -1355,6 +1356,7 @@ extern struct device_attribute *ata_common_sdev_attrs[];
        .proc_name              = drv_name,                     \
        .slave_configure        = ata_scsi_slave_config,        \
        .slave_destroy          = ata_scsi_slave_destroy,       \
+       .eh_timed_out           = ata_scsi_timed_out,           \
        .bios_param             = ata_std_bios_param,           \
        .unlock_native_capacity = ata_scsi_unlock_native_capacity, \
        .sdev_attrs             = ata_common_sdev_attrs
@@ -1823,11 +1825,11 @@ extern void ata_sff_tf_load(struct ata_port *ap, const struct ata_taskfile *tf);
 extern void ata_sff_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
 extern void ata_sff_exec_command(struct ata_port *ap,
                                 const struct ata_taskfile *tf);
-extern unsigned int ata_sff_data_xfer(struct ata_device *dev,
+extern unsigned int ata_sff_data_xfer(struct ata_queued_cmd *qc,
                        unsigned char *buf, unsigned int buflen, int rw);
-extern unsigned int ata_sff_data_xfer32(struct ata_device *dev,
+extern unsigned int ata_sff_data_xfer32(struct ata_queued_cmd *qc,
                        unsigned char *buf, unsigned int buflen, int rw);
-extern unsigned int ata_sff_data_xfer_noirq(struct ata_device *dev,
+extern unsigned int ata_sff_data_xfer_noirq(struct ata_queued_cmd *qc,
                        unsigned char *buf, unsigned int buflen, int rw);
 extern void ata_sff_irq_on(struct ata_port *ap);
 extern void ata_sff_irq_clear(struct ata_port *ap);
index 7c273bbc5351d528357d223dfb1427eb269b14c7..ca45e4a088a91eb929a208de5ffb061b33c9ff2c 100644 (file)
@@ -80,8 +80,6 @@ struct nvm_dev_ops {
        unsigned int            max_phys_sect;
 };
 
-
-
 #ifdef CONFIG_NVM
 
 #include <linux/blkdev.h>
@@ -109,6 +107,7 @@ enum {
        NVM_RSP_ERR_FAILWRITE   = 0x40ff,
        NVM_RSP_ERR_EMPTYPAGE   = 0x42ff,
        NVM_RSP_ERR_FAILECC     = 0x4281,
+       NVM_RSP_ERR_FAILCRC     = 0x4004,
        NVM_RSP_WARN_HIGHECC    = 0x4700,
 
        /* Device opcodes */
@@ -202,11 +201,10 @@ struct nvm_addr_format {
 struct nvm_id {
        u8      ver_id;
        u8      vmnt;
-       u8      cgrps;
        u32     cap;
        u32     dom;
        struct nvm_addr_format ppaf;
-       struct nvm_id_group groups[4];
+       struct nvm_id_group grp;
 } __packed;
 
 struct nvm_target {
@@ -216,10 +214,6 @@ struct nvm_target {
        struct gendisk *disk;
 };
 
-struct nvm_tgt_instance {
-       struct nvm_tgt_type *tt;
-};
-
 #define ADDR_EMPTY (~0ULL)
 
 #define NVM_VERSION_MAJOR 1
@@ -230,7 +224,6 @@ struct nvm_rq;
 typedef void (nvm_end_io_fn)(struct nvm_rq *);
 
 struct nvm_rq {
-       struct nvm_tgt_instance *ins;
        struct nvm_tgt_dev *dev;
 
        struct bio *bio;
@@ -254,6 +247,8 @@ struct nvm_rq {
 
        u64 ppa_status; /* ppa media status */
        int error;
+
+       void *private;
 };
 
 static inline struct nvm_rq *nvm_rq_from_pdu(void *pdu)
@@ -272,15 +267,6 @@ enum {
        NVM_BLK_ST_BAD =        0x8,    /* Bad block */
 };
 
-/* system block cpu representation */
-struct nvm_sb_info {
-       unsigned long           seqnr;
-       unsigned long           erase_cnt;
-       unsigned int            version;
-       char                    mmtype[NVM_MMTYPE_LEN];
-       struct ppa_addr         fs_ppa;
-};
-
 /* Device generic information */
 struct nvm_geo {
        int nr_chnls;
@@ -308,6 +294,7 @@ struct nvm_geo {
        int sec_per_lun;
 };
 
+/* sub-device structure */
 struct nvm_tgt_dev {
        /* Device information */
        struct nvm_geo geo;
@@ -329,17 +316,10 @@ struct nvm_dev {
 
        struct list_head devices;
 
-       /* Media manager */
-       struct nvmm_type *mt;
-       void *mp;
-
-       /* System blocks */
-       struct nvm_sb_info sb;
-
        /* Device information */
        struct nvm_geo geo;
 
-       /* lower page table */
+         /* lower page table */
        int lps_per_blk;
        int *lptbl;
 
@@ -359,6 +339,10 @@ struct nvm_dev {
 
        struct mutex mlock;
        spinlock_t lock;
+
+       /* target management */
+       struct list_head area_list;
+       struct list_head targets;
 };
 
 static inline struct ppa_addr linear_to_generic_addr(struct nvm_geo *geo,
@@ -391,10 +375,10 @@ static inline struct ppa_addr linear_to_generic_addr(struct nvm_geo *geo,
        return l;
 }
 
-static inline struct ppa_addr generic_to_dev_addr(struct nvm_dev *dev,
-                                               struct ppa_addr r)
+static inline struct ppa_addr generic_to_dev_addr(struct nvm_tgt_dev *tgt_dev,
+                                                 struct ppa_addr r)
 {
-       struct nvm_geo *geo = &dev->geo;
+       struct nvm_geo *geo = &tgt_dev->geo;
        struct ppa_addr l;
 
        l.ppa = ((u64)r.g.blk) << geo->ppaf.blk_offset;
@@ -407,10 +391,10 @@ static inline struct ppa_addr generic_to_dev_addr(struct nvm_dev *dev,
        return l;
 }
 
-static inline struct ppa_addr dev_to_generic_addr(struct nvm_dev *dev,
-                                               struct ppa_addr r)
+static inline struct ppa_addr dev_to_generic_addr(struct nvm_tgt_dev *tgt_dev,
+                                                 struct ppa_addr r)
 {
-       struct nvm_geo *geo = &dev->geo;
+       struct nvm_geo *geo = &tgt_dev->geo;
        struct ppa_addr l;
 
        l.ppa = 0;
@@ -452,15 +436,12 @@ static inline int ppa_cmp_blk(struct ppa_addr ppa1, struct ppa_addr ppa2)
                                        (ppa1.g.blk == ppa2.g.blk));
 }
 
-static inline int ppa_to_slc(struct nvm_dev *dev, int slc_pg)
-{
-       return dev->lptbl[slc_pg];
-}
-
 typedef blk_qc_t (nvm_tgt_make_rq_fn)(struct request_queue *, struct bio *);
 typedef sector_t (nvm_tgt_capacity_fn)(void *);
 typedef void *(nvm_tgt_init_fn)(struct nvm_tgt_dev *, struct gendisk *);
 typedef void (nvm_tgt_exit_fn)(void *);
+typedef int (nvm_tgt_sysfs_init_fn)(struct gendisk *);
+typedef void (nvm_tgt_sysfs_exit_fn)(struct gendisk *);
 
 struct nvm_tgt_type {
        const char *name;
@@ -469,12 +450,15 @@ struct nvm_tgt_type {
        /* target entry points */
        nvm_tgt_make_rq_fn *make_rq;
        nvm_tgt_capacity_fn *capacity;
-       nvm_end_io_fn *end_io;
 
        /* module-specific init/teardown */
        nvm_tgt_init_fn *init;
        nvm_tgt_exit_fn *exit;
 
+       /* sysfs */
+       nvm_tgt_sysfs_init_fn *sysfs_init;
+       nvm_tgt_sysfs_exit_fn *sysfs_exit;
+
        /* For internal use */
        struct list_head list;
 };
@@ -487,103 +471,29 @@ extern void nvm_unregister_tgt_type(struct nvm_tgt_type *);
 extern void *nvm_dev_dma_alloc(struct nvm_dev *, gfp_t, dma_addr_t *);
 extern void nvm_dev_dma_free(struct nvm_dev *, void *, dma_addr_t);
 
-typedef int (nvmm_register_fn)(struct nvm_dev *);
-typedef void (nvmm_unregister_fn)(struct nvm_dev *);
-
-typedef int (nvmm_create_tgt_fn)(struct nvm_dev *, struct nvm_ioctl_create *);
-typedef int (nvmm_remove_tgt_fn)(struct nvm_dev *, struct nvm_ioctl_remove *);
-typedef int (nvmm_submit_io_fn)(struct nvm_tgt_dev *, struct nvm_rq *);
-typedef int (nvmm_erase_blk_fn)(struct nvm_tgt_dev *, struct ppa_addr *, int);
-typedef int (nvmm_get_area_fn)(struct nvm_dev *, sector_t *, sector_t);
-typedef void (nvmm_put_area_fn)(struct nvm_dev *, sector_t);
-typedef struct ppa_addr (nvmm_trans_ppa_fn)(struct nvm_tgt_dev *,
-                                           struct ppa_addr, int);
-typedef void (nvmm_part_to_tgt_fn)(struct nvm_dev *, sector_t*, int);
-
-enum {
-       TRANS_TGT_TO_DEV =      0x0,
-       TRANS_DEV_TO_TGT =      0x1,
-};
-
-struct nvmm_type {
-       const char *name;
-       unsigned int version[3];
-
-       nvmm_register_fn *register_mgr;
-       nvmm_unregister_fn *unregister_mgr;
-
-       nvmm_create_tgt_fn *create_tgt;
-       nvmm_remove_tgt_fn *remove_tgt;
-
-       nvmm_submit_io_fn *submit_io;
-       nvmm_erase_blk_fn *erase_blk;
-
-       nvmm_get_area_fn *get_area;
-       nvmm_put_area_fn *put_area;
-
-       nvmm_trans_ppa_fn *trans_ppa;
-       nvmm_part_to_tgt_fn *part_to_tgt;
-
-       struct list_head list;
-};
-
-extern int nvm_register_mgr(struct nvmm_type *);
-extern void nvm_unregister_mgr(struct nvmm_type *);
-
 extern struct nvm_dev *nvm_alloc_dev(int);
 extern int nvm_register(struct nvm_dev *);
 extern void nvm_unregister(struct nvm_dev *);
 
-extern int nvm_set_bb_tbl(struct nvm_dev *, struct ppa_addr *, int, int);
 extern int nvm_set_tgt_bb_tbl(struct nvm_tgt_dev *, struct ppa_addr *,
                              int, int);
 extern int nvm_max_phys_sects(struct nvm_tgt_dev *);
 extern int nvm_submit_io(struct nvm_tgt_dev *, struct nvm_rq *);
-extern void nvm_generic_to_addr_mode(struct nvm_dev *, struct nvm_rq *);
-extern void nvm_addr_to_generic_mode(struct nvm_dev *, struct nvm_rq *);
 extern int nvm_set_rqd_ppalist(struct nvm_dev *, struct nvm_rq *,
                                        const struct ppa_addr *, int, int);
 extern void nvm_free_rqd_ppalist(struct nvm_dev *, struct nvm_rq *);
-extern int nvm_erase_ppa(struct nvm_dev *, struct ppa_addr *, int, int);
 extern int nvm_erase_blk(struct nvm_tgt_dev *, struct ppa_addr *, int);
 extern int nvm_get_l2p_tbl(struct nvm_tgt_dev *, u64, u32, nvm_l2p_update_fn *,
                           void *);
 extern int nvm_get_area(struct nvm_tgt_dev *, sector_t *, sector_t);
 extern void nvm_put_area(struct nvm_tgt_dev *, sector_t);
-extern void nvm_end_io(struct nvm_rq *, int);
-extern int nvm_submit_ppa(struct nvm_dev *, struct ppa_addr *, int, int, int,
-                                                               void *, int);
-extern int nvm_submit_ppa_list(struct nvm_dev *, struct ppa_addr *, int, int,
-                                                       int, void *, int);
+extern void nvm_end_io(struct nvm_rq *);
 extern int nvm_bb_tbl_fold(struct nvm_dev *, u8 *, int);
-extern int nvm_get_bb_tbl(struct nvm_dev *, struct ppa_addr, u8 *);
 extern int nvm_get_tgt_bb_tbl(struct nvm_tgt_dev *, struct ppa_addr, u8 *);
 
-/* sysblk.c */
-#define NVM_SYSBLK_MAGIC 0x4E564D53 /* "NVMS" */
-
-/* system block on disk representation */
-struct nvm_system_block {
-       __be32                  magic;          /* magic signature */
-       __be32                  seqnr;          /* sequence number */
-       __be32                  erase_cnt;      /* erase count */
-       __be16                  version;        /* version number */
-       u8                      mmtype[NVM_MMTYPE_LEN]; /* media manager name */
-       __be64                  fs_ppa;         /* PPA for media manager
-                                                * superblock */
-};
-
-extern int nvm_get_sysblock(struct nvm_dev *, struct nvm_sb_info *);
-extern int nvm_update_sysblock(struct nvm_dev *, struct nvm_sb_info *);
-extern int nvm_init_sysblock(struct nvm_dev *, struct nvm_sb_info *);
-
 extern int nvm_dev_factory(struct nvm_dev *, int flags);
 
-#define nvm_for_each_lun_ppa(geo, ppa, chid, lunid)                    \
-       for ((chid) = 0, (ppa).ppa = 0; (chid) < (geo)->nr_chnls;       \
-                                       (chid)++, (ppa).g.ch = (chid))  \
-               for ((lunid) = 0; (lunid) < (geo)->luns_per_chnl;       \
-                                       (lunid)++, (ppa).g.lun = (lunid))
+extern void nvm_part_to_tgt(struct nvm_dev *, sector_t *, int);
 
 #else /* CONFIG_NVM */
 struct nvm_dev_ops;
index 558adfa5c8a87730f0d0177a1def7570e4883596..e29d4c62a3c8e268695d9963c2250f3eaf375399 100644 (file)
  *     Return 0 if permission is granted.
  * @inode_getattr:
  *     Check permission before obtaining file attributes.
- *     @mnt is the vfsmount where the dentry was looked up
- *     @dentry contains the dentry structure for the file.
+ *     @path contains the path structure for the file.
  *     Return 0 if permission is granted.
  * @inode_setxattr:
  *     Check permission before setting the extended attributes
  *     @sig contains the signal value.
  *     @secid contains the sid of the process where the signal originated
  *     Return 0 if permission is granted.
- * @task_wait:
- *     Check permission before allowing a process to reap a child process @p
- *     and collect its status information.
- *     @p contains the task_struct for process.
- *     Return 0 if permission is granted.
  * @task_prctl:
  *     Check permission before performing a process control operation on the
  *     current process.
@@ -1507,7 +1501,6 @@ union security_list_options {
        int (*task_movememory)(struct task_struct *p);
        int (*task_kill)(struct task_struct *p, struct siginfo *info,
                                int sig, u32 secid);
-       int (*task_wait)(struct task_struct *p);
        int (*task_prctl)(int option, unsigned long arg2, unsigned long arg3,
                                unsigned long arg4, unsigned long arg5);
        void (*task_to_inode)(struct task_struct *p, struct inode *inode);
@@ -1547,8 +1540,7 @@ union security_list_options {
        void (*d_instantiate)(struct dentry *dentry, struct inode *inode);
 
        int (*getprocattr)(struct task_struct *p, char *name, char **value);
-       int (*setprocattr)(struct task_struct *p, char *name, void *value,
-                               size_t size);
+       int (*setprocattr)(const char *name, void *value, size_t size);
        int (*ismaclabel)(const char *name);
        int (*secid_to_secctx)(u32 secid, char **secdata, u32 *seclen);
        int (*secctx_to_secid)(const char *secdata, u32 seclen, u32 *secid);
@@ -1768,7 +1760,6 @@ struct security_hook_heads {
        struct list_head task_getscheduler;
        struct list_head task_movememory;
        struct list_head task_kill;
-       struct list_head task_wait;
        struct list_head task_prctl;
        struct list_head task_to_inode;
        struct list_head ipc_permission;
@@ -1876,6 +1867,7 @@ struct security_hook_list {
        struct list_head                list;
        struct list_head                *head;
        union security_list_options     hook;
+       char                            *lsm;
 };
 
 /*
@@ -1888,15 +1880,10 @@ struct security_hook_list {
        { .head = &security_hook_heads.HEAD, .hook = { .HEAD = HOOK } }
 
 extern struct security_hook_heads security_hook_heads;
+extern char *lsm_names;
 
-static inline void security_add_hooks(struct security_hook_list *hooks,
-                                     int count)
-{
-       int i;
-
-       for (i = 0; i < count; i++)
-               list_add_tail_rcu(&hooks[i].list, hooks[i].head);
-}
+extern void security_add_hooks(struct security_hook_list *hooks, int count,
+                               char *lsm);
 
 #ifdef CONFIG_SECURITY_SELINUX_DISABLE
 /*
index fba44abd05ba1a9dd4e8c802b6d60fd18766f05e..a1520d88ebf3a3465532ede9255f9e21580b56e8 100644 (file)
  */
 #define TMIO_MMC_HAVE_CMD12_CTRL       (1 << 7)
 
-/*
- * Some controllers needs to set 1 on SDIO status reserved bits
- */
-#define TMIO_MMC_SDIO_STATUS_QUIRK     (1 << 8)
+/* Controller has some SDIO status bits which must be 1 */
+#define TMIO_MMC_SDIO_STATUS_SETBITS   (1 << 8)
 
 /*
  * Some controllers have a 32-bit wide data port register
diff --git a/include/linux/mmc/boot.h b/include/linux/mmc/boot.h
deleted file mode 100644 (file)
index 23acc3b..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef LINUX_MMC_BOOT_H
-#define LINUX_MMC_BOOT_H
-
-enum { MMC_PROGRESS_ENTER, MMC_PROGRESS_INIT,
-       MMC_PROGRESS_LOAD, MMC_PROGRESS_DONE };
-
-#endif /* LINUX_MMC_BOOT_H */
index 95d69d4982965aa30fb65d9ffecfad13f4e7be8f..77e61e0a216a2728dd5cfecf55299402ac03c384 100644 (file)
@@ -11,7 +11,6 @@
 #define LINUX_MMC_CARD_H
 
 #include <linux/device.h>
-#include <linux/mmc/core.h>
 #include <linux/mod_devicetable.h>
 
 struct mmc_cid {
@@ -84,6 +83,7 @@ struct mmc_ext_csd {
        unsigned int            hpi_cmd;                /* cmd used as HPI */
        bool                    bkops;          /* background support bit */
        bool                    man_bkops_en;   /* manual bkops enable bit */
+       bool                    auto_bkops_en;  /* auto bkops enable bit */
        unsigned int            data_sector_size;       /* 512 bytes or 4KB */
        unsigned int            data_tag_unit_size;     /* DATA TAG UNIT size */
        unsigned int            boot_ro_lock;           /* ro lock support */
@@ -121,6 +121,9 @@ struct mmc_ext_csd {
        u8                      raw_pwr_cl_ddr_200_360; /* 253 */
        u8                      raw_bkops_status;       /* 246 */
        u8                      raw_sectors[4];         /* 212 - 4 bytes */
+       u8                      pre_eol_info;           /* 267 */
+       u8                      device_life_time_est_typ_a;     /* 268 */
+       u8                      device_life_time_est_typ_b;     /* 269 */
 
        unsigned int            feature_support;
 #define MMC_DISCARD_FEATURE    BIT(0)                  /* CMD38 feature */
@@ -203,7 +206,6 @@ struct sdio_cis {
 };
 
 struct mmc_host;
-struct mmc_ios;
 struct sdio_func;
 struct sdio_func_tuple;
 
@@ -247,13 +249,6 @@ struct mmc_card {
 #define MMC_TYPE_SDIO          2               /* SDIO card */
 #define MMC_TYPE_SD_COMBO      3               /* SD combo (IO+mem) card */
        unsigned int            state;          /* (our) card state */
-#define MMC_STATE_PRESENT      (1<<0)          /* present in sysfs */
-#define MMC_STATE_READONLY     (1<<1)          /* card is read-only */
-#define MMC_STATE_BLOCKADDR    (1<<2)          /* card uses block-addressing */
-#define MMC_CARD_SDXC          (1<<3)          /* card is SDXC */
-#define MMC_CARD_REMOVED       (1<<4)          /* card has been removed */
-#define MMC_STATE_DOING_BKOPS  (1<<5)          /* card is doing BKOPS */
-#define MMC_STATE_SUSPENDED    (1<<6)          /* card is suspended */
        unsigned int            quirks;         /* card quirks */
 #define MMC_QUIRK_LENIENT_FN0  (1<<0)          /* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)   /* use func->cur_blksize */
@@ -272,7 +267,6 @@ struct mmc_card {
 #define MMC_QUIRK_TRIM_BROKEN  (1<<12)         /* Skip trim */
 #define MMC_QUIRK_BROKEN_HPI   (1<<13)         /* Disable broken HPI support */
 
-
        unsigned int            erase_size;     /* erase size in sectors */
        unsigned int            erase_shift;    /* if erase unit is power 2 */
        unsigned int            pref_erase;     /* in sectors */
@@ -308,245 +302,13 @@ struct mmc_card {
        unsigned int    nr_parts;
 };
 
-/*
- * This function fill contents in mmc_part.
- */
-static inline void mmc_part_add(struct mmc_card *card, unsigned int size,
-                       unsigned int part_cfg, char *name, int idx, bool ro,
-                       int area_type)
-{
-       card->part[card->nr_parts].size = size;
-       card->part[card->nr_parts].part_cfg = part_cfg;
-       sprintf(card->part[card->nr_parts].name, name, idx);
-       card->part[card->nr_parts].force_ro = ro;
-       card->part[card->nr_parts].area_type = area_type;
-       card->nr_parts++;
-}
-
 static inline bool mmc_large_sector(struct mmc_card *card)
 {
        return card->ext_csd.data_sector_size == 4096;
 }
 
-/*
- *  The world is not perfect and supplies us with broken mmc/sdio devices.
- *  For at least some of these bugs we need a work-around.
- */
-
-struct mmc_fixup {
-       /* CID-specific fields. */
-       const char *name;
-
-       /* Valid revision range */
-       u64 rev_start, rev_end;
-
-       unsigned int manfid;
-       unsigned short oemid;
-
-       /* SDIO-specfic fields. You can use SDIO_ANY_ID here of course */
-       u16 cis_vendor, cis_device;
-
-       /* for MMC cards */
-       unsigned int ext_csd_rev;
-
-       void (*vendor_fixup)(struct mmc_card *card, int data);
-       int data;
-};
-
-#define CID_MANFID_ANY (-1u)
-#define CID_OEMID_ANY ((unsigned short) -1)
-#define CID_NAME_ANY (NULL)
-
-#define EXT_CSD_REV_ANY (-1u)
-
-#define CID_MANFID_SANDISK      0x2
-#define CID_MANFID_TOSHIBA      0x11
-#define CID_MANFID_MICRON       0x13
-#define CID_MANFID_SAMSUNG      0x15
-#define CID_MANFID_KINGSTON     0x70
-#define CID_MANFID_HYNIX       0x90
-
-#define END_FIXUP { NULL }
-
-#define _FIXUP_EXT(_name, _manfid, _oemid, _rev_start, _rev_end,       \
-                  _cis_vendor, _cis_device,                            \
-                  _fixup, _data, _ext_csd_rev)                         \
-       {                                                  \
-               .name = (_name),                           \
-               .manfid = (_manfid),                       \
-               .oemid = (_oemid),                         \
-               .rev_start = (_rev_start),                 \
-               .rev_end = (_rev_end),                     \
-               .cis_vendor = (_cis_vendor),               \
-               .cis_device = (_cis_device),               \
-               .vendor_fixup = (_fixup),                  \
-               .data = (_data),                           \
-               .ext_csd_rev = (_ext_csd_rev),             \
-        }
-
-#define MMC_FIXUP_REV(_name, _manfid, _oemid, _rev_start, _rev_end,    \
-                     _fixup, _data, _ext_csd_rev)                      \
-       _FIXUP_EXT(_name, _manfid,                                      \
-                  _oemid, _rev_start, _rev_end,                        \
-                  SDIO_ANY_ID, SDIO_ANY_ID,                            \
-                  _fixup, _data, _ext_csd_rev)                         \
-
-#define MMC_FIXUP(_name, _manfid, _oemid, _fixup, _data) \
-       MMC_FIXUP_REV(_name, _manfid, _oemid, 0, -1ull, _fixup, _data,  \
-                     EXT_CSD_REV_ANY)
-
-#define MMC_FIXUP_EXT_CSD_REV(_name, _manfid, _oemid, _fixup, _data,   \
-                             _ext_csd_rev)                             \
-       MMC_FIXUP_REV(_name, _manfid, _oemid, 0, -1ull, _fixup, _data,  \
-                     _ext_csd_rev)
-
-#define SDIO_FIXUP(_vendor, _device, _fixup, _data)                    \
-       _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_ANY,                        \
-                   CID_OEMID_ANY, 0, -1ull,                            \
-                  _vendor, _device,                                    \
-                  _fixup, _data, EXT_CSD_REV_ANY)                      \
-
-#define cid_rev(hwrev, fwrev, year, month)     \
-       (((u64) hwrev) << 40 |                  \
-        ((u64) fwrev) << 32 |                  \
-        ((u64) year) << 16 |                   \
-        ((u64) month))
-
-#define cid_rev_card(card)               \
-       cid_rev(card->cid.hwrev,          \
-                   card->cid.fwrev,      \
-                   card->cid.year,       \
-                   card->cid.month)
-
-/*
- * Unconditionally quirk add/remove.
- */
-
-static inline void __maybe_unused add_quirk(struct mmc_card *card, int data)
-{
-       card->quirks |= data;
-}
-
-static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
-{
-       card->quirks &= ~data;
-}
-
 #define mmc_card_mmc(c)                ((c)->type == MMC_TYPE_MMC)
 #define mmc_card_sd(c)         ((c)->type == MMC_TYPE_SD)
 #define mmc_card_sdio(c)       ((c)->type == MMC_TYPE_SDIO)
 
-#define mmc_card_present(c)    ((c)->state & MMC_STATE_PRESENT)
-#define mmc_card_readonly(c)   ((c)->state & MMC_STATE_READONLY)
-#define mmc_card_blockaddr(c)  ((c)->state & MMC_STATE_BLOCKADDR)
-#define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
-#define mmc_card_removed(c)    ((c) && ((c)->state & MMC_CARD_REMOVED))
-#define mmc_card_doing_bkops(c)        ((c)->state & MMC_STATE_DOING_BKOPS)
-#define mmc_card_suspended(c)  ((c)->state & MMC_STATE_SUSPENDED)
-
-#define mmc_card_set_present(c)        ((c)->state |= MMC_STATE_PRESENT)
-#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
-#define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
-#define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
-#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
-#define mmc_card_set_doing_bkops(c)    ((c)->state |= MMC_STATE_DOING_BKOPS)
-#define mmc_card_clr_doing_bkops(c)    ((c)->state &= ~MMC_STATE_DOING_BKOPS)
-#define mmc_card_set_suspended(c) ((c)->state |= MMC_STATE_SUSPENDED)
-#define mmc_card_clr_suspended(c) ((c)->state &= ~MMC_STATE_SUSPENDED)
-
-/*
- * Quirk add/remove for MMC products.
- */
-
-static inline void __maybe_unused add_quirk_mmc(struct mmc_card *card, int data)
-{
-       if (mmc_card_mmc(card))
-               card->quirks |= data;
-}
-
-static inline void __maybe_unused remove_quirk_mmc(struct mmc_card *card,
-                                                  int data)
-{
-       if (mmc_card_mmc(card))
-               card->quirks &= ~data;
-}
-
-/*
- * Quirk add/remove for SD products.
- */
-
-static inline void __maybe_unused add_quirk_sd(struct mmc_card *card, int data)
-{
-       if (mmc_card_sd(card))
-               card->quirks |= data;
-}
-
-static inline void __maybe_unused remove_quirk_sd(struct mmc_card *card,
-                                                  int data)
-{
-       if (mmc_card_sd(card))
-               card->quirks &= ~data;
-}
-
-static inline int mmc_card_lenient_fn0(const struct mmc_card *c)
-{
-       return c->quirks & MMC_QUIRK_LENIENT_FN0;
-}
-
-static inline int mmc_blksz_for_byte_mode(const struct mmc_card *c)
-{
-       return c->quirks & MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
-}
-
-static inline int mmc_card_disable_cd(const struct mmc_card *c)
-{
-       return c->quirks & MMC_QUIRK_DISABLE_CD;
-}
-
-static inline int mmc_card_nonstd_func_interface(const struct mmc_card *c)
-{
-       return c->quirks & MMC_QUIRK_NONSTD_FUNC_IF;
-}
-
-static inline int mmc_card_broken_byte_mode_512(const struct mmc_card *c)
-{
-       return c->quirks & MMC_QUIRK_BROKEN_BYTE_MODE_512;
-}
-
-static inline int mmc_card_long_read_time(const struct mmc_card *c)
-{
-       return c->quirks & MMC_QUIRK_LONG_READ_TIME;
-}
-
-static inline int mmc_card_broken_irq_polling(const struct mmc_card *c)
-{
-       return c->quirks & MMC_QUIRK_BROKEN_IRQ_POLLING;
-}
-
-static inline int mmc_card_broken_hpi(const struct mmc_card *c)
-{
-       return c->quirks & MMC_QUIRK_BROKEN_HPI;
-}
-
-#define mmc_card_name(c)       ((c)->cid.prod_name)
-#define mmc_card_id(c)         (dev_name(&(c)->dev))
-
-#define mmc_dev_to_card(d)     container_of(d, struct mmc_card, dev)
-
-/*
- * MMC device driver (e.g., Flash card, I/O card...)
- */
-struct mmc_driver {
-       struct device_driver drv;
-       int (*probe)(struct mmc_card *);
-       void (*remove)(struct mmc_card *);
-       void (*shutdown)(struct mmc_card *);
-};
-
-extern int mmc_register_driver(struct mmc_driver *);
-extern void mmc_unregister_driver(struct mmc_driver *);
-
-extern void mmc_fixup_device(struct mmc_card *card,
-                            const struct mmc_fixup *table);
-
 #endif /* LINUX_MMC_CARD_H */
index e33cc748dcfe16e65d20ea6f815ca365deb0b2db..a0c63ea28796662160b117c14418fe2d867e536e 100644 (file)
@@ -8,10 +8,9 @@
 #ifndef LINUX_MMC_CORE_H
 #define LINUX_MMC_CORE_H
 
-#include <linux/interrupt.h>
 #include <linux/completion.h>
+#include <linux/types.h>
 
-struct request;
 struct mmc_data;
 struct mmc_request;
 
@@ -159,79 +158,14 @@ struct mmc_request {
 struct mmc_card;
 struct mmc_async_req;
 
-extern int mmc_stop_bkops(struct mmc_card *);
-extern int mmc_read_bkops_status(struct mmc_card *);
-extern struct mmc_async_req *mmc_start_req(struct mmc_host *,
-                                          struct mmc_async_req *,
-                                          enum mmc_blk_status *);
-extern int mmc_interrupt_hpi(struct mmc_card *);
-extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
-extern void mmc_wait_for_req_done(struct mmc_host *host,
-                                 struct mmc_request *mrq);
-extern bool mmc_is_req_done(struct mmc_host *host, struct mmc_request *mrq);
-extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
-extern int mmc_app_cmd(struct mmc_host *, struct mmc_card *);
-extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
-       struct mmc_command *, int);
-extern void mmc_start_bkops(struct mmc_card *card, bool from_exception);
-extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
-extern int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error);
-extern int mmc_abort_tuning(struct mmc_host *host, u32 opcode);
-extern int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
-
-#define MMC_ERASE_ARG          0x00000000
-#define MMC_SECURE_ERASE_ARG   0x80000000
-#define MMC_TRIM_ARG           0x00000001
-#define MMC_DISCARD_ARG                0x00000003
-#define MMC_SECURE_TRIM1_ARG   0x80000001
-#define MMC_SECURE_TRIM2_ARG   0x80008000
-
-#define MMC_SECURE_ARGS                0x80000000
-#define MMC_TRIM_ARGS          0x00008001
-
-extern int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
-                    unsigned int arg);
-extern int mmc_can_erase(struct mmc_card *card);
-extern int mmc_can_trim(struct mmc_card *card);
-extern int mmc_can_discard(struct mmc_card *card);
-extern int mmc_can_sanitize(struct mmc_card *card);
-extern int mmc_can_secure_erase_trim(struct mmc_card *card);
-extern int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
-                                  unsigned int nr);
-extern unsigned int mmc_calc_max_discard(struct mmc_card *card);
-
-extern int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen);
-extern int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount,
-                             bool is_rel_write);
-extern int mmc_hw_reset(struct mmc_host *host);
-extern int mmc_can_reset(struct mmc_card *card);
-
-extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *);
-extern unsigned int mmc_align_data_size(struct mmc_card *, unsigned int);
-
-extern int __mmc_claim_host(struct mmc_host *host, atomic_t *abort);
-extern void mmc_release_host(struct mmc_host *host);
-
-extern void mmc_get_card(struct mmc_card *card);
-extern void mmc_put_card(struct mmc_card *card);
-
-extern int mmc_flush_cache(struct mmc_card *);
-
-extern int mmc_detect_card_removed(struct mmc_host *host);
-
-/**
- *     mmc_claim_host - exclusively claim a host
- *     @host: mmc host to claim
- *
- *     Claim a host for a set of operations.
- */
-static inline void mmc_claim_host(struct mmc_host *host)
-{
-       __mmc_claim_host(host, NULL);
-}
-
-struct device_node;
-extern u32 mmc_vddrange_to_ocrmask(int vdd_min, int vdd_max);
-extern int mmc_of_parse_voltage(struct device_node *np, u32 *mask);
+struct mmc_async_req *mmc_start_areq(struct mmc_host *host,
+                               struct mmc_async_req *areq,
+                               enum mmc_blk_status *ret_stat);
+void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq);
+int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd,
+               int retries);
+
+int mmc_hw_reset(struct mmc_host *host);
+void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card);
 
 #endif /* LINUX_MMC_CORE_H */
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
deleted file mode 100644 (file)
index 15db6f8..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Synopsys DesignWare Multimedia Card Interface driver
- *  (Based on NXP driver for lpc 31xx)
- *
- * Copyright (C) 2009 NXP Semiconductors
- * Copyright (C) 2009, 2010 Imagination Technologies 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.
- */
-
-#ifndef LINUX_MMC_DW_MMC_H
-#define LINUX_MMC_DW_MMC_H
-
-#include <linux/scatterlist.h>
-#include <linux/mmc/core.h>
-#include <linux/dmaengine.h>
-#include <linux/reset.h>
-
-#define MAX_MCI_SLOTS  2
-
-enum dw_mci_state {
-       STATE_IDLE = 0,
-       STATE_SENDING_CMD,
-       STATE_SENDING_DATA,
-       STATE_DATA_BUSY,
-       STATE_SENDING_STOP,
-       STATE_DATA_ERROR,
-       STATE_SENDING_CMD11,
-       STATE_WAITING_CMD11_DONE,
-};
-
-enum {
-       EVENT_CMD_COMPLETE = 0,
-       EVENT_XFER_COMPLETE,
-       EVENT_DATA_COMPLETE,
-       EVENT_DATA_ERROR,
-};
-
-enum dw_mci_cookie {
-       COOKIE_UNMAPPED,
-       COOKIE_PRE_MAPPED,      /* mapped by pre_req() of dwmmc */
-       COOKIE_MAPPED,          /* mapped by prepare_data() of dwmmc */
-};
-
-struct mmc_data;
-
-enum {
-       TRANS_MODE_PIO = 0,
-       TRANS_MODE_IDMAC,
-       TRANS_MODE_EDMAC
-};
-
-struct dw_mci_dma_slave {
-       struct dma_chan *ch;
-       enum dma_transfer_direction direction;
-};
-
-/**
- * struct dw_mci - MMC controller state shared between all slots
- * @lock: Spinlock protecting the queue and associated data.
- * @irq_lock: Spinlock protecting the INTMASK setting.
- * @regs: Pointer to MMIO registers.
- * @fifo_reg: Pointer to MMIO registers for data FIFO
- * @sg: Scatterlist entry currently being processed by PIO code, if any.
- * @sg_miter: PIO mapping scatterlist iterator.
- * @cur_slot: The slot which is currently using the controller.
- * @mrq: The request currently being processed on @cur_slot,
- *     or NULL if the controller is idle.
- * @cmd: The command currently being sent to the card, or NULL.
- * @data: The data currently being transferred, or NULL if no data
- *     transfer is in progress.
- * @stop_abort: The command currently prepared for stoping transfer.
- * @prev_blksz: The former transfer blksz record.
- * @timing: Record of current ios timing.
- * @use_dma: Whether DMA channel is initialized or not.
- * @using_dma: Whether DMA is in use for the current transfer.
- * @dma_64bit_address: Whether DMA supports 64-bit address mode or not.
- * @sg_dma: Bus address of DMA buffer.
- * @sg_cpu: Virtual address of DMA buffer.
- * @dma_ops: Pointer to platform-specific DMA callbacks.
- * @cmd_status: Snapshot of SR taken upon completion of the current
- * @ring_size: Buffer size for idma descriptors.
- *     command. Only valid when EVENT_CMD_COMPLETE is pending.
- * @dms: structure of slave-dma private data.
- * @phy_regs: physical address of controller's register map
- * @data_status: Snapshot of SR taken upon completion of the current
- *     data transfer. Only valid when EVENT_DATA_COMPLETE or
- *     EVENT_DATA_ERROR is pending.
- * @stop_cmdr: Value to be loaded into CMDR when the stop command is
- *     to be sent.
- * @dir_status: Direction of current transfer.
- * @tasklet: Tasklet running the request state machine.
- * @pending_events: Bitmask of events flagged by the interrupt handler
- *     to be processed by the tasklet.
- * @completed_events: Bitmask of events which the state machine has
- *     processed.
- * @state: Tasklet state.
- * @queue: List of slots waiting for access to the controller.
- * @bus_hz: The rate of @mck in Hz. This forms the basis for MMC bus
- *     rate and timeout calculations.
- * @current_speed: Configured rate of the controller.
- * @num_slots: Number of slots available.
- * @fifoth_val: The value of FIFOTH register.
- * @verid: Denote Version ID.
- * @dev: Device associated with the MMC controller.
- * @pdata: Platform data associated with the MMC controller.
- * @drv_data: Driver specific data for identified variant of the controller
- * @priv: Implementation defined private data.
- * @biu_clk: Pointer to bus interface unit clock instance.
- * @ciu_clk: Pointer to card interface unit clock instance.
- * @slot: Slots sharing this MMC controller.
- * @fifo_depth: depth of FIFO.
- * @data_shift: log2 of FIFO item size.
- * @part_buf_start: Start index in part_buf.
- * @part_buf_count: Bytes of partial data in part_buf.
- * @part_buf: Simple buffer for partial fifo reads/writes.
- * @push_data: Pointer to FIFO push function.
- * @pull_data: Pointer to FIFO pull function.
- * @vqmmc_enabled: Status of vqmmc, should be true or false.
- * @irq_flags: The flags to be passed to request_irq.
- * @irq: The irq value to be passed to request_irq.
- * @sdio_id0: Number of slot0 in the SDIO interrupt registers.
- * @cmd11_timer: Timer for SD3.0 voltage switch over scheme.
- * @dto_timer: Timer for broken data transfer over scheme.
- *
- * Locking
- * =======
- *
- * @lock is a softirq-safe spinlock protecting @queue as well as
- * @cur_slot, @mrq and @state. These must always be updated
- * at the same time while holding @lock.
- *
- * @irq_lock is an irq-safe spinlock protecting the INTMASK register
- * to allow the interrupt handler to modify it directly.  Held for only long
- * enough to read-modify-write INTMASK and no other locks are grabbed when
- * holding this one.
- *
- * The @mrq field of struct dw_mci_slot is also protected by @lock,
- * and must always be written at the same time as the slot is added to
- * @queue.
- *
- * @pending_events and @completed_events are accessed using atomic bit
- * operations, so they don't need any locking.
- *
- * None of the fields touched by the interrupt handler need any
- * locking. However, ordering is important: Before EVENT_DATA_ERROR or
- * EVENT_DATA_COMPLETE is set in @pending_events, all data-related
- * interrupts must be disabled and @data_status updated with a
- * snapshot of SR. Similarly, before EVENT_CMD_COMPLETE is set, the
- * CMDRDY interrupt must be disabled and @cmd_status updated with a
- * snapshot of SR, and before EVENT_XFER_COMPLETE can be set, the
- * bytes_xfered field of @data must be written. This is ensured by
- * using barriers.
- */
-struct dw_mci {
-       spinlock_t              lock;
-       spinlock_t              irq_lock;
-       void __iomem            *regs;
-       void __iomem            *fifo_reg;
-
-       struct scatterlist      *sg;
-       struct sg_mapping_iter  sg_miter;
-
-       struct dw_mci_slot      *cur_slot;
-       struct mmc_request      *mrq;
-       struct mmc_command      *cmd;
-       struct mmc_data         *data;
-       struct mmc_command      stop_abort;
-       unsigned int            prev_blksz;
-       unsigned char           timing;
-
-       /* DMA interface members*/
-       int                     use_dma;
-       int                     using_dma;
-       int                     dma_64bit_address;
-
-       dma_addr_t              sg_dma;
-       void                    *sg_cpu;
-       const struct dw_mci_dma_ops     *dma_ops;
-       /* For idmac */
-       unsigned int            ring_size;
-
-       /* For edmac */
-       struct dw_mci_dma_slave *dms;
-       /* Registers's physical base address */
-       resource_size_t         phy_regs;
-
-       u32                     cmd_status;
-       u32                     data_status;
-       u32                     stop_cmdr;
-       u32                     dir_status;
-       struct tasklet_struct   tasklet;
-       unsigned long           pending_events;
-       unsigned long           completed_events;
-       enum dw_mci_state       state;
-       struct list_head        queue;
-
-       u32                     bus_hz;
-       u32                     current_speed;
-       u32                     num_slots;
-       u32                     fifoth_val;
-       u16                     verid;
-       struct device           *dev;
-       struct dw_mci_board     *pdata;
-       const struct dw_mci_drv_data    *drv_data;
-       void                    *priv;
-       struct clk              *biu_clk;
-       struct clk              *ciu_clk;
-       struct dw_mci_slot      *slot[MAX_MCI_SLOTS];
-
-       /* FIFO push and pull */
-       int                     fifo_depth;
-       int                     data_shift;
-       u8                      part_buf_start;
-       u8                      part_buf_count;
-       union {
-               u16             part_buf16;
-               u32             part_buf32;
-               u64             part_buf;
-       };
-       void (*push_data)(struct dw_mci *host, void *buf, int cnt);
-       void (*pull_data)(struct dw_mci *host, void *buf, int cnt);
-
-       bool                    vqmmc_enabled;
-       unsigned long           irq_flags; /* IRQ flags */
-       int                     irq;
-
-       int                     sdio_id0;
-
-       struct timer_list       cmd11_timer;
-       struct timer_list       dto_timer;
-};
-
-/* DMA ops for Internal/External DMAC interface */
-struct dw_mci_dma_ops {
-       /* DMA Ops */
-       int (*init)(struct dw_mci *host);
-       int (*start)(struct dw_mci *host, unsigned int sg_len);
-       void (*complete)(void *host);
-       void (*stop)(struct dw_mci *host);
-       void (*cleanup)(struct dw_mci *host);
-       void (*exit)(struct dw_mci *host);
-};
-
-struct dma_pdata;
-
-/* Board platform data */
-struct dw_mci_board {
-       u32 num_slots;
-
-       unsigned int bus_hz; /* Clock speed at the cclk_in pad */
-
-       u32 caps;       /* Capabilities */
-       u32 caps2;      /* More capabilities */
-       u32 pm_caps;    /* PM capabilities */
-       /*
-        * Override fifo depth. If 0, autodetect it from the FIFOTH register,
-        * but note that this may not be reliable after a bootloader has used
-        * it.
-        */
-       unsigned int fifo_depth;
-
-       /* delay in mS before detecting cards after interrupt */
-       u32 detect_delay_ms;
-
-       struct reset_control *rstc;
-       struct dw_mci_dma_ops *dma_ops;
-       struct dma_pdata *data;
-};
-
-#endif /* LINUX_MMC_DW_MMC_H */
index 8bc8841214653c0c39d7c9e1030f6cc9b72fe78c..83f1c4a9f03b7e36b4cb9ed23346d443c2cb4f4c 100644 (file)
 #ifndef LINUX_MMC_HOST_H
 #define LINUX_MMC_HOST_H
 
-#include <linux/leds.h>
-#include <linux/mutex.h>
-#include <linux/timer.h>
 #include <linux/sched.h>
 #include <linux/device.h>
 #include <linux/fault-inject.h>
 
 #include <linux/mmc/core.h>
 #include <linux/mmc/card.h>
-#include <linux/mmc/mmc.h>
 #include <linux/mmc/pm.h>
 
 struct mmc_ios {
@@ -82,6 +78,8 @@ struct mmc_ios {
        bool enhanced_strobe;                   /* hs400es selection */
 };
 
+struct mmc_host;
+
 struct mmc_host_ops {
        /*
         * It is optional for the host to implement pre_req and post_req in
@@ -162,9 +160,6 @@ struct mmc_host_ops {
                                  unsigned int direction, int blk_size);
 };
 
-struct mmc_card;
-struct device;
-
 struct mmc_async_req {
        /* active mmc request */
        struct mmc_request      *mrq;
@@ -264,17 +259,16 @@ struct mmc_host {
 #define MMC_CAP_NONREMOVABLE   (1 << 8)        /* Nonremovable e.g. eMMC */
 #define MMC_CAP_WAIT_WHILE_BUSY        (1 << 9)        /* Waits while card is busy */
 #define MMC_CAP_ERASE          (1 << 10)       /* Allow erase/trim commands */
-#define MMC_CAP_1_8V_DDR       (1 << 11)       /* can support */
-                                               /* DDR mode at 1.8V */
-#define MMC_CAP_1_2V_DDR       (1 << 12)       /* can support */
-                                               /* DDR mode at 1.2V */
-#define MMC_CAP_POWER_OFF_CARD (1 << 13)       /* Can power off after boot */
-#define MMC_CAP_BUS_WIDTH_TEST (1 << 14)       /* CMD14/CMD19 bus width ok */
-#define MMC_CAP_UHS_SDR12      (1 << 15)       /* Host supports UHS SDR12 mode */
-#define MMC_CAP_UHS_SDR25      (1 << 16)       /* Host supports UHS SDR25 mode */
-#define MMC_CAP_UHS_SDR50      (1 << 17)       /* Host supports UHS SDR50 mode */
-#define MMC_CAP_UHS_SDR104     (1 << 18)       /* Host supports UHS SDR104 mode */
-#define MMC_CAP_UHS_DDR50      (1 << 19)       /* Host supports UHS DDR50 mode */
+#define MMC_CAP_3_3V_DDR       (1 << 11)       /* Host supports eMMC DDR 3.3V */
+#define MMC_CAP_1_8V_DDR       (1 << 12)       /* Host supports eMMC DDR 1.8V */
+#define MMC_CAP_1_2V_DDR       (1 << 13)       /* Host supports eMMC DDR 1.2V */
+#define MMC_CAP_POWER_OFF_CARD (1 << 14)       /* Can power off after boot */
+#define MMC_CAP_BUS_WIDTH_TEST (1 << 15)       /* CMD14/CMD19 bus width ok */
+#define MMC_CAP_UHS_SDR12      (1 << 16)       /* Host supports UHS SDR12 mode */
+#define MMC_CAP_UHS_SDR25      (1 << 17)       /* Host supports UHS SDR25 mode */
+#define MMC_CAP_UHS_SDR50      (1 << 18)       /* Host supports UHS SDR50 mode */
+#define MMC_CAP_UHS_SDR104     (1 << 19)       /* Host supports UHS SDR104 mode */
+#define MMC_CAP_UHS_DDR50      (1 << 20)       /* Host supports UHS DDR50 mode */
 #define MMC_CAP_DRIVER_TYPE_A  (1 << 23)       /* Host supports Driver Type A */
 #define MMC_CAP_DRIVER_TYPE_C  (1 << 24)       /* Host supports Driver Type C */
 #define MMC_CAP_DRIVER_TYPE_D  (1 << 25)       /* Host supports Driver Type D */
@@ -397,11 +391,14 @@ struct mmc_host {
        unsigned long           private[0] ____cacheline_aligned;
 };
 
+struct device_node;
+
 struct mmc_host *mmc_alloc_host(int extra, struct device *);
 int mmc_add_host(struct mmc_host *);
 void mmc_remove_host(struct mmc_host *);
 void mmc_free_host(struct mmc_host *);
 int mmc_of_parse(struct mmc_host *host);
+int mmc_of_parse_voltage(struct device_node *np, u32 *mask);
 
 static inline void *mmc_priv(struct mmc_host *host)
 {
@@ -457,6 +454,7 @@ static inline int mmc_regulator_set_vqmmc(struct mmc_host *mmc,
 }
 #endif
 
+u32 mmc_vddrange_to_ocrmask(int vdd_min, int vdd_max);
 int mmc_regulator_get_supply(struct mmc_host *mmc);
 
 static inline int mmc_card_is_removable(struct mmc_host *host)
@@ -474,56 +472,20 @@ static inline int mmc_card_wake_sdio_irq(struct mmc_host *host)
        return host->pm_flags & MMC_PM_WAKE_SDIO_IRQ;
 }
 
-static inline int mmc_host_cmd23(struct mmc_host *host)
-{
-       return host->caps & MMC_CAP_CMD23;
-}
-
-static inline int mmc_boot_partition_access(struct mmc_host *host)
-{
-       return !(host->caps2 & MMC_CAP2_BOOTPART_NOACC);
-}
-
-static inline int mmc_host_uhs(struct mmc_host *host)
-{
-       return host->caps &
-               (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
-                MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
-                MMC_CAP_UHS_DDR50);
-}
-
+/* TODO: Move to private header */
 static inline int mmc_card_hs(struct mmc_card *card)
 {
        return card->host->ios.timing == MMC_TIMING_SD_HS ||
                card->host->ios.timing == MMC_TIMING_MMC_HS;
 }
 
+/* TODO: Move to private header */
 static inline int mmc_card_uhs(struct mmc_card *card)
 {
        return card->host->ios.timing >= MMC_TIMING_UHS_SDR12 &&
                card->host->ios.timing <= MMC_TIMING_UHS_DDR50;
 }
 
-static inline bool mmc_card_hs200(struct mmc_card *card)
-{
-       return card->host->ios.timing == MMC_TIMING_MMC_HS200;
-}
-
-static inline bool mmc_card_ddr52(struct mmc_card *card)
-{
-       return card->host->ios.timing == MMC_TIMING_MMC_DDR52;
-}
-
-static inline bool mmc_card_hs400(struct mmc_card *card)
-{
-       return card->host->ios.timing == MMC_TIMING_MMC_HS400;
-}
-
-static inline bool mmc_card_hs400es(struct mmc_card *card)
-{
-       return card->host->ios.enhanced_strobe;
-}
-
 void mmc_retune_timer_stop(struct mmc_host *host);
 
 static inline void mmc_retune_needed(struct mmc_host *host)
@@ -532,18 +494,12 @@ static inline void mmc_retune_needed(struct mmc_host *host)
                host->need_retune = 1;
 }
 
-static inline void mmc_retune_recheck(struct mmc_host *host)
-{
-       if (host->hold_retune <= 1)
-               host->retune_now = 1;
-}
-
 static inline bool mmc_can_retune(struct mmc_host *host)
 {
        return host->can_retune == 1;
 }
 
-void mmc_retune_pause(struct mmc_host *host);
-void mmc_retune_unpause(struct mmc_host *host);
+int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error);
+int mmc_abort_tuning(struct mmc_host *host, u32 opcode);
 
 #endif /* LINUX_MMC_HOST_H */
index 672730acc705799ef292a620f5011a5a1d556611..3ffc27aaeeaf2451eef9d63a74ce5675d0a9988f 100644 (file)
@@ -24,6 +24,8 @@
 #ifndef LINUX_MMC_MMC_H
 #define LINUX_MMC_MMC_H
 
+#include <linux/types.h>
+
 /* Standard MMC commands (4.1)           type  argument     response */
    /* class 1 */
 #define MMC_GO_IDLE_STATE         0   /* bc                          */
@@ -182,50 +184,6 @@ static inline bool mmc_op_multi(u32 opcode)
 #define R2_SPI_OUT_OF_RANGE    (1 << 15)       /* or CSD overwrite */
 #define R2_SPI_CSD_OVERWRITE   R2_SPI_OUT_OF_RANGE
 
-/* These are unpacked versions of the actual responses */
-
-struct _mmc_csd {
-       u8  csd_structure;
-       u8  spec_vers;
-       u8  taac;
-       u8  nsac;
-       u8  tran_speed;
-       u16 ccc;
-       u8  read_bl_len;
-       u8  read_bl_partial;
-       u8  write_blk_misalign;
-       u8  read_blk_misalign;
-       u8  dsr_imp;
-       u16 c_size;
-       u8  vdd_r_curr_min;
-       u8  vdd_r_curr_max;
-       u8  vdd_w_curr_min;
-       u8  vdd_w_curr_max;
-       u8  c_size_mult;
-       union {
-               struct { /* MMC system specification version 3.1 */
-                       u8  erase_grp_size;
-                       u8  erase_grp_mult;
-               } v31;
-               struct { /* MMC system specification version 2.2 */
-                       u8  sector_size;
-                       u8  erase_grp_size;
-               } v22;
-       } erase;
-       u8  wp_grp_size;
-       u8  wp_grp_enable;
-       u8  default_ecc;
-       u8  r2w_factor;
-       u8  write_bl_len;
-       u8  write_bl_partial;
-       u8  file_format_grp;
-       u8  copy;
-       u8  perm_write_protect;
-       u8  tmp_write_protect;
-       u8  file_format;
-       u8  ecc;
-};
-
 /*
  * OCR bits are mostly in host.h
  */
@@ -339,6 +297,9 @@ struct _mmc_csd {
 #define EXT_CSD_CACHE_SIZE             249     /* RO, 4 bytes */
 #define EXT_CSD_PWR_CL_DDR_200_360     253     /* RO */
 #define EXT_CSD_FIRMWARE_VERSION       254     /* RO, 8 bytes */
+#define EXT_CSD_PRE_EOL_INFO           267     /* RO */
+#define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A     268     /* RO */
+#define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B     269     /* RO */
 #define EXT_CSD_CMDQ_DEPTH             307     /* RO */
 #define EXT_CSD_CMDQ_SUPPORT           308     /* RO */
 #define EXT_CSD_SUPPORTED_MODE         493     /* RO */
@@ -446,6 +407,7 @@ struct _mmc_csd {
  * BKOPS modes
  */
 #define EXT_CSD_MANUAL_BKOPS_MASK      0x01
+#define EXT_CSD_AUTO_BKOPS_MASK                0x02
 
 /*
  * Command Queue
@@ -457,12 +419,23 @@ struct _mmc_csd {
 /*
  * MMC_SWITCH access modes
  */
-
 #define MMC_SWITCH_MODE_CMD_SET                0x00    /* Change the command set */
 #define MMC_SWITCH_MODE_SET_BITS       0x01    /* Set bits which are 1 in value */
 #define MMC_SWITCH_MODE_CLEAR_BITS     0x02    /* Clear bits which are 1 in value */
 #define MMC_SWITCH_MODE_WRITE_BYTE     0x03    /* Set target to value */
 
+/*
+ * Erase/trim/discard
+ */
+#define MMC_ERASE_ARG                  0x00000000
+#define MMC_SECURE_ERASE_ARG           0x80000000
+#define MMC_TRIM_ARG                   0x00000001
+#define MMC_DISCARD_ARG                        0x00000003
+#define MMC_SECURE_TRIM1_ARG           0x80000001
+#define MMC_SECURE_TRIM2_ARG           0x80008000
+#define MMC_SECURE_ARGS                        0x80000000
+#define MMC_TRIM_ARGS                  0x00008001
+
 #define mmc_driver_type_mask(n)                (1 << (n))
 
 #endif /* LINUX_MMC_MMC_H */
index d43ef96bf0753ce5d11c615d91b81a8298afc69a..46794a7a531c2774cd42d7d400abfcc7e3f3a5a5 100644 (file)
@@ -51,6 +51,7 @@
 #define SDIO_DEVICE_ID_MARVELL_LIBERTAS                0x9103
 #define SDIO_DEVICE_ID_MARVELL_8688WLAN                0x9104
 #define SDIO_DEVICE_ID_MARVELL_8688BT          0x9105
+#define SDIO_DEVICE_ID_MARVELL_8797_F0         0x9128
 
 #define SDIO_VENDOR_ID_SIANO                   0x039a
 #define SDIO_DEVICE_ID_SIANO_NOVA_B0           0x0201
 #define SDIO_DEVICE_ID_SIANO_NOVA_A0           0x1100
 #define SDIO_DEVICE_ID_SIANO_STELLAR           0x5347
 
+#define SDIO_VENDOR_ID_TI                      0x0097
+#define SDIO_DEVICE_ID_TI_WL1271               0x4076
+
+#define SDIO_VENDOR_ID_STE                     0x0020
+#define SDIO_DEVICE_ID_STE_CW1200              0x2280
+
 #endif /* LINUX_MMC_SDIO_IDS_H */
index ccd8fb2cad522b6d967b05e760ce8634dcbf9106..a7baa29484c3e3350b29cc2f8ee63932d3d9b729 100644 (file)
  */
 
 struct sh_mmcif_plat_data {
-       int (*get_cd)(struct platform_device *pdef);
        unsigned int            slave_id_tx;    /* embedded slave_id_[tr]x */
        unsigned int            slave_id_rx;
-       bool                    use_cd_gpio : 1;
-       bool                    ccs_unsupported : 1;
-       bool                    clk_ctrl2_present : 1;
-       unsigned int            cd_gpio;
        u8                      sup_pclk;       /* 1 :SH7757, 0: SH7724/SH7372 */
        unsigned long           caps;
        u32                     ocr;
index a7972cd3bc149bae8b5d59d06256244491361c1a..82f0d289f110333696d8c0aa1f9b1c7f15adc556 100644 (file)
@@ -11,6 +11,9 @@
 #ifndef MMC_SLOT_GPIO_H
 #define MMC_SLOT_GPIO_H
 
+#include <linux/types.h>
+#include <linux/irqreturn.h>
+
 struct mmc_host;
 
 int mmc_gpio_get_ro(struct mmc_host *host);
index cc7cba219b207de5536f6f9e9353d1a20201e4af..5cddadff2c25a2040c8610fa2ae4a47a33b1257e 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/moduleparam.h>
 #include <linux/jump_label.h>
 #include <linux/export.h>
-#include <linux/extable.h>     /* only as arch move module.h -> extable.h */
 #include <linux/rbtree_latch.h>
 
 #include <linux/percpu.h>
index 3d1c6f1b15c9bd351fa04d4e9824ff83b5c0045a..0b676a02cf3e0899cb27c068bb6d3c1225a2506a 100644 (file)
@@ -244,6 +244,7 @@ enum {
        NVME_CTRL_ONCS_DSM                      = 1 << 2,
        NVME_CTRL_ONCS_WRITE_ZEROES             = 1 << 3,
        NVME_CTRL_VWC_PRESENT                   = 1 << 0,
+       NVME_CTRL_OACS_SEC_SUPP                 = 1 << 0,
 };
 
 struct nvme_lbaf {
@@ -553,6 +554,8 @@ enum {
        NVME_DSMGMT_AD          = 1 << 2,
 };
 
+#define NVME_DSM_MAX_RANGES    256
+
 struct nvme_dsm_range {
        __le32                  cattr;
        __le32                  nlb;
index d7e5d608faa7db52543fbb4c7cc221171dca2744..a0f2aba72fa9bc9c27335799e0b428a2c2815113 100644 (file)
@@ -29,6 +29,7 @@ extern int pinctrl_request_gpio(unsigned gpio);
 extern void pinctrl_free_gpio(unsigned gpio);
 extern int pinctrl_gpio_direction_input(unsigned gpio);
 extern int pinctrl_gpio_direction_output(unsigned gpio);
+extern int pinctrl_gpio_set_config(unsigned gpio, unsigned long config);
 
 extern struct pinctrl * __must_check pinctrl_get(struct device *dev);
 extern void pinctrl_put(struct pinctrl *p);
@@ -80,6 +81,11 @@ static inline int pinctrl_gpio_direction_output(unsigned gpio)
        return 0;
 }
 
+static inline int pinctrl_gpio_set_config(unsigned gpio, unsigned long config)
+{
+       return 0;
+}
+
 static inline struct pinctrl * __must_check pinctrl_get(struct device *dev)
 {
        return NULL;
index 12343caa114ef3ec27a5ab5a3caaf5320cbe6508..7620eb127cffc5edbc475457732a042bac357055 100644 (file)
 #ifndef __LINUX_PINCTRL_PINCONF_GENERIC_H
 #define __LINUX_PINCTRL_PINCONF_GENERIC_H
 
-/*
- * You shouldn't even be able to compile with these enums etc unless you're
- * using generic pin config. That is why this is defined out.
- */
-#ifdef CONFIG_GENERIC_PINCONF
-
 /**
  * enum pin_config_param - possible pin configuration parameters
  * @PIN_CONFIG_BIAS_BUS_HOLD: the pin will be set to weakly latch so that it
@@ -92,6 +86,8 @@
  * @PIN_CONFIG_END: this is the last enumerator for pin configurations, if
  *     you need to pass in custom configurations to the pin controller, use
  *     PIN_CONFIG_END+1 as the base offset.
+ * @PIN_CONFIG_MAX: this is the maximum configuration value that can be
+ *     presented using the packed format.
  */
 enum pin_config_param {
        PIN_CONFIG_BIAS_BUS_HOLD,
@@ -112,49 +108,53 @@ enum pin_config_param {
        PIN_CONFIG_OUTPUT,
        PIN_CONFIG_POWER_SOURCE,
        PIN_CONFIG_SLEW_RATE,
-       PIN_CONFIG_END = 0x7FFF,
-};
-
-#ifdef CONFIG_DEBUG_FS
-#define PCONFDUMP(a, b, c, d) { .param = a, .display = b, .format = c, \
-                               .has_arg = d }
-
-struct pin_config_item {
-       const enum pin_config_param param;
-       const char * const display;
-       const char * const format;
-       bool has_arg;
+       PIN_CONFIG_END = 0x7F,
+       PIN_CONFIG_MAX = 0xFF,
 };
-#endif /* CONFIG_DEBUG_FS */
 
 /*
  * Helpful configuration macro to be used in tables etc.
  */
-#define PIN_CONF_PACKED(p, a) ((a << 16) | ((unsigned long) p & 0xffffUL))
+#define PIN_CONF_PACKED(p, a) ((a << 8) | ((unsigned long) p & 0xffUL))
 
 /*
  * The following inlines stuffs a configuration parameter and data value
  * into and out of an unsigned long argument, as used by the generic pin config
- * system. We put the parameter in the lower 16 bits and the argument in the
- * upper 16 bits.
+ * system. We put the parameter in the lower 8 bits and the argument in the
+ * upper 24 bits.
  */
 
 static inline enum pin_config_param pinconf_to_config_param(unsigned long config)
 {
-       return (enum pin_config_param) (config & 0xffffUL);
+       return (enum pin_config_param) (config & 0xffUL);
 }
 
-static inline u16 pinconf_to_config_argument(unsigned long config)
+static inline u32 pinconf_to_config_argument(unsigned long config)
 {
-       return (enum pin_config_param) ((config >> 16) & 0xffffUL);
+       return (u32) ((config >> 8) & 0xffffffUL);
 }
 
 static inline unsigned long pinconf_to_config_packed(enum pin_config_param param,
-                                                    u16 argument)
+                                                    u32 argument)
 {
        return PIN_CONF_PACKED(param, argument);
 }
 
+#ifdef CONFIG_GENERIC_PINCONF
+
+#ifdef CONFIG_DEBUG_FS
+#define PCONFDUMP(a, b, c, d) {                                        \
+       .param = a, .display = b, .format = c, .has_arg = d     \
+       }
+
+struct pin_config_item {
+       const enum pin_config_param param;
+       const char * const display;
+       const char * const format;
+       bool has_arg;
+};
+#endif /* CONFIG_DEBUG_FS */
+
 #ifdef CONFIG_OF
 
 #include <linux/device.h>
index a42e57da270dcf267e6fce79bb2a35b1a7f01b38..8ce2d87a238b84d432abca342f9920e42a8d0c42 100644 (file)
@@ -141,12 +141,27 @@ struct pinctrl_desc {
 };
 
 /* External interface to pin controller */
+
+extern int pinctrl_register_and_init(struct pinctrl_desc *pctldesc,
+                                    struct device *dev, void *driver_data,
+                                    struct pinctrl_dev **pctldev);
+
+/* Please use pinctrl_register_and_init() instead */
 extern struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
                                struct device *dev, void *driver_data);
+
 extern void pinctrl_unregister(struct pinctrl_dev *pctldev);
+
+extern int devm_pinctrl_register_and_init(struct device *dev,
+                               struct pinctrl_desc *pctldesc,
+                               void *driver_data,
+                               struct pinctrl_dev **pctldev);
+
+/* Please use devm_pinctrl_register_and_init() instead */
 extern struct pinctrl_dev *devm_pinctrl_register(struct device *dev,
                                struct pinctrl_desc *pctldesc,
                                void *driver_data);
+
 extern void devm_pinctrl_unregister(struct device *dev,
                                struct pinctrl_dev *pctldev);
 
index e69e415d0d988701c73e20d97756561cab797738..896cb71a382cbf4aa8eff220638310895f0ee965 100644 (file)
@@ -41,6 +41,7 @@ struct dw_dma_slave {
  * @is_private: The device channels should be marked as private and not for
  *     by the general purpose DMA channel allocator.
  * @is_memcpy: The device channels do support memory-to-memory transfers.
+ * @is_idma32: The type of the DMA controller is iDMA32
  * @chan_allocation_order: Allocate channels starting from 0 or 7
  * @chan_priority: Set channel priority increasing from 0 to 7 or 7 to 0.
  * @block_size: Maximum block size supported by the controller
@@ -53,6 +54,7 @@ struct dw_dma_platform_data {
        unsigned int    nr_channels;
        bool            is_private;
        bool            is_memcpy;
+       bool            is_idma32;
 #define CHAN_ALLOCATION_ASCENDING      0       /* zero to seven */
 #define CHAN_ALLOCATION_DESCENDING     1       /* seven to zero */
        unsigned char   chan_allocation_order;
index 812d8730787735d15dbc273ff4bd922bbe899ca2..2c94ab568bfa52f4e8d2d22197fa11e5869bfccd 100644 (file)
@@ -1,7 +1,7 @@
-#ifndef _LIRC_RX51_H
-#define _LIRC_RX51_H
+#ifndef _IR_RX51_H
+#define _IR_RX51_H
 
-struct lirc_rx51_platform_data {
+struct ir_rx51_platform_data {
        int(*set_max_mpu_wakeup_lat)(struct device *dev, long t);
 };
 
index 29115f405af91653683465fa9112fd0cff78213f..b0fdaa9bd18567b92d30c5181a1243ae4c85773f 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef ASMARM_ARCH_MMC_H
 #define ASMARM_ARCH_MMC_H
 
+#include <linux/interrupt.h>
 #include <linux/mmc/host.h>
 
 struct device;
index 9bb63ac13f04574d5cf84a87067f4917dc79a5f8..171a271c2cbd5e1d5d806b0275116b59ee6710bf 100644 (file)
@@ -5,25 +5,14 @@ struct spi_device;
 
 /**
  * struct ep93xx_spi_info - EP93xx specific SPI descriptor
- * @num_chipselect: number of chip selects on this board, must be
- *                  at least one
+ * @chipselect: array of gpio numbers to use as chip selects
+ * @num_chipselect: ARRAY_SIZE(chipselect)
  * @use_dma: use DMA for the transfers
  */
 struct ep93xx_spi_info {
+       int     *chipselect;
        int     num_chipselect;
        bool    use_dma;
 };
 
-/**
- * struct ep93xx_spi_chip_ops - operation callbacks for SPI slave device
- * @setup: setup the chip select mechanism
- * @cleanup: cleanup the chip select mechanism
- * @cs_control: control the device chip select
- */
-struct ep93xx_spi_chip_ops {
-       int     (*setup)(struct spi_device *spi);
-       void    (*cleanup)(struct spi_device *spi);
-       void    (*cs_control)(struct spi_device *spi, int value);
-};
-
 #endif /* __ASM_MACH_EP93XX_SPI_H */
index 81ece61075dff0e7a04e56f764bdae8a142f08e5..5339ed5bd6f9d04af80cd7da068a776517d9c4ff 100644 (file)
@@ -182,6 +182,9 @@ static inline int pm_genpd_remove(struct generic_pm_domain *genpd)
 {
        return -ENOTSUPP;
 }
+
+#define simple_qos_governor            (*(struct dev_power_governor *)(NULL))
+#define pm_domain_always_on_gov                (*(struct dev_power_governor *)(NULL))
 #endif
 
 static inline int pm_genpd_add_device(struct generic_pm_domain *genpd,
index 0edd88f939047b06a80a6763695e25fe33fcc4cf..a6685b3dde269f9c60eccaf9f20fd2ff3ab4876e 100644 (file)
@@ -78,6 +78,9 @@ struct dev_pm_set_opp_data {
 
 #if defined(CONFIG_PM_OPP)
 
+struct opp_table *dev_pm_opp_get_opp_table(struct device *dev);
+void dev_pm_opp_put_opp_table(struct opp_table *opp_table);
+
 unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp);
 
 unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp);
@@ -88,7 +91,7 @@ int dev_pm_opp_get_opp_count(struct device *dev);
 unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev);
 unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev);
 unsigned long dev_pm_opp_get_max_transition_latency(struct device *dev);
-struct dev_pm_opp *dev_pm_opp_get_suspend_opp(struct device *dev);
+unsigned long dev_pm_opp_get_suspend_opp_freq(struct device *dev);
 
 struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
                                              unsigned long freq,
@@ -99,6 +102,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
 
 struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
                                             unsigned long *freq);
+void dev_pm_opp_put(struct dev_pm_opp *opp);
 
 int dev_pm_opp_add(struct device *dev, unsigned long freq,
                   unsigned long u_volt);
@@ -108,22 +112,30 @@ int dev_pm_opp_enable(struct device *dev, unsigned long freq);
 
 int dev_pm_opp_disable(struct device *dev, unsigned long freq);
 
-struct srcu_notifier_head *dev_pm_opp_get_notifier(struct device *dev);
-int dev_pm_opp_set_supported_hw(struct device *dev, const u32 *versions,
-                               unsigned int count);
-void dev_pm_opp_put_supported_hw(struct device *dev);
-int dev_pm_opp_set_prop_name(struct device *dev, const char *name);
-void dev_pm_opp_put_prop_name(struct device *dev);
+int dev_pm_opp_register_notifier(struct device *dev, struct notifier_block *nb);
+int dev_pm_opp_unregister_notifier(struct device *dev, struct notifier_block *nb);
+
+struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev, const u32 *versions, unsigned int count);
+void dev_pm_opp_put_supported_hw(struct opp_table *opp_table);
+struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name);
+void dev_pm_opp_put_prop_name(struct opp_table *opp_table);
 struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count);
 void dev_pm_opp_put_regulators(struct opp_table *opp_table);
-int dev_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data));
-void dev_pm_opp_register_put_opp_helper(struct device *dev);
+struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data));
+void dev_pm_opp_register_put_opp_helper(struct opp_table *opp_table);
 int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq);
 int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, const struct cpumask *cpumask);
 int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask);
 void dev_pm_opp_remove_table(struct device *dev);
 void dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask);
 #else
+static inline struct opp_table *dev_pm_opp_get_opp_table(struct device *dev)
+{
+       return ERR_PTR(-ENOTSUPP);
+}
+
+static inline void dev_pm_opp_put_opp_table(struct opp_table *opp_table) {}
+
 static inline unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp)
 {
        return 0;
@@ -159,9 +171,9 @@ static inline unsigned long dev_pm_opp_get_max_transition_latency(struct device
        return 0;
 }
 
-static inline struct dev_pm_opp *dev_pm_opp_get_suspend_opp(struct device *dev)
+static inline unsigned long dev_pm_opp_get_suspend_opp_freq(struct device *dev)
 {
-       return NULL;
+       return 0;
 }
 
 static inline struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
@@ -182,6 +194,8 @@ static inline struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
        return ERR_PTR(-ENOTSUPP);
 }
 
+static inline void dev_pm_opp_put(struct dev_pm_opp *opp) {}
+
 static inline int dev_pm_opp_add(struct device *dev, unsigned long freq,
                                        unsigned long u_volt)
 {
@@ -202,35 +216,39 @@ static inline int dev_pm_opp_disable(struct device *dev, unsigned long freq)
        return 0;
 }
 
-static inline struct srcu_notifier_head *dev_pm_opp_get_notifier(
-                                                       struct device *dev)
+static inline int dev_pm_opp_register_notifier(struct device *dev, struct notifier_block *nb)
 {
-       return ERR_PTR(-ENOTSUPP);
+       return -ENOTSUPP;
 }
 
-static inline int dev_pm_opp_set_supported_hw(struct device *dev,
-                                             const u32 *versions,
-                                             unsigned int count)
+static inline int dev_pm_opp_unregister_notifier(struct device *dev, struct notifier_block *nb)
 {
        return -ENOTSUPP;
 }
 
-static inline void dev_pm_opp_put_supported_hw(struct device *dev) {}
+static inline struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev,
+                                                           const u32 *versions,
+                                                           unsigned int count)
+{
+       return ERR_PTR(-ENOTSUPP);
+}
 
-static inline int dev_pm_opp_register_set_opp_helper(struct device *dev,
+static inline void dev_pm_opp_put_supported_hw(struct opp_table *opp_table) {}
+
+static inline struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev,
                        int (*set_opp)(struct dev_pm_set_opp_data *data))
 {
-       return -ENOTSUPP;
+       return ERR_PTR(-ENOTSUPP);
 }
 
-static inline void dev_pm_opp_register_put_opp_helper(struct device *dev) {}
+static inline void dev_pm_opp_register_put_opp_helper(struct opp_table *opp_table) {}
 
-static inline int dev_pm_opp_set_prop_name(struct device *dev, const char *name)
+static inline struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name)
 {
-       return -ENOTSUPP;
+       return ERR_PTR(-ENOTSUPP);
 }
 
-static inline void dev_pm_opp_put_prop_name(struct device *dev) {}
+static inline void dev_pm_opp_put_prop_name(struct opp_table *opp_table) {}
 
 static inline struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count)
 {
@@ -270,6 +288,7 @@ void dev_pm_opp_of_remove_table(struct device *dev);
 int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask);
 void dev_pm_opp_of_cpumask_remove_table(const struct cpumask *cpumask);
 int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask);
+struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev);
 #else
 static inline int dev_pm_opp_of_add_table(struct device *dev)
 {
@@ -293,6 +312,11 @@ static inline int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, struct
 {
        return -ENOTSUPP;
 }
+
+static inline struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev)
+{
+       return NULL;
+}
 #endif
 
 #endif         /* __LINUX_OPP_H__ */
index 0f65d36c2a75153c4f0c1b47f2ff351ca5365239..d4d34791e4635f168b7ac8e05ebe0c734e6a3191 100644 (file)
@@ -6,7 +6,6 @@
  */
 #include <linux/plist.h>
 #include <linux/notifier.h>
-#include <linux/miscdevice.h>
 #include <linux/device.h>
 #include <linux/workqueue.h>
 
index 856e50b2140ce76971b481a9d61777e10c5ea4d0..64e3a9c6d95fed6662f75290486ef0c01d245f28 100644 (file)
@@ -160,12 +160,12 @@ struct property_entry {
        bool is_string;
        union {
                union {
-                       void *raw_data;
-                       u8 *u8_data;
-                       u16 *u16_data;
-                       u32 *u32_data;
-                       u64 *u64_data;
-                       const char **str;
+                       const void *raw_data;
+                       const u8 *u8_data;
+                       const u16 *u16_data;
+                       const u32 *u32_data;
+                       const u64 *u64_data;
+                       const char * const *str;
                } pointer;
                union {
                        unsigned long long raw_data;
@@ -241,8 +241,13 @@ struct property_entry {
        .name = _name_,                         \
 }
 
+struct property_entry *
+property_entries_dup(const struct property_entry *properties);
+
+void property_entries_free(const struct property_entry *properties);
+
 int device_add_properties(struct device *dev,
-                         struct property_entry *properties);
+                         const struct property_entry *properties);
 void device_remove_properties(struct device *dev);
 
 bool device_dma_supported(struct device *dev);
index 2d6f0c39ed6833b96f8aad03d9ed8b2e4d445add..a0522328d7aa5c2e3f94a77dc266cd20301046a7 100644 (file)
@@ -90,9 +90,9 @@
 #define SSSR_RFL_MASK  (0xf << 12)     /* Receive FIFO Level mask */
 
 #define SSCR1_TFT      (0x000003c0)    /* Transmit FIFO Threshold (mask) */
-#define SSCR1_TxTresh(x) (((x) - 1) << 6) /* level [1..16] */
+#define SSCR1_TxTresh(x) (((x) - 1) << 6)      /* level [1..16] */
 #define SSCR1_RFT      (0x00003c00)    /* Receive FIFO Threshold (mask) */
-#define SSCR1_RxTresh(x) (((x) - 1) << 10) /* level [1..16] */
+#define SSCR1_RxTresh(x) (((x) - 1) << 10)     /* level [1..16] */
 
 #define RX_THRESH_CE4100_DFLT  2
 #define TX_THRESH_CE4100_DFLT  2
 #define CE4100_SSCR1_RxTresh(x) (((x) - 1) << 10)      /* level [1..4] */
 
 /* QUARK_X1000 SSCR0 bit definition */
-#define QUARK_X1000_SSCR0_DSS  (0x1F)          /* Data Size Select (mask) */
-#define QUARK_X1000_SSCR0_DataSize(x)  ((x) - 1)       /* Data Size Select [4..32] */
-#define QUARK_X1000_SSCR0_FRF  (0x3 << 5)      /* FRame Format (mask) */
+#define QUARK_X1000_SSCR0_DSS          (0x1F << 0)     /* Data Size Select (mask) */
+#define QUARK_X1000_SSCR0_DataSize(x)  ((x) - 1)       /* Data Size Select [4..32] */
+#define QUARK_X1000_SSCR0_FRF          (0x3 << 5)      /* FRame Format (mask) */
 #define QUARK_X1000_SSCR0_Motorola     (0x0 << 5)      /* Motorola's Serial Peripheral Interface (SPI) */
 
 #define RX_THRESH_QUARK_X1000_DFLT     1
 #define QUARK_X1000_SSCR1_TxTresh(x) (((x) - 1) << 6)  /* level [1..32] */
 #define QUARK_X1000_SSCR1_RFT  (0x1F << 11)    /* Receive FIFO Threshold (mask) */
 #define QUARK_X1000_SSCR1_RxTresh(x) (((x) - 1) << 11) /* level [1..32] */
-#define QUARK_X1000_SSCR1_STRF       (1 << 17)         /* Select FIFO or EFWR */
-#define QUARK_X1000_SSCR1_EFWR (1 << 16)               /* Enable FIFO Write/Read */
+#define QUARK_X1000_SSCR1_STRF (1 << 17)       /* Select FIFO or EFWR */
+#define QUARK_X1000_SSCR1_EFWR (1 << 16)       /* Enable FIFO Write/Read */
 
 /* extra bits in PXA255, PXA26x and PXA27x SSP ports */
 #define SSCR0_TISSP            (1 << 4)        /* TI Sync Serial Protocol */
index f6673132431d09c3caa0c1394286fb310c93f9c1..e88649225a6073fea86bc77d99bdf3109fe7838d 100644 (file)
@@ -40,12 +40,13 @@ enum regcache_type {
 };
 
 /**
- * Default value for a register.  We use an array of structs rather
- * than a simple array as many modern devices have very sparse
- * register maps.
+ * struct reg_default - Default value for a register.
  *
  * @reg: Register address.
  * @def: Register default value.
+ *
+ * We use an array of structs rather than a simple array as many modern devices
+ * have very sparse register maps.
  */
 struct reg_default {
        unsigned int reg;
@@ -53,12 +54,14 @@ struct reg_default {
 };
 
 /**
- * Register/value pairs for sequences of writes with an optional delay in
- * microseconds to be applied after each write.
+ * struct reg_sequence - An individual write from a sequence of writes.
  *
  * @reg: Register address.
  * @def: Register value.
  * @delay_us: Delay to be applied after the register write in microseconds
+ *
+ * Register/value pairs for sequences of writes with an optional delay in
+ * microseconds to be applied after each write.
  */
 struct reg_sequence {
        unsigned int reg;
@@ -98,6 +101,7 @@ struct reg_sequence {
 
 /**
  * regmap_read_poll_timeout - Poll until a condition is met or a timeout occurs
+ *
  * @map: Regmap to read from
  * @addr: Address to poll
  * @val: Unsigned integer variable to read the value into
@@ -146,8 +150,8 @@ enum regmap_endian {
 };
 
 /**
- * A register range, used for access related checks
- * (readable/writeable/volatile/precious checks)
+ * struct regmap_range - A register range, used for access related checks
+ *                       (readable/writeable/volatile/precious checks)
  *
  * @range_min: address of first register
  * @range_max: address of last register
@@ -159,16 +163,18 @@ struct regmap_range {
 
 #define regmap_reg_range(low, high) { .range_min = low, .range_max = high, }
 
-/*
- * A table of ranges including some yes ranges and some no ranges.
- * If a register belongs to a no_range, the corresponding check function
- * will return false. If a register belongs to a yes range, the corresponding
- * check function will return true. "no_ranges" are searched first.
+/**
+ * struct regmap_access_table - A table of register ranges for access checks
  *
  * @yes_ranges : pointer to an array of regmap ranges used as "yes ranges"
  * @n_yes_ranges: size of the above array
  * @no_ranges: pointer to an array of regmap ranges used as "no ranges"
  * @n_no_ranges: size of the above array
+ *
+ * A table of ranges including some yes ranges and some no ranges.
+ * If a register belongs to a no_range, the corresponding check function
+ * will return false. If a register belongs to a yes range, the corresponding
+ * check function will return true. "no_ranges" are searched first.
  */
 struct regmap_access_table {
        const struct regmap_range *yes_ranges;
@@ -181,7 +187,7 @@ typedef void (*regmap_lock)(void *);
 typedef void (*regmap_unlock)(void *);
 
 /**
- * Configuration for the register map of a device.
+ * struct regmap_config - Configuration for the register map of a device.
  *
  * @name: Optional name of the regmap. Useful when a device has multiple
  *        register regions.
@@ -314,22 +320,24 @@ struct regmap_config {
 };
 
 /**
- * Configuration for indirectly accessed or paged registers.
- * Registers, mapped to this virtual range, are accessed in two steps:
- *     1. page selector register update;
- *     2. access through data window registers.
+ * struct regmap_range_cfg - Configuration for indirectly accessed or paged
+ *                           registers.
  *
  * @name: Descriptive name for diagnostics
  *
  * @range_min: Address of the lowest register address in virtual range.
  * @range_max: Address of the highest register in virtual range.
  *
- * @page_sel_reg: Register with selector field.
- * @page_sel_mask: Bit shift for selector value.
- * @page_sel_shift: Bit mask for selector value.
+ * @selector_reg: Register with selector field.
+ * @selector_mask: Bit shift for selector value.
+ * @selector_shift: Bit mask for selector value.
  *
  * @window_start: Address of first (lowest) register in data window.
  * @window_len: Number of registers in data window.
+ *
+ * Registers, mapped to this virtual range, are accessed in two steps:
+ *     1. page selector register update;
+ *     2. access through data window registers.
  */
 struct regmap_range_cfg {
        const char *name;
@@ -372,7 +380,8 @@ typedef struct regmap_async *(*regmap_hw_async_alloc)(void);
 typedef void (*regmap_hw_free_context)(void *context);
 
 /**
- * Description of a hardware bus for the register map infrastructure.
+ * struct regmap_bus - Description of a hardware bus for the register map
+ *                     infrastructure.
  *
  * @fast_io: Register IO is fast. Use a spinlock instead of a mutex
  *          to perform locking. This field is ignored if custom lock/unlock
@@ -385,6 +394,10 @@ typedef void (*regmap_hw_free_context)(void *context);
  *               must serialise with respect to non-async I/O.
  * @reg_write: Write a single register value to the given register address. This
  *             write operation has to complete when returning from the function.
+ * @reg_update_bits: Update bits operation to be used against volatile
+ *                   registers, intended for devices supporting some mechanism
+ *                   for setting clearing bits without having to
+ *                   read/modify/write.
  * @read: Read operation.  Data is returned in the buffer used to transmit
  *         data.
  * @reg_read: Read a single register value from a given register address.
@@ -514,7 +527,7 @@ struct regmap *__devm_regmap_init_ac97(struct snd_ac97 *ac97,
 #endif
 
 /**
- * regmap_init(): Initialise register map
+ * regmap_init() - Initialise register map
  *
  * @dev: Device that will be interacted with
  * @bus: Bus-specific callbacks to use with device
@@ -532,7 +545,7 @@ int regmap_attach_dev(struct device *dev, struct regmap *map,
                      const struct regmap_config *config);
 
 /**
- * regmap_init_i2c(): Initialise register map
+ * regmap_init_i2c() - Initialise register map
  *
  * @i2c: Device that will be interacted with
  * @config: Configuration for register map
@@ -545,9 +558,9 @@ int regmap_attach_dev(struct device *dev, struct regmap *map,
                                i2c, config)
 
 /**
- * regmap_init_spi(): Initialise register map
+ * regmap_init_spi() - Initialise register map
  *
- * @spi: Device that will be interacted with
+ * @dev: Device that will be interacted with
  * @config: Configuration for register map
  *
  * The return value will be an ERR_PTR() on error or a valid pointer to
@@ -558,8 +571,9 @@ int regmap_attach_dev(struct device *dev, struct regmap *map,
                                dev, config)
 
 /**
- * regmap_init_spmi_base(): Create regmap for the Base register space
- * @sdev:      SPMI device that will be interacted with
+ * regmap_init_spmi_base() - Create regmap for the Base register space
+ *
+ * @dev:       SPMI device that will be interacted with
  * @config:    Configuration for register map
  *
  * The return value will be an ERR_PTR() on error or a valid pointer to
@@ -570,8 +584,9 @@ int regmap_attach_dev(struct device *dev, struct regmap *map,
                                dev, config)
 
 /**
- * regmap_init_spmi_ext(): Create regmap for Ext register space
- * @sdev:      Device that will be interacted with
+ * regmap_init_spmi_ext() - Create regmap for Ext register space
+ *
+ * @dev:       Device that will be interacted with
  * @config:    Configuration for register map
  *
  * The return value will be an ERR_PTR() on error or a valid pointer to
@@ -582,7 +597,7 @@ int regmap_attach_dev(struct device *dev, struct regmap *map,
                                dev, config)
 
 /**
- * regmap_init_mmio_clk(): Initialise register map with register clock
+ * regmap_init_mmio_clk() - Initialise register map with register clock
  *
  * @dev: Device that will be interacted with
  * @clk_id: register clock consumer ID
@@ -597,7 +612,7 @@ int regmap_attach_dev(struct device *dev, struct regmap *map,
                                dev, clk_id, regs, config)
 
 /**
- * regmap_init_mmio(): Initialise register map
+ * regmap_init_mmio() - Initialise register map
  *
  * @dev: Device that will be interacted with
  * @regs: Pointer to memory-mapped IO region
@@ -610,7 +625,7 @@ int regmap_attach_dev(struct device *dev, struct regmap *map,
        regmap_init_mmio_clk(dev, NULL, regs, config)
 
 /**
- * regmap_init_ac97(): Initialise AC'97 register map
+ * regmap_init_ac97() - Initialise AC'97 register map
  *
  * @ac97: Device that will be interacted with
  * @config: Configuration for register map
@@ -624,7 +639,7 @@ int regmap_attach_dev(struct device *dev, struct regmap *map,
 bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
 
 /**
- * devm_regmap_init(): Initialise managed register map
+ * devm_regmap_init() - Initialise managed register map
  *
  * @dev: Device that will be interacted with
  * @bus: Bus-specific callbacks to use with device
@@ -641,7 +656,7 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
                                dev, bus, bus_context, config)
 
 /**
- * devm_regmap_init_i2c(): Initialise managed register map
+ * devm_regmap_init_i2c() - Initialise managed register map
  *
  * @i2c: Device that will be interacted with
  * @config: Configuration for register map
@@ -655,9 +670,9 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
                                i2c, config)
 
 /**
- * devm_regmap_init_spi(): Initialise register map
+ * devm_regmap_init_spi() - Initialise register map
  *
- * @spi: Device that will be interacted with
+ * @dev: Device that will be interacted with
  * @config: Configuration for register map
  *
  * The return value will be an ERR_PTR() on error or a valid pointer
@@ -669,8 +684,9 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
                                dev, config)
 
 /**
- * devm_regmap_init_spmi_base(): Create managed regmap for Base register space
- * @sdev:      SPMI device that will be interacted with
+ * devm_regmap_init_spmi_base() - Create managed regmap for Base register space
+ *
+ * @dev:       SPMI device that will be interacted with
  * @config:    Configuration for register map
  *
  * The return value will be an ERR_PTR() on error or a valid pointer
@@ -682,8 +698,9 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
                                dev, config)
 
 /**
- * devm_regmap_init_spmi_ext(): Create managed regmap for Ext register space
- * @sdev:      SPMI device that will be interacted with
+ * devm_regmap_init_spmi_ext() - Create managed regmap for Ext register space
+ *
+ * @dev:       SPMI device that will be interacted with
  * @config:    Configuration for register map
  *
  * The return value will be an ERR_PTR() on error or a valid pointer
@@ -695,7 +712,7 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
                                dev, config)
 
 /**
- * devm_regmap_init_mmio_clk(): Initialise managed register map with clock
+ * devm_regmap_init_mmio_clk() - Initialise managed register map with clock
  *
  * @dev: Device that will be interacted with
  * @clk_id: register clock consumer ID
@@ -711,7 +728,7 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
                                dev, clk_id, regs, config)
 
 /**
- * devm_regmap_init_mmio(): Initialise managed register map
+ * devm_regmap_init_mmio() - Initialise managed register map
  *
  * @dev: Device that will be interacted with
  * @regs: Pointer to memory-mapped IO region
@@ -725,7 +742,7 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
        devm_regmap_init_mmio_clk(dev, NULL, regs, config)
 
 /**
- * devm_regmap_init_ac97(): Initialise AC'97 register map
+ * devm_regmap_init_ac97() - Initialise AC'97 register map
  *
  * @ac97: Device that will be interacted with
  * @config: Configuration for register map
@@ -800,7 +817,7 @@ bool regmap_reg_in_ranges(unsigned int reg,
                          unsigned int nranges);
 
 /**
- * Description of an register field
+ * struct reg_field - Description of an register field
  *
  * @reg: Offset of the register within the regmap bank
  * @lsb: lsb of the register field.
@@ -841,7 +858,7 @@ int regmap_fields_update_bits_base(struct regmap_field *field,  unsigned int id,
                                   bool *change, bool async, bool force);
 
 /**
- * Description of an IRQ for the generic regmap irq_chip.
+ * struct regmap_irq - Description of an IRQ for the generic regmap irq_chip.
  *
  * @reg_offset: Offset of the status/mask register within the bank
  * @mask:       Mask used to flag/control the register.
@@ -861,9 +878,7 @@ struct regmap_irq {
        [_irq] = { .reg_offset = (_off), .mask = (_mask) }
 
 /**
- * Description of a generic regmap irq_chip.  This is not intended to
- * handle every possible interrupt controller, but it should handle a
- * substantial proportion of those that are found in the wild.
+ * struct regmap_irq_chip - Description of a generic regmap irq_chip.
  *
  * @name:        Descriptive name for IRQ controller.
  *
@@ -897,6 +912,10 @@ struct regmap_irq {
  *                  after handling the interrupts in regmap_irq_handler().
  * @irq_drv_data:    Driver specific IRQ data which is passed as parameter when
  *                  driver specific pre/post interrupt handler is called.
+ *
+ * This is not intended to handle every possible interrupt controller, but
+ * it should handle a substantial proportion of those that are found in the
+ * wild.
  */
 struct regmap_irq_chip {
        const char *name;
index f017fd6e69c4f64cdd3612fee5329a40fa82e75f..d4e0a204c118c7244e7e5d167cc3d0429832de01 100644 (file)
@@ -258,6 +258,26 @@ static inline int sbitmap_test_bit(struct sbitmap *sb, unsigned int bitnr)
 
 unsigned int sbitmap_weight(const struct sbitmap *sb);
 
+/**
+ * sbitmap_show() - Dump &struct sbitmap information to a &struct seq_file.
+ * @sb: Bitmap to show.
+ * @m: struct seq_file to write to.
+ *
+ * This is intended for debugging. The format may change at any time.
+ */
+void sbitmap_show(struct sbitmap *sb, struct seq_file *m);
+
+/**
+ * sbitmap_bitmap_show() - Write a hex dump of a &struct sbitmap to a &struct
+ * seq_file.
+ * @sb: Bitmap to show.
+ * @m: struct seq_file to write to.
+ *
+ * This is intended for debugging. The output isn't guaranteed to be internally
+ * consistent.
+ */
+void sbitmap_bitmap_show(struct sbitmap *sb, struct seq_file *m);
+
 /**
  * sbitmap_queue_init_node() - Initialize a &struct sbitmap_queue on a specific
  * memory node.
@@ -370,4 +390,14 @@ static inline struct sbq_wait_state *sbq_wait_ptr(struct sbitmap_queue *sbq,
  */
 void sbitmap_queue_wake_all(struct sbitmap_queue *sbq);
 
+/**
+ * sbitmap_queue_show() - Dump &struct sbitmap_queue information to a &struct
+ * seq_file.
+ * @sbq: Bitmap queue to show.
+ * @m: struct seq_file to write to.
+ *
+ * This is intended for debugging. The format may change at any time.
+ */
+void sbitmap_queue_show(struct sbitmap_queue *sbq, struct seq_file *m);
+
 #endif /* __LINUX_SCALE_BITMAP_H */
index c2125e9093e8e51b51662ba8ce4a5faa767710b6..d3868f2ebada82b87ba5eb0969f239cdf9a646b2 100644 (file)
@@ -332,7 +332,6 @@ int security_task_getscheduler(struct task_struct *p);
 int security_task_movememory(struct task_struct *p);
 int security_task_kill(struct task_struct *p, struct siginfo *info,
                        int sig, u32 secid);
-int security_task_wait(struct task_struct *p);
 int security_task_prctl(int option, unsigned long arg2, unsigned long arg3,
                        unsigned long arg4, unsigned long arg5);
 void security_task_to_inode(struct task_struct *p, struct inode *inode);
@@ -361,7 +360,7 @@ int security_sem_semop(struct sem_array *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);
-int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size);
+int security_setprocattr(const char *name, void *value, size_t size);
 int security_netlink_send(struct sock *sk, struct sk_buff *skb);
 int security_ismaclabel(const char *name);
 int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
@@ -980,11 +979,6 @@ static inline int security_task_kill(struct task_struct *p,
        return 0;
 }
 
-static inline int security_task_wait(struct task_struct *p)
-{
-       return 0;
-}
-
 static inline int security_task_prctl(int option, unsigned long arg2,
                                      unsigned long arg3,
                                      unsigned long arg4,
@@ -1106,7 +1100,7 @@ static inline int security_getprocattr(struct task_struct *p, char *name, char *
        return -EINVAL;
 }
 
-static inline int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size)
+static inline int security_setprocattr(char *name, void *value, size_t size)
 {
        return -EINVAL;
 }
diff --git a/include/linux/sed-opal.h b/include/linux/sed-opal.h
new file mode 100644 (file)
index 0000000..deee23d
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright Â© 2016 Intel Corporation
+ *
+ * Authors:
+ *    Rafael Antognolli <rafael.antognolli@intel.com>
+ *    Scott  Bauer      <scott.bauer@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * 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 LINUX_OPAL_H
+#define LINUX_OPAL_H
+
+#include <uapi/linux/sed-opal.h>
+#include <linux/kernel.h>
+
+struct opal_dev;
+
+typedef int (sec_send_recv)(void *data, u16 spsp, u8 secp, void *buffer,
+               size_t len, bool send);
+
+#ifdef CONFIG_BLK_SED_OPAL
+bool opal_unlock_from_suspend(struct opal_dev *dev);
+struct opal_dev *init_opal_dev(void *data, sec_send_recv *send_recv);
+int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *ioctl_ptr);
+
+static inline bool is_sed_ioctl(unsigned int cmd)
+{
+       switch (cmd) {
+       case IOC_OPAL_SAVE:
+       case IOC_OPAL_LOCK_UNLOCK:
+       case IOC_OPAL_TAKE_OWNERSHIP:
+       case IOC_OPAL_ACTIVATE_LSP:
+       case IOC_OPAL_SET_PW:
+       case IOC_OPAL_ACTIVATE_USR:
+       case IOC_OPAL_REVERT_TPR:
+       case IOC_OPAL_LR_SETUP:
+       case IOC_OPAL_ADD_USR_TO_LR:
+       case IOC_OPAL_ENABLE_DISABLE_MBR:
+       case IOC_OPAL_ERASE_LR:
+       case IOC_OPAL_SECURE_ERASE_LR:
+               return true;
+       }
+       return false;
+}
+#else
+static inline bool is_sed_ioctl(unsigned int cmd)
+{
+       return false;
+}
+
+static inline int sed_ioctl(struct opal_dev *dev, unsigned int cmd,
+                           void __user *ioctl_ptr)
+{
+       return 0;
+}
+static inline bool opal_unlock_from_suspend(struct opal_dev *dev)
+{
+       return false;
+}
+#define init_opal_dev(data, send_recv)         NULL
+#endif /* CONFIG_BLK_SED_OPAL */
+#endif /* LINUX_OPAL_H */
index e2e9de1acc5b789534892853f7f4b63d6d3cc0b6..e57eb4b6cc5a54f51be67d9f3a6e2b43393bba06 100644 (file)
@@ -12,6 +12,8 @@
 #ifndef __LINUX_SOC_EXYNOS_PMU_H
 #define __LINUX_SOC_EXYNOS_PMU_H
 
+struct regmap;
+
 enum sys_powerdown {
        SYS_AFTR,
        SYS_LPA,
@@ -20,5 +22,13 @@ enum sys_powerdown {
 };
 
 extern void exynos_sys_powerdown_conf(enum sys_powerdown mode);
+#ifdef CONFIG_EXYNOS_PMU
+extern struct regmap *exynos_get_pmu_regmap(void);
+#else
+static inline struct regmap *exynos_get_pmu_regmap(void)
+{
+       return ERR_PTR(-ENODEV);
+}
+#endif
 
 #endif /* __LINUX_SOC_EXYNOS_PMU_H */
index 4900baedd55af4518fd9d06ac4887f4dd65bf2bd..987e49e8f9c99e73ea3eb3fff2ee47c9cfd45b98 100644 (file)
  * but WITHOUT 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 _PPI_H_
index 5773874bf266f6ffaf737ff7c76b9ec9fd365437..a27defcf972c723ea35af46cc5b502e74d284494 100644 (file)
  * 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 _CCDC_TYPES_H
 #define _CCDC_TYPES_H
index c669a9fb75e57504673b3c4c86d7a37c57555a3a..e6bc72f6b60f6415026155c03ee8a9a9e4a7a86e 100644 (file)
  * but WITHOUT 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 _DM355_CCDC_H
 #define _DM355_CCDC_H
index 984fb79031de62274363cde081341daea3688593..7c909da29d435759970b0523cc5ce98ae6493955 100644 (file)
  * but WITHOUT 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 _DM644X_CCDC_H
 #define _DM644X_CCDC_H
index 7f3d76a4b9e3f2749db14d48bc0812f9c655cfa2..170a7b9cf8240b7706f71ee9c384d60877be458b 100644 (file)
  * 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
- *
  * isif header file
  */
 #ifndef _ISIF_H
index 4376beeb28c2c9b2db4efe2dbb0a8869bd6ecd93..79a566d7defd00353651c8a06fc0d3a3d62a8615 100644 (file)
@@ -9,10 +9,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 _VPBE_H
 #define _VPBE_H
index de59364d7ed2a98263bddc76e92dd5c6414c0574..32f77bcae6b3e0f852e3b4d67f1324b0936f686f 100644 (file)
  * 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 _OSD_H
 #define _OSD_H
index 05dbe0ba514c0bc3e657df60d5c15258b7a9dcf5..c10690b15935a46ccca22bff69d045b4303d937f 100644 (file)
@@ -9,10 +9,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 _VPBE_TYPES_H
 #define _VPBE_TYPES_H
index 3dbd200261078bdeaad5c1d8a5fa365d5638a93d..e32617bc7f9d0ffbaa46bc93ae7c67b8bd4a680b 100644 (file)
@@ -9,10 +9,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 _VPBE_VENC_H
 #define _VPBE_VENC_H
index 28bcd71cdd2608f9ad7f19ab124f61679f88b409..8e1a4d88daa024cc2b5df4e687d1d96f3925ae61 100644 (file)
  * but WITHOUT 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 _VPFE_CAPTURE_H
index 76fb74bad08c14b9b75785b5b6d5342a88d20e8d..498a274047617c33380db68d571c4f25e8cade6c 100644 (file)
  * but WITHOUT 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 _VPFE_TYPES_H
 #define _VPFE_TYPES_H
index 3cb1704a0650d2020f3bb67cc055bc4bd695c0d0..c49c306cba6177fc21e5f9765059a98935bddc9a 100644 (file)
@@ -9,10 +9,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 _VPIF_TYPES_H
 #define _VPIF_TYPES_H
@@ -82,6 +78,7 @@ struct vpif_capture_config {
        struct vpif_capture_chan_config chan_config[VPIF_CAPTURE_MAX_CHANNELS];
        struct vpif_subdev_info *subdev_info;
        int subdev_count;
+       int i2c_adapter_id;
        const char *card_name;
        struct v4l2_async_subdev **asd; /* Flat array, arranged in groups */
        int *asd_sizes;         /* 0-terminated array of asd group sizes */
index 153473daaa32fc9d559ef47661692e3668074f05..98e7f41fc387becfee39ead5f48ce31daeff49fe 100644 (file)
  * 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
- *
  * vpss - video processing subsystem module header file.
  *
  * Include this header file if a driver needs to configure vpss system
index fb272d48ba33e34104ca6ed91b4388b48ee2e74c..ba4923844d1dc9d6e3d3fe973a81944d491a5998 100644 (file)
  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *   GNU General Public License for more details.
  *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
  */
 
 #include <linux/videodev2.h>
index 0b6709335dff77eaf812ee161be46981b3d8917f..8a79f7200f5d64f7e0ca6b5a4d3b900a1623f976 100644 (file)
  * 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 St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
  */
 
 #ifndef ADP1653_H
index c5c2d377c0a60ed50a3f40d97fa9c75f6b7d30c0..2ad8c3d0b7d2697ebbf7f0df4fd27c2bff1f5530 100644 (file)
  * but WITHOUT 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 _ADV7183_H_
index 0e07484ddc33779ca03a83008cd44d66af4142bf..fffd4b563f5ad608b3566acf23f7f4377b3a32ad 100644 (file)
  * 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 St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
  */
 
 #ifndef __AS3645A_H__
index 5ed942a8ac326a6f97826418c36d97e1b2ab18b7..a5bd310c9e1ed33e51754f16c319b224dc4e4320 100644 (file)
  * 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 St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
  */
 
 #ifndef __LM3560_H__
index c3a78114d7a6cac3e23d5d1d5236c36debc5fdee..30d02a1af708bf65401bd15cd7beded3de299b43 100644 (file)
  * 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 St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
  */
 
 #ifndef MT9M032_H
index 635007e7441a9f5695771683351e85a59b794e5c..525d55b2afeb81ee1c1ae12716343c6b26a13f37 100644 (file)
  * 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 St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
  */
 
 #ifndef __SMIAPP_H_
index a7b49297da82ca9792d9d55e1bce8190cc3f9537..834e2f95b630540399f3f7b3cfafeb5265cf51ce 100644 (file)
  * but WITHOUT 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 THS7353_H
index 86ed7e8068304e1c44bc9a59d95c59e655940a82..c4896702f2d022470b535ae3b8fb035b38714eef 100644 (file)
  * 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 _TVP514X_H
index fadb6afe9ef0a003ef8db8c5db3733321b55c744..5ee007c1cead8e392a784f725a3960eee049f64b 100644 (file)
  * but WITHOUT 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 _TVP7002_H_
 #define _TVP7002_H_
index 3ad6a32e1bce20e9043bebffd785b214d2ce28cc..48ec03c4ef23258cf7080259c21d7a437d77f77f 100644 (file)
  * but WITHOUT 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.
  */
 
 #ifndef _UPD64031A_H_
index 59b6f32ba300e84a882cfff87c72c86d0b7efff5..4bed7371fdde9429ef32244ff027553c94227802 100644 (file)
  * but WITHOUT 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.
  */
 
 #ifndef _UPD64083_H_
index c21b4c5f587192ce206689bf083a3552e10060e8..6896266031b9905ff6ba61eb0706e5550e85f616 100644 (file)
  * but WITHOUT 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 _MEDIA_DEVICE_H
@@ -125,6 +121,8 @@ struct media_device_ops {
  *    bridge driver finds the media_device during probe.
  *    Bridge driver sets source_priv with information
  *    necessary to run @enable_source and @disable_source handlers.
+ *    Callers should hold graph_mutex to access and call @enable_source
+ *    and @disable_source handlers.
  */
 struct media_device {
        /* dev->driver_data points to this struct. */
@@ -154,7 +152,7 @@ struct media_device {
 
        /* Serializes graph operations. */
        struct mutex graph_mutex;
-       struct media_entity_graph pm_count_walk;
+       struct media_graph pm_count_walk;
 
        void *source_priv;
        int (*enable_source)(struct media_entity *entity,
index cd23e915764cd00c24881fee879abfb85889ee2b..511615d3bf6f4310726eac73d86662534bdb2479 100644 (file)
  * 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
- *
  * --
  *
  * Common functions for media-related drivers to register and unregister media
index b2203ee7a4c1020a5d973bf04f1ed4914498f36e..c7c254c5bca1761b5767c093a67078658654920a 100644 (file)
  * but WITHOUT 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 _MEDIA_ENTITY_H
@@ -86,7 +82,7 @@ struct media_entity_enum {
 };
 
 /**
- * struct media_entity_graph - Media graph traversal state
+ * struct media_graph - Media graph traversal state
  *
  * @stack:             Graph traversal stack; the stack contains information
  *                     on the path the media entities to be walked and the
@@ -94,7 +90,7 @@ struct media_entity_enum {
  * @ent_enum:          Visited entities
  * @top:               The top of the stack
  */
-struct media_entity_graph {
+struct media_graph {
        struct {
                struct media_entity *entity;
                struct list_head *link;
@@ -112,7 +108,7 @@ struct media_entity_graph {
  */
 struct media_pipeline {
        int streaming_count;
-       struct media_entity_graph graph;
+       struct media_graph graph;
 };
 
 /**
@@ -179,7 +175,7 @@ struct media_pad {
  *                     return an error, in which case link setup will be
  *                     cancelled. Optional.
  * @link_validate:     Return whether a link is valid from the entity point of
- *                     view. The media_entity_pipeline_start() function
+ *                     view. The media_pipeline_start() function
  *                     validates all links by calling this operation. Optional.
  *
  * .. note::
@@ -820,20 +816,20 @@ struct media_pad *media_entity_remote_pad(struct media_pad *pad);
 struct media_entity *media_entity_get(struct media_entity *entity);
 
 /**
- * media_entity_graph_walk_init - Allocate resources used by graph walk.
+ * media_graph_walk_init - Allocate resources used by graph walk.
  *
  * @graph: Media graph structure that will be used to walk the graph
  * @mdev: Pointer to the &media_device that contains the object
  */
-__must_check int media_entity_graph_walk_init(
-       struct media_entity_graph *graph, struct media_device *mdev);
+__must_check int media_graph_walk_init(
+       struct media_graph *graph, struct media_device *mdev);
 
 /**
- * media_entity_graph_walk_cleanup - Release resources used by graph walk.
+ * media_graph_walk_cleanup - Release resources used by graph walk.
  *
  * @graph: Media graph structure that will be used to walk the graph
  */
-void media_entity_graph_walk_cleanup(struct media_entity_graph *graph);
+void media_graph_walk_cleanup(struct media_graph *graph);
 
 /**
  * media_entity_put - Release the reference to the parent module
@@ -847,40 +843,39 @@ void media_entity_graph_walk_cleanup(struct media_entity_graph *graph);
 void media_entity_put(struct media_entity *entity);
 
 /**
- * media_entity_graph_walk_start - Start walking the media graph at a
+ * media_graph_walk_start - Start walking the media graph at a
  *     given entity
  *
  * @graph: Media graph structure that will be used to walk the graph
  * @entity: Starting entity
  *
- * Before using this function, media_entity_graph_walk_init() must be
+ * Before using this function, media_graph_walk_init() must be
  * used to allocate resources used for walking the graph. This
  * function initializes the graph traversal structure to walk the
  * entities graph starting at the given entity. The traversal
  * structure must not be modified by the caller during graph
  * traversal. After the graph walk, the resources must be released
- * using media_entity_graph_walk_cleanup().
+ * using media_graph_walk_cleanup().
  */
-void media_entity_graph_walk_start(struct media_entity_graph *graph,
-                                  struct media_entity *entity);
+void media_graph_walk_start(struct media_graph *graph,
+                           struct media_entity *entity);
 
 /**
- * media_entity_graph_walk_next - Get the next entity in the graph
+ * media_graph_walk_next - Get the next entity in the graph
  * @graph: Media graph structure
  *
  * Perform a depth-first traversal of the given media entities graph.
  *
  * The graph structure must have been previously initialized with a call to
- * media_entity_graph_walk_start().
+ * media_graph_walk_start().
  *
  * Return: returns the next entity in the graph or %NULL if the whole graph
  * have been traversed.
  */
-struct media_entity *
-media_entity_graph_walk_next(struct media_entity_graph *graph);
+struct media_entity *media_graph_walk_next(struct media_graph *graph);
 
 /**
- * media_entity_pipeline_start - Mark a pipeline as streaming
+ * media_pipeline_start - Mark a pipeline as streaming
  * @entity: Starting entity
  * @pipe: Media pipeline to be assigned to all entities in the pipeline.
  *
@@ -889,45 +884,45 @@ media_entity_graph_walk_next(struct media_entity_graph *graph);
  * to every entity in the pipeline and stored in the media_entity pipe field.
  *
  * Calls to this function can be nested, in which case the same number of
- * media_entity_pipeline_stop() calls will be required to stop streaming. The
+ * media_pipeline_stop() calls will be required to stop streaming. The
  * pipeline pointer must be identical for all nested calls to
- * media_entity_pipeline_start().
+ * media_pipeline_start().
  */
-__must_check int media_entity_pipeline_start(struct media_entity *entity,
-                                            struct media_pipeline *pipe);
+__must_check int media_pipeline_start(struct media_entity *entity,
+                                     struct media_pipeline *pipe);
 /**
- * __media_entity_pipeline_start - Mark a pipeline as streaming
+ * __media_pipeline_start - Mark a pipeline as streaming
  *
  * @entity: Starting entity
  * @pipe: Media pipeline to be assigned to all entities in the pipeline.
  *
- * ..note:: This is the non-locking version of media_entity_pipeline_start()
+ * ..note:: This is the non-locking version of media_pipeline_start()
  */
-__must_check int __media_entity_pipeline_start(struct media_entity *entity,
-                                              struct media_pipeline *pipe);
+__must_check int __media_pipeline_start(struct media_entity *entity,
+                                       struct media_pipeline *pipe);
 
 /**
- * media_entity_pipeline_stop - Mark a pipeline as not streaming
+ * media_pipeline_stop - Mark a pipeline as not streaming
  * @entity: Starting entity
  *
  * Mark all entities connected to a given entity through enabled links, either
  * directly or indirectly, as not streaming. The media_entity pipe field is
  * reset to %NULL.
  *
- * If multiple calls to media_entity_pipeline_start() have been made, the same
+ * If multiple calls to media_pipeline_start() have been made, the same
  * number of calls to this function are required to mark the pipeline as not
  * streaming.
  */
-void media_entity_pipeline_stop(struct media_entity *entity);
+void media_pipeline_stop(struct media_entity *entity);
 
 /**
- * __media_entity_pipeline_stop - Mark a pipeline as not streaming
+ * __media_pipeline_stop - Mark a pipeline as not streaming
  *
  * @entity: Starting entity
  *
- * .. note:: This is the non-locking version of media_entity_pipeline_stop()
+ * .. note:: This is the non-locking version of media_pipeline_stop()
  */
-void __media_entity_pipeline_stop(struct media_entity *entity);
+void __media_pipeline_stop(struct media_entity *entity);
 
 /**
  * media_devnode_create() - creates and initializes a device node interface
index 55281b92105a3ebd0d2e899028c3781e298738ea..73ddd721d7bafe03c2eabef4263b54f4c1ff6984 100644 (file)
@@ -32,13 +32,16 @@ do {                                                                \
 /**
  * enum rc_driver_type - type of the RC output
  *
- * @RC_DRIVER_SCANCODE:        Driver or hardware generates a scancode
- * @RC_DRIVER_IR_RAW:  Driver or hardware generates pulse/space sequences.
- *                     It needs a Infra-Red pulse/space decoder
+ * @RC_DRIVER_SCANCODE:         Driver or hardware generates a scancode
+ * @RC_DRIVER_IR_RAW:   Driver or hardware generates pulse/space sequences.
+ *                      It needs a Infra-Red pulse/space decoder
+ * @RC_DRIVER_IR_RAW_TX: Device transmitter only,
+ *                      driver requires pulse/space data sequence.
  */
 enum rc_driver_type {
        RC_DRIVER_SCANCODE = 0,
        RC_DRIVER_IR_RAW,
+       RC_DRIVER_IR_RAW_TX,
 };
 
 /**
@@ -83,10 +86,13 @@ enum rc_filter_type {
  * @input_dev: the input child device used to communicate events to userspace
  * @driver_type: specifies if protocol decoding is done in hardware or software
  * @idle: used to keep track of RX state
+ * @encode_wakeup: wakeup filtering uses IR encode API, therefore the allowed
+ *     wakeup protocols is the set of all raw encoders
  * @allowed_protocols: bitmask with the supported RC_BIT_* protocols
  * @enabled_protocols: bitmask with the enabled RC_BIT_* protocols
  * @allowed_wakeup_protocols: bitmask with the supported RC_BIT_* wakeup protocols
- * @enabled_wakeup_protocols: bitmask with the enabled RC_BIT_* wakeup protocols
+ * @wakeup_protocol: the enabled RC_TYPE_* wakeup protocol or
+ *     RC_TYPE_UNKNOWN if disabled.
  * @scancode_filter: scancode filter
  * @scancode_wakeup_filter: scancode wakeup filters
  * @scancode_mask: some hardware decoders are not capable of providing the full
@@ -110,8 +116,6 @@ enum rc_filter_type {
  * @rx_resolution : resolution (in ns) of input sampler
  * @tx_resolution: resolution (in ns) of output sampler
  * @change_protocol: allow changing the protocol used on hardware decoders
- * @change_wakeup_protocol: allow changing the protocol used for wakeup
- *     filtering
  * @open: callback to allow drivers to enable polling/irq when IR input device
  *     is opened.
  * @close: callback to allow drivers to disable polling/irq when IR input device
@@ -126,7 +130,9 @@ enum rc_filter_type {
  * @s_learning_mode: enable wide band receiver used for learning
  * @s_carrier_report: enable carrier reports
  * @s_filter: set the scancode filter
- * @s_wakeup_filter: set the wakeup scancode filter
+ * @s_wakeup_filter: set the wakeup scancode filter. If the mask is zero
+ *     then wakeup should be disabled. wakeup_protocol will be set to
+ *     a valid protocol if mask is nonzero.
  * @s_timeout: set hardware timeout in ns
  */
 struct rc_dev {
@@ -146,10 +152,11 @@ struct rc_dev {
        struct input_dev                *input_dev;
        enum rc_driver_type             driver_type;
        bool                            idle;
+       bool                            encode_wakeup;
        u64                             allowed_protocols;
        u64                             enabled_protocols;
        u64                             allowed_wakeup_protocols;
-       u64                             enabled_wakeup_protocols;
+       enum rc_type                    wakeup_protocol;
        struct rc_scancode_filter       scancode_filter;
        struct rc_scancode_filter       scancode_wakeup_filter;
        u32                             scancode_mask;
@@ -169,7 +176,6 @@ struct rc_dev {
        u32                             rx_resolution;
        u32                             tx_resolution;
        int                             (*change_protocol)(struct rc_dev *dev, u64 *rc_type);
-       int                             (*change_wakeup_protocol)(struct rc_dev *dev, u64 *rc_type);
        int                             (*open)(struct rc_dev *dev);
        void                            (*close)(struct rc_dev *dev);
        int                             (*s_tx_mask)(struct rc_dev *dev, u32 mask);
@@ -200,17 +206,19 @@ struct rc_dev {
 /**
  * rc_allocate_device - Allocates a RC device
  *
+ * @rc_driver_type: specifies the type of the RC output to be allocated
  * returns a pointer to struct rc_dev.
  */
-struct rc_dev *rc_allocate_device(void);
+struct rc_dev *rc_allocate_device(enum rc_driver_type);
 
 /**
  * devm_rc_allocate_device - Managed RC device allocation
  *
  * @dev: pointer to struct device
+ * @rc_driver_type: specifies the type of the RC output to be allocated
  * returns a pointer to struct rc_dev.
  */
-struct rc_dev *devm_rc_allocate_device(struct device *dev);
+struct rc_dev *devm_rc_allocate_device(struct device *dev, enum rc_driver_type);
 
 /**
  * rc_free_device - Frees a RC device
@@ -306,6 +314,8 @@ int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type);
 int ir_raw_event_store_with_filter(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_type protocol, u32 scancode,
+                          struct ir_raw_event *events, unsigned int max);
 
 static inline void ir_raw_event_reset(struct rc_dev *dev)
 {
index e1cc14cba3914f86aec8c5c9c5d90103f6f80fbc..a704749280d2342d10f64fbd01b2b9a90604a045 100644 (file)
@@ -17,7 +17,7 @@
  * @RC_TYPE_UNKNOWN: Protocol not known
  * @RC_TYPE_OTHER: Protocol known but proprietary
  * @RC_TYPE_RC5: Philips RC5 protocol
- * @RC_TYPE_RC5X: Philips RC5x protocol
+ * @RC_TYPE_RC5X_20: Philips RC5x 20 bit protocol
  * @RC_TYPE_RC5_SZ: StreamZap variant of RC5
  * @RC_TYPE_JVC: JVC protocol
  * @RC_TYPE_SONY12: Sony 12 bit protocol
@@ -41,7 +41,7 @@ enum rc_type {
        RC_TYPE_UNKNOWN         = 0,
        RC_TYPE_OTHER           = 1,
        RC_TYPE_RC5             = 2,
-       RC_TYPE_RC5X            = 3,
+       RC_TYPE_RC5X_20         = 3,
        RC_TYPE_RC5_SZ          = 4,
        RC_TYPE_JVC             = 5,
        RC_TYPE_SONY12          = 6,
@@ -66,7 +66,7 @@ enum rc_type {
 #define RC_BIT_UNKNOWN         (1ULL << RC_TYPE_UNKNOWN)
 #define RC_BIT_OTHER           (1ULL << RC_TYPE_OTHER)
 #define RC_BIT_RC5             (1ULL << RC_TYPE_RC5)
-#define RC_BIT_RC5X            (1ULL << RC_TYPE_RC5X)
+#define RC_BIT_RC5X_20         (1ULL << RC_TYPE_RC5X_20)
 #define RC_BIT_RC5_SZ          (1ULL << RC_TYPE_RC5_SZ)
 #define RC_BIT_JVC             (1ULL << RC_TYPE_JVC)
 #define RC_BIT_SONY12          (1ULL << RC_TYPE_SONY12)
@@ -87,7 +87,7 @@ enum rc_type {
 #define RC_BIT_CEC             (1ULL << RC_TYPE_CEC)
 
 #define RC_BIT_ALL     (RC_BIT_UNKNOWN | RC_BIT_OTHER | \
-                        RC_BIT_RC5 | RC_BIT_RC5X | RC_BIT_RC5_SZ | \
+                        RC_BIT_RC5 | RC_BIT_RC5X_20 | RC_BIT_RC5_SZ | \
                         RC_BIT_JVC | \
                         RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20 | \
                         RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32 | \
@@ -95,7 +95,26 @@ enum rc_type {
                         RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | \
                         RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE | RC_BIT_SHARP | \
                         RC_BIT_XMP | RC_BIT_CEC)
+/* All rc protocols for which we have decoders */
+#define RC_BIT_ALL_IR_DECODER \
+                       (RC_BIT_RC5 | RC_BIT_RC5X_20 | RC_BIT_RC5_SZ | \
+                        RC_BIT_JVC | \
+                        RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20 | \
+                        RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32 | \
+                        RC_BIT_SANYO | RC_BIT_MCE_KBD | RC_BIT_RC6_0 | \
+                        RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | \
+                        RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE | RC_BIT_SHARP | \
+                        RC_BIT_XMP)
 
+#define RC_BIT_ALL_IR_ENCODER \
+                       (RC_BIT_RC5 | RC_BIT_RC5X_20 | RC_BIT_RC5_SZ | \
+                        RC_BIT_JVC | \
+                        RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20 | \
+                        RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32 | \
+                        RC_BIT_SANYO | \
+                        RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | \
+                        RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE | \
+                        RC_BIT_SHARP)
 
 #define RC_SCANCODE_UNKNOWN(x)                 (x)
 #define RC_SCANCODE_OTHER(x)                   (x)
@@ -198,6 +217,7 @@ struct rc_map *rc_map_get(const char *name);
 #define RC_MAP_CEC                       "rc-cec"
 #define RC_MAP_CINERGY_1400              "rc-cinergy-1400"
 #define RC_MAP_CINERGY                   "rc-cinergy"
+#define RC_MAP_D680_DMB                  "rc-d680-dmb"
 #define RC_MAP_DELOCK_61959              "rc-delock-61959"
 #define RC_MAP_DIB0700_NEC_TABLE         "rc-dib0700-nec"
 #define RC_MAP_DIB0700_RC5_TABLE         "rc-dib0700-rc5"
@@ -208,6 +228,8 @@ struct rc_map *rc_map_get(const char *name);
 #define RC_MAP_DNTV_LIVE_DVB_T           "rc-dntv-live-dvb-t"
 #define RC_MAP_DTT200U                   "rc-dtt200u"
 #define RC_MAP_DVBSKY                    "rc-dvbsky"
+#define RC_MAP_DVICO_MCE                "rc-dvico-mce"
+#define RC_MAP_DVICO_PORTABLE           "rc-dvico-portable"
 #define RC_MAP_EMPTY                     "rc-empty"
 #define RC_MAP_EM_TERRATEC               "rc-em-terratec"
 #define RC_MAP_ENCORE_ENLTV2             "rc-encore-enltv2"
@@ -219,6 +241,7 @@ struct rc_map *rc_map_get(const char *name);
 #define RC_MAP_FLYVIDEO                  "rc-flyvideo"
 #define RC_MAP_FUSIONHDTV_MCE            "rc-fusionhdtv-mce"
 #define RC_MAP_GADMEI_RM008Z             "rc-gadmei-rm008z"
+#define RC_MAP_GEEKBOX                   "rc-geekbox"
 #define RC_MAP_GENIUS_TVGO_A11MCE        "rc-genius-tvgo-a11mce"
 #define RC_MAP_GOTVIEW7135               "rc-gotview7135"
 #define RC_MAP_HAUPPAUGE_NEW             "rc-hauppauge"
index a700285c64a93de046cd5277f8cae66cc133fd4a..6741910c3a18978cfd7fd2dc295a4a11ea680538 100644 (file)
  * WITHOUT 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 St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #ifndef V4L2_EVENT_H
index e19e6246e21c85dc78fa545b95e0f62b011026bb..62633e7d2630ce590311ed908558e582595c8900 100644 (file)
  * WITHOUT 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 St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #ifndef V4L2_FH_H
index cf778c5dca1806e2877d24044c857b31c4705549..0ab1c5df6fac87f94d2752be0624be3d333fecf4 100644 (file)
@@ -592,9 +592,9 @@ struct v4l2_subdev_ir_ops {
 /**
  * struct v4l2_subdev_pad_config - Used for storing subdev pad information.
  *
- * @try_fmt: pointer to &struct v4l2_mbus_framefmt
- * @try_crop: pointer to &struct v4l2_rect to be used for crop
- * @try_compose: pointer to &struct v4l2_rect to be used for compose
+ * @try_fmt: &struct v4l2_mbus_framefmt
+ * @try_crop: &struct v4l2_rect to be used for crop
+ * @try_compose: &struct v4l2_rect to be used for compose
  *
  * This structure only needs to be passed to the pad op if the 'which' field
  * of the main argument is set to %V4L2_SUBDEV_FORMAT_TRY. For
index 4d1c46aac3319de315239dc1e1908c3204a8ad20..b0e275de6dec0d2be9adf09810e889c89d7ad06c 100644 (file)
@@ -383,6 +383,7 @@ extern int iscsi_eh_recover_target(struct scsi_cmnd *sc);
 extern int iscsi_eh_session_reset(struct scsi_cmnd *sc);
 extern int iscsi_eh_device_reset(struct scsi_cmnd *sc);
 extern int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc);
+extern enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc);
 
 /*
  * iSCSI host helpers.
index 8ec7c30e35af088331245ca56bb1c7aba3428ccf..a1e1930b7a8722924847d1d1b85b005767d40d61 100644 (file)
@@ -29,16 +29,6 @@ enum scsi_timeouts {
  */
 #define SCAN_WILD_CARD ~0
 
-#ifdef CONFIG_ACPI
-struct acpi_bus_type;
-
-extern int
-scsi_register_acpi_bus_type(struct acpi_bus_type *bus);
-
-extern void
-scsi_unregister_acpi_bus_type(struct acpi_bus_type *bus);
-#endif
-
 /** scsi_status_is_good - check the status return.
  *
  * @status: the status passed up from the driver (including host and
index 9fc1aecfc81369b9cfc694bece77b9bdfde131e5..b379f93a2c482ce223cce3c0673df34d1ba82068 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/timer.h>
 #include <linux/scatterlist.h>
 #include <scsi/scsi_device.h>
+#include <scsi/scsi_request.h>
 
 struct Scsi_Host;
 struct scsi_driver;
@@ -57,6 +58,7 @@ struct scsi_pointer {
 #define SCMD_TAGGED            (1 << 0)
 
 struct scsi_cmnd {
+       struct scsi_request req;
        struct scsi_device *device;
        struct list_head list;  /* scsi_cmnd participates in queue lists */
        struct list_head eh_entry; /* entry for the host eh_cmd_q */
@@ -149,7 +151,7 @@ static inline void *scsi_cmd_priv(struct scsi_cmnd *cmd)
        return cmd + 1;
 }
 
-/* make sure not to use it with REQ_TYPE_BLOCK_PC commands */
+/* make sure not to use it with passthrough commands */
 static inline struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd)
 {
        return *(struct scsi_driver **)cmd->request->rq_disk->private_data;
index 36680f13270d7c02eea5fc2028f4f37df9808f1f..3cd8c3bec6384e02328bbb31aafb9aec84f78c37 100644 (file)
@@ -551,9 +551,6 @@ struct Scsi_Host {
        struct list_head        __devices;
        struct list_head        __targets;
        
-       struct scsi_host_cmd_pool *cmd_pool;
-       spinlock_t              free_list_lock;
-       struct list_head        free_list; /* backup store of cmd structs */
        struct list_head        starved_list;
 
        spinlock_t              default_lock;
@@ -826,8 +823,6 @@ extern void scsi_block_requests(struct Scsi_Host *);
 
 struct class_container;
 
-extern struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
-                                               void (*) (struct request_queue *));
 /*
  * These two functions are used to allocate and free a pseudo device
  * which will connect to the host adapter itself rather than any
diff --git a/include/scsi/scsi_request.h b/include/scsi/scsi_request.h
new file mode 100644 (file)
index 0000000..ba0aeb9
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef _SCSI_SCSI_REQUEST_H
+#define _SCSI_SCSI_REQUEST_H
+
+#include <linux/blk-mq.h>
+
+#define BLK_MAX_CDB    16
+
+struct scsi_request {
+       unsigned char   __cmd[BLK_MAX_CDB];
+       unsigned char   *cmd;
+       unsigned short  cmd_len;
+       unsigned int    sense_len;
+       unsigned int    resid_len;      /* residual count */
+       void            *sense;
+};
+
+static inline struct scsi_request *scsi_req(struct request *rq)
+{
+       return blk_mq_rq_to_pdu(rq);
+}
+
+static inline void scsi_req_free_cmd(struct scsi_request *req)
+{
+       if (req->cmd != req->__cmd)
+               kfree(req->cmd);
+}
+
+void scsi_req_init(struct request *);
+
+#endif /* _SCSI_SCSI_REQUEST_H */
index 81292392adbcdf9142de2a97a83b14b44f335cfe..a3dcb1bfb3628e10a296c33a551fd29c2feef93d 100644 (file)
@@ -56,29 +56,6 @@ struct scsi_transport_template {
         * Allows a transport to override the default error handler.
         */
        void (* eh_strategy_handler)(struct Scsi_Host *);
-
-       /*
-        * This is an optional routine that allows the transport to become
-        * involved when a scsi io timer fires. The return value tells the
-        * timer routine how to finish the io timeout handling:
-        * EH_HANDLED:          I fixed the error, please complete the command
-        * EH_RESET_TIMER:      I need more time, reset the timer and
-        *                      begin counting again
-        * EH_NOT_HANDLED       Begin normal error recovery
-        */
-       enum blk_eh_timer_return (*eh_timed_out)(struct scsi_cmnd *);
-
-       /*
-        * Used as callback for the completion of i_t_nexus request
-        * for target drivers.
-        */
-       int (* it_nexus_response)(struct Scsi_Host *, u64, int);
-
-       /*
-        * Used as callback for the completion of task management
-        * request for target drivers.
-        */
-       int (* tsk_mgmt_response)(struct Scsi_Host *, u64, u64, int);
 };
 
 #define transport_class_to_shost(tc) \
@@ -119,4 +96,6 @@ scsi_transport_device_data(struct scsi_device *sdev)
                + shost->transportt->device_private_offset;
 }
 
+void __scsi_init_queue(struct Scsi_Host *shost, struct request_queue *q);
+
 #endif /* SCSI_TRANSPORT_H */
index 924c8e614b451684ae0f4623cf9921d7274800fc..b21b8aa58c4d6b8890592754bab2439db5769188 100644 (file)
@@ -808,6 +808,7 @@ struct fc_vport *fc_vport_create(struct Scsi_Host *shost, int channel,
                struct fc_vport_identifiers *);
 int fc_vport_terminate(struct fc_vport *vport);
 int fc_block_scsi_eh(struct scsi_cmnd *cmnd);
+enum blk_eh_timer_return fc_eh_timed_out(struct scsi_cmnd *scmd);
 
 static inline struct Scsi_Host *fc_bsg_to_shost(struct bsg_job *job)
 {
index d40d3ef25707bd7979a36d9e6e094a394d9f915e..dd096330734e3656829776f05ab20d02ba9a8d73 100644 (file)
@@ -88,10 +88,6 @@ struct srp_rport {
  * @terminate_rport_io: Callback function for terminating all outstanding I/O
  *     requests for an rport.
  * @rport_delete: Callback function that deletes an rport.
- *
- * Fields that are only relevant for SRP target drivers:
- * @tsk_mgmt_response: Callback function for sending a task management response.
- * @it_nexus_response: Callback function for processing an IT nexus response.
  */
 struct srp_function_template {
        /* for initiator drivers */
@@ -103,9 +99,6 @@ struct srp_function_template {
        int (*reconnect)(struct srp_rport *rport);
        void (*terminate_rport_io)(struct srp_rport *rport);
        void (*rport_delete)(struct srp_rport *rport);
-       /* for target drivers */
-       int (* tsk_mgmt_response)(struct Scsi_Host *, u64, u64, int);
-       int (* it_nexus_response)(struct Scsi_Host *, u64, int);
 };
 
 extern struct scsi_transport_template *
@@ -124,6 +117,7 @@ extern int srp_reconnect_rport(struct srp_rport *rport);
 extern void srp_start_tl_fail_timers(struct srp_rport *rport);
 extern void srp_remove_host(struct Scsi_Host *);
 extern void srp_stop_rport_timers(struct srp_rport *rport);
+enum blk_eh_timer_return srp_timed_out(struct scsi_cmnd *scmd);
 
 /**
  * srp_chkready() - evaluate the transport layer state before I/O
index 3e02e3a2541373748ebc9a55f76f707c7f322349..a88ed13446ff88e200ed642db63badf4c9a4b680 100644 (file)
@@ -73,19 +73,17 @@ DECLARE_EVENT_CLASS(block_rq_with_error,
                __field(  unsigned int, nr_sector               )
                __field(  int,          errors                  )
                __array(  char,         rwbs,   RWBS_LEN        )
-               __dynamic_array( char,  cmd,    blk_cmd_buf_len(rq)     )
+               __dynamic_array( char,  cmd,    1               )
        ),
 
        TP_fast_assign(
                __entry->dev       = rq->rq_disk ? disk_devt(rq->rq_disk) : 0;
-               __entry->sector    = (rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
-                                       0 : blk_rq_pos(rq);
-               __entry->nr_sector = (rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
-                                       0 : blk_rq_sectors(rq);
+               __entry->sector    = blk_rq_trace_sector(rq);
+               __entry->nr_sector = blk_rq_trace_nr_sectors(rq);
                __entry->errors    = rq->errors;
 
                blk_fill_rwbs(__entry->rwbs, rq->cmd_flags, blk_rq_bytes(rq));
-               blk_dump_cmd(__get_str(cmd), rq);
+               __get_str(cmd)[0] = '\0';
        ),
 
        TP_printk("%d,%d %s (%s) %llu + %u [%d]",
@@ -153,7 +151,7 @@ TRACE_EVENT(block_rq_complete,
                __field(  unsigned int, nr_sector               )
                __field(  int,          errors                  )
                __array(  char,         rwbs,   RWBS_LEN        )
-               __dynamic_array( char,  cmd,    blk_cmd_buf_len(rq)     )
+               __dynamic_array( char,  cmd,    1               )
        ),
 
        TP_fast_assign(
@@ -163,7 +161,7 @@ TRACE_EVENT(block_rq_complete,
                __entry->errors    = rq->errors;
 
                blk_fill_rwbs(__entry->rwbs, rq->cmd_flags, nr_bytes);
-               blk_dump_cmd(__get_str(cmd), rq);
+               __get_str(cmd)[0] = '\0';
        ),
 
        TP_printk("%d,%d %s (%s) %llu + %u [%d]",
@@ -186,20 +184,17 @@ DECLARE_EVENT_CLASS(block_rq,
                __field(  unsigned int, bytes                   )
                __array(  char,         rwbs,   RWBS_LEN        )
                __array(  char,         comm,   TASK_COMM_LEN   )
-               __dynamic_array( char,  cmd,    blk_cmd_buf_len(rq)     )
+               __dynamic_array( char,  cmd,    1               )
        ),
 
        TP_fast_assign(
                __entry->dev       = rq->rq_disk ? disk_devt(rq->rq_disk) : 0;
-               __entry->sector    = (rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
-                                       0 : blk_rq_pos(rq);
-               __entry->nr_sector = (rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
-                                       0 : blk_rq_sectors(rq);
-               __entry->bytes     = (rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
-                                       blk_rq_bytes(rq) : 0;
+               __entry->sector    = blk_rq_trace_sector(rq);
+               __entry->nr_sector = blk_rq_trace_nr_sectors(rq);
+               __entry->bytes     = blk_rq_bytes(rq);
 
                blk_fill_rwbs(__entry->rwbs, rq->cmd_flags, blk_rq_bytes(rq));
-               blk_dump_cmd(__get_str(cmd), rq);
+               __get_str(cmd)[0] = '\0';
                memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
        ),
 
diff --git a/include/trace/events/ufs.h b/include/trace/events/ufs.h
new file mode 100644 (file)
index 0000000..bf6f826
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM ufs
+
+#if !defined(_TRACE_UFS_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_UFS_H
+
+#include <linux/tracepoint.h>
+
+#define UFS_LINK_STATES                        \
+       EM(UIC_LINK_OFF_STATE)          \
+       EM(UIC_LINK_ACTIVE_STATE)       \
+       EMe(UIC_LINK_HIBERN8_STATE)
+
+#define UFS_PWR_MODES                  \
+       EM(UFS_ACTIVE_PWR_MODE)         \
+       EM(UFS_SLEEP_PWR_MODE)          \
+       EMe(UFS_POWERDOWN_PWR_MODE)
+
+#define UFSCHD_CLK_GATING_STATES       \
+       EM(CLKS_OFF)                    \
+       EM(CLKS_ON)                     \
+       EM(REQ_CLKS_OFF)                \
+       EMe(REQ_CLKS_ON)
+
+/* Enums require being exported to userspace, for user tool parsing */
+#undef EM
+#undef EMe
+#define EM(a)  TRACE_DEFINE_ENUM(a);
+#define EMe(a) TRACE_DEFINE_ENUM(a);
+
+UFS_LINK_STATES;
+UFS_PWR_MODES;
+UFSCHD_CLK_GATING_STATES;
+
+/*
+ * Now redefine the EM() and EMe() macros to map the enums to the strings
+ * that will be printed in the output.
+ */
+#undef EM
+#undef EMe
+#define EM(a)  { a, #a },
+#define EMe(a) { a, #a }
+
+TRACE_EVENT(ufshcd_clk_gating,
+
+       TP_PROTO(const char *dev_name, int state),
+
+       TP_ARGS(dev_name, state),
+
+       TP_STRUCT__entry(
+               __string(dev_name, dev_name)
+               __field(int, state)
+       ),
+
+       TP_fast_assign(
+               __assign_str(dev_name, dev_name);
+               __entry->state = state;
+       ),
+
+       TP_printk("%s: gating state changed to %s",
+               __get_str(dev_name),
+               __print_symbolic(__entry->state, UFSCHD_CLK_GATING_STATES))
+);
+
+TRACE_EVENT(ufshcd_clk_scaling,
+
+       TP_PROTO(const char *dev_name, const char *state, const char *clk,
+               u32 prev_state, u32 curr_state),
+
+       TP_ARGS(dev_name, state, clk, prev_state, curr_state),
+
+       TP_STRUCT__entry(
+               __string(dev_name, dev_name)
+               __string(state, state)
+               __string(clk, clk)
+               __field(u32, prev_state)
+               __field(u32, curr_state)
+       ),
+
+       TP_fast_assign(
+               __assign_str(dev_name, dev_name);
+               __assign_str(state, state);
+               __assign_str(clk, clk);
+               __entry->prev_state = prev_state;
+               __entry->curr_state = curr_state;
+       ),
+
+       TP_printk("%s: %s %s from %u to %u Hz",
+               __get_str(dev_name), __get_str(state), __get_str(clk),
+               __entry->prev_state, __entry->curr_state)
+);
+
+TRACE_EVENT(ufshcd_auto_bkops_state,
+
+       TP_PROTO(const char *dev_name, const char *state),
+
+       TP_ARGS(dev_name, state),
+
+       TP_STRUCT__entry(
+               __string(dev_name, dev_name)
+               __string(state, state)
+       ),
+
+       TP_fast_assign(
+               __assign_str(dev_name, dev_name);
+               __assign_str(state, state);
+       ),
+
+       TP_printk("%s: auto bkops - %s",
+               __get_str(dev_name), __get_str(state))
+);
+
+DECLARE_EVENT_CLASS(ufshcd_profiling_template,
+       TP_PROTO(const char *dev_name, const char *profile_info, s64 time_us,
+                int err),
+
+       TP_ARGS(dev_name, profile_info, time_us, err),
+
+       TP_STRUCT__entry(
+               __string(dev_name, dev_name)
+               __string(profile_info, profile_info)
+               __field(s64, time_us)
+               __field(int, err)
+       ),
+
+       TP_fast_assign(
+               __assign_str(dev_name, dev_name);
+               __assign_str(profile_info, profile_info);
+               __entry->time_us = time_us;
+               __entry->err = err;
+       ),
+
+       TP_printk("%s: %s: took %lld usecs, err %d",
+               __get_str(dev_name), __get_str(profile_info),
+               __entry->time_us, __entry->err)
+);
+
+DEFINE_EVENT(ufshcd_profiling_template, ufshcd_profile_hibern8,
+       TP_PROTO(const char *dev_name, const char *profile_info, s64 time_us,
+                int err),
+       TP_ARGS(dev_name, profile_info, time_us, err));
+
+DEFINE_EVENT(ufshcd_profiling_template, ufshcd_profile_clk_gating,
+       TP_PROTO(const char *dev_name, const char *profile_info, s64 time_us,
+                int err),
+       TP_ARGS(dev_name, profile_info, time_us, err));
+
+DEFINE_EVENT(ufshcd_profiling_template, ufshcd_profile_clk_scaling,
+       TP_PROTO(const char *dev_name, const char *profile_info, s64 time_us,
+                int err),
+       TP_ARGS(dev_name, profile_info, time_us, err));
+
+DECLARE_EVENT_CLASS(ufshcd_template,
+       TP_PROTO(const char *dev_name, int err, s64 usecs,
+                int dev_state, int link_state),
+
+       TP_ARGS(dev_name, err, usecs, dev_state, link_state),
+
+       TP_STRUCT__entry(
+               __field(s64, usecs)
+               __field(int, err)
+               __string(dev_name, dev_name)
+               __field(int, dev_state)
+               __field(int, link_state)
+       ),
+
+       TP_fast_assign(
+               __entry->usecs = usecs;
+               __entry->err = err;
+               __assign_str(dev_name, dev_name);
+               __entry->dev_state = dev_state;
+               __entry->link_state = link_state;
+       ),
+
+       TP_printk(
+               "%s: took %lld usecs, dev_state: %s, link_state: %s, err %d",
+               __get_str(dev_name),
+               __entry->usecs,
+               __print_symbolic(__entry->dev_state, UFS_PWR_MODES),
+               __print_symbolic(__entry->link_state, UFS_LINK_STATES),
+               __entry->err
+       )
+);
+
+DEFINE_EVENT(ufshcd_template, ufshcd_system_suspend,
+            TP_PROTO(const char *dev_name, int err, s64 usecs,
+                     int dev_state, int link_state),
+            TP_ARGS(dev_name, err, usecs, dev_state, link_state));
+
+DEFINE_EVENT(ufshcd_template, ufshcd_system_resume,
+            TP_PROTO(const char *dev_name, int err, s64 usecs,
+                     int dev_state, int link_state),
+            TP_ARGS(dev_name, err, usecs, dev_state, link_state));
+
+DEFINE_EVENT(ufshcd_template, ufshcd_runtime_suspend,
+            TP_PROTO(const char *dev_name, int err, s64 usecs,
+                     int dev_state, int link_state),
+            TP_ARGS(dev_name, err, usecs, dev_state, link_state));
+
+DEFINE_EVENT(ufshcd_template, ufshcd_runtime_resume,
+            TP_PROTO(const char *dev_name, int err, s64 usecs,
+                     int dev_state, int link_state),
+            TP_ARGS(dev_name, err, usecs, dev_state, link_state));
+
+DEFINE_EVENT(ufshcd_template, ufshcd_init,
+            TP_PROTO(const char *dev_name, int err, s64 usecs,
+                     int dev_state, int link_state),
+            TP_ARGS(dev_name, err, usecs, dev_state, link_state));
+
+TRACE_EVENT(ufshcd_command,
+       TP_PROTO(const char *dev_name, const char *str, unsigned int tag,
+                       u32 doorbell, int transfer_len, u32 intr, u64 lba,
+                       u8 opcode),
+
+       TP_ARGS(dev_name, str, tag, doorbell, transfer_len, intr, lba, opcode),
+
+       TP_STRUCT__entry(
+               __string(dev_name, dev_name)
+               __string(str, str)
+               __field(unsigned int, tag)
+               __field(u32, doorbell)
+               __field(int, transfer_len)
+               __field(u32, intr)
+               __field(u64, lba)
+               __field(u8, opcode)
+       ),
+
+       TP_fast_assign(
+               __assign_str(dev_name, dev_name);
+               __assign_str(str, str);
+               __entry->tag = tag;
+               __entry->doorbell = doorbell;
+               __entry->transfer_len = transfer_len;
+               __entry->intr = intr;
+               __entry->lba = lba;
+               __entry->opcode = opcode;
+       ),
+
+       TP_printk(
+               "%s: %s: tag: %u, DB: 0x%x, size: %d, IS: %u, LBA: %llu, opcode: 0x%x",
+               __get_str(str), __get_str(dev_name), __entry->tag,
+               __entry->doorbell, __entry->transfer_len,
+               __entry->intr, __entry->lba, (u32)__entry->opcode
+       )
+);
+
+#endif /* if !defined(_TRACE_UFS_H) || defined(TRACE_HEADER_MULTI_READ) */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
index 1c107cb1c83f80236cac0234a456d665bb9b7a15..0714a66f0e0cd6018758d991163b1de1f6326dd2 100644 (file)
 #define AUDIT_PROCTITLE                1327    /* Proctitle emit event */
 #define AUDIT_FEATURE_CHANGE   1328    /* audit log listing feature changes */
 #define AUDIT_REPLACE          1329    /* Replace auditd if this packet unanswerd */
+#define AUDIT_KERN_MODULE      1330    /* Kernel Module events */
 
 #define AUDIT_AVC              1400    /* SE Linux avc denial or grant */
 #define AUDIT_SELINUX_ERR      1401    /* Internal SE Linux Errors */
@@ -326,17 +327,21 @@ enum {
 #define AUDIT_STATUS_RATE_LIMIT                0x0008
 #define AUDIT_STATUS_BACKLOG_LIMIT     0x0010
 #define AUDIT_STATUS_BACKLOG_WAIT_TIME 0x0020
+#define AUDIT_STATUS_LOST              0x0040
 
 #define AUDIT_FEATURE_BITMAP_BACKLOG_LIMIT     0x00000001
 #define AUDIT_FEATURE_BITMAP_BACKLOG_WAIT_TIME 0x00000002
 #define AUDIT_FEATURE_BITMAP_EXECUTABLE_PATH   0x00000004
 #define AUDIT_FEATURE_BITMAP_EXCLUDE_EXTEND    0x00000008
 #define AUDIT_FEATURE_BITMAP_SESSIONID_FILTER  0x00000010
+#define AUDIT_FEATURE_BITMAP_LOST_RESET                0x00000020
+
 #define AUDIT_FEATURE_BITMAP_ALL (AUDIT_FEATURE_BITMAP_BACKLOG_LIMIT | \
                                  AUDIT_FEATURE_BITMAP_BACKLOG_WAIT_TIME | \
                                  AUDIT_FEATURE_BITMAP_EXECUTABLE_PATH | \
                                  AUDIT_FEATURE_BITMAP_EXCLUDE_EXTEND | \
-                                 AUDIT_FEATURE_BITMAP_SESSIONID_FILTER)
+                                 AUDIT_FEATURE_BITMAP_SESSIONID_FILTER | \
+                                 AUDIT_FEATURE_BITMAP_LOST_RESET)
 
 /* deprecated: AUDIT_VERSION_* */
 #define AUDIT_VERSION_LATEST           AUDIT_FEATURE_BITMAP_ALL
index 3af60ee69053322b9c6ca72d3120ce9f23da1c80..f5a8d96e1e098543d7cad6af1d7a77b117701f40 100644 (file)
  * e.g. teletext or data broadcast application (MHEG, MHP, HbbTV, etc.)
  */
 #define KEY_DATA                       0x277
+#define KEY_ONSCREEN_KEYBOARD          0x278
 
 #define BTN_TRIGGER_HAPPY              0x2c0
 #define BTN_TRIGGER_HAPPY1             0x2c0
index 774a43128a7aa4c039576513e1e3ff7355d0fc0d..fd19f36b3129278343f37ee5e59dfa280713eb9c 100644 (file)
@@ -122,6 +122,44 @@ struct nvm_ioctl_dev_factory {
        __u32 flags;
 };
 
+struct nvm_user_vio {
+       __u8 opcode;
+       __u8 flags;
+       __u16 control;
+       __u16 nppas;
+       __u16 rsvd;
+       __u64 metadata;
+       __u64 addr;
+       __u64 ppa_list;
+       __u32 metadata_len;
+       __u32 data_len;
+       __u64 status;
+       __u32 result;
+       __u32 rsvd3[3];
+};
+
+struct nvm_passthru_vio {
+       __u8 opcode;
+       __u8 flags;
+       __u8 rsvd[2];
+       __u32 nsid;
+       __u32 cdw2;
+       __u32 cdw3;
+       __u64 metadata;
+       __u64 addr;
+       __u32 metadata_len;
+       __u32 data_len;
+       __u64 ppa_list;
+       __u16 nppas;
+       __u16 control;
+       __u32 cdw13;
+       __u32 cdw14;
+       __u32 cdw15;
+       __u64 status;
+       __u32 result;
+       __u32 timeout_ms;
+};
+
 /* The ioctl type, 'L', 0x20 - 0x2F documented in ioctl-number.txt */
 enum {
        /* top level cmds */
@@ -137,6 +175,11 @@ enum {
 
        /* Factory reset device */
        NVM_DEV_FACTORY_CMD,
+
+       /* Vector user I/O */
+       NVM_DEV_VIO_ADMIN_CMD = 0x41,
+       NVM_DEV_VIO_CMD = 0x42,
+       NVM_DEV_VIO_USER_CMD = 0x43,
 };
 
 #define NVM_IOCTL 'L' /* 0x4c */
@@ -154,6 +197,13 @@ enum {
 #define NVM_DEV_FACTORY                _IOW(NVM_IOCTL, NVM_DEV_FACTORY_CMD, \
                                                struct nvm_ioctl_dev_factory)
 
+#define NVME_NVM_IOCTL_IO_VIO          _IOWR(NVM_IOCTL, NVM_DEV_VIO_USER_CMD, \
+                                               struct nvm_passthru_vio)
+#define NVME_NVM_IOCTL_ADMIN_VIO       _IOWR(NVM_IOCTL, NVM_DEV_VIO_ADMIN_CMD,\
+                                               struct nvm_passthru_vio)
+#define NVME_NVM_IOCTL_SUBMIT_VIO      _IOWR(NVM_IOCTL, NVM_DEV_VIO_CMD,\
+                                               struct nvm_user_vio)
+
 #define NVM_VERSION_MAJOR      1
 #define NVM_VERSION_MINOR      0
 #define NVM_VERSION_PATCHLEVEL 0
diff --git a/include/uapi/linux/sed-opal.h b/include/uapi/linux/sed-opal.h
new file mode 100644 (file)
index 0000000..c72e073
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright Â© 2016 Intel Corporation
+ *
+ * Authors:
+ *    Rafael Antognolli <rafael.antognolli@intel.com>
+ *    Scott  Bauer      <scott.bauer@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * 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 _UAPI_SED_OPAL_H
+#define _UAPI_SED_OPAL_H
+
+#include <linux/types.h>
+
+#define OPAL_KEY_MAX 256
+#define OPAL_MAX_LRS 9
+
+enum opal_mbr {
+       OPAL_MBR_ENABLE = 0x0,
+       OPAL_MBR_DISABLE = 0x01,
+};
+
+enum opal_user {
+       OPAL_ADMIN1 = 0x0,
+       OPAL_USER1 = 0x01,
+       OPAL_USER2 = 0x02,
+       OPAL_USER3 = 0x03,
+       OPAL_USER4 = 0x04,
+       OPAL_USER5 = 0x05,
+       OPAL_USER6 = 0x06,
+       OPAL_USER7 = 0x07,
+       OPAL_USER8 = 0x08,
+       OPAL_USER9 = 0x09,
+};
+
+enum opal_lock_state {
+       OPAL_RO = 0x01, /* 0001 */
+       OPAL_RW = 0x02, /* 0010 */
+       OPAL_LK = 0x04, /* 0100 */
+};
+
+struct opal_key {
+       __u8 lr;
+       __u8 key_len;
+       __u8 __align[6];
+       __u8 key[OPAL_KEY_MAX];
+};
+
+struct opal_lr_act {
+       struct opal_key key;
+       __u32 sum;
+       __u8    num_lrs;
+       __u8 lr[OPAL_MAX_LRS];
+       __u8 align[2]; /* Align to 8 byte boundary */
+};
+
+struct opal_session_info {
+       __u32 sum;
+       __u32 who;
+       struct opal_key opal_key;
+};
+
+struct opal_user_lr_setup {
+       __u64 range_start;
+       __u64 range_length;
+       __u32 RLE; /* Read Lock enabled */
+       __u32 WLE; /* Write Lock Enabled */
+       struct opal_session_info session;
+};
+
+struct opal_lock_unlock {
+       struct opal_session_info session;
+       __u32 l_state;
+       __u8 __align[4];
+};
+
+struct opal_new_pw {
+       struct opal_session_info session;
+
+       /* When we're not operating in sum, and we first set
+        * passwords we need to set them via ADMIN authority.
+        * After passwords are changed, we can set them via,
+        * User authorities.
+        * Because of this restriction we need to know about
+        * Two different users. One in 'session' which we will use
+        * to start the session and new_userr_pw as the user we're
+        * chaning the pw for.
+        */
+       struct opal_session_info new_user_pw;
+};
+
+struct opal_mbr_data {
+       struct opal_key key;
+       __u8 enable_disable;
+       __u8 __align[7];
+};
+
+#define IOC_OPAL_SAVE              _IOW('p', 220, struct opal_lock_unlock)
+#define IOC_OPAL_LOCK_UNLOCK       _IOW('p', 221, struct opal_lock_unlock)
+#define IOC_OPAL_TAKE_OWNERSHIP            _IOW('p', 222, struct opal_key)
+#define IOC_OPAL_ACTIVATE_LSP       _IOW('p', 223, struct opal_lr_act)
+#define IOC_OPAL_SET_PW             _IOW('p', 224, struct opal_new_pw)
+#define IOC_OPAL_ACTIVATE_USR       _IOW('p', 225, struct opal_session_info)
+#define IOC_OPAL_REVERT_TPR         _IOW('p', 226, struct opal_key)
+#define IOC_OPAL_LR_SETUP           _IOW('p', 227, struct opal_user_lr_setup)
+#define IOC_OPAL_ADD_USR_TO_LR      _IOW('p', 228, struct opal_lock_unlock)
+#define IOC_OPAL_ENABLE_DISABLE_MBR _IOW('p', 229, struct opal_mbr_data)
+#define IOC_OPAL_ERASE_LR           _IOW('p', 230, struct opal_session_info)
+#define IOC_OPAL_SECURE_ERASE_LR    _IOW('p', 231, struct opal_session_info)
+
+#endif /* _UAPI_SED_OPAL_H */
index 6bf1f8a022b10f6499dde0901b051e035d650c1a..e9fdc12ad98475d900aeb607ff65160750ec39c8 100644 (file)
@@ -40,6 +40,7 @@ struct dk_cxlflash_hdr {
  */
 #define DK_CXLFLASH_ALL_PORTS_ACTIVE   0x0000000000000001ULL
 #define DK_CXLFLASH_APP_CLOSE_ADAP_FD  0x0000000000000002ULL
+#define DK_CXLFLASH_CONTEXT_SQ_CMD_MODE        0x0000000000000004ULL
 
 /*
  * General Notes:
index 7ddeeda9380971b0327b09fc639eee9ebf82f1f7..63ee95c9dabb44d5943934c122e65c73a4770b81 100644 (file)
@@ -77,6 +77,17 @@ struct privcmd_mmapbatch_v2 {
        int __user *err;  /* array of error codes */
 };
 
+struct privcmd_dm_op_buf {
+       void __user *uptr;
+       size_t size;
+};
+
+struct privcmd_dm_op {
+       domid_t dom;
+       __u16 num;
+       const struct privcmd_dm_op_buf __user *ubufs;
+};
+
 /*
  * @cmd: IOCTL_PRIVCMD_HYPERCALL
  * @arg: &privcmd_hypercall_t
@@ -98,5 +109,9 @@ struct privcmd_mmapbatch_v2 {
        _IOC(_IOC_NONE, 'P', 3, sizeof(struct privcmd_mmapbatch))
 #define IOCTL_PRIVCMD_MMAPBATCH_V2                             \
        _IOC(_IOC_NONE, 'P', 4, sizeof(struct privcmd_mmapbatch_v2))
+#define IOCTL_PRIVCMD_DM_OP                                    \
+       _IOC(_IOC_NONE, 'P', 5, sizeof(struct privcmd_dm_op))
+#define IOCTL_PRIVCMD_RESTRICT                                 \
+       _IOC(_IOC_NONE, 'P', 6, sizeof(domid_t))
 
 #endif /* __LINUX_PUBLIC_PRIVCMD_H__ */
index 9d874db13c0e7a7cb847b06adaa66d8392760414..73db4b2eeb8929bddea8511442ed3dab8cc0e24d 100644 (file)
@@ -53,6 +53,7 @@ int HYPERVISOR_physdev_op(int cmd, void *arg);
 int HYPERVISOR_vcpu_op(int cmd, int vcpuid, void *extra_args);
 int HYPERVISOR_tmem_op(void *arg);
 int HYPERVISOR_vm_assist(unsigned int cmd, unsigned int type);
+int HYPERVISOR_dm_op(domid_t domid, unsigned int nr_bufs, void *bufs);
 int HYPERVISOR_platform_op_raw(void *arg);
 static inline int HYPERVISOR_platform_op(struct xen_platform_op *op)
 {
index f90b0345465918b6a833a73a1931d18a4de86757..9e9f9bf7c66db84f07b9cbff8f47d6c7065f2bf6 100644 (file)
  */
 #define XEN_ELFNOTE_SUPPORTED_FEATURES 17
 
+/*
+ * Physical entry point into the kernel.
+ *
+ * 32bit entry point into the kernel. When requested to launch the
+ * guest kernel in a HVM container, Xen will use this entry point to
+ * launch the guest in 32bit protected mode with paging disabled.
+ * Ignored otherwise.
+ */
+#define XEN_ELFNOTE_PHYS32_ENTRY 18
+
 /*
  * The number of the highest elfnote defined.
  */
-#define XEN_ELFNOTE_MAX XEN_ELFNOTE_SUPPORTED_FEATURES
+#define XEN_ELFNOTE_MAX XEN_ELFNOTE_PHYS32_ENTRY
 
 #endif /* __XEN_PUBLIC_ELFNOTE_H__ */
 
diff --git a/include/xen/interface/hvm/dm_op.h b/include/xen/interface/hvm/dm_op.h
new file mode 100644 (file)
index 0000000..ee9e480
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2016, Citrix Systems Inc
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 __XEN_PUBLIC_HVM_DM_OP_H__
+#define __XEN_PUBLIC_HVM_DM_OP_H__
+
+struct xen_dm_op_buf {
+       GUEST_HANDLE(void) h;
+       xen_ulong_t size;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_dm_op_buf);
+
+#endif /* __XEN_PUBLIC_HVM_DM_OP_H__ */
diff --git a/include/xen/interface/hvm/hvm_vcpu.h b/include/xen/interface/hvm/hvm_vcpu.h
new file mode 100644 (file)
index 0000000..32ca83e
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 (c) 2015, Roger Pau Monne <roger.pau@citrix.com>
+ */
+
+#ifndef __XEN_PUBLIC_HVM_HVM_VCPU_H__
+#define __XEN_PUBLIC_HVM_HVM_VCPU_H__
+
+#include "../xen.h"
+
+struct vcpu_hvm_x86_32 {
+    uint32_t eax;
+    uint32_t ecx;
+    uint32_t edx;
+    uint32_t ebx;
+    uint32_t esp;
+    uint32_t ebp;
+    uint32_t esi;
+    uint32_t edi;
+    uint32_t eip;
+    uint32_t eflags;
+
+    uint32_t cr0;
+    uint32_t cr3;
+    uint32_t cr4;
+
+    uint32_t pad1;
+
+    /*
+     * EFER should only be used to set the NXE bit (if required)
+     * when starting a vCPU in 32bit mode with paging enabled or
+     * to set the LME/LMA bits in order to start the vCPU in
+     * compatibility mode.
+     */
+    uint64_t efer;
+
+    uint32_t cs_base;
+    uint32_t ds_base;
+    uint32_t ss_base;
+    uint32_t es_base;
+    uint32_t tr_base;
+    uint32_t cs_limit;
+    uint32_t ds_limit;
+    uint32_t ss_limit;
+    uint32_t es_limit;
+    uint32_t tr_limit;
+    uint16_t cs_ar;
+    uint16_t ds_ar;
+    uint16_t ss_ar;
+    uint16_t es_ar;
+    uint16_t tr_ar;
+
+    uint16_t pad2[3];
+};
+
+/*
+ * The layout of the _ar fields of the segment registers is the
+ * following:
+ *
+ * Bits   [0,3]: type (bits 40-43).
+ * Bit        4: s    (descriptor type, bit 44).
+ * Bit    [5,6]: dpl  (descriptor privilege level, bits 45-46).
+ * Bit        7: p    (segment-present, bit 47).
+ * Bit        8: avl  (available for system software, bit 52).
+ * Bit        9: l    (64-bit code segment, bit 53).
+ * Bit       10: db   (meaning depends on the segment, bit 54).
+ * Bit       11: g    (granularity, bit 55)
+ * Bits [12,15]: unused, must be blank.
+ *
+ * A more complete description of the meaning of this fields can be
+ * obtained from the Intel SDM, Volume 3, section 3.4.5.
+ */
+
+struct vcpu_hvm_x86_64 {
+    uint64_t rax;
+    uint64_t rcx;
+    uint64_t rdx;
+    uint64_t rbx;
+    uint64_t rsp;
+    uint64_t rbp;
+    uint64_t rsi;
+    uint64_t rdi;
+    uint64_t rip;
+    uint64_t rflags;
+
+    uint64_t cr0;
+    uint64_t cr3;
+    uint64_t cr4;
+    uint64_t efer;
+
+    /*
+     * Using VCPU_HVM_MODE_64B implies that the vCPU is launched
+     * directly in long mode, so the cached parts of the segment
+     * registers get set to match that environment.
+     *
+     * If the user wants to launch the vCPU in compatibility mode
+     * the 32-bit structure should be used instead.
+     */
+};
+
+struct vcpu_hvm_context {
+#define VCPU_HVM_MODE_32B 0  /* 32bit fields of the structure will be used. */
+#define VCPU_HVM_MODE_64B 1  /* 64bit fields of the structure will be used. */
+    uint32_t mode;
+
+    uint32_t pad;
+
+    /* CPU registers. */
+    union {
+        struct vcpu_hvm_x86_32 x86_32;
+        struct vcpu_hvm_x86_64 x86_64;
+    } cpu_regs;
+};
+typedef struct vcpu_hvm_context vcpu_hvm_context_t;
+
+#endif /* __XEN_PUBLIC_HVM_HVM_VCPU_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/include/xen/interface/hvm/start_info.h b/include/xen/interface/hvm/start_info.h
new file mode 100644 (file)
index 0000000..6484159
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 (c) 2016, Citrix Systems, Inc.
+ */
+
+#ifndef __XEN_PUBLIC_ARCH_X86_HVM_START_INFO_H__
+#define __XEN_PUBLIC_ARCH_X86_HVM_START_INFO_H__
+
+/*
+ * Start of day structure passed to PVH guests and to HVM guests in %ebx.
+ *
+ * NOTE: nothing will be loaded at physical address 0, so a 0 value in any
+ * of the address fields should be treated as not present.
+ *
+ *  0 +----------------+
+ *    | magic          | Contains the magic value XEN_HVM_START_MAGIC_VALUE
+ *    |                | ("xEn3" with the 0x80 bit of the "E" set).
+ *  4 +----------------+
+ *    | version        | Version of this structure. Current version is 0. New
+ *    |                | versions are guaranteed to be backwards-compatible.
+ *  8 +----------------+
+ *    | flags          | SIF_xxx flags.
+ * 12 +----------------+
+ *    | nr_modules     | Number of modules passed to the kernel.
+ * 16 +----------------+
+ *    | modlist_paddr  | Physical address of an array of modules
+ *    |                | (layout of the structure below).
+ * 24 +----------------+
+ *    | cmdline_paddr  | Physical address of the command line,
+ *    |                | a zero-terminated ASCII string.
+ * 32 +----------------+
+ *    | rsdp_paddr     | Physical address of the RSDP ACPI data structure.
+ * 40 +----------------+
+ *
+ * The layout of each entry in the module structure is the following:
+ *
+ *  0 +----------------+
+ *    | paddr          | Physical address of the module.
+ *  8 +----------------+
+ *    | size           | Size of the module in bytes.
+ * 16 +----------------+
+ *    | cmdline_paddr  | Physical address of the command line,
+ *    |                | a zero-terminated ASCII string.
+ * 24 +----------------+
+ *    | reserved       |
+ * 32 +----------------+
+ *
+ * The address and sizes are always a 64bit little endian unsigned integer.
+ *
+ * NB: Xen on x86 will always try to place all the data below the 4GiB
+ * boundary.
+ */
+#define XEN_HVM_START_MAGIC_VALUE 0x336ec578
+
+/*
+ * C representation of the x86/HVM start info layout.
+ *
+ * The canonical definition of this layout is above, this is just a way to
+ * represent the layout described there using C types.
+ */
+struct hvm_start_info {
+    uint32_t magic;             /* Contains the magic value 0x336ec578       */
+                                /* ("xEn3" with the 0x80 bit of the "E" set).*/
+    uint32_t version;           /* Version of this structure.                */
+    uint32_t flags;             /* SIF_xxx flags.                            */
+    uint32_t nr_modules;        /* Number of modules passed to the kernel.   */
+    uint64_t modlist_paddr;     /* Physical address of an array of           */
+                                /* hvm_modlist_entry.                        */
+    uint64_t cmdline_paddr;     /* Physical address of the command line.     */
+    uint64_t rsdp_paddr;        /* Physical address of the RSDP ACPI data    */
+                                /* structure.                                */
+};
+
+struct hvm_modlist_entry {
+    uint64_t paddr;             /* Physical address of the module.           */
+    uint64_t size;              /* Size of the module in bytes.              */
+    uint64_t cmdline_paddr;     /* Physical address of the command line.     */
+    uint64_t reserved;
+};
+
+#endif /* __XEN_PUBLIC_ARCH_X86_HVM_START_INFO_H__ */
index 1b0d189cd3d33f7ce19f739663afdcd7080703c9..4f4830ef8f93496df5d5c908ced15cc25ad1eb55 100644 (file)
@@ -81,6 +81,7 @@
 #define __HYPERVISOR_tmem_op              38
 #define __HYPERVISOR_xc_reserved_op       39 /* reserved for XenClient */
 #define __HYPERVISOR_xenpmu_op            40
+#define __HYPERVISOR_dm_op                41
 
 /* Architecture-specific hypercall definitions. */
 #define __HYPERVISOR_arch_0               48
index f0f0252cff9aab2442e8df64430ec118a2f391aa..6e8b7fc798017e4c13188339cf83b1e68fcd16e4 100644 (file)
@@ -30,16 +30,10 @@ extern enum xen_domain_type xen_domain_type;
 #endif /* CONFIG_XEN_DOM0 */
 
 #ifdef CONFIG_XEN_PVH
-/* This functionality exists only for x86. The XEN_PVHVM support exists
- * only in x86 world - hence on ARM it will be always disabled.
- * N.B. ARM guests are neither PV nor HVM nor PVHVM.
- * It's a bit like PVH but is different also (it's further towards the H
- * end of the spectrum than even PVH).
- */
-#include <xen/features.h>
-#define xen_pvh_domain() (xen_pv_domain() && \
-                         xen_feature(XENFEAT_auto_translated_physmap))
+extern bool xen_pvh;
+#define xen_pvh_domain()       (xen_hvm_domain() && xen_pvh)
 #else
 #define xen_pvh_domain()       (0)
 #endif
+
 #endif /* _XEN_XEN_H */
index 271ba62503c7e5fe23abc3a9628d556bad65e606..869c816d5f8c3097b09298a9d086e7f75fff540e 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/notifier.h>
 #include <linux/mutex.h>
 #include <linux/export.h>
+#include <linux/fs.h>
 #include <linux/completion.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -60,7 +61,7 @@ struct xenbus_watch
 
        /* Callback (executed in a process context with no locks held). */
        void (*callback)(struct xenbus_watch *,
-                        const char **vec, unsigned int len);
+                        const char *path, const char *token);
 };
 
 
@@ -175,16 +176,9 @@ void xs_suspend(void);
 void xs_resume(void);
 void xs_suspend_cancel(void);
 
-/* Used by xenbus_dev to borrow kernel's store connection. */
-void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg);
-
 struct work_struct;
 
-/* Prepare for domain suspend: then resume or cancel the suspend. */
-void xenbus_suspend(void);
-void xenbus_resume(void);
 void xenbus_probe(struct work_struct *);
-void xenbus_suspend_cancel(void);
 
 #define XENBUS_IS_ERR_READ(str) ({                     \
        if (!IS_ERR(str) && strlen(str) == 0) {         \
@@ -199,11 +193,11 @@ void xenbus_suspend_cancel(void);
 int xenbus_watch_path(struct xenbus_device *dev, const char *path,
                      struct xenbus_watch *watch,
                      void (*callback)(struct xenbus_watch *,
-                                      const char **, unsigned int));
+                                      const char *, const char *));
 __printf(4, 5)
 int xenbus_watch_pathfmt(struct xenbus_device *dev, struct xenbus_watch *watch,
                         void (*callback)(struct xenbus_watch *,
-                                         const char **, unsigned int),
+                                         const char *, const char *),
                         const char *pathfmt, ...);
 
 int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state new_state);
@@ -235,4 +229,8 @@ const char *xenbus_strstate(enum xenbus_state state);
 int xenbus_dev_is_online(struct xenbus_device *dev);
 int xenbus_frontend_closed(struct xenbus_device *dev);
 
+extern const struct file_operations xen_xenbus_fops;
+extern struct xenstore_domain_interface *xen_store_interface;
+extern int xen_store_evtchn;
+
 #endif /* _XEN_XENBUS_H */
index 6ced14a3df12a8ae55b3c16bd03525de6a7c20ea..6d98664e843b0a4bb9d4d6ebdc71fd98797bff14 100644 (file)
@@ -12,6 +12,7 @@
 #define DEBUG          /* Enable initcall_debug */
 
 #include <linux/types.h>
+#include <linux/extable.h>
 #include <linux/module.h>
 #include <linux/proc_fs.h>
 #include <linux/kernel.h>
index 6e399bb69d7c6ab54ddf22d2d908c630c0d17fc0..e794544f5e63334afccadf6cc70f5fb2541e1e2e 100644 (file)
@@ -121,7 +121,7 @@ u32         audit_sig_sid = 0;
    3) suppressed due to audit_rate_limit
    4) suppressed due to audit_backlog_limit
 */
-static atomic_t    audit_lost = ATOMIC_INIT(0);
+static atomic_t        audit_lost = ATOMIC_INIT(0);
 
 /* The netlink socket. */
 static struct sock *audit_sock;
@@ -1058,6 +1058,12 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                        if (err < 0)
                                return err;
                }
+               if (s.mask == AUDIT_STATUS_LOST) {
+                       u32 lost = atomic_xchg(&audit_lost, 0);
+
+                       audit_log_config_change("lost", 0, lost, 1);
+                       return lost;
+               }
                break;
        }
        case AUDIT_GET_FEATURE:
@@ -1349,7 +1355,9 @@ static int __init audit_init(void)
                panic("audit: failed to start the kauditd thread (%d)\n", err);
        }
 
-       audit_log(NULL, GFP_KERNEL, AUDIT_KERNEL, "initialized");
+       audit_log(NULL, GFP_KERNEL, AUDIT_KERNEL,
+               "state=initialized audit_enabled=%u res=1",
+                audit_enabled);
 
        return 0;
 }
index 960d49c9db5e3c79b70171c6c9ca1f4d8acf58f2..ca579880303ab475b2c81839a4948bdb128e92f8 100644 (file)
@@ -199,6 +199,9 @@ struct audit_context {
                struct {
                        int                     argc;
                } execve;
+               struct {
+                       char                    *name;
+               } module;
        };
        int fds[2];
        struct audit_proctitle proctitle;
index cf1fa43512c111b6fff0a81403acb62f9a4620a4..d6a8de5f8fa3d0ba33c14b20e6341e32d62dab2a 100644 (file)
@@ -1221,7 +1221,7 @@ static void show_special(struct audit_context *context, int *call_panic)
                                context->ipc.perm_mode);
                }
                break; }
-       case AUDIT_MQ_OPEN: {
+       case AUDIT_MQ_OPEN:
                audit_log_format(ab,
                        "oflag=0x%x mode=%#ho mq_flags=0x%lx mq_maxmsg=%ld "
                        "mq_msgsize=%ld mq_curmsgs=%ld",
@@ -1230,8 +1230,8 @@ static void show_special(struct audit_context *context, int *call_panic)
                        context->mq_open.attr.mq_maxmsg,
                        context->mq_open.attr.mq_msgsize,
                        context->mq_open.attr.mq_curmsgs);
-               break; }
-       case AUDIT_MQ_SENDRECV: {
+               break;
+       case AUDIT_MQ_SENDRECV:
                audit_log_format(ab,
                        "mqdes=%d msg_len=%zd msg_prio=%u "
                        "abs_timeout_sec=%ld abs_timeout_nsec=%ld",
@@ -1240,12 +1240,12 @@ static void show_special(struct audit_context *context, int *call_panic)
                        context->mq_sendrecv.msg_prio,
                        context->mq_sendrecv.abs_timeout.tv_sec,
                        context->mq_sendrecv.abs_timeout.tv_nsec);
-               break; }
-       case AUDIT_MQ_NOTIFY: {
+               break;
+       case AUDIT_MQ_NOTIFY:
                audit_log_format(ab, "mqdes=%d sigev_signo=%d",
                                context->mq_notify.mqdes,
                                context->mq_notify.sigev_signo);
-               break; }
+               break;
        case AUDIT_MQ_GETSETATTR: {
                struct mq_attr *attr = &context->mq_getsetattr.mqstat;
                audit_log_format(ab,
@@ -1255,19 +1255,24 @@ static void show_special(struct audit_context *context, int *call_panic)
                        attr->mq_flags, attr->mq_maxmsg,
                        attr->mq_msgsize, attr->mq_curmsgs);
                break; }
-       case AUDIT_CAPSET: {
+       case AUDIT_CAPSET:
                audit_log_format(ab, "pid=%d", context->capset.pid);
                audit_log_cap(ab, "cap_pi", &context->capset.cap.inheritable);
                audit_log_cap(ab, "cap_pp", &context->capset.cap.permitted);
                audit_log_cap(ab, "cap_pe", &context->capset.cap.effective);
-               break; }
-       case AUDIT_MMAP: {
+               break;
+       case AUDIT_MMAP:
                audit_log_format(ab, "fd=%d flags=0x%x", context->mmap.fd,
                                 context->mmap.flags);
-               break; }
-       case AUDIT_EXECVE: {
+               break;
+       case AUDIT_EXECVE:
                audit_log_execve_info(context, &ab);
-               break; }
+               break;
+       case AUDIT_KERN_MODULE:
+               audit_log_format(ab, "name=");
+               audit_log_untrustedstring(ab, context->module.name);
+               kfree(context->module.name);
+               break;
        }
        audit_log_end(ab);
 }
@@ -2368,6 +2373,15 @@ void __audit_mmap_fd(int fd, int flags)
        context->type = AUDIT_MMAP;
 }
 
+void __audit_log_kern_module(char *name)
+{
+       struct audit_context *context = current->audit_context;
+
+       context->module.name = kmalloc(strlen(name) + 1, GFP_KERNEL);
+       strcpy(context->module.name, name);
+       context->type = AUDIT_KERN_MODULE;
+}
+
 static void audit_log_task(struct audit_buffer *ab)
 {
        kuid_t auid, uid;
@@ -2411,7 +2425,7 @@ void audit_core_dumps(long signr)
        if (unlikely(!ab))
                return;
        audit_log_task(ab);
-       audit_log_format(ab, " sig=%ld", signr);
+       audit_log_format(ab, " sig=%ld res=1", signr);
        audit_log_end(ab);
 }
 
index b67c57faa705d991f87b13e6b17bde64afea9131..580da79e38ee89992a93e6cb61f2c16232d580a6 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/tty.h>
 #include <linux/iocontext.h>
 #include <linux/key.h>
-#include <linux/security.h>
 #include <linux/cpu.h>
 #include <linux/acct.h>
 #include <linux/tsacct_kern.h>
@@ -1390,7 +1389,7 @@ static int wait_task_continued(struct wait_opts *wo, struct task_struct *p)
  * Returns nonzero for a final return, when we have unlocked tasklist_lock.
  * Returns zero if the search for a child should continue;
  * then ->notask_error is 0 if @p is an eligible child,
- * or another error from security_task_wait(), or still -ECHILD.
+ * or still -ECHILD.
  */
 static int wait_consider_task(struct wait_opts *wo, int ptrace,
                                struct task_struct *p)
@@ -1410,20 +1409,6 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace,
        if (!ret)
                return ret;
 
-       ret = security_task_wait(p);
-       if (unlikely(ret < 0)) {
-               /*
-                * If we have not yet seen any eligible child,
-                * then let this error code replace -ECHILD.
-                * A permission error will give the user a clue
-                * to look for security policy problems, rather
-                * than for mysterious wait bugs.
-                */
-               if (wo->notask_error)
-                       wo->notask_error = ret;
-               return 0;
-       }
-
        if (unlikely(exit_state == EXIT_TRACE)) {
                /*
                 * ptrace == 0 means we are the natural parent. In this case
@@ -1516,7 +1501,7 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace,
  * Returns nonzero for a final return, when we have unlocked tasklist_lock.
  * Returns zero if the search for a child should continue; then
  * ->notask_error is 0 if there were any eligible children,
- * or another error from security_task_wait(), or still -ECHILD.
+ * or still -ECHILD.
  */
 static int do_wait_thread(struct wait_opts *wo, struct task_struct *tsk)
 {
index e1359474baa5a55288a37386f290cb68b61ddd85..6b0d09051efbfab707babae601141b19bd7340f8 100644 (file)
@@ -17,6 +17,7 @@
 */
 #include <linux/ftrace.h>
 #include <linux/memory.h>
+#include <linux/extable.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/init.h>
index 3d8f126208e3ae04eeff3fd1b1e00044c0e3d0d2..1a17ec0c8ae7889a34ffcf53cde513b3d0ebc2c5 100644 (file)
@@ -17,6 +17,7 @@
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 #include <linux/export.h>
+#include <linux/extable.h>
 #include <linux/moduleloader.h>
 #include <linux/trace_events.h>
 #include <linux/init.h>
@@ -61,6 +62,7 @@
 #include <linux/pfn.h>
 #include <linux/bsearch.h>
 #include <linux/dynamic_debug.h>
+#include <linux/audit.h>
 #include <uapi/linux/module.h>
 #include "module-internal.h"
 
@@ -3608,6 +3610,8 @@ static int load_module(struct load_info *info, const char __user *uargs,
                goto free_copy;
        }
 
+       audit_log_kern_module(mod->name);
+
        /* Reserve our place in the list. */
        err = add_unformed_module(mod);
        if (err)
@@ -3696,7 +3700,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
                       mod->name, after_dashes);
        }
 
-       /* Link in to syfs. */
+       /* Link in to sysfs. */
        err = mod_sysfs_setup(mod, info, mod->kp, mod->num_kp);
        if (err < 0)
                goto coming_cleanup;
index bdff5ed57f10a5ef57a015856830471422f3918a..5db217051232de97afcc20208ee504ae3d06a430 100644 (file)
@@ -166,7 +166,7 @@ static int __init setup_test_suspend(char *value)
                        return 0;
        }
 
-       for (i = 0; pm_labels[i]; i++)
+       for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++)
                if (!strcmp(pm_labels[i], suspend_type)) {
                        test_state_label = pm_labels[i];
                        return 0;
index 32e0c232efbafa4a3c8f6f40468c61eaad937d5b..f80fd33639e0e5f5b4fc7b1fb53ecfd87b1eaa4d 100644 (file)
@@ -201,7 +201,7 @@ void free_all_swap_pages(int swap)
                struct swsusp_extent *ext;
                unsigned long offset;
 
-               ext = container_of(node, struct swsusp_extent, node);
+               ext = rb_entry(node, struct swsusp_extent, node);
                rb_erase(node, &swsusp_extents);
                for (offset = ext->start; offset <= ext->end; offset++)
                        swap_free(swp_entry(swap, offset));
index 34e2291a9a6c163be3dfd774ed110bf07ab0e890..e1ae6ac15eac94bb6562cb8d206190ec60a9cd5f 100644 (file)
@@ -23,6 +23,9 @@
 
 #include <asm/switch_to.h>
 #include <asm/tlb.h>
+#ifdef CONFIG_PARAVIRT
+#include <asm/paravirt.h>
+#endif
 
 #include "sched.h"
 #include "../workqueue_internal.h"
index f7ce79a46050e2ee6c99bcc9d2784f21721f6d25..f8f88ebcb3baa9d29c2607ff9024c43da43ab0be 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/atomic.h>
 #include <linux/audit.h>
 #include <linux/compat.h>
+#include <linux/coredump.h>
 #include <linux/sched.h>
 #include <linux/seccomp.h>
 #include <linux/slab.h>
@@ -486,6 +487,17 @@ void put_seccomp_filter(struct task_struct *tsk)
        }
 }
 
+static void seccomp_init_siginfo(siginfo_t *info, int syscall, int reason)
+{
+       memset(info, 0, sizeof(*info));
+       info->si_signo = SIGSYS;
+       info->si_code = SYS_SECCOMP;
+       info->si_call_addr = (void __user *)KSTK_EIP(current);
+       info->si_errno = reason;
+       info->si_arch = syscall_get_arch();
+       info->si_syscall = syscall;
+}
+
 /**
  * seccomp_send_sigsys - signals the task to allow in-process syscall emulation
  * @syscall: syscall number to send to userland
@@ -496,13 +508,7 @@ void put_seccomp_filter(struct task_struct *tsk)
 static void seccomp_send_sigsys(int syscall, int reason)
 {
        struct siginfo info;
-       memset(&info, 0, sizeof(info));
-       info.si_signo = SIGSYS;
-       info.si_code = SYS_SECCOMP;
-       info.si_call_addr = (void __user *)KSTK_EIP(current);
-       info.si_errno = reason;
-       info.si_arch = syscall_get_arch();
-       info.si_syscall = syscall;
+       seccomp_init_siginfo(&info, syscall, reason);
        force_sig_info(SIGSYS, &info, current);
 }
 #endif /* CONFIG_SECCOMP_FILTER */
@@ -634,10 +640,17 @@ static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd,
                return 0;
 
        case SECCOMP_RET_KILL:
-       default:
+       default: {
+               siginfo_t info;
                audit_seccomp(this_syscall, SIGSYS, action);
+               /* Show the original registers in the dump. */
+               syscall_rollback(current, task_pt_regs(current));
+               /* Trigger a manual coredump since do_exit skips it. */
+               seccomp_init_siginfo(&info, this_syscall, data);
+               do_coredump(&info);
                do_exit(SIGSYS);
        }
+       }
 
        unreachable();
 
index 95cecbf67f5ca0903d582b0ed45ef4b409fa3c99..b2058a7f94bd8797f5629158aeed8bf045c20e4f 100644 (file)
@@ -28,6 +28,8 @@
 #include <linux/uaccess.h>
 #include <linux/list.h>
 
+#include "../../block/blk.h"
+
 #include <trace/events/block.h>
 
 #include "trace_output.h"
@@ -292,9 +294,6 @@ record_it:
        local_irq_restore(flags);
 }
 
-static struct dentry *blk_tree_root;
-static DEFINE_MUTEX(blk_tree_mutex);
-
 static void blk_trace_free(struct blk_trace *bt)
 {
        debugfs_remove(bt->msg_file);
@@ -433,9 +432,9 @@ static void blk_trace_setup_lba(struct blk_trace *bt,
 /*
  * Setup everything required to start tracing
  */
-int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
-                      struct block_device *bdev,
-                      struct blk_user_trace_setup *buts)
+static int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
+                             struct block_device *bdev,
+                             struct blk_user_trace_setup *buts)
 {
        struct blk_trace *bt = NULL;
        struct dentry *dir = NULL;
@@ -468,22 +467,15 @@ int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
 
        ret = -ENOENT;
 
-       mutex_lock(&blk_tree_mutex);
-       if (!blk_tree_root) {
-               blk_tree_root = debugfs_create_dir("block", NULL);
-               if (!blk_tree_root) {
-                       mutex_unlock(&blk_tree_mutex);
-                       goto err;
-               }
-       }
-       mutex_unlock(&blk_tree_mutex);
-
-       dir = debugfs_create_dir(buts->name, blk_tree_root);
+       if (!blk_debugfs_root)
+               goto err;
 
+       dir = debugfs_lookup(buts->name, blk_debugfs_root);
+       if (!dir)
+               bt->dir = dir = debugfs_create_dir(buts->name, blk_debugfs_root);
        if (!dir)
                goto err;
 
-       bt->dir = dir;
        bt->dev = dev;
        atomic_set(&bt->dropped, 0);
        INIT_LIST_HEAD(&bt->running_list);
@@ -525,9 +517,12 @@ int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
        if (atomic_inc_return(&blk_probes_ref) == 1)
                blk_register_tracepoints();
 
-       return 0;
+       ret = 0;
 err:
-       blk_trace_free(bt);
+       if (dir && !bt->dir)
+               dput(dir);
+       if (ret)
+               blk_trace_free(bt);
        return ret;
 }
 
@@ -712,15 +707,13 @@ static void blk_add_trace_rq(struct request_queue *q, struct request *rq,
        if (likely(!bt))
                return;
 
-       if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
+       if (blk_rq_is_passthrough(rq))
                what |= BLK_TC_ACT(BLK_TC_PC);
-               __blk_add_trace(bt, 0, nr_bytes, req_op(rq), rq->cmd_flags,
-                               what, rq->errors, rq->cmd_len, rq->cmd);
-       } else  {
+       else
                what |= BLK_TC_ACT(BLK_TC_FS);
-               __blk_add_trace(bt, blk_rq_pos(rq), nr_bytes, req_op(rq),
-                               rq->cmd_flags, what, rq->errors, 0, NULL);
-       }
+
+       __blk_add_trace(bt, blk_rq_trace_sector(rq), nr_bytes, req_op(rq),
+                       rq->cmd_flags, what, rq->errors, 0, NULL);
 }
 
 static void blk_add_trace_rq_abort(void *ignore,
@@ -972,11 +965,7 @@ void blk_add_driver_data(struct request_queue *q,
        if (likely(!bt))
                return;
 
-       if (rq->cmd_type == REQ_TYPE_BLOCK_PC)
-               __blk_add_trace(bt, 0, blk_rq_bytes(rq), 0, 0,
-                               BLK_TA_DRV_DATA, rq->errors, len, data);
-       else
-               __blk_add_trace(bt, blk_rq_pos(rq), blk_rq_bytes(rq), 0, 0,
+       __blk_add_trace(bt, blk_rq_trace_sector(rq), blk_rq_bytes(rq), 0, 0,
                                BLK_TA_DRV_DATA, rq->errors, len, data);
 }
 EXPORT_SYMBOL_GPL(blk_add_driver_data);
@@ -1752,31 +1741,6 @@ void blk_trace_remove_sysfs(struct device *dev)
 
 #ifdef CONFIG_EVENT_TRACING
 
-void blk_dump_cmd(char *buf, struct request *rq)
-{
-       int i, end;
-       int len = rq->cmd_len;
-       unsigned char *cmd = rq->cmd;
-
-       if (rq->cmd_type != REQ_TYPE_BLOCK_PC) {
-               buf[0] = '\0';
-               return;
-       }
-
-       for (end = len - 1; end >= 0; end--)
-               if (cmd[end])
-                       break;
-       end++;
-
-       for (i = 0; i < len; i++) {
-               buf += sprintf(buf, "%s%02x", i == 0 ? "" : " ", cmd[i]);
-               if (i == end && end != len - 1) {
-                       sprintf(buf, " ..");
-                       break;
-               }
-       }
-}
-
 void blk_fill_rwbs(char *rwbs, unsigned int op, int bytes)
 {
        int i = 0;
index bc4073a8cd08da8377053c54a09e61f753a3fc7b..19ea76149a37f688b8784cf7f025bcb211b1e0ca 100644 (file)
@@ -31,7 +31,7 @@ lib-$(CONFIG_HAS_DMA) += dma-noop.o
 lib-y  += kobject.o klist.o
 obj-y  += lockref.o
 
-obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
+obj-y += bcd.o div64.o sort.o parser.o debug_locks.o random32.o \
         bust_spinlocks.o kasprintf.o bitmap.o scatterlist.o \
         gcd.o lcm.o list_sort.o uuid.o flex_array.o iov_iter.o clz_ctz.o \
         bsearch.o find_bit.o llist.o memweight.o kfifo.o \
diff --git a/lib/halfmd4.c b/lib/halfmd4.c
deleted file mode 100644 (file)
index 137e861..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-#include <linux/compiler.h>
-#include <linux/export.h>
-#include <linux/cryptohash.h>
-#include <linux/bitops.h>
-
-/* F, G and H are basic MD4 functions: selection, majority, parity */
-#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
-#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z)))
-#define H(x, y, z) ((x) ^ (y) ^ (z))
-
-/*
- * The generic round function.  The application is so specific that
- * we don't bother protecting all the arguments with parens, as is generally
- * good macro practice, in favor of extra legibility.
- * Rotation is separate from addition to prevent recomputation
- */
-#define ROUND(f, a, b, c, d, x, s)     \
-       (a += f(b, c, d) + x, a = rol32(a, s))
-#define K1 0
-#define K2 013240474631UL
-#define K3 015666365641UL
-
-/*
- * Basic cut-down MD4 transform.  Returns only 32 bits of result.
- */
-__u32 half_md4_transform(__u32 buf[4], __u32 const in[8])
-{
-       __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
-
-       /* Round 1 */
-       ROUND(F, a, b, c, d, in[0] + K1,  3);
-       ROUND(F, d, a, b, c, in[1] + K1,  7);
-       ROUND(F, c, d, a, b, in[2] + K1, 11);
-       ROUND(F, b, c, d, a, in[3] + K1, 19);
-       ROUND(F, a, b, c, d, in[4] + K1,  3);
-       ROUND(F, d, a, b, c, in[5] + K1,  7);
-       ROUND(F, c, d, a, b, in[6] + K1, 11);
-       ROUND(F, b, c, d, a, in[7] + K1, 19);
-
-       /* Round 2 */
-       ROUND(G, a, b, c, d, in[1] + K2,  3);
-       ROUND(G, d, a, b, c, in[3] + K2,  5);
-       ROUND(G, c, d, a, b, in[5] + K2,  9);
-       ROUND(G, b, c, d, a, in[7] + K2, 13);
-       ROUND(G, a, b, c, d, in[0] + K2,  3);
-       ROUND(G, d, a, b, c, in[2] + K2,  5);
-       ROUND(G, c, d, a, b, in[4] + K2,  9);
-       ROUND(G, b, c, d, a, in[6] + K2, 13);
-
-       /* Round 3 */
-       ROUND(H, a, b, c, d, in[3] + K3,  3);
-       ROUND(H, d, a, b, c, in[7] + K3,  9);
-       ROUND(H, c, d, a, b, in[2] + K3, 11);
-       ROUND(H, b, c, d, a, in[6] + K3, 15);
-       ROUND(H, a, b, c, d, in[1] + K3,  3);
-       ROUND(H, d, a, b, c, in[5] + K3,  9);
-       ROUND(H, c, d, a, b, in[0] + K3, 11);
-       ROUND(H, b, c, d, a, in[4] + K3, 15);
-
-       buf[0] += a;
-       buf[1] += b;
-       buf[2] += c;
-       buf[3] += d;
-
-       return buf[1]; /* "most hashed" word */
-}
-EXPORT_SYMBOL(half_md4_transform);
index 2cecf05c82fd832ce0c1a49cfffdc8f547ea5eb0..55e11c4b2f3b8e65ca118fe107ae931b877f187f 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/random.h>
 #include <linux/sbitmap.h>
+#include <linux/seq_file.h>
 
 int sbitmap_init_node(struct sbitmap *sb, unsigned int depth, int shift,
                      gfp_t flags, int node)
@@ -180,6 +181,62 @@ unsigned int sbitmap_weight(const struct sbitmap *sb)
 }
 EXPORT_SYMBOL_GPL(sbitmap_weight);
 
+void sbitmap_show(struct sbitmap *sb, struct seq_file *m)
+{
+       seq_printf(m, "depth=%u\n", sb->depth);
+       seq_printf(m, "busy=%u\n", sbitmap_weight(sb));
+       seq_printf(m, "bits_per_word=%u\n", 1U << sb->shift);
+       seq_printf(m, "map_nr=%u\n", sb->map_nr);
+}
+EXPORT_SYMBOL_GPL(sbitmap_show);
+
+static inline void emit_byte(struct seq_file *m, unsigned int offset, u8 byte)
+{
+       if ((offset & 0xf) == 0) {
+               if (offset != 0)
+                       seq_putc(m, '\n');
+               seq_printf(m, "%08x:", offset);
+       }
+       if ((offset & 0x1) == 0)
+               seq_putc(m, ' ');
+       seq_printf(m, "%02x", byte);
+}
+
+void sbitmap_bitmap_show(struct sbitmap *sb, struct seq_file *m)
+{
+       u8 byte = 0;
+       unsigned int byte_bits = 0;
+       unsigned int offset = 0;
+       int i;
+
+       for (i = 0; i < sb->map_nr; i++) {
+               unsigned long word = READ_ONCE(sb->map[i].word);
+               unsigned int word_bits = READ_ONCE(sb->map[i].depth);
+
+               while (word_bits > 0) {
+                       unsigned int bits = min(8 - byte_bits, word_bits);
+
+                       byte |= (word & (BIT(bits) - 1)) << byte_bits;
+                       byte_bits += bits;
+                       if (byte_bits == 8) {
+                               emit_byte(m, offset, byte);
+                               byte = 0;
+                               byte_bits = 0;
+                               offset++;
+                       }
+                       word >>= bits;
+                       word_bits -= bits;
+               }
+       }
+       if (byte_bits) {
+               emit_byte(m, offset, byte);
+               offset++;
+       }
+       if (offset)
+               seq_putc(m, '\n');
+}
+EXPORT_SYMBOL_GPL(sbitmap_bitmap_show);
+
 static unsigned int sbq_calc_wake_batch(unsigned int depth)
 {
        unsigned int wake_batch;
@@ -239,7 +296,19 @@ EXPORT_SYMBOL_GPL(sbitmap_queue_init_node);
 
 void sbitmap_queue_resize(struct sbitmap_queue *sbq, unsigned int depth)
 {
-       sbq->wake_batch = sbq_calc_wake_batch(depth);
+       unsigned int wake_batch = sbq_calc_wake_batch(depth);
+       int i;
+
+       if (sbq->wake_batch != wake_batch) {
+               WRITE_ONCE(sbq->wake_batch, wake_batch);
+               /*
+                * Pairs with the memory barrier in sbq_wake_up() to ensure that
+                * the batch size is updated before the wait counts.
+                */
+               smp_mb__before_atomic();
+               for (i = 0; i < SBQ_WAIT_QUEUES; i++)
+                       atomic_set(&sbq->ws[i].wait_cnt, 1);
+       }
        sbitmap_resize(&sbq->sb, depth);
 }
 EXPORT_SYMBOL_GPL(sbitmap_queue_resize);
@@ -297,20 +366,39 @@ static struct sbq_wait_state *sbq_wake_ptr(struct sbitmap_queue *sbq)
 static void sbq_wake_up(struct sbitmap_queue *sbq)
 {
        struct sbq_wait_state *ws;
+       unsigned int wake_batch;
        int wait_cnt;
 
-       /* Ensure that the wait list checks occur after clear_bit(). */
-       smp_mb();
+       /*
+        * Pairs with the memory barrier in set_current_state() to ensure the
+        * proper ordering of clear_bit()/waitqueue_active() in the waker and
+        * test_and_set_bit()/prepare_to_wait()/finish_wait() in the waiter. See
+        * the comment on waitqueue_active(). This is __after_atomic because we
+        * just did clear_bit() in the caller.
+        */
+       smp_mb__after_atomic();
 
        ws = sbq_wake_ptr(sbq);
        if (!ws)
                return;
 
        wait_cnt = atomic_dec_return(&ws->wait_cnt);
-       if (unlikely(wait_cnt < 0))
-               wait_cnt = atomic_inc_return(&ws->wait_cnt);
-       if (wait_cnt == 0) {
-               atomic_add(sbq->wake_batch, &ws->wait_cnt);
+       if (wait_cnt <= 0) {
+               wake_batch = READ_ONCE(sbq->wake_batch);
+               /*
+                * Pairs with the memory barrier in sbitmap_queue_resize() to
+                * ensure that we see the batch size update before the wait
+                * count is reset.
+                */
+               smp_mb__before_atomic();
+               /*
+                * If there are concurrent callers to sbq_wake_up(), the last
+                * one to decrement the wait count below zero will bump it back
+                * up. If there is a concurrent resize, the count reset will
+                * either cause the cmpxchg to fail or overwrite after the
+                * cmpxchg.
+                */
+               atomic_cmpxchg(&ws->wait_cnt, wait_cnt, wait_cnt + wake_batch);
                sbq_index_atomic_inc(&sbq->wake_index);
                wake_up(&ws->wait);
        }
@@ -331,7 +419,8 @@ void sbitmap_queue_wake_all(struct sbitmap_queue *sbq)
        int i, wake_index;
 
        /*
-        * Make sure all changes prior to this are visible from other CPUs.
+        * Pairs with the memory barrier in set_current_state() like in
+        * sbq_wake_up().
         */
        smp_mb();
        wake_index = atomic_read(&sbq->wake_index);
@@ -345,3 +434,37 @@ void sbitmap_queue_wake_all(struct sbitmap_queue *sbq)
        }
 }
 EXPORT_SYMBOL_GPL(sbitmap_queue_wake_all);
+
+void sbitmap_queue_show(struct sbitmap_queue *sbq, struct seq_file *m)
+{
+       bool first;
+       int i;
+
+       sbitmap_show(&sbq->sb, m);
+
+       seq_puts(m, "alloc_hint={");
+       first = true;
+       for_each_possible_cpu(i) {
+               if (!first)
+                       seq_puts(m, ", ");
+               first = false;
+               seq_printf(m, "%u", *per_cpu_ptr(sbq->alloc_hint, i));
+       }
+       seq_puts(m, "}\n");
+
+       seq_printf(m, "wake_batch=%u\n", sbq->wake_batch);
+       seq_printf(m, "wake_index=%d\n", atomic_read(&sbq->wake_index));
+
+       seq_puts(m, "ws={\n");
+       for (i = 0; i < SBQ_WAIT_QUEUES; i++) {
+               struct sbq_wait_state *ws = &sbq->ws[i];
+
+               seq_printf(m, "\t{.wait_cnt=%d, .wait=%s},\n",
+                          atomic_read(&ws->wait_cnt),
+                          waitqueue_active(&ws->wait) ? "active" : "inactive");
+       }
+       seq_puts(m, "}\n");
+
+       seq_printf(m, "round_robin=%d\n", sbq->round_robin);
+}
+EXPORT_SYMBOL_GPL(sbitmap_queue_show);
index 3bfed5ab2475cba5c4c6607eeb0b80414c78b34b..39ce616a9d7162661cd5122405abb161a7e4349a 100644 (file)
@@ -237,6 +237,7 @@ static __init int bdi_class_init(void)
 
        bdi_class->dev_groups = bdi_dev_groups;
        bdi_debug_init();
+
        return 0;
 }
 postcore_initcall(bdi_class_init);
@@ -758,15 +759,20 @@ static int cgwb_bdi_init(struct backing_dev_info *bdi)
        if (!bdi->wb_congested)
                return -ENOMEM;
 
+       atomic_set(&bdi->wb_congested->refcnt, 1);
+
        err = wb_init(&bdi->wb, bdi, 1, GFP_KERNEL);
        if (err) {
-               kfree(bdi->wb_congested);
+               wb_congested_put(bdi->wb_congested);
                return err;
        }
        return 0;
 }
 
-static void cgwb_bdi_destroy(struct backing_dev_info *bdi) { }
+static void cgwb_bdi_destroy(struct backing_dev_info *bdi)
+{
+       wb_congested_put(bdi->wb_congested);
+}
 
 #endif /* CONFIG_CGROUP_WRITEBACK */
 
@@ -776,6 +782,7 @@ int bdi_init(struct backing_dev_info *bdi)
 
        bdi->dev = NULL;
 
+       kref_init(&bdi->refcnt);
        bdi->min_ratio = 0;
        bdi->max_ratio = 100;
        bdi->max_prop_frac = FPROP_FRAC_BASE;
@@ -791,6 +798,22 @@ int bdi_init(struct backing_dev_info *bdi)
 }
 EXPORT_SYMBOL(bdi_init);
 
+struct backing_dev_info *bdi_alloc_node(gfp_t gfp_mask, int node_id)
+{
+       struct backing_dev_info *bdi;
+
+       bdi = kmalloc_node(sizeof(struct backing_dev_info),
+                          gfp_mask | __GFP_ZERO, node_id);
+       if (!bdi)
+               return NULL;
+
+       if (bdi_init(bdi)) {
+               kfree(bdi);
+               return NULL;
+       }
+       return bdi;
+}
+
 int bdi_register(struct backing_dev_info *bdi, struct device *parent,
                const char *fmt, ...)
 {
@@ -871,12 +894,26 @@ void bdi_unregister(struct backing_dev_info *bdi)
        }
 }
 
-void bdi_exit(struct backing_dev_info *bdi)
+static void bdi_exit(struct backing_dev_info *bdi)
 {
        WARN_ON_ONCE(bdi->dev);
        wb_exit(&bdi->wb);
 }
 
+static void release_bdi(struct kref *ref)
+{
+       struct backing_dev_info *bdi =
+                       container_of(ref, struct backing_dev_info, refcnt);
+
+       bdi_exit(bdi);
+       kfree(bdi);
+}
+
+void bdi_put(struct backing_dev_info *bdi)
+{
+       kref_put(&bdi->refcnt, release_bdi);
+}
+
 void bdi_destroy(struct backing_dev_info *bdi)
 {
        bdi_unregister(bdi);
index 290e8b7d3181f69c5d5f3e44d410a056e0b1f354..2164498258594aff4a72e1263798e1cdec47e3d4 100644 (file)
@@ -1988,11 +1988,11 @@ void laptop_mode_timer_fn(unsigned long data)
         * We want to write everything out, not just down to the dirty
         * threshold
         */
-       if (!bdi_has_dirty_io(&q->backing_dev_info))
+       if (!bdi_has_dirty_io(q->backing_dev_info))
                return;
 
        rcu_read_lock();
-       list_for_each_entry_rcu(wb, &q->backing_dev_info.wb_list, bdi_node)
+       list_for_each_entry_rcu(wb, &q->backing_dev_info->wb_list, bdi_node)
                if (wb_has_dirty_io(wb))
                        wb_start_writeback(wb, nr_pages, true,
                                           WB_REASON_LAPTOP_TIMER);
index 96c544b05b15e3287cff8905b4b6007af69322af..d69f539ca0bc5021fd8b20f6ee6297ccd07cad28 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/filter.h>
 #include <linux/compat.h>
 #include <linux/security.h>
+#include <linux/audit.h>
 #include <linux/export.h>
 
 #include <net/scm.h>
@@ -781,14 +782,24 @@ COMPAT_SYSCALL_DEFINE5(recvmmsg, int, fd, struct compat_mmsghdr __user *, mmsg,
 
 COMPAT_SYSCALL_DEFINE2(socketcall, int, call, u32 __user *, args)
 {
-       int ret;
-       u32 a[6];
+       u32 a[AUDITSC_ARGS];
+       unsigned int len;
        u32 a0, a1;
+       int ret;
 
        if (call < SYS_SOCKET || call > SYS_SENDMMSG)
                return -EINVAL;
-       if (copy_from_user(a, args, nas[call]))
+       len = nas[call];
+       if (len > sizeof(a))
+               return -EINVAL;
+
+       if (copy_from_user(a, args, len))
                return -EFAULT;
+
+       ret = audit_socketcall_compat(len / sizeof(a[0]), a);
+       if (ret)
+               return ret;
+
        a0 = a[0];
        a1 = a[1];
 
index 38ee70f3cd5b970101edd6d2edb52b4df8d73d14..1d8de9edd8580776afe209c6c8d31cb1311b7871 100644 (file)
@@ -138,7 +138,7 @@ union arg64 {
 #define ARG_32(idx) \
        BPF_STMT(BPF_LD+BPF_W+BPF_ABS, LO_ARG(idx))
 
-/* Loads hi into A and lo in X */
+/* Loads lo into M[0] and hi into M[1] and A */
 #define ARG_64(idx) \
        BPF_STMT(BPF_LD+BPF_W+BPF_ABS, LO_ARG(idx)), \
        BPF_STMT(BPF_ST, 0), /* lo -> M[0] */ \
@@ -153,88 +153,107 @@ union arg64 {
        BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (value), 1, 0), \
        jt
 
-/* Checks the lo, then swaps to check the hi. A=lo,X=hi */
+#define JA32(value, jt) \
+       BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (value), 0, 1), \
+       jt
+
+#define JGE32(value, jt) \
+       BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 0, 1), \
+       jt
+
+#define JGT32(value, jt) \
+       BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 0, 1), \
+       jt
+
+#define JLE32(value, jt) \
+       BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 1, 0), \
+       jt
+
+#define JLT32(value, jt) \
+       BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 1, 0), \
+       jt
+
+/*
+ * All the JXX64 checks assume lo is saved in M[0] and hi is saved in both
+ * A and M[1]. This invariant is kept by restoring A if necessary.
+ */
 #define JEQ64(lo, hi, jt) \
+       /* if (hi != arg.hi) goto NOMATCH; */ \
        BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
        BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
+       /* if (lo != arg.lo) goto NOMATCH; */ \
        BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (lo), 0, 2), \
-       BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \
+       BPF_STMT(BPF_LD+BPF_MEM, 1), \
        jt, \
-       BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */
+       BPF_STMT(BPF_LD+BPF_MEM, 1)
 
 #define JNE64(lo, hi, jt) \
-       BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 5, 0), \
-       BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
+       /* if (hi != arg.hi) goto MATCH; */ \
+       BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 3), \
+       BPF_STMT(BPF_LD+BPF_MEM, 0), \
+       /* if (lo != arg.lo) goto MATCH; */ \
        BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (lo), 2, 0), \
-       BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \
+       BPF_STMT(BPF_LD+BPF_MEM, 1), \
        jt, \
-       BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */
-
-#define JA32(value, jt) \
-       BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (value), 0, 1), \
-       jt
+       BPF_STMT(BPF_LD+BPF_MEM, 1)
 
 #define JA64(lo, hi, jt) \
+       /* if (hi & arg.hi) goto MATCH; */ \
        BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (hi), 3, 0), \
-       BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
+       BPF_STMT(BPF_LD+BPF_MEM, 0), \
+       /* if (lo & arg.lo) goto MATCH; */ \
        BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (lo), 0, 2), \
-       BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \
+       BPF_STMT(BPF_LD+BPF_MEM, 1), \
        jt, \
-       BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */
+       BPF_STMT(BPF_LD+BPF_MEM, 1)
 
-#define JGE32(value, jt) \
-       BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 0, 1), \
-       jt
-
-#define JLT32(value, jt) \
-       BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 1, 0), \
-       jt
-
-/* Shortcut checking if hi > arg.hi. */
 #define JGE64(lo, hi, jt) \
+       /* if (hi > arg.hi) goto MATCH; */ \
        BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 4, 0), \
+       /* if (hi != arg.hi) goto NOMATCH; */ \
        BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
-       BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
+       BPF_STMT(BPF_LD+BPF_MEM, 0), \
+       /* if (lo >= arg.lo) goto MATCH; */ \
        BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (lo), 0, 2), \
-       BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \
-       jt, \
-       BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */
-
-#define JLT64(lo, hi, jt) \
-       BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (hi), 0, 4), \
-       BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
-       BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
-       BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 2, 0), \
-       BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \
+       BPF_STMT(BPF_LD+BPF_MEM, 1), \
        jt, \
-       BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */
+       BPF_STMT(BPF_LD+BPF_MEM, 1)
 
-#define JGT32(value, jt) \
-       BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 0, 1), \
-       jt
-
-#define JLE32(value, jt) \
-       BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 1, 0), \
-       jt
-
-/* Check hi > args.hi first, then do the GE checking */
 #define JGT64(lo, hi, jt) \
+       /* if (hi > arg.hi) goto MATCH; */ \
        BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 4, 0), \
+       /* if (hi != arg.hi) goto NOMATCH; */ \
        BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
-       BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
+       BPF_STMT(BPF_LD+BPF_MEM, 0), \
+       /* if (lo > arg.lo) goto MATCH; */ \
        BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 0, 2), \
-       BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \
+       BPF_STMT(BPF_LD+BPF_MEM, 1), \
        jt, \
-       BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */
+       BPF_STMT(BPF_LD+BPF_MEM, 1)
 
 #define JLE64(lo, hi, jt) \
-       BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 6, 0), \
-       BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 3), \
-       BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
+       /* if (hi < arg.hi) goto MATCH; */ \
+       BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (hi), 0, 4), \
+       /* if (hi != arg.hi) goto NOMATCH; */ \
+       BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
+       BPF_STMT(BPF_LD+BPF_MEM, 0), \
+       /* if (lo <= arg.lo) goto MATCH; */ \
        BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 2, 0), \
-       BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \
+       BPF_STMT(BPF_LD+BPF_MEM, 1), \
+       jt, \
+       BPF_STMT(BPF_LD+BPF_MEM, 1)
+
+#define JLT64(lo, hi, jt) \
+       /* if (hi < arg.hi) goto MATCH; */ \
+       BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (hi), 0, 4), \
+       /* if (hi != arg.hi) goto NOMATCH; */ \
+       BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
+       BPF_STMT(BPF_LD+BPF_MEM, 0), \
+       /* if (lo < arg.lo) goto MATCH; */ \
+       BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (lo), 2, 0), \
+       BPF_STMT(BPF_LD+BPF_MEM, 1), \
        jt, \
-       BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */
+       BPF_STMT(BPF_LD+BPF_MEM, 1)
 
 #define LOAD_SYSCALL_NR \
        BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
index 179219845dfcdfbeb586d12c5ec1296095d9fbf4..d6ca649cb0e96d4d91a4980048912544b8183e06 100644 (file)
@@ -284,7 +284,7 @@ ksym_dep_filter =                                                            \
            $(CPP) $(call flags_nodeps,c_flags) -D__KSYM_DEPS__ $< ;;        \
          as_*_S|cpp_s_S)                                                    \
            $(CPP) $(call flags_nodeps,a_flags) -D__KSYM_DEPS__ $< ;;        \
-         boot*|build*|*cpp_lds_S|dtc|host*|vdso*) : ;;                      \
+         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'
 
index a0ba48fa2c5eaa6d1c883dde91e0223676b4d135..20cdb2bc1daec4fc1205c71c38c8d082f0602863 100755 (executable)
 #         https://01.org/suspendresume
 #       Source repo
 #         https://github.com/01org/suspendresume
-#       Documentation
-#         Getting Started
-#           https://01.org/suspendresume/documentation/getting-started
-#         Command List:
-#           https://01.org/suspendresume/documentation/command-list
 #
 # Description:
 #       This tool is designed to assist kernel and OS developers in optimizing
@@ -66,6 +61,8 @@ import platform
 from datetime import datetime
 import struct
 import ConfigParser
+from threading import Thread
+from subprocess import call, Popen, PIPE
 
 # ----------------- CLASSES --------------------
 
@@ -75,11 +72,15 @@ import ConfigParser
 #       store system values and test parameters
 class SystemValues:
        ansi = False
-       version = '4.2'
+       version = '4.5'
        verbose = False
        addlogs = False
-       mindevlen = 0.001
-       mincglen = 1.0
+       mindevlen = 0.0
+       mincglen = 0.0
+       cgphase = ''
+       cgtest = -1
+       callloopmaxgap = 0.0001
+       callloopmaxlen = 0.005
        srgap = 0
        cgexp = False
        outdir = ''
@@ -92,6 +93,7 @@ class SystemValues:
                'device_pm_callback_end',
                'device_pm_callback_start'
        ]
+       logmsg = ''
        testcommand = ''
        mempath = '/dev/mem'
        powerfile = '/sys/power/state'
@@ -117,19 +119,19 @@ class SystemValues:
        usetracemarkers = True
        usekprobes = True
        usedevsrc = False
+       useprocmon = False
        notestrun = False
+       mixedphaseheight = True
        devprops = dict()
-       postresumetime = 0
+       predelay = 0
+       postdelay = 0
+       procexecfmt = 'ps - (?P<ps>.*)$'
        devpropfmt = '# Device Properties: .*'
        tracertypefmt = '# tracer: (?P<t>.*)'
        firmwarefmt = '# fwsuspend (?P<s>[0-9]*) fwresume (?P<r>[0-9]*)$'
-       postresumefmt = '# post resume time (?P<t>[0-9]*)$'
        stampfmt = '# suspend-(?P<m>[0-9]{2})(?P<d>[0-9]{2})(?P<y>[0-9]{2})-'+\
                                '(?P<H>[0-9]{2})(?P<M>[0-9]{2})(?P<S>[0-9]{2})'+\
                                ' (?P<host>.*) (?P<mode>.*) (?P<kernel>.*)$'
-       kprobecolor = 'rgba(204,204,204,0.5)'
-       synccolor = 'rgba(204,204,204,0.5)'
-       debugfuncs = []
        tracefuncs = {
                'sys_sync': dict(),
                'pm_prepare_console': dict(),
@@ -152,44 +154,66 @@ class SystemValues:
                'CPU_OFF': {
                        'func':'_cpu_down',
                        'args_x86_64': {'cpu':'%di:s32'},
-                       'format': 'CPU_OFF[{cpu}]',
-                       'mask': 'CPU_.*_DOWN'
+                       'format': 'CPU_OFF[{cpu}]'
                },
                'CPU_ON': {
                        'func':'_cpu_up',
                        'args_x86_64': {'cpu':'%di:s32'},
-                       'format': 'CPU_ON[{cpu}]',
-                       'mask': 'CPU_.*_UP'
+                       'format': 'CPU_ON[{cpu}]'
                },
        }
        dev_tracefuncs = {
                # general wait/delay/sleep
-               'msleep': { 'args_x86_64': {'time':'%di:s32'} },
-               'udelay': { 'func':'__const_udelay', 'args_x86_64': {'loops':'%di:s32'} },
-               'acpi_os_stall': dict(),
+               'msleep': { 'args_x86_64': {'time':'%di:s32'}, 'ub': 1 },
+               'schedule_timeout_uninterruptible': { 'args_x86_64': {'timeout':'%di:s32'}, 'ub': 1 },
+               'schedule_timeout': { 'args_x86_64': {'timeout':'%di:s32'}, 'ub': 1 },
+               'udelay': { 'func':'__const_udelay', 'args_x86_64': {'loops':'%di:s32'}, 'ub': 1 },
+               'usleep_range': { 'args_x86_64': {'min':'%di:s32', 'max':'%si:s32'}, 'ub': 1 },
+               'mutex_lock_slowpath': { 'func':'__mutex_lock_slowpath', 'ub': 1 },
+               'acpi_os_stall': {'ub': 1},
                # ACPI
                'acpi_resume_power_resources': dict(),
                'acpi_ps_parse_aml': dict(),
                # filesystem
                'ext4_sync_fs': dict(),
+               # 80211
+               'iwlagn_mac_start': dict(),
+               'iwlagn_alloc_bcast_station': dict(),
+               'iwl_trans_pcie_start_hw': dict(),
+               'iwl_trans_pcie_start_fw': dict(),
+               'iwl_run_init_ucode': dict(),
+               'iwl_load_ucode_wait_alive': dict(),
+               'iwl_alive_start': dict(),
+               'iwlagn_mac_stop': dict(),
+               'iwlagn_mac_suspend': dict(),
+               'iwlagn_mac_resume': dict(),
+               'iwlagn_mac_add_interface': dict(),
+               'iwlagn_mac_remove_interface': dict(),
+               'iwlagn_mac_change_interface': dict(),
+               'iwlagn_mac_config': dict(),
+               'iwlagn_configure_filter': dict(),
+               'iwlagn_mac_hw_scan': dict(),
+               'iwlagn_bss_info_changed': dict(),
+               'iwlagn_mac_channel_switch': dict(),
+               'iwlagn_mac_flush': dict(),
                # ATA
                'ata_eh_recover': { 'args_x86_64': {'port':'+36(%di):s32'} },
                # i915
-               'i915_gem_restore_gtt_mappings': dict(),
+               'i915_gem_resume': dict(),
+               'i915_restore_state': dict(),
                'intel_opregion_setup': dict(),
+               'g4x_pre_enable_dp': dict(),
+               'vlv_pre_enable_dp': dict(),
+               'chv_pre_enable_dp': dict(),
+               'g4x_enable_dp': dict(),
+               'vlv_enable_dp': dict(),
+               'intel_hpd_init': dict(),
+               'intel_opregion_register': dict(),
                'intel_dp_detect': dict(),
                'intel_hdmi_detect': dict(),
                'intel_opregion_init': dict(),
+               'intel_fbdev_set_suspend': dict(),
        }
-       kprobes_postresume = [
-               {
-                       'name': 'ataportrst',
-                       'func': 'ata_eh_recover',
-                       'args': {'port':'+36(%di):s32'},
-                       'format': 'ata{port}_port_reset',
-                       'mask': 'ata.*_port_reset'
-               }
-       ]
        kprobes = dict()
        timeformat = '%.3f'
        def __init__(self):
@@ -198,6 +222,7 @@ class SystemValues:
                        self.embedded = True
                        self.addlogs = True
                        self.htmlfile = os.environ['LOG_FILE']
+               self.archargs = 'args_'+platform.machine()
                self.hostname = platform.node()
                if(self.hostname == ''):
                        self.hostname = 'localhost'
@@ -214,6 +239,13 @@ class SystemValues:
                if num < 0 or num > 6:
                        return
                self.timeformat = '%.{0}f'.format(num)
+       def setOutputFolder(self, value):
+               args = dict()
+               n = datetime.now()
+               args['date'] = n.strftime('%y%m%d')
+               args['time'] = n.strftime('%H%M%S')
+               args['hostname'] = self.hostname
+               self.outdir = value.format(**args)
        def setOutputFile(self):
                if((self.htmlfile == '') and (self.dmesgfile != '')):
                        m = re.match('(?P<name>.*)_dmesg\.txt$', self.dmesgfile)
@@ -253,10 +285,14 @@ class SystemValues:
                        self.testdir+'/'+self.prefix+'_'+self.suspendmode+'.html'
                if not os.path.isdir(self.testdir):
                        os.mkdir(self.testdir)
-       def setDeviceFilter(self, devnames):
-               self.devicefilter = string.split(devnames)
+       def setDeviceFilter(self, value):
+               self.devicefilter = []
+               if value:
+                       value = value.split(',')
+               for i in value:
+                       self.devicefilter.append(i.strip())
        def rtcWakeAlarmOn(self):
-               os.system('echo 0 > '+self.rtcpath+'/wakealarm')
+               call('echo 0 > '+self.rtcpath+'/wakealarm', shell=True)
                outD = open(self.rtcpath+'/date', 'r').read().strip()
                outT = open(self.rtcpath+'/time', 'r').read().strip()
                mD = re.match('^(?P<y>[0-9]*)-(?P<m>[0-9]*)-(?P<d>[0-9]*)', outD)
@@ -272,12 +308,12 @@ class SystemValues:
                        # if hardware time fails, use the software time
                        nowtime = int(datetime.now().strftime('%s'))
                alarm = nowtime + self.rtcwaketime
-               os.system('echo %d > %s/wakealarm' % (alarm, self.rtcpath))
+               call('echo %d > %s/wakealarm' % (alarm, self.rtcpath), shell=True)
        def rtcWakeAlarmOff(self):
-               os.system('echo 0 > %s/wakealarm' % self.rtcpath)
+               call('echo 0 > %s/wakealarm' % self.rtcpath, shell=True)
        def initdmesg(self):
                # get the latest time stamp from the dmesg log
-               fp = os.popen('dmesg')
+               fp = Popen('dmesg', stdout=PIPE).stdout
                ktime = '0'
                for line in fp:
                        line = line.replace('\r\n', '')
@@ -291,7 +327,7 @@ class SystemValues:
                self.dmesgstart = float(ktime)
        def getdmesg(self):
                # store all new dmesg lines since initdmesg was called
-               fp = os.popen('dmesg')
+               fp = Popen('dmesg', stdout=PIPE).stdout
                op = open(self.dmesgfile, 'a')
                for line in fp:
                        line = line.replace('\r\n', '')
@@ -317,25 +353,18 @@ class SystemValues:
        def getFtraceFilterFunctions(self, current):
                rootCheck(True)
                if not current:
-                       os.system('cat '+self.tpath+'available_filter_functions')
+                       call('cat '+self.tpath+'available_filter_functions', shell=True)
                        return
                fp = open(self.tpath+'available_filter_functions')
                master = fp.read().split('\n')
                fp.close()
-               if len(self.debugfuncs) > 0:
-                       for i in self.debugfuncs:
-                               if i in master:
-                                       print i
-                               else:
-                                       print self.colorText(i)
-               else:
-                       for i in self.tracefuncs:
-                               if 'func' in self.tracefuncs[i]:
-                                       i = self.tracefuncs[i]['func']
-                               if i in master:
-                                       print i
-                               else:
-                                       print self.colorText(i)
+               for i in self.tracefuncs:
+                       if 'func' in self.tracefuncs[i]:
+                               i = self.tracefuncs[i]['func']
+                       if i in master:
+                               print i
+                       else:
+                               print self.colorText(i)
        def setFtraceFilterFunctions(self, list):
                fp = open(self.tpath+'available_filter_functions')
                master = fp.read().split('\n')
@@ -351,22 +380,15 @@ class SystemValues:
                fp = open(self.tpath+'set_graph_function', 'w')
                fp.write(flist)
                fp.close()
-       def kprobeMatch(self, name, target):
-               if name not in self.kprobes:
-                       return False
-               if re.match(self.kprobes[name]['mask'], target):
-                       return True
-               return False
        def basicKprobe(self, name):
-               self.kprobes[name] = {'name': name,'func': name,'args': dict(),'format': name,'mask': name}
+               self.kprobes[name] = {'name': name,'func': name,'args': dict(),'format': name}
        def defaultKprobe(self, name, kdata):
                k = kdata
-               for field in ['name', 'format', 'mask', 'func']:
+               for field in ['name', 'format', 'func']:
                        if field not in k:
                                k[field] = name
-               archargs = 'args_'+platform.machine()
-               if archargs in k:
-                       k['args'] = k[archargs]
+               if self.archargs in k:
+                       k['args'] = k[self.archargs]
                else:
                        k['args'] = dict()
                        k['format'] = name
@@ -403,49 +425,80 @@ class SystemValues:
                out = fmt.format(**arglist)
                out = out.replace(' ', '_').replace('"', '')
                return out
-       def kprobeText(self, kprobe):
-               name, fmt, func, args = kprobe['name'], kprobe['format'], kprobe['func'], kprobe['args']
+       def kprobeText(self, kname, kprobe):
+               name = fmt = func = kname
+               args = dict()
+               if 'name' in kprobe:
+                       name = kprobe['name']
+               if 'format' in kprobe:
+                       fmt = kprobe['format']
+               if 'func' in kprobe:
+                       func = kprobe['func']
+               if self.archargs in kprobe:
+                       args = kprobe[self.archargs]
+               if 'args' in kprobe:
+                       args = kprobe['args']
                if re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', func):
-                       doError('Kprobe "%s" has format info in the function name "%s"' % (name, func), False)
+                       doError('Kprobe "%s" has format info in the function name "%s"' % (name, func))
                for arg in re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', fmt):
                        if arg not in args:
-                               doError('Kprobe "%s" is missing argument "%s"' % (name, arg), False)
+                               doError('Kprobe "%s" is missing argument "%s"' % (name, arg))
                val = 'p:%s_cal %s' % (name, func)
                for i in sorted(args):
                        val += ' %s=%s' % (i, args[i])
                val += '\nr:%s_ret %s $retval\n' % (name, func)
                return val
-       def addKprobes(self):
+       def addKprobes(self, output=False):
+               if len(sysvals.kprobes) < 1:
+                       return
+               if output:
+                       print('    kprobe functions in this kernel:')
                # first test each kprobe
-               print('INITIALIZING KPROBES...')
                rejects = []
+               # sort kprobes: trace, ub-dev, custom, dev
+               kpl = [[], [], [], []]
                for name in sorted(self.kprobes):
-                       if not self.testKprobe(self.kprobes[name]):
+                       res = self.colorText('YES', 32)
+                       if not self.testKprobe(name, self.kprobes[name]):
+                               res = self.colorText('NO')
                                rejects.append(name)
+                       else:
+                               if name in self.tracefuncs:
+                                       kpl[0].append(name)
+                               elif name in self.dev_tracefuncs:
+                                       if 'ub' in self.dev_tracefuncs[name]:
+                                               kpl[1].append(name)
+                                       else:
+                                               kpl[3].append(name)
+                               else:
+                                       kpl[2].append(name)
+                       if output:
+                               print('         %s: %s' % (name, res))
+               kplist = kpl[0] + kpl[1] + kpl[2] + kpl[3]
                # remove all failed ones from the list
                for name in rejects:
-                       vprint('Skipping KPROBE: %s' % name)
                        self.kprobes.pop(name)
+               # set the kprobes all at once
                self.fsetVal('', 'kprobe_events')
                kprobeevents = ''
-               # set the kprobes all at once
-               for kp in self.kprobes:
-                       val = self.kprobeText(self.kprobes[kp])
-                       vprint('Adding KPROBE: %s\n%s' % (kp, val.strip()))
-                       kprobeevents += self.kprobeText(self.kprobes[kp])
+               for kp in kplist:
+                       kprobeevents += self.kprobeText(kp, self.kprobes[kp])
                self.fsetVal(kprobeevents, 'kprobe_events')
                # verify that the kprobes were set as ordered
                check = self.fgetVal('kprobe_events')
-               linesout = len(kprobeevents.split('\n'))
-               linesack = len(check.split('\n'))
-               if linesack < linesout:
-                       # if not, try appending the kprobes 1 by 1
-                       for kp in self.kprobes:
-                               kprobeevents = self.kprobeText(self.kprobes[kp])
-                               self.fsetVal(kprobeevents, 'kprobe_events', 'a')
+               linesout = len(kprobeevents.split('\n')) - 1
+               linesack = len(check.split('\n')) - 1
+               if output:
+                       res = '%d/%d' % (linesack, linesout)
+                       if linesack < linesout:
+                               res = self.colorText(res, 31)
+                       else:
+                               res = self.colorText(res, 32)
+                       print('    working kprobe functions enabled: %s' % res)
                self.fsetVal('1', 'events/kprobes/enable')
-       def testKprobe(self, kprobe):
-               kprobeevents = self.kprobeText(kprobe)
+       def testKprobe(self, kname, kprobe):
+               self.fsetVal('0', 'events/kprobes/enable')
+               kprobeevents = self.kprobeText(kname, kprobe)
                if not kprobeevents:
                        return False
                try:
@@ -463,8 +516,9 @@ class SystemValues:
                if not os.path.exists(file):
                        return False
                try:
-                       fp = open(file, mode)
+                       fp = open(file, mode, 0)
                        fp.write(val)
+                       fp.flush()
                        fp.close()
                except:
                        pass
@@ -491,21 +545,17 @@ class SystemValues:
                for name in self.dev_tracefuncs:
                        self.defaultKprobe(name, self.dev_tracefuncs[name])
        def isCallgraphFunc(self, name):
-               if len(self.debugfuncs) < 1 and self.suspendmode == 'command':
-                       return True
-               if name in self.debugfuncs:
+               if len(self.tracefuncs) < 1 and self.suspendmode == 'command':
                        return True
-               funclist = []
                for i in self.tracefuncs:
                        if 'func' in self.tracefuncs[i]:
-                               funclist.append(self.tracefuncs[i]['func'])
+                               f = self.tracefuncs[i]['func']
                        else:
-                               funclist.append(i)
-               if name in funclist:
-                       return True
+                               f = i
+                       if name == f:
+                               return True
                return False
        def initFtrace(self, testing=False):
-               tp = self.tpath
                print('INITIALIZING FTRACE...')
                # turn trace off
                self.fsetVal('0', 'tracing_on')
@@ -518,18 +568,7 @@ class SystemValues:
                # go no further if this is just a status check
                if testing:
                        return
-               if self.usekprobes:
-                       # add tracefunc kprobes so long as were not using full callgraph
-                       if(not self.usecallgraph or len(self.debugfuncs) > 0):
-                               for name in self.tracefuncs:
-                                       self.defaultKprobe(name, self.tracefuncs[name])
-                               if self.usedevsrc:
-                                       for name in self.dev_tracefuncs:
-                                               self.defaultKprobe(name, self.dev_tracefuncs[name])
-                       else:
-                               self.usedevsrc = False
-                       self.addKprobes()
-               # initialize the callgraph trace, unless this is an x2 run
+               # initialize the callgraph trace
                if(self.usecallgraph):
                        # set trace type
                        self.fsetVal('function_graph', 'current_tracer')
@@ -545,20 +584,24 @@ class SystemValues:
                        self.fsetVal('context-info', 'trace_options')
                        self.fsetVal('graph-time', 'trace_options')
                        self.fsetVal('0', 'max_graph_depth')
-                       if len(self.debugfuncs) > 0:
-                               self.setFtraceFilterFunctions(self.debugfuncs)
-                       elif self.suspendmode == 'command':
-                               self.fsetVal('', 'set_graph_function')
-                       else:
-                               cf = ['dpm_run_callback']
-                               if(self.usetraceeventsonly):
-                                       cf += ['dpm_prepare', 'dpm_complete']
-                               for fn in self.tracefuncs:
-                                       if 'func' in self.tracefuncs[fn]:
-                                               cf.append(self.tracefuncs[fn]['func'])
-                                       else:
-                                               cf.append(fn)
-                               self.setFtraceFilterFunctions(cf)
+                       cf = ['dpm_run_callback']
+                       if(self.usetraceeventsonly):
+                               cf += ['dpm_prepare', 'dpm_complete']
+                       for fn in self.tracefuncs:
+                               if 'func' in self.tracefuncs[fn]:
+                                       cf.append(self.tracefuncs[fn]['func'])
+                               else:
+                                       cf.append(fn)
+                       self.setFtraceFilterFunctions(cf)
+               # initialize the kprobe trace
+               elif self.usekprobes:
+                       for name in self.tracefuncs:
+                               self.defaultKprobe(name, self.tracefuncs[name])
+                       if self.usedevsrc:
+                               for name in self.dev_tracefuncs:
+                                       self.defaultKprobe(name, self.dev_tracefuncs[name])
+                       print('INITIALIZING KPROBES...')
+                       self.addKprobes(self.verbose)
                if(self.usetraceevents):
                        # turn trace events on
                        events = iter(self.traceevents)
@@ -590,10 +633,10 @@ class SystemValues:
                        if(os.path.exists(tp+f) == False):
                                return False
                return True
-       def colorText(self, str):
+       def colorText(self, str, color=31):
                if not self.ansi:
                        return str
-               return '\x1B[31;40m'+str+'\x1B[m'
+               return '\x1B[%d;40m%s\x1B[m' % (color, str)
 
 sysvals = SystemValues()
 
@@ -625,8 +668,8 @@ class DevProps:
                if self.xtraclass:
                        return ' '+self.xtraclass
                if self.async:
-                       return ' async'
-               return ' sync'
+                       return ' async_device'
+               return ' sync_device'
 
 # Class: DeviceNode
 # Description:
@@ -646,8 +689,6 @@ class DeviceNode:
 #       The primary container for suspend/resume test data. There is one for
 #       each test run. The data is organized into a cronological hierarchy:
 #       Data.dmesg {
-#              root structure, started as dmesg & ftrace, but now only ftrace
-#              contents: times for suspend start/end, resume start/end, fwdata
 #              phases {
 #                      10 sequential, non-overlapping phases of S/R
 #                      contents: times for phase start/end, order/color data for html
@@ -658,7 +699,7 @@ class DeviceNode:
 #                                      contents: start/stop times, pid/cpu/driver info
 #                                              parents/children, html id for timeline/callgraph
 #                                              optionally includes an ftrace callgraph
-#                                              optionally includes intradev trace events
+#                                              optionally includes dev/ps data
 #                              }
 #                      }
 #              }
@@ -671,19 +712,24 @@ class Data:
        end = 0.0   # test end
        tSuspended = 0.0 # low-level suspend start
        tResumed = 0.0   # low-level resume start
+       tKernSus = 0.0   # kernel level suspend start
+       tKernRes = 0.0   # kernel level resume end
        tLow = 0.0       # time spent in low-level suspend (standby/freeze)
        fwValid = False  # is firmware data available
        fwSuspend = 0    # time spent in firmware suspend
        fwResume = 0     # time spent in firmware resume
        dmesgtext = []   # dmesg text file in memory
+       pstl = 0         # process timeline
        testnumber = 0
        idstr = ''
        html_device_id = 0
        stamp = 0
        outfile = ''
-       dev_ubiquitous = ['msleep', 'udelay']
+       devpids = []
+       kerror = False
        def __init__(self, num):
-               idchar = 'abcdefghijklmnopqrstuvwxyz'
+               idchar = 'abcdefghij'
+               self.pstl = dict()
                self.testnumber = num
                self.idstr = idchar[num]
                self.dmesgtext = []
@@ -714,16 +760,39 @@ class Data:
                self.devicegroups = []
                for phase in self.phases:
                        self.devicegroups.append([phase])
-       def getStart(self):
-               return self.dmesg[self.phases[0]]['start']
+               self.errorinfo = {'suspend':[],'resume':[]}
+       def extractErrorInfo(self, dmesg):
+               error = ''
+               tm = 0.0
+               for i in range(len(dmesg)):
+                       if 'Call Trace:' in dmesg[i]:
+                               m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) .*', dmesg[i])
+                               if not m:
+                                       continue
+                               tm = float(m.group('ktime'))
+                               if tm < self.start or tm > self.end:
+                                       continue
+                               for j in range(i-10, i+1):
+                                       error += dmesg[j]
+                               continue
+                       if error:
+                               m = re.match('[ \t]*\[ *[0-9\.]*\]  \[\<[0-9a-fA-F]*\>\] .*', dmesg[i])
+                               if m:
+                                       error += dmesg[i]
+                               else:
+                                       if tm < self.tSuspended:
+                                               dir = 'suspend'
+                                       else:
+                                               dir = 'resume'
+                                       error = error.replace('<', '&lt').replace('>', '&gt')
+                                       vprint('kernel error found in %s at %f' % (dir, tm))
+                                       self.errorinfo[dir].append((tm, error))
+                                       self.kerror = True
+                                       error = ''
        def setStart(self, time):
                self.start = time
-               self.dmesg[self.phases[0]]['start'] = time
-       def getEnd(self):
-               return self.dmesg[self.phases[-1]]['end']
        def setEnd(self, time):
                self.end = time
-               self.dmesg[self.phases[-1]]['end'] = time
        def isTraceEventOutsideDeviceCalls(self, pid, time):
                for phase in self.phases:
                        list = self.dmesg[phase]['list']
@@ -733,39 +802,67 @@ class Data:
                                        time < d['end']):
                                        return False
                return True
-       def targetDevice(self, phaselist, start, end, pid=-1):
+       def sourcePhase(self, start):
+               for phase in self.phases:
+                       pend = self.dmesg[phase]['end']
+                       if start <= pend:
+                               return phase
+               return 'resume_complete'
+       def sourceDevice(self, phaselist, start, end, pid, type):
                tgtdev = ''
                for phase in phaselist:
                        list = self.dmesg[phase]['list']
                        for devname in list:
                                dev = list[devname]
-                               if(pid >= 0 and dev['pid'] != pid):
+                               # pid must match
+                               if dev['pid'] != pid:
                                        continue
                                devS = dev['start']
                                devE = dev['end']
-                               if(start < devS or start >= devE or end <= devS or end > devE):
-                                       continue
+                               if type == 'device':
+                                       # device target event is entirely inside the source boundary
+                                       if(start < devS or start >= devE or end <= devS or end > devE):
+                                               continue
+                               elif type == 'thread':
+                                       # thread target event will expand the source boundary
+                                       if start < devS:
+                                               dev['start'] = start
+                                       if end > devE:
+                                               dev['end'] = end
                                tgtdev = dev
                                break
                return tgtdev
        def addDeviceFunctionCall(self, displayname, kprobename, proc, pid, start, end, cdata, rdata):
-               machstart = self.dmesg['suspend_machine']['start']
-               machend = self.dmesg['resume_machine']['end']
-               tgtdev = self.targetDevice(self.phases, start, end, pid)
-               if not tgtdev and start >= machstart and end < machend:
-                       # device calls in machine phases should be serial
-                       tgtdev = self.targetDevice(['suspend_machine', 'resume_machine'], start, end)
+               # try to place the call in a device
+               tgtdev = self.sourceDevice(self.phases, start, end, pid, 'device')
+               # calls with device pids that occur outside device bounds are dropped
+               # TODO: include these somehow
+               if not tgtdev and pid in self.devpids:
+                       return False
+               # try to place the call in a thread
                if not tgtdev:
-                       if 'scsi_eh' in proc:
-                               self.newActionGlobal(proc, start, end, pid)
-                               self.addDeviceFunctionCall(displayname, kprobename, proc, pid, start, end, cdata, rdata)
+                       tgtdev = self.sourceDevice(self.phases, start, end, pid, 'thread')
+               # create new thread blocks, expand as new calls are found
+               if not tgtdev:
+                       if proc == '<...>':
+                               threadname = 'kthread-%d' % (pid)
                        else:
-                               vprint('IGNORE: %s[%s](%d) [%f - %f] | %s | %s | %s' % (displayname, kprobename,
-                                       pid, start, end, cdata, rdata, proc))
+                               threadname = '%s-%d' % (proc, pid)
+                       tgtphase = self.sourcePhase(start)
+                       self.newAction(tgtphase, threadname, pid, '', start, end, '', ' kth', '')
+                       return self.addDeviceFunctionCall(displayname, kprobename, proc, pid, start, end, cdata, rdata)
+               # this should not happen
+               if not tgtdev:
+                       vprint('[%f - %f] %s-%d %s %s %s' % \
+                               (start, end, proc, pid, kprobename, cdata, rdata))
                        return False
-               # detail block fits within tgtdev
+               # place the call data inside the src element of the tgtdev
                if('src' not in tgtdev):
                        tgtdev['src'] = []
+               dtf = sysvals.dev_tracefuncs
+               ubiquitous = False
+               if kprobename in dtf and 'ub' in dtf[kprobename]:
+                       ubiquitous = True
                title = cdata+' '+rdata
                mstr = '\(.*\) *(?P<args>.*) *\((?P<caller>.*)\+.* arg1=(?P<ret>.*)'
                m = re.match(mstr, title)
@@ -777,14 +874,81 @@ class Data:
                                r = ''
                        else:
                                r = 'ret=%s ' % r
-                       l = '%0.3fms' % ((end - start) * 1000)
-                       if kprobename in self.dev_ubiquitous:
-                               title = '%s(%s) <- %s, %s(%s)' % (displayname, a, c, r, l)
-                       else:
-                               title = '%s(%s) %s(%s)' % (displayname, a, r, l)
-               e = TraceEvent(title, kprobename, start, end - start)
+                       if ubiquitous and c in dtf and 'ub' in dtf[c]:
+                               return False
+               color = sysvals.kprobeColor(kprobename)
+               e = DevFunction(displayname, a, c, r, start, end, ubiquitous, proc, pid, color)
                tgtdev['src'].append(e)
                return True
+       def overflowDevices(self):
+               # get a list of devices that extend beyond the end of this test run
+               devlist = []
+               for phase in self.phases:
+                       list = self.dmesg[phase]['list']
+                       for devname in list:
+                               dev = list[devname]
+                               if dev['end'] > self.end:
+                                       devlist.append(dev)
+               return devlist
+       def mergeOverlapDevices(self, devlist):
+               # merge any devices that overlap devlist
+               for dev in devlist:
+                       devname = dev['name']
+                       for phase in self.phases:
+                               list = self.dmesg[phase]['list']
+                               if devname not in list:
+                                       continue
+                               tdev = list[devname]
+                               o = min(dev['end'], tdev['end']) - max(dev['start'], tdev['start'])
+                               if o <= 0:
+                                       continue
+                               dev['end'] = tdev['end']
+                               if 'src' not in dev or 'src' not in tdev:
+                                       continue
+                               dev['src'] += tdev['src']
+                               del list[devname]
+       def usurpTouchingThread(self, name, dev):
+               # the caller test has priority of this thread, give it to him
+               for phase in self.phases:
+                       list = self.dmesg[phase]['list']
+                       if name in list:
+                               tdev = list[name]
+                               if tdev['start'] - dev['end'] < 0.1:
+                                       dev['end'] = tdev['end']
+                                       if 'src' not in dev:
+                                               dev['src'] = []
+                                       if 'src' in tdev:
+                                               dev['src'] += tdev['src']
+                                       del list[name]
+                               break
+       def stitchTouchingThreads(self, testlist):
+               # merge any threads between tests that touch
+               for phase in self.phases:
+                       list = self.dmesg[phase]['list']
+                       for devname in list:
+                               dev = list[devname]
+                               if 'htmlclass' not in dev or 'kth' not in dev['htmlclass']:
+                                       continue
+                               for data in testlist:
+                                       data.usurpTouchingThread(devname, dev)
+       def optimizeDevSrc(self):
+               # merge any src call loops to reduce timeline size
+               for phase in self.phases:
+                       list = self.dmesg[phase]['list']
+                       for dev in list:
+                               if 'src' not in list[dev]:
+                                       continue
+                               src = list[dev]['src']
+                               p = 0
+                               for e in sorted(src, key=lambda event: event.time):
+                                       if not p or not e.repeat(p):
+                                               p = e
+                                               continue
+                                       # e is another iteration of p, move it into p
+                                       p.end = e.end
+                                       p.length = p.end - p.time
+                                       p.count += 1
+                                       src.remove(e)
        def trimTimeVal(self, t, t0, dT, left):
                if left:
                        if(t > t0):
@@ -804,6 +968,8 @@ class Data:
                self.tSuspended = self.trimTimeVal(self.tSuspended, t0, dT, left)
                self.tResumed = self.trimTimeVal(self.tResumed, t0, dT, left)
                self.start = self.trimTimeVal(self.start, t0, dT, left)
+               self.tKernSus = self.trimTimeVal(self.tKernSus, t0, dT, left)
+               self.tKernRes = self.trimTimeVal(self.tKernRes, t0, dT, left)
                self.end = self.trimTimeVal(self.end, t0, dT, left)
                for phase in self.phases:
                        p = self.dmesg[phase]
@@ -832,36 +998,6 @@ class Data:
                        else:
                                self.trimTime(self.tSuspended, \
                                        self.tResumed-self.tSuspended, False)
-       def newPhaseWithSingleAction(self, phasename, devname, start, end, color):
-               for phase in self.phases:
-                       self.dmesg[phase]['order'] += 1
-               self.html_device_id += 1
-               devid = '%s%d' % (self.idstr, self.html_device_id)
-               list = dict()
-               list[devname] = \
-                       {'start': start, 'end': end, 'pid': 0, 'par': '',
-                       'length': (end-start), 'row': 0, 'id': devid, 'drv': '' };
-               self.dmesg[phasename] = \
-                       {'list': list, 'start': start, 'end': end,
-                       'row': 0, 'color': color, 'order': 0}
-               self.phases = self.sortedPhases()
-       def newPhase(self, phasename, start, end, color, order):
-               if(order < 0):
-                       order = len(self.phases)
-               for phase in self.phases[order:]:
-                       self.dmesg[phase]['order'] += 1
-               if(order > 0):
-                       p = self.phases[order-1]
-                       self.dmesg[p]['end'] = start
-               if(order < len(self.phases)):
-                       p = self.phases[order]
-                       self.dmesg[p]['start'] = end
-               list = dict()
-               self.dmesg[phasename] = \
-                       {'list': list, 'start': start, 'end': end,
-                       'row': 0, 'color': color, 'order': order}
-               self.phases = self.sortedPhases()
-               self.devicegroups.append([phasename])
        def setPhase(self, phase, ktime, isbegin):
                if(isbegin):
                        self.dmesg[phase]['start'] = ktime
@@ -881,7 +1017,7 @@ class Data:
                for t in sorted(tmp):
                        slist.append(tmp[t])
                return slist
-       def fixupInitcalls(self, phase, end):
+       def fixupInitcalls(self, phase):
                # if any calls never returned, clip them at system resume end
                phaselist = self.dmesg[phase]['list']
                for devname in phaselist:
@@ -893,37 +1029,23 @@ class Data:
                                                break
                                vprint('%s (%s): callback didnt return' % (devname, phase))
        def deviceFilter(self, devicefilter):
-               # remove all by the relatives of the filter devnames
-               filter = []
-               for phase in self.phases:
-                       list = self.dmesg[phase]['list']
-                       for name in devicefilter:
-                               dev = name
-                               while(dev in list):
-                                       if(dev not in filter):
-                                               filter.append(dev)
-                                       dev = list[dev]['par']
-                               children = self.deviceDescendants(name, phase)
-                               for dev in children:
-                                       if(dev not in filter):
-                                               filter.append(dev)
                for phase in self.phases:
                        list = self.dmesg[phase]['list']
                        rmlist = []
                        for name in list:
-                               pid = list[name]['pid']
-                               if(name not in filter and pid >= 0):
+                               keep = False
+                               for filter in devicefilter:
+                                       if filter in name or \
+                                               ('drv' in list[name] and filter in list[name]['drv']):
+                                               keep = True
+                               if not keep:
                                        rmlist.append(name)
                        for name in rmlist:
                                del list[name]
        def fixupInitcallsThatDidntReturn(self):
                # if any calls never returned, clip them at system resume end
                for phase in self.phases:
-                       self.fixupInitcalls(phase, self.getEnd())
-       def isInsideTimeline(self, start, end):
-               if(self.start <= start and self.end > start):
-                       return True
-               return False
+                       self.fixupInitcalls(phase)
        def phaseOverlap(self, phases):
                rmgroups = []
                newgroup = []
@@ -940,30 +1062,35 @@ class Data:
                        self.devicegroups.remove(group)
                self.devicegroups.append(newgroup)
        def newActionGlobal(self, name, start, end, pid=-1, color=''):
-               # if event starts before timeline start, expand timeline
-               if(start < self.start):
-                       self.setStart(start)
-               # if event ends after timeline end, expand the timeline
-               if(end > self.end):
-                       self.setEnd(end)
-               # which phase is this device callback or action "in"
-               targetphase = "none"
+               # which phase is this device callback or action in
+               targetphase = 'none'
                htmlclass = ''
                overlap = 0.0
                phases = []
                for phase in self.phases:
                        pstart = self.dmesg[phase]['start']
                        pend = self.dmesg[phase]['end']
+                       # see if the action overlaps this phase
                        o = max(0, min(end, pend) - max(start, pstart))
                        if o > 0:
                                phases.append(phase)
+                       # set the target phase to the one that overlaps most
                        if o > overlap:
                                if overlap > 0 and phase == 'post_resume':
                                        continue
                                targetphase = phase
                                overlap = o
+               # if no target phase was found, pin it to the edge
+               if targetphase == 'none':
+                       p0start = self.dmesg[self.phases[0]]['start']
+                       if start <= p0start:
+                               targetphase = self.phases[0]
+                       else:
+                               targetphase = self.phases[-1]
                if pid == -2:
                        htmlclass = ' bg'
+               elif pid == -3:
+                       htmlclass = ' ps'
                if len(phases) > 1:
                        htmlclass = ' bg'
                        self.phaseOverlap(phases)
@@ -985,29 +1112,13 @@ class Data:
                        while(name in list):
                                name = '%s[%d]' % (origname, i)
                                i += 1
-               list[name] = {'start': start, 'end': end, 'pid': pid, 'par': parent,
-                                         'length': length, 'row': 0, 'id': devid, 'drv': drv }
+               list[name] = {'name': name, 'start': start, 'end': end, 'pid': pid,
+                       'par': parent, 'length': length, 'row': 0, 'id': devid, 'drv': drv }
                if htmlclass:
                        list[name]['htmlclass'] = htmlclass
                if color:
                        list[name]['color'] = color
                return name
-       def deviceIDs(self, devlist, phase):
-               idlist = []
-               list = self.dmesg[phase]['list']
-               for devname in list:
-                       if devname in devlist:
-                               idlist.append(list[devname]['id'])
-               return idlist
-       def deviceParentID(self, devname, phase):
-               pdev = ''
-               pdevid = ''
-               list = self.dmesg[phase]['list']
-               if devname in list:
-                       pdev = list[devname]['par']
-               if pdev in list:
-                       return list[pdev]['id']
-               return pdev
        def deviceChildren(self, devname, phase):
                devlist = []
                list = self.dmesg[phase]['list']
@@ -1015,21 +1126,15 @@ class Data:
                        if(list[child]['par'] == devname):
                                devlist.append(child)
                return devlist
-       def deviceDescendants(self, devname, phase):
-               children = self.deviceChildren(devname, phase)
-               family = children
-               for child in children:
-                       family += self.deviceDescendants(child, phase)
-               return family
-       def deviceChildrenIDs(self, devname, phase):
-               devlist = self.deviceChildren(devname, phase)
-               return self.deviceIDs(devlist, phase)
        def printDetails(self):
+               vprint('Timeline Details:')
                vprint('          test start: %f' % self.start)
+               vprint('kernel suspend start: %f' % self.tKernSus)
                for phase in self.phases:
                        dc = len(self.dmesg[phase]['list'])
                        vprint('    %16s: %f - %f (%d devices)' % (phase, \
                                self.dmesg[phase]['start'], self.dmesg[phase]['end'], dc))
+               vprint('   kernel resume end: %f' % self.tKernRes)
                vprint('            test end: %f' % self.end)
        def deviceChildrenAllPhases(self, devname):
                devlist = []
@@ -1108,21 +1213,134 @@ class Data:
                                if width != '0.000000' and length >= mindevlen:
                                        devlist.append(dev)
                        self.tdevlist[phase] = devlist
-
-# Class: TraceEvent
+       def addHorizontalDivider(self, devname, devend):
+               phase = 'suspend_prepare'
+               self.newAction(phase, devname, -2, '', \
+                       self.start, devend, '', ' sec', '')
+               if phase not in self.tdevlist:
+                       self.tdevlist[phase] = []
+               self.tdevlist[phase].append(devname)
+               d = DevItem(0, phase, self.dmesg[phase]['list'][devname])
+               return d
+       def addProcessUsageEvent(self, name, times):
+               # get the start and end times for this process
+               maxC = 0
+               tlast = 0
+               start = -1
+               end = -1
+               for t in sorted(times):
+                       if tlast == 0:
+                               tlast = t
+                               continue
+                       if name in self.pstl[t]:
+                               if start == -1 or tlast < start:
+                                       start = tlast
+                               if end == -1 or t > end:
+                                       end = t
+                       tlast = t
+               if start == -1 or end == -1:
+                       return 0
+               # add a new action for this process and get the object
+               out = self.newActionGlobal(name, start, end, -3)
+               if not out:
+                       return 0
+               phase, devname = out
+               dev = self.dmesg[phase]['list'][devname]
+               # get the cpu exec data
+               tlast = 0
+               clast = 0
+               cpuexec = dict()
+               for t in sorted(times):
+                       if tlast == 0 or t <= start or t > end:
+                               tlast = t
+                               continue
+                       list = self.pstl[t]
+                       c = 0
+                       if name in list:
+                               c = list[name]
+                       if c > maxC:
+                               maxC = c
+                       if c != clast:
+                               key = (tlast, t)
+                               cpuexec[key] = c
+                               tlast = t
+                               clast = c
+               dev['cpuexec'] = cpuexec
+               return maxC
+       def createProcessUsageEvents(self):
+               # get an array of process names
+               proclist = []
+               for t in self.pstl:
+                       pslist = self.pstl[t]
+                       for ps in pslist:
+                               if ps not in proclist:
+                                       proclist.append(ps)
+               # get a list of data points for suspend and resume
+               tsus = []
+               tres = []
+               for t in sorted(self.pstl):
+                       if t < self.tSuspended:
+                               tsus.append(t)
+                       else:
+                               tres.append(t)
+               # process the events for suspend and resume
+               if len(proclist) > 0:
+                       vprint('Process Execution:')
+               for ps in proclist:
+                       c = self.addProcessUsageEvent(ps, tsus)
+                       if c > 0:
+                               vprint('%25s (sus): %d' % (ps, c))
+                       c = self.addProcessUsageEvent(ps, tres)
+                       if c > 0:
+                               vprint('%25s (res): %d' % (ps, c))
+
+# Class: DevFunction
 # Description:
-#       A container for trace event data found in the ftrace file
-class TraceEvent:
-       text = ''
-       time = 0.0
-       length = 0.0
-       title = ''
+#       A container for kprobe function data we want in the dev timeline
+class DevFunction:
        row = 0
-       def __init__(self, a, n, t, l):
-               self.title = a
-               self.text = n
-               self.time = t
-               self.length = l
+       count = 1
+       def __init__(self, name, args, caller, ret, start, end, u, proc, pid, color):
+               self.name = name
+               self.args = args
+               self.caller = caller
+               self.ret = ret
+               self.time = start
+               self.length = end - start
+               self.end = end
+               self.ubiquitous = u
+               self.proc = proc
+               self.pid = pid
+               self.color = color
+       def title(self):
+               cnt = ''
+               if self.count > 1:
+                       cnt = '(x%d)' % self.count
+               l = '%0.3fms' % (self.length * 1000)
+               if self.ubiquitous:
+                       title = '%s(%s)%s <- %s, %s(%s)' % \
+                               (self.name, self.args, cnt, self.caller, self.ret, l)
+               else:
+                       title = '%s(%s) %s%s(%s)' % (self.name, self.args, self.ret, cnt, l)
+               return title.replace('"', '')
+       def text(self):
+               if self.count > 1:
+                       text = '%s(x%d)' % (self.name, self.count)
+               else:
+                       text = self.name
+               return text
+       def repeat(self, tgt):
+               # is the tgt call just a repeat of this call (e.g. are we in a loop)
+               dt = self.time - tgt.end
+               # only combine calls if -all- attributes are identical
+               if tgt.caller == self.caller and \
+                       tgt.name == self.name and tgt.args == self.args and \
+                       tgt.proc == self.proc and tgt.pid == self.pid and \
+                       tgt.ret == self.ret and dt >= 0 and \
+                       dt <= sysvals.callloopmaxgap and \
+                       self.length < sysvals.callloopmaxlen:
+                       return True
+               return False
 
 # Class: FTraceLine
 # Description:
@@ -1226,7 +1444,6 @@ class FTraceLine:
                        print('%s -- %f (%02d): %s() { (%.3f us)' % (dev, self.time, \
                                self.depth, self.name, self.length*1000000))
        def startMarker(self):
-               global sysvals
                # Is this the starting line of a suspend?
                if not self.fevent:
                        return False
@@ -1506,6 +1723,16 @@ class FTraceCallGraph:
                                        l.depth, l.name, l.length*1000000))
                print(' ')
 
+class DevItem:
+       def __init__(self, test, phase, dev):
+               self.test = test
+               self.phase = phase
+               self.dev = dev
+       def isa(self, cls):
+               if 'htmlclass' in self.dev and cls in self.dev['htmlclass']:
+                       return True
+               return False
+
 # Class: Timeline
 # Description:
 #       A container for a device timeline which calculates
@@ -1517,12 +1744,11 @@ class Timeline:
        rowH = 30       # device row height
        bodyH = 0       # body height
        rows = 0        # total timeline rows
-       phases = []
-       rowmaxlines = dict()
-       rowcount = dict()
+       rowlines = dict()
        rowheight = dict()
-       def __init__(self, rowheight):
+       def __init__(self, rowheight, scaleheight):
                self.rowH = rowheight
+               self.scaleH = scaleheight
                self.html = {
                        'header': '',
                        'timeline': '',
@@ -1537,21 +1763,19 @@ class Timeline:
        #        The total number of rows needed to display this phase of the timeline
        def getDeviceRows(self, rawlist):
                # clear all rows and set them to undefined
-               lendict = dict()
+               sortdict = dict()
                for item in rawlist:
                        item.row = -1
-                       lendict[item] = item.length
-               list = []
-               for i in sorted(lendict, key=lendict.get, reverse=True):
-                       list.append(i)
-               remaining = len(list)
+                       sortdict[item] = item.length
+               sortlist = sorted(sortdict, key=sortdict.get, reverse=True)
+               remaining = len(sortlist)
                rowdata = dict()
                row = 1
                # try to pack each row with as many ranges as possible
                while(remaining > 0):
                        if(row not in rowdata):
                                rowdata[row] = []
-                       for i in list:
+                       for i in sortlist:
                                if(i.row >= 0):
                                        continue
                                s = i.time
@@ -1575,81 +1799,86 @@ class Timeline:
        #        Organize the timeline entries into the smallest
        #        number of rows possible, with no entry overlapping
        # Arguments:
-       #        list: the list of devices/actions for a single phase
-       #        devlist: string list of device names to use
+       #        devlist: the list of devices/actions in a group of contiguous phases
        # Output:
        #        The total number of rows needed to display this phase of the timeline
-       def getPhaseRows(self, dmesg, devlist):
+       def getPhaseRows(self, devlist, row=0):
                # clear all rows and set them to undefined
                remaining = len(devlist)
                rowdata = dict()
-               row = 0
-               lendict = dict()
+               sortdict = dict()
                myphases = []
+               # initialize all device rows to -1 and calculate devrows
                for item in devlist:
-                       if item[0] not in self.phases:
-                               self.phases.append(item[0])
-                       if item[0] not in myphases:
-                               myphases.append(item[0])
-                               self.rowmaxlines[item[0]] = dict()
-                               self.rowheight[item[0]] = dict()
-                       dev = dmesg[item[0]]['list'][item[1]]
+                       dev = item.dev
+                       tp = (item.test, item.phase)
+                       if tp not in myphases:
+                               myphases.append(tp)
                        dev['row'] = -1
-                       lendict[item] = float(dev['end']) - float(dev['start'])
+                       # sort by length 1st, then name 2nd
+                       sortdict[item] = (float(dev['end']) - float(dev['start']), item.dev['name'])
                        if 'src' in dev:
                                dev['devrows'] = self.getDeviceRows(dev['src'])
-               lenlist = []
-               for i in sorted(lendict, key=lendict.get, reverse=True):
-                       lenlist.append(i)
+               # sort the devlist by length so that large items graph on top
+               sortlist = sorted(sortdict, key=sortdict.get, reverse=True)
                orderedlist = []
-               for item in lenlist:
-                       dev = dmesg[item[0]]['list'][item[1]]
-                       if dev['pid'] == -2:
+               for item in sortlist:
+                       if item.dev['pid'] == -2:
                                orderedlist.append(item)
-               for item in lenlist:
+               for item in sortlist:
                        if item not in orderedlist:
                                orderedlist.append(item)
-               # try to pack each row with as many ranges as possible
+               # try to pack each row with as many devices as possible
                while(remaining > 0):
                        rowheight = 1
                        if(row not in rowdata):
                                rowdata[row] = []
                        for item in orderedlist:
-                               dev = dmesg[item[0]]['list'][item[1]]
+                               dev = item.dev
                                if(dev['row'] < 0):
                                        s = dev['start']
                                        e = dev['end']
                                        valid = True
                                        for ritem in rowdata[row]:
-                                               rs = ritem['start']
-                                               re = ritem['end']
+                                               rs = ritem.dev['start']
+                                               re = ritem.dev['end']
                                                if(not (((s <= rs) and (e <= rs)) or
                                                        ((s >= re) and (e >= re)))):
                                                        valid = False
                                                        break
                                        if(valid):
-                                               rowdata[row].append(dev)
+                                               rowdata[row].append(item)
                                                dev['row'] = row
                                                remaining -= 1
                                                if 'devrows' in dev and dev['devrows'] > rowheight:
                                                        rowheight = dev['devrows']
-                       for phase in myphases:
-                               self.rowmaxlines[phase][row] = rowheight
-                               self.rowheight[phase][row] = rowheight * self.rowH
+                       for t, p in myphases:
+                               if t not in self.rowlines or t not in self.rowheight:
+                                       self.rowlines[t] = dict()
+                                       self.rowheight[t] = dict()
+                               if p not in self.rowlines[t] or p not in self.rowheight[t]:
+                                       self.rowlines[t][p] = dict()
+                                       self.rowheight[t][p] = dict()
+                               rh = self.rowH
+                               # section headers should use a different row height
+                               if len(rowdata[row]) == 1 and \
+                                       'htmlclass' in rowdata[row][0].dev and \
+                                       'sec' in rowdata[row][0].dev['htmlclass']:
+                                       rh = 15
+                               self.rowlines[t][p][row] = rowheight
+                               self.rowheight[t][p][row] = rowheight * rh
                        row += 1
                if(row > self.rows):
                        self.rows = int(row)
-               for phase in myphases:
-                       self.rowcount[phase] = row
                return row
-       def phaseRowHeight(self, phase, row):
-               return self.rowheight[phase][row]
-       def phaseRowTop(self, phase, row):
+       def phaseRowHeight(self, test, phase, row):
+               return self.rowheight[test][phase][row]
+       def phaseRowTop(self, test, phase, row):
                top = 0
-               for i in sorted(self.rowheight[phase]):
+               for i in sorted(self.rowheight[test][phase]):
                        if i >= row:
                                break
-                       top += self.rowheight[phase][i]
+                       top += self.rowheight[test][phase][i]
                return top
        # Function: calcTotalRows
        # Description:
@@ -1657,19 +1886,21 @@ class Timeline:
        def calcTotalRows(self):
                maxrows = 0
                standardphases = []
-               for phase in self.phases:
-                       total = 0
-                       for i in sorted(self.rowmaxlines[phase]):
-                               total += self.rowmaxlines[phase][i]
-                       if total > maxrows:
-                               maxrows = total
-                       if total == self.rowcount[phase]:
-                               standardphases.append(phase)
+               for t in self.rowlines:
+                       for p in self.rowlines[t]:
+                               total = 0
+                               for i in sorted(self.rowlines[t][p]):
+                                       total += self.rowlines[t][p][i]
+                               if total > maxrows:
+                                       maxrows = total
+                               if total == len(self.rowlines[t][p]):
+                                       standardphases.append((t, p))
                self.height = self.scaleH + (maxrows*self.rowH)
                self.bodyH = self.height - self.scaleH
-               for phase in standardphases:
-                       for i in sorted(self.rowheight[phase]):
-                               self.rowheight[phase][i] = self.bodyH/self.rowcount[phase]
+               # if there is 1 line per row, draw them the standard way
+               for t, p in standardphases:
+                       for i in sorted(self.rowheight[t][p]):
+                               self.rowheight[t][p][i] = self.bodyH/len(self.rowlines[t][p])
        # Function: createTimeScale
        # Description:
        #        Create the timescale for a timeline block
@@ -1716,7 +1947,6 @@ class Timeline:
 #       A list of values describing the properties of these test runs
 class TestProps:
        stamp = ''
-       tracertype = ''
        S0i3 = False
        fwdata = []
        ftrace_line_fmt_fg = \
@@ -1734,14 +1964,13 @@ class TestProps:
        def __init__(self):
                self.ktemp = dict()
        def setTracerType(self, tracer):
-               self.tracertype = tracer
                if(tracer == 'function_graph'):
                        self.cgformat = True
                        self.ftrace_line_fmt = self.ftrace_line_fmt_fg
                elif(tracer == 'nop'):
                        self.ftrace_line_fmt = self.ftrace_line_fmt_nop
                else:
-                       doError('Invalid tracer format: [%s]' % tracer, False)
+                       doError('Invalid tracer format: [%s]' % tracer)
 
 # Class: TestRun
 # Description:
@@ -1756,6 +1985,51 @@ class TestRun:
                self.ftemp = dict()
                self.ttemp = dict()
 
+class ProcessMonitor:
+       proclist = dict()
+       running = False
+       def procstat(self):
+               c = ['cat /proc/[1-9]*/stat 2>/dev/null']
+               process = Popen(c, shell=True, stdout=PIPE)
+               running = dict()
+               for line in process.stdout:
+                       data = line.split()
+                       pid = data[0]
+                       name = re.sub('[()]', '', data[1])
+                       user = int(data[13])
+                       kern = int(data[14])
+                       kjiff = ujiff = 0
+                       if pid not in self.proclist:
+                               self.proclist[pid] = {'name' : name, 'user' : user, 'kern' : kern}
+                       else:
+                               val = self.proclist[pid]
+                               ujiff = user - val['user']
+                               kjiff = kern - val['kern']
+                               val['user'] = user
+                               val['kern'] = kern
+                       if ujiff > 0 or kjiff > 0:
+                               running[pid] = ujiff + kjiff
+               result = process.wait()
+               out = ''
+               for pid in running:
+                       jiffies = running[pid]
+                       val = self.proclist[pid]
+                       if out:
+                               out += ','
+                       out += '%s-%s %d' % (val['name'], pid, jiffies)
+               return 'ps - '+out
+       def processMonitor(self, tid):
+               while self.running:
+                       out = self.procstat()
+                       if out:
+                               sysvals.fsetVal(out, 'trace_marker')
+       def start(self):
+               self.thread = Thread(target=self.processMonitor, args=(0,))
+               self.running = True
+               self.thread.start()
+       def stop(self):
+               self.running = False
+
 # ----------------- FUNCTIONS --------------------
 
 # Function: vprint
@@ -1764,7 +2038,7 @@ class TestRun:
 # Arguments:
 #       msg: the debug/log message to print
 def vprint(msg):
-       global sysvals
+       sysvals.logmsg += msg+'\n'
        if(sysvals.verbose):
                print(msg)
 
@@ -1775,8 +2049,6 @@ def vprint(msg):
 # Arguments:
 #       m: the valid re.match output for the stamp line
 def parseStamp(line, data):
-       global sysvals
-
        m = re.match(sysvals.stampfmt, line)
        data.stamp = {'time': '', 'host': '', 'mode': ''}
        dt = datetime(int(m.group('y'))+2000, int(m.group('m')),
@@ -1788,6 +2060,14 @@ def parseStamp(line, data):
        data.stamp['kernel'] = m.group('kernel')
        sysvals.hostname = data.stamp['host']
        sysvals.suspendmode = data.stamp['mode']
+       if sysvals.suspendmode == 'command' and sysvals.ftracefile != '':
+               modes = ['on', 'freeze', 'standby', 'mem']
+               out = Popen(['grep', 'suspend_enter', sysvals.ftracefile],
+                       stderr=PIPE, stdout=PIPE).stdout.read()
+               m = re.match('.* suspend_enter\[(?P<mode>.*)\]', out)
+               if m and m.group('mode') in ['1', '2', '3']:
+                       sysvals.suspendmode = modes[int(m.group('mode'))]
+                       data.stamp['mode'] = sysvals.suspendmode
        if not sysvals.stamp:
                sysvals.stamp = data.stamp
 
@@ -1817,18 +2097,17 @@ def diffStamp(stamp1, stamp2):
 #       required for primary parsing. Set the usetraceevents and/or
 #       usetraceeventsonly flags in the global sysvals object
 def doesTraceLogHaveTraceEvents():
-       global sysvals
-
        # check for kprobes
        sysvals.usekprobes = False
-       out = os.system('grep -q "_cal: (" '+sysvals.ftracefile)
+       out = call('grep -q "_cal: (" '+sysvals.ftracefile, shell=True)
        if(out == 0):
                sysvals.usekprobes = True
        # check for callgraph data on trace event blocks
-       out = os.system('grep -q "_cpu_down()" '+sysvals.ftracefile)
+       out = call('grep -q "_cpu_down()" '+sysvals.ftracefile, shell=True)
        if(out == 0):
                sysvals.usekprobes = True
-       out = os.popen('head -1 '+sysvals.ftracefile).read().replace('\n', '')
+       out = Popen(['head', '-1', sysvals.ftracefile],
+               stderr=PIPE, stdout=PIPE).stdout.read().replace('\n', '')
        m = re.match(sysvals.stampfmt, out)
        if m and m.group('mode') == 'command':
                sysvals.usetraceeventsonly = True
@@ -1838,14 +2117,14 @@ def doesTraceLogHaveTraceEvents():
        sysvals.usetraceeventsonly = True
        sysvals.usetraceevents = False
        for e in sysvals.traceevents:
-               out = os.system('grep -q "'+e+': " '+sysvals.ftracefile)
+               out = call('grep -q "'+e+': " '+sysvals.ftracefile, shell=True)
                if(out != 0):
                        sysvals.usetraceeventsonly = False
                if(e == 'suspend_resume' and out == 0):
                        sysvals.usetraceevents = True
        # determine is this log is properly formatted
        for e in ['SUSPEND START', 'RESUME COMPLETE']:
-               out = os.system('grep -q "'+e+'" '+sysvals.ftracefile)
+               out = call('grep -q "'+e+'" '+sysvals.ftracefile, shell=True)
                if(out != 0):
                        sysvals.usetracemarkers = False
 
@@ -1860,8 +2139,6 @@ def doesTraceLogHaveTraceEvents():
 # Arguments:
 #       testruns: the array of Data objects obtained from parseKernelLog
 def appendIncompleteTraceLog(testruns):
-       global sysvals
-
        # create TestRun vessels for ftrace parsing
        testcnt = len(testruns)
        testidx = 0
@@ -2052,8 +2329,7 @@ def appendIncompleteTraceLog(testruns):
                                                                dev['ftrace'] = cg
                                                break
 
-               if(sysvals.verbose):
-                       test.data.printDetails()
+               test.data.printDetails()
 
 # Function: parseTraceLog
 # Description:
@@ -2064,14 +2340,12 @@ def appendIncompleteTraceLog(testruns):
 # Output:
 #       An array of Data objects
 def parseTraceLog():
-       global sysvals
-
        vprint('Analyzing the ftrace data...')
        if(os.path.exists(sysvals.ftracefile) == False):
-               doError('%s does not exist' % sysvals.ftracefile, False)
+               doError('%s does not exist' % sysvals.ftracefile)
 
        sysvals.setupAllKprobes()
-       tracewatch = ['suspend_enter']
+       tracewatch = []
        if sysvals.usekprobes:
                tracewatch += ['sync_filesystems', 'freeze_processes', 'syscore_suspend',
                        'syscore_resume', 'resume_console', 'thaw_processes', 'CPU_ON', 'CPU_OFF']
@@ -2102,17 +2376,13 @@ def parseTraceLog():
                if(m):
                        tp.setTracerType(m.group('t'))
                        continue
-               # post resume time line: did this test run include post-resume data
-               m = re.match(sysvals.postresumefmt, line)
-               if(m):
-                       t = int(m.group('t'))
-                       if(t > 0):
-                               sysvals.postresumetime = t
-                       continue
                # device properties line
                if(re.match(sysvals.devpropfmt, line)):
                        devProps(line)
                        continue
+               # ignore all other commented lines
+               if line[0] == '#':
+                       continue
                # ftrace line: parse only valid lines
                m = re.match(tp.ftrace_line_fmt, line)
                if(not m):
@@ -2142,20 +2412,36 @@ def parseTraceLog():
                        testrun = TestRun(data)
                        testruns.append(testrun)
                        parseStamp(tp.stamp, data)
-                       if len(tp.fwdata) > data.testnumber:
-                               data.fwSuspend, data.fwResume = tp.fwdata[data.testnumber]
-                               if(data.fwSuspend > 0 or data.fwResume > 0):
-                                       data.fwValid = True
                        data.setStart(t.time)
+                       data.tKernSus = t.time
                        continue
                if(not data):
                        continue
+               # process cpu exec line
+               if t.type == 'tracing_mark_write':
+                       m = re.match(sysvals.procexecfmt, t.name)
+                       if(m):
+                               proclist = dict()
+                               for ps in m.group('ps').split(','):
+                                       val = ps.split()
+                                       if not val:
+                                               continue
+                                       name = val[0].replace('--', '-')
+                                       proclist[name] = int(val[1])
+                               data.pstl[t.time] = proclist
+                               continue
                # find the end of resume
                if(t.endMarker()):
-                       if(sysvals.usetracemarkers and sysvals.postresumetime > 0):
-                               phase = 'post_resume'
-                               data.newPhase(phase, t.time, t.time, '#F0F0F0', -1)
                        data.setEnd(t.time)
+                       if data.tKernRes == 0.0:
+                               data.tKernRes = t.time
+                       if data.dmesg['resume_complete']['end'] < 0:
+                               data.dmesg['resume_complete']['end'] = t.time
+                       if sysvals.suspendmode == 'mem' and len(tp.fwdata) > data.testnumber:
+                               data.fwSuspend, data.fwResume = tp.fwdata[data.testnumber]
+                               if(data.tSuspended != 0 and data.tResumed != 0 and \
+                                       (data.fwSuspend > 0 or data.fwResume > 0)):
+                                       data.fwValid = True
                        if(not sysvals.usetracemarkers):
                                # no trace markers? then quit and be sure to finish recording
                                # the event we used to trigger resume end
@@ -2190,8 +2476,14 @@ def parseTraceLog():
                                if(name.split('[')[0] in tracewatch):
                                        continue
                                # -- phase changes --
+                               # start of kernel suspend
+                               if(re.match('suspend_enter\[.*', t.name)):
+                                       if(isbegin):
+                                               data.dmesg[phase]['start'] = t.time
+                                               data.tKernSus = t.time
+                                       continue
                                # suspend_prepare start
-                               if(re.match('dpm_prepare\[.*', t.name)):
+                               elif(re.match('dpm_prepare\[.*', t.name)):
                                        phase = 'suspend_prepare'
                                        if(not isbegin):
                                                data.dmesg[phase]['end'] = t.time
@@ -2291,6 +2583,8 @@ def parseTraceLog():
                                p = m.group('p')
                                if(n and p):
                                        data.newAction(phase, n, pid, p, t.time, -1, drv)
+                                       if pid not in data.devpids:
+                                               data.devpids.append(pid)
                        # device callback finish
                        elif(t.type == 'device_pm_callback_end'):
                                m = re.match('(?P<drv>.*) (?P<d>.*), err.*', t.name);
@@ -2332,6 +2626,12 @@ def parseTraceLog():
                                else:
                                        e['end'] = t.time
                                        e['rdata'] = kprobedata
+                               # end of kernel resume
+                               if(kprobename == 'pm_notifier_call_chain' or \
+                                       kprobename == 'pm_restore_console'):
+                                       data.dmesg[phase]['end'] = t.time
+                                       data.tKernRes = t.time
+
                # callgraph processing
                elif sysvals.usecallgraph:
                        # create a callgraph object for the data
@@ -2348,24 +2648,37 @@ def parseTraceLog():
        if sysvals.suspendmode == 'command':
                for test in testruns:
                        for p in test.data.phases:
-                               if p == 'resume_complete':
+                               if p == 'suspend_prepare':
                                        test.data.dmesg[p]['start'] = test.data.start
                                        test.data.dmesg[p]['end'] = test.data.end
                                else:
-                                       test.data.dmesg[p]['start'] = test.data.start
-                                       test.data.dmesg[p]['end'] = test.data.start
-                       test.data.tSuspended = test.data.start
-                       test.data.tResumed = test.data.start
+                                       test.data.dmesg[p]['start'] = test.data.end
+                                       test.data.dmesg[p]['end'] = test.data.end
+                       test.data.tSuspended = test.data.end
+                       test.data.tResumed = test.data.end
                        test.data.tLow = 0
                        test.data.fwValid = False
 
-       for test in testruns:
+       # dev source and procmon events can be unreadable with mixed phase height
+       if sysvals.usedevsrc or sysvals.useprocmon:
+               sysvals.mixedphaseheight = False
+
+       for i in range(len(testruns)):
+               test = testruns[i]
+               data = test.data
+               # find the total time range for this test (begin, end)
+               tlb, tle = data.start, data.end
+               if i < len(testruns) - 1:
+                       tle = testruns[i+1].data.start
+               # add the process usage data to the timeline
+               if sysvals.useprocmon:
+                       data.createProcessUsageEvents()
                # add the traceevent data to the device hierarchy
                if(sysvals.usetraceevents):
                        # add actual trace funcs
                        for name in test.ttemp:
                                for event in test.ttemp[name]:
-                                       test.data.newActionGlobal(name, event['begin'], event['end'], event['pid'])
+                                       data.newActionGlobal(name, event['begin'], event['end'], event['pid'])
                        # add the kprobe based virtual tracefuncs as actual devices
                        for key in tp.ktemp:
                                name, pid = key
@@ -2373,24 +2686,20 @@ def parseTraceLog():
                                        continue
                                for e in tp.ktemp[key]:
                                        kb, ke = e['begin'], e['end']
-                                       if kb == ke or not test.data.isInsideTimeline(kb, ke):
+                                       if kb == ke or tlb > kb or tle <= kb:
                                                continue
-                                       test.data.newActionGlobal(e['name'], kb, ke, pid)
+                                       color = sysvals.kprobeColor(name)
+                                       data.newActionGlobal(e['name'], kb, ke, pid, color)
                        # add config base kprobes and dev kprobes
-                       for key in tp.ktemp:
-                               name, pid = key
-                               if name in sysvals.tracefuncs:
-                                       continue
-                               for e in tp.ktemp[key]:
-                                       kb, ke = e['begin'], e['end']
-                                       if kb == ke or not test.data.isInsideTimeline(kb, ke):
+                       if sysvals.usedevsrc:
+                               for key in tp.ktemp:
+                                       name, pid = key
+                                       if name in sysvals.tracefuncs or name not in sysvals.dev_tracefuncs:
                                                continue
-                                       color = sysvals.kprobeColor(e['name'])
-                                       if name not in sysvals.dev_tracefuncs:
-                                               # config base kprobe
-                                               test.data.newActionGlobal(e['name'], kb, ke, -2, color)
-                                       elif sysvals.usedevsrc:
-                                               # dev kprobe
+                                       for e in tp.ktemp[key]:
+                                               kb, ke = e['begin'], e['end']
+                                               if kb == ke or tlb > kb or tle <= kb:
+                                                       continue
                                                data.addDeviceFunctionCall(e['name'], name, e['proc'], pid, kb,
                                                        ke, e['cdata'], e['rdata'])
                if sysvals.usecallgraph:
@@ -2407,7 +2716,7 @@ def parseTraceLog():
                                                        id+', ignoring this callback')
                                                continue
                                        # match cg data to devices
-                                       if sysvals.suspendmode == 'command' or not cg.deviceMatch(pid, test.data):
+                                       if sysvals.suspendmode == 'command' or not cg.deviceMatch(pid, data):
                                                sortkey = '%f%f%d' % (cg.start, cg.end, pid)
                                                sortlist[sortkey] = cg
                        # create blocks for orphan cg data
@@ -2416,12 +2725,11 @@ def parseTraceLog():
                                name = cg.list[0].name
                                if sysvals.isCallgraphFunc(name):
                                        vprint('Callgraph found for task %d: %.3fms, %s' % (cg.pid, (cg.end - cg.start)*1000, name))
-                                       cg.newActionFromFunction(test.data)
+                                       cg.newActionFromFunction(data)
 
        if sysvals.suspendmode == 'command':
-               if(sysvals.verbose):
-                       for data in testdata:
-                               data.printDetails()
+               for data in testdata:
+                       data.printDetails()
                return testdata
 
        # fill in any missing phases
@@ -2429,7 +2737,7 @@ def parseTraceLog():
                lp = data.phases[0]
                for p in data.phases:
                        if(data.dmesg[p]['start'] < 0 and data.dmesg[p]['end'] < 0):
-                               print('WARNING: phase "%s" is missing!' % p)
+                               vprint('WARNING: phase "%s" is missing!' % p)
                        if(data.dmesg[p]['start'] < 0):
                                data.dmesg[p]['start'] = data.dmesg[lp]['end']
                                if(p == 'resume_machine'):
@@ -2438,60 +2746,27 @@ def parseTraceLog():
                                        data.tLow = 0
                        if(data.dmesg[p]['end'] < 0):
                                data.dmesg[p]['end'] = data.dmesg[p]['start']
+                       if(p != lp and not ('machine' in p and 'machine' in lp)):
+                               data.dmesg[lp]['end'] = data.dmesg[p]['start']
                        lp = p
 
                if(len(sysvals.devicefilter) > 0):
                        data.deviceFilter(sysvals.devicefilter)
                data.fixupInitcallsThatDidntReturn()
-               if(sysvals.verbose):
-                       data.printDetails()
+               if sysvals.usedevsrc:
+                       data.optimizeDevSrc()
+               data.printDetails()
 
+       # x2: merge any overlapping devices between test runs
+       if sysvals.usedevsrc and len(testdata) > 1:
+               tc = len(testdata)
+               for i in range(tc - 1):
+                       devlist = testdata[i].overflowDevices()
+                       for j in range(i + 1, tc):
+                               testdata[j].mergeOverlapDevices(devlist)
+               testdata[0].stitchTouchingThreads(testdata[1:])
        return testdata
 
-# Function: loadRawKernelLog
-# Description:
-#       Load a raw kernel log that wasn't created by this tool, it might be
-#       possible to extract a valid suspend/resume log
-def loadRawKernelLog(dmesgfile):
-       global sysvals
-
-       stamp = {'time': '', 'host': '', 'mode': 'mem', 'kernel': ''}
-       stamp['time'] = datetime.now().strftime('%B %d %Y, %I:%M:%S %p')
-       stamp['host'] = sysvals.hostname
-
-       testruns = []
-       data = 0
-       lf = open(dmesgfile, 'r')
-       for line in lf:
-               line = line.replace('\r\n', '')
-               idx = line.find('[')
-               if idx > 1:
-                       line = line[idx:]
-               m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line)
-               if(not m):
-                       continue
-               msg = m.group("msg")
-               m = re.match('PM: Syncing filesystems.*', msg)
-               if(m):
-                       if(data):
-                               testruns.append(data)
-                       data = Data(len(testruns))
-                       data.stamp = stamp
-               if(data):
-                       m = re.match('.* *(?P<k>[0-9]\.[0-9]{2}\.[0-9]-.*) .*', msg)
-                       if(m):
-                               stamp['kernel'] = m.group('k')
-                       m = re.match('PM: Preparing system for (?P<m>.*) sleep', msg)
-                       if(m):
-                               stamp['mode'] = m.group('m')
-                       data.dmesgtext.append(line)
-       if(data):
-               testruns.append(data)
-               sysvals.stamp = stamp
-               sysvals.suspendmode = stamp['mode']
-       lf.close()
-       return testruns
-
 # Function: loadKernelLog
 # Description:
 #       [deprecated for kernel 3.15.0 or newer]
@@ -2499,15 +2774,16 @@ def loadRawKernelLog(dmesgfile):
 #       The dmesg filename is taken from sysvals
 # Output:
 #       An array of empty Data objects with only their dmesgtext attributes set
-def loadKernelLog():
-       global sysvals
-
+def loadKernelLog(justtext=False):
        vprint('Analyzing the dmesg data...')
        if(os.path.exists(sysvals.dmesgfile) == False):
-               doError('%s does not exist' % sysvals.dmesgfile, False)
+               doError('%s does not exist' % sysvals.dmesgfile)
 
+       if justtext:
+               dmesgtext = []
        # there can be multiple test runs in a single file
        tp = TestProps()
+       tp.stamp = datetime.now().strftime('# suspend-%m%d%y-%H%M%S localhost mem unknown')
        testruns = []
        data = 0
        lf = open(sysvals.dmesgfile, 'r')
@@ -2528,6 +2804,9 @@ def loadKernelLog():
                if(not m):
                        continue
                msg = m.group("msg")
+               if justtext:
+                       dmesgtext.append(line)
+                       continue
                if(re.match('PM: Syncing filesystems.*', msg)):
                        if(data):
                                testruns.append(data)
@@ -2537,24 +2816,24 @@ def loadKernelLog():
                                data.fwSuspend, data.fwResume = tp.fwdata[data.testnumber]
                                if(data.fwSuspend > 0 or data.fwResume > 0):
                                        data.fwValid = True
-               if(re.match('ACPI: resume from mwait', msg)):
-                       print('NOTE: This suspend appears to be freeze rather than'+\
-                               ' %s, it will be treated as such' % sysvals.suspendmode)
-                       sysvals.suspendmode = 'freeze'
                if(not data):
                        continue
+               m = re.match('.* *(?P<k>[0-9]\.[0-9]{2}\.[0-9]-.*) .*', msg)
+               if(m):
+                       sysvals.stamp['kernel'] = m.group('k')
+               m = re.match('PM: Preparing system for (?P<m>.*) sleep', msg)
+               if(m):
+                       sysvals.stamp['mode'] = sysvals.suspendmode = m.group('m')
                data.dmesgtext.append(line)
-       if(data):
-               testruns.append(data)
        lf.close()
 
-       if(len(testruns) < 1):
-               # bad log, but see if you can extract something meaningful anyway
-               testruns = loadRawKernelLog(sysvals.dmesgfile)
-
-       if(len(testruns) < 1):
-               doError(' dmesg log is completely unreadable: %s' \
-                       % sysvals.dmesgfile, False)
+       if justtext:
+               return dmesgtext
+       if data:
+               testruns.append(data)
+       if len(testruns) < 1:
+               doError(' dmesg log has no suspend/resume data: %s' \
+                       % sysvals.dmesgfile)
 
        # fix lines with same timestamp/function with the call and return swapped
        for data in testruns:
@@ -2586,8 +2865,6 @@ def loadKernelLog():
 # Output:
 #       The filled Data object
 def parseKernelLog(data):
-       global sysvals
-
        phase = 'suspend_runtime'
 
        if(data.fwValid):
@@ -2645,7 +2922,6 @@ def parseKernelLog(data):
        prevktime = -1.0
        actions = dict()
        for line in data.dmesgtext:
-               # -- preprocessing --
                # parse each dmesg line into the time and message
                m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line)
                if(m):
@@ -2653,8 +2929,6 @@ def parseKernelLog(data):
                        try:
                                ktime = float(val)
                        except:
-                               doWarning('INVALID DMESG LINE: '+\
-                                       line.replace('\n', ''), 'dmesg')
                                continue
                        msg = m.group('msg')
                        # initialize data start to first line time
@@ -2672,12 +2946,12 @@ def parseKernelLog(data):
                        phase = 'resume_noirq'
                        data.dmesg[phase]['start'] = ktime
 
-               # -- phase changes --
                # suspend start
                if(re.match(dm['suspend_prepare'], msg)):
                        phase = 'suspend_prepare'
                        data.dmesg[phase]['start'] = ktime
                        data.setStart(ktime)
+                       data.tKernSus = ktime
                # suspend start
                elif(re.match(dm['suspend'], msg)):
                        data.dmesg['suspend_prepare']['end'] = ktime
@@ -2734,7 +3008,7 @@ def parseKernelLog(data):
                elif(re.match(dm['post_resume'], msg)):
                        data.dmesg['resume_complete']['end'] = ktime
                        data.setEnd(ktime)
-                       phase = 'post_resume'
+                       data.tKernRes = ktime
                        break
 
                # -- device callbacks --
@@ -2761,7 +3035,6 @@ def parseKernelLog(data):
                                        dev['length'] = int(t)
                                        dev['end'] = ktime
 
-               # -- non-devicecallback actions --
                # if trace events are not available, these are better than nothing
                if(not sysvals.usetraceevents):
                        # look for known actions
@@ -2821,8 +3094,7 @@ def parseKernelLog(data):
                for event in actions[name]:
                        data.newActionGlobal(name, event['begin'], event['end'])
 
-       if(sysvals.verbose):
-               data.printDetails()
+       data.printDetails()
        if(len(sysvals.devicefilter) > 0):
                data.deviceFilter(sysvals.devicefilter)
        data.fixupInitcallsThatDidntReturn()
@@ -2834,8 +3106,6 @@ def parseKernelLog(data):
 # Arguments:
 #       testruns: array of Data objects from parseTraceLog
 def createHTMLSummarySimple(testruns, htmlfile):
-       global sysvals
-
        # print out the basic summary of all the tests
        hf = open(htmlfile, 'w')
 
@@ -2960,7 +3230,6 @@ def createHTMLSummarySimple(testruns, htmlfile):
        hf.close()
 
 def htmlTitle():
-       global sysvals
        modename = {
                'freeze': 'Freeze (S0)',
                'standby': 'Standby (S1)',
@@ -2993,13 +3262,14 @@ def ordinal(value):
 # Output:
 #       True if the html file was created, false if it failed
 def createHTML(testruns):
-       global sysvals
-
        if len(testruns) < 1:
                print('ERROR: Not enough test data to build a timeline')
                return
 
+       kerror = False
        for data in testruns:
+               if data.kerror:
+                       kerror = True
                data.normalizeTime(testruns[-1].tSuspended)
 
        x2changes = ['', 'absolute']
@@ -3009,53 +3279,59 @@ def createHTML(testruns):
        headline_version = '<div class="version"><a href="https://01.org/suspendresume">AnalyzeSuspend v%s</a></div>' % sysvals.version
        headline_stamp = '<div class="stamp">{0} {1} {2} {3}</div>\n'
        html_devlist1 = '<button id="devlist1" class="devlist" style="float:left;">Device Detail%s</button>' % x2changes[0]
-       html_zoombox = '<center><button id="zoomin">ZOOM IN</button><button id="zoomout">ZOOM OUT</button><button id="zoomdef">ZOOM 1:1</button></center>\n'
+       html_zoombox = '<center><button id="zoomin">ZOOM IN +</button><button id="zoomout">ZOOM OUT -</button><button id="zoomdef">ZOOM 1:1</button></center>\n'
        html_devlist2 = '<button id="devlist2" class="devlist" style="float:right;">Device Detail2</button>\n'
        html_timeline = '<div id="dmesgzoombox" class="zoombox">\n<div id="{0}" class="timeline" style="height:{1}px">\n'
-       html_tblock = '<div id="block{0}" class="tblock" style="left:{1}%;width:{2}%;">\n'
+       html_tblock = '<div id="block{0}" class="tblock" style="left:{1}%;width:{2}%;"><div class="tback" style="height:{3}px"></div>\n'
        html_device = '<div id="{0}" title="{1}" class="thread{7}" style="left:{2}%;top:{3}px;height:{4}px;width:{5}%;{8}">{6}</div>\n'
-       html_traceevent = '<div title="{0}" class="traceevent" style="left:{1}%;top:{2}px;height:{3}px;width:{4}%;line-height:{3}px;">{5}</div>\n'
+       html_error = '<div id="{1}" title="kernel error/warning" class="err" style="right:{0}%">ERROR&rarr;</div>\n'
+       html_traceevent = '<div title="{0}" class="traceevent{6}" style="left:{1}%;top:{2}px;height:{3}px;width:{4}%;line-height:{3}px;{7}">{5}</div>\n'
+       html_cpuexec = '<div class="jiffie" style="left:{0}%;top:{1}px;height:{2}px;width:{3}%;background:{4};"></div>\n'
        html_phase = '<div class="phase" style="left:{0}%;width:{1}%;top:{2}px;height:{3}px;background-color:{4}">{5}</div>\n'
-       html_phaselet = '<div id="{0}" class="phaselet" style="left:{1}%;width:{2}%;background-color:{3}"></div>\n'
+       html_phaselet = '<div id="{0}" class="phaselet" style="left:{1}%;width:{2}%;background:{3}"></div>\n'
        html_legend = '<div id="p{3}" class="square" style="left:{0}%;background-color:{1}">&nbsp;{2}</div>\n'
        html_timetotal = '<table class="time1">\n<tr>'\
-               '<td class="green">{2} Suspend Time: <b>{0} ms</b></td>'\
-               '<td class="yellow">{2} Resume Time: <b>{1} ms</b></td>'\
+               '<td class="green" title="{3}">{2} Suspend Time: <b>{0} ms</b></td>'\
+               '<td class="yellow" title="{4}">{2} Resume Time: <b>{1} ms</b></td>'\
                '</tr>\n</table>\n'
        html_timetotal2 = '<table class="time1">\n<tr>'\
-               '<td class="green">{3} Suspend Time: <b>{0} ms</b></td>'\
-               '<td class="gray">'+sysvals.suspendmode+' time: <b>{1} ms</b></td>'\
-               '<td class="yellow">{3} Resume Time: <b>{2} ms</b></td>'\
+               '<td class="green" title="{4}">{3} Suspend Time: <b>{0} ms</b></td>'\
+               '<td class="gray" title="time spent in low-power mode with clock running">'+sysvals.suspendmode+' time: <b>{1} ms</b></td>'\
+               '<td class="yellow" title="{5}">{3} Resume Time: <b>{2} ms</b></td>'\
                '</tr>\n</table>\n'
        html_timetotal3 = '<table class="time1">\n<tr>'\
                '<td class="green">Execution Time: <b>{0} ms</b></td>'\
                '<td class="yellow">Command: <b>{1}</b></td>'\
                '</tr>\n</table>\n'
        html_timegroups = '<table class="time2">\n<tr>'\
-               '<td class="green">{4}Kernel Suspend: {0} ms</td>'\
+               '<td class="green" title="time from kernel enter_state({5}) to firmware mode [kernel time only]">{4}Kernel Suspend: {0} ms</td>'\
                '<td class="purple">{4}Firmware Suspend: {1} ms</td>'\
                '<td class="purple">{4}Firmware Resume: {2} ms</td>'\
-               '<td class="yellow">{4}Kernel Resume: {3} ms</td>'\
+               '<td class="yellow" title="time from firmware mode to return from kernel enter_state({5}) [kernel time only]">{4}Kernel Resume: {3} ms</td>'\
                '</tr>\n</table>\n'
 
        # html format variables
-       rowheight = 30
-       devtextS = '14px'
-       devtextH = '30px'
-       hoverZ = 'z-index:10;'
-
+       hoverZ = 'z-index:8;'
        if sysvals.usedevsrc:
                hoverZ = ''
+       scaleH = 20
+       scaleTH = 20
+       if kerror:
+               scaleH = 40
+               scaleTH = 60
 
        # device timeline
        vprint('Creating Device Timeline...')
 
-       devtl = Timeline(rowheight)
+       devtl = Timeline(30, scaleH)
 
        # Generate the header for this timeline
        for data in testruns:
                tTotal = data.end - data.start
-               tEnd = data.dmesg['resume_complete']['end']
+               sktime = (data.dmesg['suspend_machine']['end'] - \
+                       data.tKernSus) * 1000
+               rktime = (data.dmesg['resume_complete']['end'] - \
+                       data.dmesg['resume_machine']['start']) * 1000
                if(tTotal == 0):
                        print('ERROR: No timeline data')
                        sys.exit()
@@ -3072,59 +3348,85 @@ def createHTML(testruns):
                        thtml = html_timetotal3.format(run_time, testdesc)
                        devtl.html['header'] += thtml
                elif data.fwValid:
-                       suspend_time = '%.0f'%((data.tSuspended-data.start)*1000 + \
-                               (data.fwSuspend/1000000.0))
-                       resume_time = '%.0f'%((tEnd-data.tSuspended)*1000 + \
-                               (data.fwResume/1000000.0))
+                       suspend_time = '%.0f'%(sktime + (data.fwSuspend/1000000.0))
+                       resume_time = '%.0f'%(rktime + (data.fwResume/1000000.0))
                        testdesc1 = 'Total'
                        testdesc2 = ''
+                       stitle = 'time from kernel enter_state(%s) to low-power mode [kernel & firmware time]' % sysvals.suspendmode
+                       rtitle = 'time from low-power mode to return from kernel enter_state(%s) [firmware & kernel time]' % sysvals.suspendmode
                        if(len(testruns) > 1):
                                testdesc1 = testdesc2 = ordinal(data.testnumber+1)
                                testdesc2 += ' '
                        if(data.tLow == 0):
                                thtml = html_timetotal.format(suspend_time, \
-                                       resume_time, testdesc1)
+                                       resume_time, testdesc1, stitle, rtitle)
                        else:
                                thtml = html_timetotal2.format(suspend_time, low_time, \
-                                       resume_time, testdesc1)
+                                       resume_time, testdesc1, stitle, rtitle)
                        devtl.html['header'] += thtml
-                       sktime = '%.3f'%((data.dmesg['suspend_machine']['end'] - \
-                               data.getStart())*1000)
                        sftime = '%.3f'%(data.fwSuspend / 1000000.0)
                        rftime = '%.3f'%(data.fwResume / 1000000.0)
-                       rktime = '%.3f'%((data.dmesg['resume_complete']['end'] - \
-                               data.dmesg['resume_machine']['start'])*1000)
-                       devtl.html['header'] += html_timegroups.format(sktime, \
-                               sftime, rftime, rktime, testdesc2)
+                       devtl.html['header'] += html_timegroups.format('%.3f'%sktime, \
+                               sftime, rftime, '%.3f'%rktime, testdesc2, sysvals.suspendmode)
                else:
-                       suspend_time = '%.0f'%((data.tSuspended-data.start)*1000)
-                       resume_time = '%.0f'%((tEnd-data.tSuspended)*1000)
+                       suspend_time = '%.3f' % sktime
+                       resume_time = '%.3f' % rktime
                        testdesc = 'Kernel'
+                       stitle = 'time from kernel enter_state(%s) to firmware mode [kernel time only]' % sysvals.suspendmode
+                       rtitle = 'time from firmware mode to return from kernel enter_state(%s) [kernel time only]' % sysvals.suspendmode
                        if(len(testruns) > 1):
                                testdesc = ordinal(data.testnumber+1)+' '+testdesc
                        if(data.tLow == 0):
                                thtml = html_timetotal.format(suspend_time, \
-                                       resume_time, testdesc)
+                                       resume_time, testdesc, stitle, rtitle)
                        else:
                                thtml = html_timetotal2.format(suspend_time, low_time, \
-                                       resume_time, testdesc)
+                                       resume_time, testdesc, stitle, rtitle)
                        devtl.html['header'] += thtml
 
        # time scale for potentially multiple datasets
        t0 = testruns[0].start
        tMax = testruns[-1].end
-       tSuspended = testruns[-1].tSuspended
        tTotal = tMax - t0
 
        # determine the maximum number of rows we need to draw
+       fulllist = []
+       threadlist = []
+       pscnt = 0
+       devcnt = 0
        for data in testruns:
                data.selectTimelineDevices('%f', tTotal, sysvals.mindevlen)
                for group in data.devicegroups:
                        devlist = []
                        for phase in group:
                                for devname in data.tdevlist[phase]:
-                                       devlist.append((phase,devname))
-                       devtl.getPhaseRows(data.dmesg, devlist)
+                                       d = DevItem(data.testnumber, phase, data.dmesg[phase]['list'][devname])
+                                       devlist.append(d)
+                                       if d.isa('kth'):
+                                               threadlist.append(d)
+                                       else:
+                                               if d.isa('ps'):
+                                                       pscnt += 1
+                                               else:
+                                                       devcnt += 1
+                                               fulllist.append(d)
+                       if sysvals.mixedphaseheight:
+                               devtl.getPhaseRows(devlist)
+       if not sysvals.mixedphaseheight:
+               if len(threadlist) > 0 and len(fulllist) > 0:
+                       if pscnt > 0 and devcnt > 0:
+                               msg = 'user processes & device pm callbacks'
+                       elif pscnt > 0:
+                               msg = 'user processes'
+                       else:
+                               msg = 'device pm callbacks'
+                       d = testruns[0].addHorizontalDivider(msg, testruns[-1].end)
+                       fulllist.insert(0, d)
+               devtl.getPhaseRows(fulllist)
+               if len(threadlist) > 0:
+                       d = testruns[0].addHorizontalDivider('asynchronous kernel threads', testruns[-1].end)
+                       threadlist.insert(0, d)
+                       devtl.getPhaseRows(threadlist, devtl.rows)
        devtl.calcTotalRows()
 
        # create bounding box, add buttons
@@ -3145,18 +3447,6 @@ def createHTML(testruns):
 
        # draw each test run chronologically
        for data in testruns:
-               # if nore than one test, draw a block to represent user mode
-               if(data.testnumber > 0):
-                       m0 = testruns[data.testnumber-1].end
-                       mMax = testruns[data.testnumber].start
-                       mTotal = mMax - m0
-                       name = 'usermode%d' % data.testnumber
-                       top = '%d' % devtl.scaleH
-                       left = '%f' % (((m0-t0)*100.0)/tTotal)
-                       width = '%f' % ((mTotal*100.0)/tTotal)
-                       title = 'user mode (%0.3f ms) ' % (mTotal*1000)
-                       devtl.html['timeline'] += html_device.format(name, \
-                               title, left, top, '%d'%devtl.bodyH, width, '', '', '')
                # now draw the actual timeline blocks
                for dir in phases:
                        # draw suspend and resume blocks separately
@@ -3169,13 +3459,16 @@ def createHTML(testruns):
                        else:
                                m0 = testruns[data.testnumber].tSuspended
                                mMax = testruns[data.testnumber].end
+                               # in an x2 run, remove any gap between blocks
+                               if len(testruns) > 1 and data.testnumber == 0:
+                                       mMax = testruns[1].start
                                mTotal = mMax - m0
                                left = '%f' % ((((m0-t0)*100.0)+sysvals.srgap/2)/tTotal)
                        # if a timeline block is 0 length, skip altogether
                        if mTotal == 0:
                                continue
                        width = '%f' % (((mTotal*100.0)-sysvals.srgap/2)/tTotal)
-                       devtl.html['timeline'] += html_tblock.format(bname, left, width)
+                       devtl.html['timeline'] += html_tblock.format(bname, left, width, devtl.scaleH)
                        for b in sorted(phases[dir]):
                                # draw the phase color background
                                phase = data.dmesg[b]
@@ -3185,6 +3478,12 @@ def createHTML(testruns):
                                devtl.html['timeline'] += html_phase.format(left, width, \
                                        '%.3f'%devtl.scaleH, '%.3f'%devtl.bodyH, \
                                        data.dmesg[b]['color'], '')
+                       for e in data.errorinfo[dir]:
+                               # draw red lines for any kernel errors found
+                               t, err = e
+                               right = '%f' % (((mMax-t)*100.0)/mTotal)
+                               devtl.html['timeline'] += html_error.format(right, err)
+                       for b in sorted(phases[dir]):
                                # draw the devices for this phase
                                phaselist = data.dmesg[b]['list']
                                for d in data.tdevlist[b]:
@@ -3196,46 +3495,62 @@ def createHTML(testruns):
                                        xtrastyle = ''
                                        if 'htmlclass' in dev:
                                                xtraclass = dev['htmlclass']
-                                               xtrainfo = dev['htmlclass']
                                        if 'color' in dev:
                                                xtrastyle = 'background-color:%s;' % dev['color']
                                        if(d in sysvals.devprops):
                                                name = sysvals.devprops[d].altName(d)
                                                xtraclass = sysvals.devprops[d].xtraClass()
                                                xtrainfo = sysvals.devprops[d].xtraInfo()
+                                       elif xtraclass == ' kth':
+                                               xtrainfo = ' kernel_thread'
                                        if('drv' in dev and dev['drv']):
                                                drv = ' {%s}' % dev['drv']
-                                       rowheight = devtl.phaseRowHeight(b, dev['row'])
-                                       rowtop = devtl.phaseRowTop(b, dev['row'])
+                                       rowheight = devtl.phaseRowHeight(data.testnumber, b, dev['row'])
+                                       rowtop = devtl.phaseRowTop(data.testnumber, b, dev['row'])
                                        top = '%.3f' % (rowtop + devtl.scaleH)
                                        left = '%f' % (((dev['start']-m0)*100)/mTotal)
                                        width = '%f' % (((dev['end']-dev['start'])*100)/mTotal)
                                        length = ' (%0.3f ms) ' % ((dev['end']-dev['start'])*1000)
+                                       title = name+drv+xtrainfo+length
                                        if sysvals.suspendmode == 'command':
-                                               title = name+drv+xtrainfo+length+'cmdexec'
+                                               title += sysvals.testcommand
+                                       elif xtraclass == ' ps':
+                                               if 'suspend' in b:
+                                                       title += 'pre_suspend_process'
+                                               else:
+                                                       title += 'post_resume_process'
                                        else:
-                                               title = name+drv+xtrainfo+length+b
+                                               title += b
                                        devtl.html['timeline'] += html_device.format(dev['id'], \
                                                title, left, top, '%.3f'%rowheight, width, \
                                                d+drv, xtraclass, xtrastyle)
+                                       if('cpuexec' in dev):
+                                               for t in sorted(dev['cpuexec']):
+                                                       start, end = t
+                                                       j = float(dev['cpuexec'][t]) / 5
+                                                       if j > 1.0:
+                                                               j = 1.0
+                                                       height = '%.3f' % (rowheight/3)
+                                                       top = '%.3f' % (rowtop + devtl.scaleH + 2*rowheight/3)
+                                                       left = '%f' % (((start-m0)*100)/mTotal)
+                                                       width = '%f' % ((end-start)*100/mTotal)
+                                                       color = 'rgba(255, 0, 0, %f)' % j
+                                                       devtl.html['timeline'] += \
+                                                               html_cpuexec.format(left, top, height, width, color)
                                        if('src' not in dev):
                                                continue
                                        # draw any trace events for this device
-                                       vprint('Debug trace events found for device %s' % d)
-                                       vprint('%20s %20s %10s %8s' % ('title', \
-                                               'name', 'time(ms)', 'length(ms)'))
                                        for e in dev['src']:
-                                               vprint('%20s %20s %10.3f %8.3f' % (e.title, \
-                                                       e.text, e.time*1000, e.length*1000))
-                                               height = devtl.rowH
+                                               height = '%.3f' % devtl.rowH
                                                top = '%.3f' % (rowtop + devtl.scaleH + (e.row*devtl.rowH))
                                                left = '%f' % (((e.time-m0)*100)/mTotal)
                                                width = '%f' % (e.length*100/mTotal)
-                                               color = 'rgba(204,204,204,0.5)'
+                                               xtrastyle = ''
+                                               if e.color:
+                                                       xtrastyle = 'background:%s;' % e.color
                                                devtl.html['timeline'] += \
-                                                       html_traceevent.format(e.title, \
-                                                               left, top, '%.3f'%height, \
-                                                               width, e.text)
+                                                       html_traceevent.format(e.title(), \
+                                                               left, top, height, width, e.text(), '', xtrastyle)
                        # draw the time scale, try to make the number of labels readable
                        devtl.html['timeline'] += devtl.createTimeScale(m0, mMax, tTotal, dir)
                        devtl.html['timeline'] += '</div>\n'
@@ -3284,8 +3599,7 @@ def createHTML(testruns):
                t2 {color:black;font:25px Times;}\n\
                t3 {color:black;font:20px Times;white-space:nowrap;}\n\
                t4 {color:black;font:bold 30px Times;line-height:60px;white-space:nowrap;}\n\
-               cS {color:blue;font:bold 11px Times;}\n\
-               cR {color:red;font:bold 11px Times;}\n\
+               cS {font:bold 13px Times;}\n\
                table {width:100%;}\n\
                .gray {background-color:rgba(80,80,80,0.1);}\n\
                .green {background-color:rgba(204,255,204,0.4);}\n\
@@ -3302,20 +3616,22 @@ def createHTML(testruns):
                .pf:'+cgchk+' + label {background:url(\'data:image/svg+xml;utf,<?xml version="1.0" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" height="18" width="18" version="1.1"><circle cx="9" cy="9" r="8" stroke="black" stroke-width="1" fill="white"/><rect x="4" y="8" width="10" height="2" style="fill:black;stroke-width:0"/><rect x="8" y="4" width="2" height="10" style="fill:black;stroke-width:0"/></svg>\') no-repeat left center;}\n\
                .pf:'+cgnchk+' ~ label {background:url(\'data:image/svg+xml;utf,<?xml version="1.0" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" height="18" width="18" version="1.1"><circle cx="9" cy="9" r="8" stroke="black" stroke-width="1" fill="white"/><rect x="4" y="8" width="10" height="2" style="fill:black;stroke-width:0"/></svg>\') no-repeat left center;}\n\
                .pf:'+cgchk+' ~ *:not(:nth-child(2)) {display:none;}\n\
-               .zoombox {position:relative;width:100%;overflow-x:scroll;}\n\
+               .zoombox {position:relative;width:100%;overflow-x:scroll;-webkit-user-select:none;-moz-user-select:none;user-select:none;}\n\
                .timeline {position:relative;font-size:14px;cursor:pointer;width:100%; overflow:hidden;background:linear-gradient(#cccccc, white);}\n\
-               .thread {position:absolute;height:0%;overflow:hidden;line-height:'+devtextH+';font-size:'+devtextS+';border:1px solid;text-align:center;white-space:nowrap;background-color:rgba(204,204,204,0.5);}\n\
-               .thread.sync {background-color:'+sysvals.synccolor+';}\n\
-               .thread.bg {background-color:'+sysvals.kprobecolor+';}\n\
+               .thread {position:absolute;height:0%;overflow:hidden;z-index:7;line-height:30px;font-size:14px;border:1px solid;text-align:center;white-space:nowrap;}\n\
+               .thread.ps {border-radius:3px;background:linear-gradient(to top, #ccc, #eee);}\n\
                .thread:hover {background-color:white;border:1px solid red;'+hoverZ+'}\n\
+               .thread.sec,.thread.sec:hover {background-color:black;border:0;color:white;line-height:15px;font-size:10px;}\n\
                .hover {background-color:white;border:1px solid red;'+hoverZ+'}\n\
                .hover.sync {background-color:white;}\n\
-               .hover.bg {background-color:white;}\n\
-               .traceevent {position:absolute;font-size:10px;overflow:hidden;color:black;text-align:center;white-space:nowrap;border-radius:5px;border:1px solid black;background:linear-gradient(to bottom right,rgba(204,204,204,1),rgba(150,150,150,1));}\n\
-               .traceevent:hover {background:white;}\n\
+               .hover.bg,.hover.kth,.hover.sync,.hover.ps {background-color:white;}\n\
+               .jiffie {position:absolute;pointer-events: none;z-index:8;}\n\
+               .traceevent {position:absolute;font-size:10px;z-index:7;overflow:hidden;color:black;text-align:center;white-space:nowrap;border-radius:5px;border:1px solid black;background:linear-gradient(to bottom right,#CCC,#969696);}\n\
+               .traceevent:hover {color:white;font-weight:bold;border:1px solid white;}\n\
                .phase {position:absolute;overflow:hidden;border:0px;text-align:center;}\n\
                .phaselet {position:absolute;overflow:hidden;border:0px;text-align:center;height:100px;font-size:24px;}\n\
-               .t {z-index:2;position:absolute;pointer-events:none;top:0%;height:100%;border-right:1px solid black;}\n\
+               .t {position:absolute;line-height:'+('%d'%scaleTH)+'px;pointer-events:none;top:0;height:100%;border-right:1px solid black;z-index:6;}\n\
+               .err {position:absolute;top:0%;height:100%;border-right:3px solid red;color:red;font:bold 14px Times;line-height:18px;}\n\
                .legend {position:relative; width:100%; height:40px; text-align:center;margin-bottom:20px}\n\
                .legend .square {position:absolute;cursor:pointer;top:10px; width:0px;height:20px;border:1px solid;padding-left:20px;}\n\
                button {height:40px;width:200px;margin-bottom:20px;margin-top:20px;font-size:24px;}\n\
@@ -3327,7 +3643,8 @@ def createHTML(testruns):
                a:active {color:white;}\n\
                .version {position:relative;float:left;color:white;font-size:10px;line-height:30px;margin-left:10px;}\n\
                #devicedetail {height:100px;box-shadow:5px 5px 20px black;}\n\
-               .tblock {position:absolute;height:100%;}\n\
+               .tblock {position:absolute;height:100%;background-color:#ddd;}\n\
+               .tback {position:absolute;width:100%;background:linear-gradient(#ccc, #ddd);}\n\
                .bg {z-index:1;}\n\
        </style>\n</head>\n<body>\n'
 
@@ -3342,6 +3659,8 @@ def createHTML(testruns):
        # write the test title and general info header
        if(sysvals.stamp['time'] != ""):
                hf.write(headline_version)
+               if sysvals.logmsg:
+                       hf.write('<button id="showtest" class="logbtn">log</button>')
                if sysvals.addlogs and sysvals.dmesgfile:
                        hf.write('<button id="showdmesg" class="logbtn">dmesg</button>')
                if sysvals.addlogs and sysvals.ftracefile:
@@ -3359,6 +3678,9 @@ def createHTML(testruns):
        # draw the colored boxes for the device detail section
        for data in testruns:
                hf.write('<div id="devicedetail%d">\n' % data.testnumber)
+               pscolor = 'linear-gradient(to top left, #ccc, #eee)'
+               hf.write(html_phaselet.format('pre_suspend_process', \
+                       '0', '0', pscolor))
                for b in data.phases:
                        phase = data.dmesg[b]
                        length = phase['end']-phase['start']
@@ -3366,14 +3688,18 @@ def createHTML(testruns):
                        width = '%.3f' % ((length*100.0)/tTotal)
                        hf.write(html_phaselet.format(b, left, width, \
                                data.dmesg[b]['color']))
+               hf.write(html_phaselet.format('post_resume_process', \
+                       '0', '0', pscolor))
                if sysvals.suspendmode == 'command':
-                       hf.write(html_phaselet.format('cmdexec', '0', '0', \
-                               data.dmesg['resume_complete']['color']))
+                       hf.write(html_phaselet.format('cmdexec', '0', '0', pscolor))
                hf.write('</div>\n')
        hf.write('</div>\n')
 
        # write the ftrace data (callgraph)
-       data = testruns[-1]
+       if sysvals.cgtest >= 0 and len(testruns) > sysvals.cgtest:
+               data = testruns[sysvals.cgtest]
+       else:
+               data = testruns[-1]
        if(sysvals.usecallgraph and not sysvals.embedded):
                hf.write('<section id="callgraphs" class="callgraph">\n')
                # write out the ftrace data converted to html
@@ -3383,6 +3709,8 @@ def createHTML(testruns):
                html_func_leaf = '<article>{0} {1}</article>\n'
                num = 0
                for p in data.phases:
+                       if sysvals.cgphase and p != sysvals.cgphase:
+                               continue
                        list = data.dmesg[p]['list']
                        for devname in data.sortedDevices(p):
                                if('ftrace' not in list[devname]):
@@ -3420,11 +3748,15 @@ def createHTML(testruns):
                                hf.write(html_func_end)
                hf.write('\n\n    </section>\n')
 
+       # add the test log as a hidden div
+       if sysvals.logmsg:
+               hf.write('<div id="testlog" style="display:none;">\n'+sysvals.logmsg+'</div>\n')
        # add the dmesg log as a hidden div
        if sysvals.addlogs and sysvals.dmesgfile:
                hf.write('<div id="dmesglog" style="display:none;">\n')
                lf = open(sysvals.dmesgfile, 'r')
                for line in lf:
+                       line = line.replace('<', '&lt').replace('>', '&gt')
                        hf.write(line)
                lf.close()
                hf.write('</div>\n')
@@ -3475,8 +3807,9 @@ def addScriptCode(hf, testruns):
        script_code = \
        '<script type="text/javascript">\n'+detail+\
        '       var resolution = -1;\n'\
+       '       var dragval = [0, 0];\n'\
        '       function redrawTimescale(t0, tMax, tS) {\n'\
-       '               var rline = \'<div class="t" style="left:0;border-left:1px solid black;border-right:0;"><cR><-R</cR></div>\';\n'\
+       '               var rline = \'<div class="t" style="left:0;border-left:1px solid black;border-right:0;"><cS>&larr;R</cS></div>\';\n'\
        '               var tTotal = tMax - t0;\n'\
        '               var list = document.getElementsByClassName("tblock");\n'\
        '               for (var i = 0; i < list.length; i++) {\n'\
@@ -3501,7 +3834,7 @@ def addScriptCode(hf, testruns):
        '                                       pos = 100 - (((j)*tS*100)/mTotal) - divEdge;\n'\
        '                                       val = (j-divTotal+1)*tS;\n'\
        '                                       if(j == divTotal - 1)\n'\
-       '                                               htmlline = \'<div class="t" style="right:\'+pos+\'%"><cS>S-></cS></div>\';\n'\
+       '                                               htmlline = \'<div class="t" style="right:\'+pos+\'%"><cS>S&rarr;</cS></div>\';\n'\
        '                                       else\n'\
        '                                               htmlline = \'<div class="t" style="right:\'+pos+\'%">\'+val+\'ms</div>\';\n'\
        '                               }\n'\
@@ -3513,6 +3846,7 @@ def addScriptCode(hf, testruns):
        '       function zoomTimeline() {\n'\
        '               var dmesg = document.getElementById("dmesg");\n'\
        '               var zoombox = document.getElementById("dmesgzoombox");\n'\
+       '               var left = zoombox.scrollLeft;\n'\
        '               var val = parseFloat(dmesg.style.width);\n'\
        '               var newval = 100;\n'\
        '               var sh = window.outerWidth / 2;\n'\
@@ -3520,12 +3854,12 @@ def addScriptCode(hf, testruns):
        '                       newval = val * 1.2;\n'\
        '                       if(newval > 910034) newval = 910034;\n'\
        '                       dmesg.style.width = newval+"%";\n'\
-       '                       zoombox.scrollLeft = ((zoombox.scrollLeft + sh) * newval / val) - sh;\n'\
+       '                       zoombox.scrollLeft = ((left + sh) * newval / val) - sh;\n'\
        '               } else if (this.id == "zoomout") {\n'\
        '                       newval = val / 1.2;\n'\
        '                       if(newval < 100) newval = 100;\n'\
        '                       dmesg.style.width = newval+"%";\n'\
-       '                       zoombox.scrollLeft = ((zoombox.scrollLeft + sh) * newval / val) - sh;\n'\
+       '                       zoombox.scrollLeft = ((left + sh) * newval / val) - sh;\n'\
        '               } else {\n'\
        '                       zoombox.scrollLeft = 0;\n'\
        '                       dmesg.style.width = "100%";\n'\
@@ -3542,8 +3876,12 @@ def addScriptCode(hf, testruns):
        '               resolution = tS[i];\n'\
        '               redrawTimescale(t0, tMax, tS[i]);\n'\
        '       }\n'\
+       '       function deviceName(title) {\n'\
+       '               var name = title.slice(0, title.indexOf(" ("));\n'\
+       '               return name;\n'\
+       '       }\n'\
        '       function deviceHover() {\n'\
-       '               var name = this.title.slice(0, this.title.indexOf(" ("));\n'\
+       '               var name = deviceName(this.title);\n'\
        '               var dmesg = document.getElementById("dmesg");\n'\
        '               var dev = dmesg.getElementsByClassName("thread");\n'\
        '               var cpu = -1;\n'\
@@ -3552,7 +3890,7 @@ def addScriptCode(hf, testruns):
        '               else if(name.match("CPU_OFF\[[0-9]*\]"))\n'\
        '                       cpu = parseInt(name.slice(8));\n'\
        '               for (var i = 0; i < dev.length; i++) {\n'\
-       '                       dname = dev[i].title.slice(0, dev[i].title.indexOf(" ("));\n'\
+       '                       dname = deviceName(dev[i].title);\n'\
        '                       var cname = dev[i].className.slice(dev[i].className.indexOf("thread"));\n'\
        '                       if((cpu >= 0 && dname.match("CPU_O[NF]*\\\[*"+cpu+"\\\]")) ||\n'\
        '                               (name == dname))\n'\
@@ -3578,7 +3916,7 @@ def addScriptCode(hf, testruns):
        '                       total[2] = (total[2]+total[4])/2;\n'\
        '               }\n'\
        '               var devtitle = document.getElementById("devicedetailtitle");\n'\
-       '               var name = title.slice(0, title.indexOf(" ("));\n'\
+       '               var name = deviceName(title);\n'\
        '               if(cpu >= 0) name = "CPU"+cpu;\n'\
        '               var driver = "";\n'\
        '               var tS = "<t2>(</t2>";\n'\
@@ -3600,7 +3938,7 @@ def addScriptCode(hf, testruns):
        '       function deviceDetail() {\n'\
        '               var devinfo = document.getElementById("devicedetail");\n'\
        '               devinfo.style.display = "block";\n'\
-       '               var name = this.title.slice(0, this.title.indexOf(" ("));\n'\
+       '               var name = deviceName(this.title);\n'\
        '               var cpu = -1;\n'\
        '               if(name.match("CPU_ON\[[0-9]*\]"))\n'\
        '                       cpu = parseInt(name.slice(7));\n'\
@@ -3615,7 +3953,7 @@ def addScriptCode(hf, testruns):
        '               var pd = pdata[0];\n'\
        '               var total = [0.0, 0.0, 0.0];\n'\
        '               for (var i = 0; i < dev.length; i++) {\n'\
-       '                       dname = dev[i].title.slice(0, dev[i].title.indexOf(" ("));\n'\
+       '                       dname = deviceName(dev[i].title);\n'\
        '                       if((cpu >= 0 && dname.match("CPU_O[NF]*\\\[*"+cpu+"\\\]")) ||\n'\
        '                               (name == dname))\n'\
        '                       {\n'\
@@ -3656,7 +3994,7 @@ def addScriptCode(hf, testruns):
        '                                       phases[i].title = phases[i].id+" "+pd[phases[i].id]+" ms";\n'\
        '                                       left += w;\n'\
        '                                       var time = "<t4 style=\\"font-size:"+fs+"px\\">"+pd[phases[i].id]+" ms<br></t4>";\n'\
-       '                                       var pname = "<t3 style=\\"font-size:"+fs2+"px\\">"+phases[i].id.replace("_", " ")+"</t3>";\n'\
+       '                                       var pname = "<t3 style=\\"font-size:"+fs2+"px\\">"+phases[i].id.replace(new RegExp("_", "g"), " ")+"</t3>";\n'\
        '                                       phases[i].innerHTML = time+pname;\n'\
        '                               } else {\n'\
        '                                       phases[i].style.width = "0%";\n'\
@@ -3677,12 +4015,7 @@ def addScriptCode(hf, testruns):
        '               }\n'\
        '       }\n'\
        '       function devListWindow(e) {\n'\
-       '               var sx = e.clientX;\n'\
-       '               if(sx > window.innerWidth - 440)\n'\
-       '                       sx = window.innerWidth - 440;\n'\
-       '               var cfg="top="+e.screenY+", left="+sx+", width=440, height=720, scrollbars=yes";\n'\
-       '               var win = window.open("", "_blank", cfg);\n'\
-       '               if(window.chrome) win.moveBy(sx, 0);\n'\
+       '               var win = window.open();\n'\
        '               var html = "<title>"+e.target.innerHTML+"</title>"+\n'\
        '                       "<style type=\\"text/css\\">"+\n'\
        '                       "   ul {list-style-type:circle;padding-left:10px;margin-left:10px;}"+\n'\
@@ -3692,6 +4025,12 @@ def addScriptCode(hf, testruns):
        '                       dt = devtable[1];\n'\
        '               win.document.write(html+dt);\n'\
        '       }\n'\
+       '       function errWindow() {\n'\
+       '               var text = this.id;\n'\
+       '               var win = window.open();\n'\
+       '               win.document.write("<pre>"+text+"</pre>");\n'\
+       '               win.document.close();\n'\
+       '       }\n'\
        '       function logWindow(e) {\n'\
        '               var name = e.target.id.slice(4);\n'\
        '               var win = window.open();\n'\
@@ -3702,16 +4041,46 @@ def addScriptCode(hf, testruns):
        '       }\n'\
        '       function onClickPhase(e) {\n'\
        '       }\n'\
+       '       function onMouseDown(e) {\n'\
+       '               dragval[0] = e.clientX;\n'\
+       '               dragval[1] = document.getElementById("dmesgzoombox").scrollLeft;\n'\
+       '               document.onmousemove = onMouseMove;\n'\
+       '       }\n'\
+       '       function onMouseMove(e) {\n'\
+       '               var zoombox = document.getElementById("dmesgzoombox");\n'\
+       '               zoombox.scrollLeft = dragval[1] + dragval[0] - e.clientX;\n'\
+       '       }\n'\
+       '       function onMouseUp(e) {\n'\
+       '               document.onmousemove = null;\n'\
+       '       }\n'\
+       '       function onKeyPress(e) {\n'\
+       '               var c = e.charCode;\n'\
+       '               if(c != 42 && c != 43 && c != 45) return;\n'\
+       '               var click = document.createEvent("Events");\n'\
+       '               click.initEvent("click", true, false);\n'\
+       '               if(c == 43)  \n'\
+       '                       document.getElementById("zoomin").dispatchEvent(click);\n'\
+       '               else if(c == 45)\n'\
+       '                       document.getElementById("zoomout").dispatchEvent(click);\n'\
+       '               else if(c == 42)\n'\
+       '                       document.getElementById("zoomdef").dispatchEvent(click);\n'\
+       '       }\n'\
        '       window.addEventListener("resize", function () {zoomTimeline();});\n'\
        '       window.addEventListener("load", function () {\n'\
        '               var dmesg = document.getElementById("dmesg");\n'\
        '               dmesg.style.width = "100%"\n'\
+       '               dmesg.onmousedown = onMouseDown;\n'\
+       '               document.onmouseup = onMouseUp;\n'\
+       '               document.onkeypress = onKeyPress;\n'\
        '               document.getElementById("zoomin").onclick = zoomTimeline;\n'\
        '               document.getElementById("zoomout").onclick = zoomTimeline;\n'\
        '               document.getElementById("zoomdef").onclick = zoomTimeline;\n'\
        '               var list = document.getElementsByClassName("square");\n'\
        '               for (var i = 0; i < list.length; i++)\n'\
        '                       list[i].onclick = onClickPhase;\n'\
+       '               var list = document.getElementsByClassName("err");\n'\
+       '               for (var i = 0; i < list.length; i++)\n'\
+       '                       list[i].onclick = errWindow;\n'\
        '               var list = document.getElementsByClassName("logbtn");\n'\
        '               for (var i = 0; i < list.length; i++)\n'\
        '                       list[i].onclick = logWindow;\n'\
@@ -3734,9 +4103,7 @@ def addScriptCode(hf, testruns):
 #       Execute system suspend through the sysfs interface, then copy the output
 #       dmesg and ftrace files to the test output directory.
 def executeSuspend():
-       global sysvals
-
-       t0 = time.time()*1000
+       pm = ProcessMonitor()
        tp = sysvals.tpath
        fwdata = []
        # mark the start point in the kernel ring buffer just as we start
@@ -3745,30 +4112,39 @@ def executeSuspend():
        if(sysvals.usecallgraph or sysvals.usetraceevents):
                print('START TRACING')
                sysvals.fsetVal('1', 'tracing_on')
+               if sysvals.useprocmon:
+                       pm.start()
        # execute however many s/r runs requested
        for count in range(1,sysvals.execcount+1):
-               # if this is test2 and there's a delay, start here
+               # x2delay in between test runs
                if(count > 1 and sysvals.x2delay > 0):
-                       tN = time.time()*1000
-                       while (tN - t0) < sysvals.x2delay:
-                               tN = time.time()*1000
-                               time.sleep(0.001)
-               # initiate suspend
-               if(sysvals.usecallgraph or sysvals.usetraceevents):
-                       sysvals.fsetVal('SUSPEND START', 'trace_marker')
-               if sysvals.suspendmode == 'command':
+                       sysvals.fsetVal('WAIT %d' % sysvals.x2delay, 'trace_marker')
+                       time.sleep(sysvals.x2delay/1000.0)
+                       sysvals.fsetVal('WAIT END', 'trace_marker')
+               # start message
+               if sysvals.testcommand != '':
                        print('COMMAND START')
-                       if(sysvals.rtcwake):
-                               print('will issue an rtcwake in %d seconds' % sysvals.rtcwaketime)
-                               sysvals.rtcWakeAlarmOn()
-                       os.system(sysvals.testcommand)
                else:
                        if(sysvals.rtcwake):
                                print('SUSPEND START')
-                               print('will autoresume in %d seconds' % sysvals.rtcwaketime)
-                               sysvals.rtcWakeAlarmOn()
                        else:
                                print('SUSPEND START (press a key to resume)')
+               # set rtcwake
+               if(sysvals.rtcwake):
+                       print('will issue an rtcwake in %d seconds' % sysvals.rtcwaketime)
+                       sysvals.rtcWakeAlarmOn()
+               # start of suspend trace marker
+               if(sysvals.usecallgraph or sysvals.usetraceevents):
+                       sysvals.fsetVal('SUSPEND START', 'trace_marker')
+               # predelay delay
+               if(count == 1 and sysvals.predelay > 0):
+                       sysvals.fsetVal('WAIT %d' % sysvals.predelay, 'trace_marker')
+                       time.sleep(sysvals.predelay/1000.0)
+                       sysvals.fsetVal('WAIT END', 'trace_marker')
+               # initiate suspend or command
+               if sysvals.testcommand != '':
+                       call(sysvals.testcommand+' 2>&1', shell=True);
+               else:
                        pf = open(sysvals.powerfile, 'w')
                        pf.write(sysvals.suspendmode)
                        # execution will pause here
@@ -3776,26 +4152,27 @@ def executeSuspend():
                                pf.close()
                        except:
                                pass
-               t0 = time.time()*1000
                if(sysvals.rtcwake):
                        sysvals.rtcWakeAlarmOff()
+               # postdelay delay
+               if(count == sysvals.execcount and sysvals.postdelay > 0):
+                       sysvals.fsetVal('WAIT %d' % sysvals.postdelay, 'trace_marker')
+                       time.sleep(sysvals.postdelay/1000.0)
+                       sysvals.fsetVal('WAIT END', 'trace_marker')
                # return from suspend
                print('RESUME COMPLETE')
                if(sysvals.usecallgraph or sysvals.usetraceevents):
                        sysvals.fsetVal('RESUME COMPLETE', 'trace_marker')
-               if(sysvals.suspendmode == 'mem'):
+               if(sysvals.suspendmode == 'mem' or sysvals.suspendmode == 'command'):
                        fwdata.append(getFPDT(False))
-       # look for post resume events after the last test run
-       t = sysvals.postresumetime
-       if(t > 0):
-               print('Waiting %d seconds for POST-RESUME trace events...' % t)
-               time.sleep(t)
        # stop ftrace
        if(sysvals.usecallgraph or sysvals.usetraceevents):
+               if sysvals.useprocmon:
+                       pm.stop()
                sysvals.fsetVal('0', 'tracing_on')
                print('CAPTURING TRACE')
                writeDatafileHeader(sysvals.ftracefile, fwdata)
-               os.system('cat '+tp+'trace >> '+sysvals.ftracefile)
+               call('cat '+tp+'trace >> '+sysvals.ftracefile, shell=True)
                sysvals.fsetVal('', 'trace')
                devProps()
        # grab a copy of the dmesg output
@@ -3804,17 +4181,12 @@ def executeSuspend():
        sysvals.getdmesg()
 
 def writeDatafileHeader(filename, fwdata):
-       global sysvals
-
-       prt = sysvals.postresumetime
        fp = open(filename, 'a')
        fp.write(sysvals.teststamp+'\n')
-       if(sysvals.suspendmode == 'mem'):
+       if(sysvals.suspendmode == 'mem' or sysvals.suspendmode == 'command'):
                for fw in fwdata:
                        if(fw):
                                fp.write('# fwsuspend %u fwresume %u\n' % (fw[0], fw[1]))
-       if(prt > 0):
-               fp.write('# post resume time %u\n' % prt)
        fp.close()
 
 # Function: setUSBDevicesAuto
@@ -3824,18 +4196,16 @@ def writeDatafileHeader(filename, fwdata):
 #       to always-on since the kernel cant determine if the device can
 #       properly autosuspend
 def setUSBDevicesAuto():
-       global sysvals
-
        rootCheck(True)
        for dirname, dirnames, filenames in os.walk('/sys/devices'):
                if(re.match('.*/usb[0-9]*.*', dirname) and
                        'idVendor' in filenames and 'idProduct' in filenames):
-                       os.system('echo auto > %s/power/control' % dirname)
+                       call('echo auto > %s/power/control' % dirname, shell=True)
                        name = dirname.split('/')[-1]
-                       desc = os.popen('cat %s/product 2>/dev/null' % \
-                               dirname).read().replace('\n', '')
-                       ctrl = os.popen('cat %s/power/control 2>/dev/null' % \
-                               dirname).read().replace('\n', '')
+                       desc = Popen(['cat', '%s/product' % dirname],
+                               stderr=PIPE, stdout=PIPE).stdout.read().replace('\n', '')
+                       ctrl = Popen(['cat', '%s/power/control' % dirname],
+                               stderr=PIPE, stdout=PIPE).stdout.read().replace('\n', '')
                        print('control is %s for %6s: %s' % (ctrl, name, desc))
 
 # Function: yesno
@@ -3872,8 +4242,6 @@ def ms2nice(val):
 #       Detect all the USB hosts and devices currently connected and add
 #       a list of USB device names to sysvals for better timeline readability
 def detectUSB():
-       global sysvals
-
        field = {'idVendor':'', 'idProduct':'', 'product':'', 'speed':''}
        power = {'async':'', 'autosuspend':'', 'autosuspend_delay_ms':'',
                         'control':'', 'persist':'', 'runtime_enabled':'',
@@ -3899,12 +4267,12 @@ def detectUSB():
                if(re.match('.*/usb[0-9]*.*', dirname) and
                        'idVendor' in filenames and 'idProduct' in filenames):
                        for i in field:
-                               field[i] = os.popen('cat %s/%s 2>/dev/null' % \
-                                       (dirname, i)).read().replace('\n', '')
+                               field[i] = Popen(['cat', '%s/%s' % (dirname, i)],
+                                       stderr=PIPE, stdout=PIPE).stdout.read().replace('\n', '')
                        name = dirname.split('/')[-1]
                        for i in power:
-                               power[i] = os.popen('cat %s/power/%s 2>/dev/null' % \
-                                       (dirname, i)).read().replace('\n', '')
+                               power[i] = Popen(['cat', '%s/power/%s' % (dirname, i)],
+                                       stderr=PIPE, stdout=PIPE).stdout.read().replace('\n', '')
                        if(re.match('usb[0-9]*', name)):
                                first = '%-8s' % name
                        else:
@@ -3928,7 +4296,6 @@ def detectUSB():
 # Description:
 #       Retrieve a list of properties for all devices in the trace log
 def devProps(data=0):
-       global sysvals
        props = dict()
 
        if data:
@@ -3953,7 +4320,7 @@ def devProps(data=0):
                return
 
        if(os.path.exists(sysvals.ftracefile) == False):
-               doError('%s does not exist' % sysvals.ftracefile, False)
+               doError('%s does not exist' % sysvals.ftracefile)
 
        # first get the list of devices we need properties for
        msghead = 'Additional data added by AnalyzeSuspend'
@@ -3976,7 +4343,7 @@ def devProps(data=0):
                m = re.match('.*: (?P<drv>.*) (?P<d>.*), parent: *(?P<p>.*), .*', m.group('msg'));
                if(not m):
                        continue
-               drv, dev, par = m.group('drv'), m.group('d'), m.group('p')
+               dev = m.group('d')
                if dev not in props:
                        props[dev] = DevProps()
        tf.close()
@@ -4052,7 +4419,6 @@ def devProps(data=0):
 # Output:
 #       A string list of the available modes
 def getModes():
-       global sysvals
        modes = ''
        if(os.path.exists(sysvals.powerfile)):
                fp = open(sysvals.powerfile, 'r')
@@ -4066,8 +4432,6 @@ def getModes():
 # Arguments:
 #       output: True to output the info to stdout, False otherwise
 def getFPDT(output):
-       global sysvals
-
        rectype = {}
        rectype[0] = 'Firmware Basic Boot Performance Record'
        rectype[1] = 'S3 Performance Table Record'
@@ -4078,19 +4442,19 @@ def getFPDT(output):
        rootCheck(True)
        if(not os.path.exists(sysvals.fpdtpath)):
                if(output):
-                       doError('file does not exist: %s' % sysvals.fpdtpath, False)
+                       doError('file does not exist: %s' % sysvals.fpdtpath)
                return False
        if(not os.access(sysvals.fpdtpath, os.R_OK)):
                if(output):
-                       doError('file is not readable: %s' % sysvals.fpdtpath, False)
+                       doError('file is not readable: %s' % sysvals.fpdtpath)
                return False
        if(not os.path.exists(sysvals.mempath)):
                if(output):
-                       doError('file does not exist: %s' % sysvals.mempath, False)
+                       doError('file does not exist: %s' % sysvals.mempath)
                return False
        if(not os.access(sysvals.mempath, os.R_OK)):
                if(output):
-                       doError('file is not readable: %s' % sysvals.mempath, False)
+                       doError('file is not readable: %s' % sysvals.mempath)
                return False
 
        fp = open(sysvals.fpdtpath, 'rb')
@@ -4100,7 +4464,7 @@ def getFPDT(output):
        if(len(buf) < 36):
                if(output):
                        doError('Invalid FPDT table data, should '+\
-                               'be at least 36 bytes', False)
+                               'be at least 36 bytes')
                return False
 
        table = struct.unpack('4sIBB6s8sI4sI', buf[0:36])
@@ -4199,7 +4563,6 @@ def getFPDT(output):
 # Output:
 #       True if the test will work, False if not
 def statusCheck(probecheck=False):
-       global sysvals
        status = True
 
        print('Checking this system (%s)...' % platform.node())
@@ -4282,37 +4645,14 @@ def statusCheck(probecheck=False):
        if not probecheck:
                return status
 
-       if (sysvals.usecallgraph and len(sysvals.debugfuncs) > 0) or len(sysvals.kprobes) > 0:
-               sysvals.initFtrace(True)
-
-       # verify callgraph debugfuncs
-       if sysvals.usecallgraph and len(sysvals.debugfuncs) > 0:
-               print('    verifying these ftrace callgraph functions work:')
-               sysvals.setFtraceFilterFunctions(sysvals.debugfuncs)
-               fp = open(sysvals.tpath+'set_graph_function', 'r')
-               flist = fp.read().split('\n')
-               fp.close()
-               for func in sysvals.debugfuncs:
-                       res = sysvals.colorText('NO')
-                       if func in flist:
-                               res = 'YES'
-                       else:
-                               for i in flist:
-                                       if ' [' in i and func == i.split(' ')[0]:
-                                               res = 'YES'
-                                               break
-                       print('         %s: %s' % (func, res))
-
        # verify kprobes
-       if len(sysvals.kprobes) > 0:
-               print('    verifying these kprobes work:')
-               for name in sorted(sysvals.kprobes):
-                       if name in sysvals.tracefuncs:
-                               continue
-                       res = sysvals.colorText('NO')
-                       if sysvals.testKprobe(sysvals.kprobes[name]):
-                               res = 'YES'
-                       print('         %s: %s' % (name, res))
+       if sysvals.usekprobes:
+               for name in sysvals.tracefuncs:
+                       sysvals.defaultKprobe(name, sysvals.tracefuncs[name])
+               if sysvals.usedevsrc:
+                       for name in sysvals.dev_tracefuncs:
+                               sysvals.defaultKprobe(name, sysvals.dev_tracefuncs[name])
+               sysvals.addKprobes(True)
 
        return status
 
@@ -4322,33 +4662,20 @@ def statusCheck(probecheck=False):
 # Arguments:
 #       msg: the error message to print
 #       help: True if printHelp should be called after, False otherwise
-def doError(msg, help):
+def doError(msg, help=False):
        if(help == True):
                printHelp()
        print('ERROR: %s\n') % msg
        sys.exit()
 
-# Function: doWarning
-# Description:
-#       generic warning function for non-catastrophic anomalies
-# Arguments:
-#       msg: the warning message to print
-#       file: If not empty, a filename to request be sent to the owner for debug
-def doWarning(msg, file=''):
-       print('/* %s */') % msg
-       if(file):
-               print('/* For a fix, please send this'+\
-                       ' %s file to <todd.e.brandt@intel.com> */' % file)
-
 # Function: rootCheck
 # Description:
 #       quick check to see if we have root access
 def rootCheck(fatal):
-       global sysvals
        if(os.access(sysvals.powerfile, os.W_OK)):
                return True
        if fatal:
-               doError('This command must be run as root', False)
+               doError('This command must be run as root')
        return False
 
 # Function: getArgInt
@@ -4389,71 +4716,61 @@ def getArgFloat(name, args, min, max, main=True):
                doError(name+': value should be between %f and %f' % (min, max), True)
        return val
 
-# Function: rerunTest
-# Description:
-#       generate an output from an existing set of ftrace/dmesg logs
-def rerunTest():
-       global sysvals
-
-       if(sysvals.ftracefile != ''):
-               doesTraceLogHaveTraceEvents()
-       if(sysvals.dmesgfile == '' and not sysvals.usetraceeventsonly):
-               doError('recreating this html output '+\
-                       'requires a dmesg file', False)
-       sysvals.setOutputFile()
-       vprint('Output file: %s' % sysvals.htmlfile)
+def processData():
        print('PROCESSING DATA')
        if(sysvals.usetraceeventsonly):
                testruns = parseTraceLog()
+               if sysvals.dmesgfile:
+                       dmesgtext = loadKernelLog(True)
+                       for data in testruns:
+                               data.extractErrorInfo(dmesgtext)
        else:
                testruns = loadKernelLog()
                for data in testruns:
                        parseKernelLog(data)
-               if(sysvals.ftracefile != ''):
+               if(sysvals.ftracefile and (sysvals.usecallgraph or sysvals.usetraceevents)):
                        appendIncompleteTraceLog(testruns)
        createHTML(testruns)
 
+# Function: rerunTest
+# Description:
+#       generate an output from an existing set of ftrace/dmesg logs
+def rerunTest():
+       if sysvals.ftracefile:
+               doesTraceLogHaveTraceEvents()
+       if not sysvals.dmesgfile and not sysvals.usetraceeventsonly:
+               doError('recreating this html output requires a dmesg file')
+       sysvals.setOutputFile()
+       vprint('Output file: %s' % sysvals.htmlfile)
+       if(os.path.exists(sysvals.htmlfile) and not os.access(sysvals.htmlfile, os.W_OK)):
+               doError('missing permission to write to %s' % sysvals.htmlfile)
+       processData()
+
 # Function: runTest
 # Description:
 #       execute a suspend/resume, gather the logs, and generate the output
 def runTest(subdir, testpath=''):
-       global sysvals
-
        # prepare for the test
        sysvals.initFtrace()
        sysvals.initTestOutput(subdir, testpath)
-
-       vprint('Output files:\n    %s' % sysvals.dmesgfile)
-       if(sysvals.usecallgraph or
-               sysvals.usetraceevents or
-               sysvals.usetraceeventsonly):
-               vprint('    %s' % sysvals.ftracefile)
-       vprint('    %s' % sysvals.htmlfile)
+       vprint('Output files:\n\t%s\n\t%s\n\t%s' % \
+               (sysvals.dmesgfile, sysvals.ftracefile, sysvals.htmlfile))
 
        # execute the test
        executeSuspend()
        sysvals.cleanupFtrace()
+       processData()
 
-       # analyze the data and create the html output
-       print('PROCESSING DATA')
-       if(sysvals.usetraceeventsonly):
-               # data for kernels 3.15 or newer is entirely in ftrace
-               testruns = parseTraceLog()
-       else:
-               # data for kernels older than 3.15 is primarily in dmesg
-               testruns = loadKernelLog()
-               for data in testruns:
-                       parseKernelLog(data)
-               if(sysvals.usecallgraph or sysvals.usetraceevents):
-                       appendIncompleteTraceLog(testruns)
-       createHTML(testruns)
+       # if running as root, change output dir owner to sudo_user
+       if os.path.isdir(sysvals.testdir) and os.getuid() == 0 and \
+               'SUDO_USER' in os.environ:
+               cmd = 'chown -R {0}:{0} {1} > /dev/null 2>&1'
+               call(cmd.format(os.environ['SUDO_USER'], sysvals.testdir), shell=True)
 
 # Function: runSummary
 # Description:
 #       create a summary of tests in a sub-directory
 def runSummary(subdir, output):
-       global sysvals
-
        # get a list of ftrace output files
        files = []
        for dirname, dirnames, filenames in os.walk(subdir):
@@ -4509,12 +4826,12 @@ def checkArgBool(value):
 # Description:
 #       Configure the script via the info in a config file
 def configFromFile(file):
-       global sysvals
        Config = ConfigParser.ConfigParser()
 
-       ignorekprobes = False
        Config.read(file)
        sections = Config.sections()
+       overridekprobes = False
+       overridedevkprobes = False
        if 'Settings' in sections:
                for opt in Config.options('Settings'):
                        value = Config.get('Settings', opt).lower()
@@ -4524,19 +4841,19 @@ def configFromFile(file):
                                sysvals.addlogs = checkArgBool(value)
                        elif(opt.lower() == 'dev'):
                                sysvals.usedevsrc = checkArgBool(value)
-                       elif(opt.lower() == 'ignorekprobes'):
-                               ignorekprobes = checkArgBool(value)
+                       elif(opt.lower() == 'proc'):
+                               sysvals.useprocmon = checkArgBool(value)
                        elif(opt.lower() == 'x2'):
                                if checkArgBool(value):
                                        sysvals.execcount = 2
                        elif(opt.lower() == 'callgraph'):
                                sysvals.usecallgraph = checkArgBool(value)
-                       elif(opt.lower() == 'callgraphfunc'):
-                               sysvals.debugfuncs = []
-                               if value:
-                                       value = value.split(',')
-                               for i in value:
-                                       sysvals.debugfuncs.append(i.strip())
+                       elif(opt.lower() == 'override-timeline-functions'):
+                               overridekprobes = checkArgBool(value)
+                       elif(opt.lower() == 'override-dev-timeline-functions'):
+                               overridedevkprobes = checkArgBool(value)
+                       elif(opt.lower() == 'devicefilter'):
+                               sysvals.setDeviceFilter(value)
                        elif(opt.lower() == 'expandcg'):
                                sysvals.cgexp = checkArgBool(value)
                        elif(opt.lower() == 'srgap'):
@@ -4548,8 +4865,10 @@ def configFromFile(file):
                                sysvals.testcommand = value
                        elif(opt.lower() == 'x2delay'):
                                sysvals.x2delay = getArgInt('-x2delay', value, 0, 60000, False)
-                       elif(opt.lower() == 'postres'):
-                               sysvals.postresumetime = getArgInt('-postres', value, 0, 3600, False)
+                       elif(opt.lower() == 'predelay'):
+                               sysvals.predelay = getArgInt('-predelay', value, 0, 60000, False)
+                       elif(opt.lower() == 'postdelay'):
+                               sysvals.postdelay = getArgInt('-postdelay', value, 0, 60000, False)
                        elif(opt.lower() == 'rtcwake'):
                                sysvals.rtcwake = True
                                sysvals.rtcwaketime = getArgInt('-rtcwake', value, 0, 3600, False)
@@ -4557,53 +4876,50 @@ def configFromFile(file):
                                sysvals.setPrecision(getArgInt('-timeprec', value, 0, 6, False))
                        elif(opt.lower() == 'mindev'):
                                sysvals.mindevlen = getArgFloat('-mindev', value, 0.0, 10000.0, False)
+                       elif(opt.lower() == 'callloop-maxgap'):
+                               sysvals.callloopmaxgap = getArgFloat('-callloop-maxgap', value, 0.0, 1.0, False)
+                       elif(opt.lower() == 'callloop-maxlen'):
+                               sysvals.callloopmaxgap = getArgFloat('-callloop-maxlen', value, 0.0, 1.0, False)
                        elif(opt.lower() == 'mincg'):
                                sysvals.mincglen = getArgFloat('-mincg', value, 0.0, 10000.0, False)
-                       elif(opt.lower() == 'kprobecolor'):
-                               try:
-                                       val = int(value, 16)
-                                       sysvals.kprobecolor = '#'+value
-                               except:
-                                       sysvals.kprobecolor = value
-                       elif(opt.lower() == 'synccolor'):
-                               try:
-                                       val = int(value, 16)
-                                       sysvals.synccolor = '#'+value
-                               except:
-                                       sysvals.synccolor = value
                        elif(opt.lower() == 'output-dir'):
-                               args = dict()
-                               n = datetime.now()
-                               args['date'] = n.strftime('%y%m%d')
-                               args['time'] = n.strftime('%H%M%S')
-                               args['hostname'] = sysvals.hostname
-                               sysvals.outdir = value.format(**args)
+                               sysvals.setOutputFolder(value)
 
        if sysvals.suspendmode == 'command' and not sysvals.testcommand:
-               doError('No command supplied for mode "command"', False)
+               doError('No command supplied for mode "command"')
+
+       # compatibility errors
        if sysvals.usedevsrc and sysvals.usecallgraph:
-               doError('dev and callgraph cannot both be true', False)
-       if sysvals.usecallgraph and sysvals.execcount > 1:
-               doError('-x2 is not compatible with -f', False)
+               doError('-dev is not compatible with -f')
+       if sysvals.usecallgraph and sysvals.useprocmon:
+               doError('-proc is not compatible with -f')
 
-       if ignorekprobes:
-               return
+       if overridekprobes:
+               sysvals.tracefuncs = dict()
+       if overridedevkprobes:
+               sysvals.dev_tracefuncs = dict()
 
        kprobes = dict()
-       archkprobe = 'Kprobe_'+platform.machine()
-       if archkprobe in sections:
-               for name in Config.options(archkprobe):
-                       kprobes[name] = Config.get(archkprobe, name)
-       if 'Kprobe' in sections:
-               for name in Config.options('Kprobe'):
-                       kprobes[name] = Config.get('Kprobe', name)
+       kprobesec = 'dev_timeline_functions_'+platform.machine()
+       if kprobesec in sections:
+               for name in Config.options(kprobesec):
+                       text = Config.get(kprobesec, name)
+                       kprobes[name] = (text, True)
+       kprobesec = 'timeline_functions_'+platform.machine()
+       if kprobesec in sections:
+               for name in Config.options(kprobesec):
+                       if name in kprobes:
+                               doError('Duplicate timeline function found "%s"' % (name))
+                       text = Config.get(kprobesec, name)
+                       kprobes[name] = (text, False)
 
        for name in kprobes:
                function = name
                format = name
                color = ''
                args = dict()
-               data = kprobes[name].split()
+               text, dev = kprobes[name]
+               data = text.split()
                i = 0
                for val in data:
                        # bracketted strings are special formatting, read them separately
@@ -4626,28 +4942,30 @@ def configFromFile(file):
                                args[d[0]] = d[1]
                        i += 1
                if not function or not format:
-                       doError('Invalid kprobe: %s' % name, False)
+                       doError('Invalid kprobe: %s' % name)
                for arg in re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', format):
                        if arg not in args:
-                               doError('Kprobe "%s" is missing argument "%s"' % (name, arg), False)
-               if name in sysvals.kprobes:
-                       doError('Duplicate kprobe found "%s"' % (name), False)
-               vprint('Adding KPROBE: %s %s %s %s' % (name, function, format, args))
-               sysvals.kprobes[name] = {
+                               doError('Kprobe "%s" is missing argument "%s"' % (name, arg))
+               if (dev and name in sysvals.dev_tracefuncs) or (not dev and name in sysvals.tracefuncs):
+                       doError('Duplicate timeline function found "%s"' % (name))
+
+               kp = {
                        'name': name,
                        'func': function,
                        'format': format,
-                       'args': args,
-                       'mask': re.sub('{(?P<n>[a-z,A-Z,0-9]*)}', '.*', format)
+                       sysvals.archargs: args
                }
                if color:
-                       sysvals.kprobes[name]['color'] = color
+                       kp['color'] = color
+               if dev:
+                       sysvals.dev_tracefuncs[name] = kp
+               else:
+                       sysvals.tracefuncs[name] = kp
 
 # Function: printHelp
 # Description:
 #       print out the help text
 def printHelp():
-       global sysvals
        modes = getModes()
 
        print('')
@@ -4670,44 +4988,47 @@ def printHelp():
        print('')
        print('Options:')
        print('  [general]')
-       print('    -h          Print this help text')
-       print('    -v          Print the current tool version')
-       print('    -config file Pull arguments and config options from a file')
-       print('    -verbose    Print extra information during execution and analysis')
-       print('    -status     Test to see if the system is enabled to run this tool')
-       print('    -modes      List available suspend modes')
-       print('    -m mode     Mode to initiate for suspend %s (default: %s)') % (modes, sysvals.suspendmode)
-       print('    -o subdir   Override the output subdirectory')
+       print('   -h           Print this help text')
+       print('   -v           Print the current tool version')
+       print('   -config fn   Pull arguments and config options from file fn')
+       print('   -verbose     Print extra information during execution and analysis')
+       print('   -status      Test to see if the system is enabled to run this tool')
+       print('   -modes       List available suspend modes')
+       print('   -m mode      Mode to initiate for suspend %s (default: %s)') % (modes, sysvals.suspendmode)
+       print('   -o subdir    Override the output subdirectory')
+       print('   -rtcwake t   Use rtcwake to autoresume after <t> seconds (default: disabled)')
+       print('   -addlogs     Add the dmesg and ftrace logs to the html output')
+       print('   -srgap       Add a visible gap in the timeline between sus/res (default: disabled)')
        print('  [advanced]')
-       print('    -rtcwake t  Use rtcwake to autoresume after <t> seconds (default: disabled)')
-       print('    -addlogs    Add the dmesg and ftrace logs to the html output')
-       print('    -multi n d  Execute <n> consecutive tests at <d> seconds intervals. The outputs will')
+       print('   -cmd {s}     Run the timeline over a custom command, e.g. "sync -d"')
+       print('   -proc        Add usermode process info into the timeline (default: disabled)')
+       print('   -dev         Add kernel function calls and threads to the timeline (default: disabled)')
+       print('   -x2          Run two suspend/resumes back to back (default: disabled)')
+       print('   -x2delay t   Include t ms delay between multiple test runs (default: 0 ms)')
+       print('   -predelay t  Include t ms delay before 1st suspend (default: 0 ms)')
+       print('   -postdelay t Include t ms delay after last resume (default: 0 ms)')
+       print('   -mindev ms   Discard all device blocks shorter than ms milliseconds (e.g. 0.001 for us)')
+       print('   -multi n d   Execute <n> consecutive tests at <d> seconds intervals. The outputs will')
        print('                be created in a new subdirectory with a summary page.')
-       print('    -srgap      Add a visible gap in the timeline between sus/res (default: disabled)')
-       print('    -cmd {s}    Instead of suspend/resume, run a command, e.g. "sync -d"')
-       print('    -mindev ms  Discard all device blocks shorter than ms milliseconds (e.g. 0.001 for us)')
-       print('    -mincg  ms  Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)')
-       print('    -timeprec N Number of significant digits in timestamps (0:S, [3:ms], 6:us)')
        print('  [debug]')
-       print('    -f          Use ftrace to create device callgraphs (default: disabled)')
-       print('    -expandcg   pre-expand the callgraph data in the html output (default: disabled)')
-       print('    -flist      Print the list of functions currently being captured in ftrace')
-       print('    -flistall   Print all functions capable of being captured in ftrace')
-       print('    -fadd file  Add functions to be graphed in the timeline from a list in a text file')
-       print('    -filter "d1 d2 ..." Filter out all but this list of device names')
-       print('    -dev        Display common low level functions in the timeline')
-       print('  [post-resume task analysis]')
-       print('    -x2         Run two suspend/resumes back to back (default: disabled)')
-       print('    -x2delay t  Minimum millisecond delay <t> between the two test runs (default: 0 ms)')
-       print('    -postres t  Time after resume completion to wait for post-resume events (default: 0 S)')
+       print('   -f           Use ftrace to create device callgraphs (default: disabled)')
+       print('   -expandcg    pre-expand the callgraph data in the html output (default: disabled)')
+       print('   -flist       Print the list of functions currently being captured in ftrace')
+       print('   -flistall    Print all functions capable of being captured in ftrace')
+       print('   -fadd file   Add functions to be graphed in the timeline from a list in a text file')
+       print('   -filter "d1,d2,..." Filter out all but this comma-delimited list of device names')
+       print('   -mincg  ms   Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)')
+       print('   -cgphase P   Only show callgraph data for phase P (e.g. suspend_late)')
+       print('   -cgtest N    Only show callgraph data for test N (e.g. 0 or 1 in an x2 run)')
+       print('   -timeprec N  Number of significant digits in timestamps (0:S, [3:ms], 6:us)')
        print('  [utilities]')
-       print('    -fpdt       Print out the contents of the ACPI Firmware Performance Data Table')
-       print('    -usbtopo    Print out the current USB topology with power info')
-       print('    -usbauto    Enable autosuspend for all connected USB devices')
+       print('   -fpdt        Print out the contents of the ACPI Firmware Performance Data Table')
+       print('   -usbtopo     Print out the current USB topology with power info')
+       print('   -usbauto     Enable autosuspend for all connected USB devices')
        print('  [re-analyze data from previous runs]')
-       print('    -ftrace ftracefile  Create HTML output using ftrace input')
-       print('    -dmesg dmesgfile    Create HTML output using dmesg (not needed for kernel >= 3.15)')
-       print('    -summary directory  Create a summary of all test in this dir')
+       print('   -ftrace ftracefile  Create HTML output using ftrace input')
+       print('   -dmesg dmesgfile    Create HTML output using dmesg (not needed for kernel >= 3.15)')
+       print('   -summary directory  Create a summary of all test in this dir')
        print('')
        return True
 
@@ -4739,26 +5060,22 @@ if __name__ == '__main__':
                        sys.exit()
                elif(arg == '-x2'):
                        sysvals.execcount = 2
-                       if(sysvals.usecallgraph):
-                               doError('-x2 is not compatible with -f', False)
                elif(arg == '-x2delay'):
                        sysvals.x2delay = getArgInt('-x2delay', args, 0, 60000)
-               elif(arg == '-postres'):
-                       sysvals.postresumetime = getArgInt('-postres', args, 0, 3600)
+               elif(arg == '-predelay'):
+                       sysvals.predelay = getArgInt('-predelay', args, 0, 60000)
+               elif(arg == '-postdelay'):
+                       sysvals.postdelay = getArgInt('-postdelay', args, 0, 60000)
                elif(arg == '-f'):
                        sysvals.usecallgraph = True
-                       if(sysvals.execcount > 1):
-                               doError('-x2 is not compatible with -f', False)
-                       if(sysvals.usedevsrc):
-                               doError('-dev is not compatible with -f', False)
                elif(arg == '-addlogs'):
                        sysvals.addlogs = True
                elif(arg == '-verbose'):
                        sysvals.verbose = True
+               elif(arg == '-proc'):
+                       sysvals.useprocmon = True
                elif(arg == '-dev'):
                        sysvals.usedevsrc = True
-                       if(sysvals.usecallgraph):
-                               doError('-dev is not compatible with -f', False)
                elif(arg == '-rtcwake'):
                        sysvals.rtcwake = True
                        sysvals.rtcwaketime = getArgInt('-rtcwake', args, 0, 3600)
@@ -4768,6 +5085,21 @@ if __name__ == '__main__':
                        sysvals.mindevlen = getArgFloat('-mindev', args, 0.0, 10000.0)
                elif(arg == '-mincg'):
                        sysvals.mincglen = getArgFloat('-mincg', args, 0.0, 10000.0)
+               elif(arg == '-cgtest'):
+                       sysvals.cgtest = getArgInt('-cgtest', args, 0, 1)
+               elif(arg == '-cgphase'):
+                       try:
+                               val = args.next()
+                       except:
+                               doError('No phase name supplied', True)
+                       d = Data(0)
+                       if val not in d.phases:
+                               doError('Invalid phase, valid phaess are %s' % d.phases, True)
+                       sysvals.cgphase = val
+               elif(arg == '-callloop-maxgap'):
+                       sysvals.callloopmaxgap = getArgFloat('-callloop-maxgap', args, 0.0, 1.0)
+               elif(arg == '-callloop-maxlen'):
+                       sysvals.callloopmaxlen = getArgFloat('-callloop-maxlen', args, 0.0, 1.0)
                elif(arg == '-cmd'):
                        try:
                                val = args.next()
@@ -4788,14 +5120,14 @@ if __name__ == '__main__':
                                val = args.next()
                        except:
                                doError('No subdirectory name supplied', True)
-                       sysvals.outdir = val
+                       sysvals.setOutputFolder(val)
                elif(arg == '-config'):
                        try:
                                val = args.next()
                        except:
                                doError('No text file supplied', True)
                        if(os.path.exists(val) == False):
-                               doError('%s does not exist' % val, False)
+                               doError('%s does not exist' % val)
                        configFromFile(val)
                elif(arg == '-fadd'):
                        try:
@@ -4803,7 +5135,7 @@ if __name__ == '__main__':
                        except:
                                doError('No text file supplied', True)
                        if(os.path.exists(val) == False):
-                               doError('%s does not exist' % val, False)
+                               doError('%s does not exist' % val)
                        sysvals.addFtraceFilterFunctions(val)
                elif(arg == '-dmesg'):
                        try:
@@ -4813,7 +5145,7 @@ if __name__ == '__main__':
                        sysvals.notestrun = True
                        sysvals.dmesgfile = val
                        if(os.path.exists(sysvals.dmesgfile) == False):
-                               doError('%s does not exist' % sysvals.dmesgfile, False)
+                               doError('%s does not exist' % sysvals.dmesgfile)
                elif(arg == '-ftrace'):
                        try:
                                val = args.next()
@@ -4822,7 +5154,7 @@ if __name__ == '__main__':
                        sysvals.notestrun = True
                        sysvals.ftracefile = val
                        if(os.path.exists(sysvals.ftracefile) == False):
-                               doError('%s does not exist' % sysvals.ftracefile, False)
+                               doError('%s does not exist' % sysvals.ftracefile)
                elif(arg == '-summary'):
                        try:
                                val = args.next()
@@ -4832,7 +5164,7 @@ if __name__ == '__main__':
                        cmdarg = val
                        sysvals.notestrun = True
                        if(os.path.isdir(val) == False):
-                               doError('%s is not accesible' % val, False)
+                               doError('%s is not accesible' % val)
                elif(arg == '-filter'):
                        try:
                                val = args.next()
@@ -4842,6 +5174,12 @@ if __name__ == '__main__':
                else:
                        doError('Invalid argument: '+arg, True)
 
+       # compatibility errors
+       if(sysvals.usecallgraph and sysvals.usedevsrc):
+               doError('-dev is not compatible with -f')
+       if(sysvals.usecallgraph and sysvals.useprocmon):
+               doError('-proc is not compatible with -f')
+
        # callgraph size cannot exceed device size
        if sysvals.mincglen < sysvals.mindevlen:
                sysvals.mincglen = sysvals.mindevlen
@@ -4855,8 +5193,7 @@ if __name__ == '__main__':
                elif(cmd == 'usbtopo'):
                        detectUSB()
                elif(cmd == 'modes'):
-                       modes = getModes()
-                       print modes
+                       print getModes()
                elif(cmd == 'flist'):
                        sysvals.getFtraceFilterFunctions(True)
                elif(cmd == 'flistall'):
index 19ec468b1168f4bf209e333bc194088257716960..fbd34b8e8f578aba003533348c907899779fb62c 100644 (file)
@@ -41,7 +41,9 @@
  * signing with anything other than SHA1 - so we're stuck with that if such is
  * the case.
  */
-#if OPENSSL_VERSION_NUMBER < 0x10000000L || defined(OPENSSL_NO_CMS)
+#if defined(LIBRESSL_VERSION_NUMBER) || \
+       OPENSSL_VERSION_NUMBER < 0x10000000L || \
+       defined(OPENSSL_NO_CMS)
 #define USE_PKCS7
 #endif
 #ifndef USE_PKCS7
index be5e9414a29574c80aca1cd9cab242a99ce77508..b6b68a7750ce36597ecba044f82385c8e6efc71f 100644 (file)
@@ -36,7 +36,6 @@ config SECURITY_APPARMOR_HASH
        select CRYPTO
        select CRYPTO_SHA1
        default y
-
        help
          This option selects whether introspection of loaded policy
          is available to userspace via the apparmor filesystem.
@@ -45,7 +44,6 @@ config SECURITY_APPARMOR_HASH_DEFAULT
        bool "Enable policy hash introspection by default"
        depends on SECURITY_APPARMOR_HASH
        default y
-
        help
          This option selects whether sha1 hashing of loaded policy
         is enabled by default. The generation of sha1 hashes for
@@ -54,3 +52,32 @@ config SECURITY_APPARMOR_HASH_DEFAULT
         however it can slow down policy load on some devices. In
         these cases policy hashing can be disabled by default and
         enabled only if needed.
+
+config SECURITY_APPARMOR_DEBUG
+       bool "Build AppArmor with debug code"
+       depends on SECURITY_APPARMOR
+       default n
+       help
+         Build apparmor with debugging logic in apparmor. Not all
+         debugging logic will necessarily be enabled. A submenu will
+         provide fine grained control of the debug options that are
+         available.
+
+config SECURITY_APPARMOR_DEBUG_ASSERTS
+       bool "Build AppArmor with debugging asserts"
+       depends on SECURITY_APPARMOR_DEBUG
+       default y
+       help
+         Enable code assertions made with AA_BUG. These are primarily
+         function entry preconditions but also exist at other key
+         points. If the assert is triggered it will trigger a WARN
+         message.
+
+config SECURITY_APPARMOR_DEBUG_MESSAGES
+       bool "Debug messages enabled by default"
+       depends on SECURITY_APPARMOR_DEBUG
+       default n
+       help
+         Set the default value of the apparmor.debug kernel parameter.
+         When enabled, various debug messages will be logged to
+         the kernel message buffer.
index d693df87481837fa8d2fb95137d54f3b155cc280..ad369a7aac24af6bdebac7229d8c6cb6389bafa8 100644 (file)
@@ -4,7 +4,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
 
 apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
               path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
-              resource.o sid.o file.o
+              resource.o secid.o file.o policy_ns.o
 apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
 
 clean-files := capability_names.h rlim_names.h
index 5923d5665209df45ef37e116f147f9cac2f846d3..41073f70eb41db135b8b68defa7523c161624991 100644 (file)
 #include <linux/module.h>
 #include <linux/seq_file.h>
 #include <linux/uaccess.h>
+#include <linux/mount.h>
 #include <linux/namei.h>
 #include <linux/capability.h>
 #include <linux/rcupdate.h>
+#include <uapi/linux/major.h>
+#include <linux/fs.h>
 
 #include "include/apparmor.h"
 #include "include/apparmorfs.h"
@@ -28,7 +31,9 @@
 #include "include/context.h"
 #include "include/crypto.h"
 #include "include/policy.h"
+#include "include/policy_ns.h"
 #include "include/resource.h"
+#include "include/policy_unpack.h"
 
 /**
  * aa_mangle_name - mangle a profile name to std profile layout form
@@ -37,7 +42,7 @@
  *
  * Returns: length of mangled name
  */
-static int mangle_name(char *name, char *target)
+static int mangle_name(const char *name, char *target)
 {
        char *t = target;
 
@@ -71,7 +76,6 @@ static int mangle_name(char *name, char *target)
 
 /**
  * aa_simple_write_to_buffer - common routine for getting policy from user
- * @op: operation doing the user buffer copy
  * @userbuf: user buffer to copy data from  (NOT NULL)
  * @alloc_size: size of user buffer (REQUIRES: @alloc_size >= @copy_size)
  * @copy_size: size of data to copy from user buffer
@@ -80,31 +84,29 @@ static int mangle_name(char *name, char *target)
  * Returns: kernel buffer containing copy of user buffer data or an
  *          ERR_PTR on failure.
  */
-static char *aa_simple_write_to_buffer(int op, const char __user *userbuf,
-                                      size_t alloc_size, size_t copy_size,
-                                      loff_t *pos)
+static struct aa_loaddata *aa_simple_write_to_buffer(const char __user *userbuf,
+                                                    size_t alloc_size,
+                                                    size_t copy_size,
+                                                    loff_t *pos)
 {
-       char *data;
+       struct aa_loaddata *data;
 
-       BUG_ON(copy_size > alloc_size);
+       AA_BUG(copy_size > alloc_size);
 
        if (*pos != 0)
                /* only writes from pos 0, that is complete writes */
                return ERR_PTR(-ESPIPE);
 
-       /*
-        * Don't allow profile load/replace/remove from profiles that don't
-        * have CAP_MAC_ADMIN
-        */
-       if (!aa_may_manage_policy(op))
-               return ERR_PTR(-EACCES);
-
        /* freed by caller to simple_write_to_buffer */
-       data = kvmalloc(alloc_size);
+       data = kvmalloc(sizeof(*data) + alloc_size);
        if (data == NULL)
                return ERR_PTR(-ENOMEM);
+       kref_init(&data->count);
+       data->size = copy_size;
+       data->hash = NULL;
+       data->abi = 0;
 
-       if (copy_from_user(data, userbuf, copy_size)) {
+       if (copy_from_user(data->data, userbuf, copy_size)) {
                kvfree(data);
                return ERR_PTR(-EFAULT);
        }
@@ -112,25 +114,43 @@ static char *aa_simple_write_to_buffer(int op, const char __user *userbuf,
        return data;
 }
 
-
-/* .load file hook fn to load policy */
-static ssize_t profile_load(struct file *f, const char __user *buf, size_t size,
-                           loff_t *pos)
+static ssize_t policy_update(int binop, const char __user *buf, size_t size,
+                            loff_t *pos, struct aa_ns *ns)
 {
-       char *data;
        ssize_t error;
+       struct aa_loaddata *data;
+       struct aa_profile *profile = aa_current_profile();
+       const char *op = binop == PROF_ADD ? OP_PROF_LOAD : OP_PROF_REPL;
+       /* high level check about policy management - fine grained in
+        * below after unpack
+        */
+       error = aa_may_manage_policy(profile, ns, op);
+       if (error)
+               return error;
 
-       data = aa_simple_write_to_buffer(OP_PROF_LOAD, buf, size, size, pos);
-
+       data = aa_simple_write_to_buffer(buf, size, size, pos);
        error = PTR_ERR(data);
        if (!IS_ERR(data)) {
-               error = aa_replace_profiles(data, size, PROF_ADD);
-               kvfree(data);
+               error = aa_replace_profiles(ns ? ns : profile->ns, profile,
+                                           binop, data);
+               aa_put_loaddata(data);
        }
 
        return error;
 }
 
+/* .load file hook fn to load policy */
+static ssize_t profile_load(struct file *f, const char __user *buf, size_t size,
+                           loff_t *pos)
+{
+       struct aa_ns *ns = aa_get_ns(f->f_inode->i_private);
+       int error = policy_update(PROF_ADD, buf, size, pos, ns);
+
+       aa_put_ns(ns);
+
+       return error;
+}
+
 static const struct file_operations aa_fs_profile_load = {
        .write = profile_load,
        .llseek = default_llseek,
@@ -140,15 +160,10 @@ static const struct file_operations aa_fs_profile_load = {
 static ssize_t profile_replace(struct file *f, const char __user *buf,
                               size_t size, loff_t *pos)
 {
-       char *data;
-       ssize_t error;
+       struct aa_ns *ns = aa_get_ns(f->f_inode->i_private);
+       int error = policy_update(PROF_REPLACE, buf, size, pos, ns);
 
-       data = aa_simple_write_to_buffer(OP_PROF_REPL, buf, size, size, pos);
-       error = PTR_ERR(data);
-       if (!IS_ERR(data)) {
-               error = aa_replace_profiles(data, size, PROF_REPLACE);
-               kvfree(data);
-       }
+       aa_put_ns(ns);
 
        return error;
 }
@@ -162,22 +177,34 @@ static const struct file_operations aa_fs_profile_replace = {
 static ssize_t profile_remove(struct file *f, const char __user *buf,
                              size_t size, loff_t *pos)
 {
-       char *data;
+       struct aa_loaddata *data;
+       struct aa_profile *profile;
        ssize_t error;
+       struct aa_ns *ns = aa_get_ns(f->f_inode->i_private);
+
+       profile = aa_current_profile();
+       /* high level check about policy management - fine grained in
+        * below after unpack
+        */
+       error = aa_may_manage_policy(profile, ns, OP_PROF_RM);
+       if (error)
+               goto out;
 
        /*
         * aa_remove_profile needs a null terminated string so 1 extra
         * byte is allocated and the copied data is null terminated.
         */
-       data = aa_simple_write_to_buffer(OP_PROF_RM, buf, size + 1, size, pos);
+       data = aa_simple_write_to_buffer(buf, size + 1, size, pos);
 
        error = PTR_ERR(data);
        if (!IS_ERR(data)) {
-               data[size] = 0;
-               error = aa_remove_profiles(data, size);
-               kvfree(data);
+               data->data[size] = 0;
+               error = aa_remove_profiles(ns ? ns : profile->ns, profile,
+                                          data->data, size);
+               aa_put_loaddata(data);
        }
-
+ out:
+       aa_put_ns(ns);
        return error;
 }
 
@@ -186,6 +213,144 @@ static const struct file_operations aa_fs_profile_remove = {
        .llseek = default_llseek,
 };
 
+/**
+ * query_data - queries a policy and writes its data to buf
+ * @buf: the resulting data is stored here (NOT NULL)
+ * @buf_len: size of buf
+ * @query: query string used to retrieve data
+ * @query_len: size of query including second NUL byte
+ *
+ * The buffers pointed to by buf and query may overlap. The query buffer is
+ * parsed before buf is written to.
+ *
+ * The query should look like "<LABEL>\0<KEY>\0", where <LABEL> is the name of
+ * the security confinement context and <KEY> is the name of the data to
+ * retrieve. <LABEL> and <KEY> must not be NUL-terminated.
+ *
+ * Don't expect the contents of buf to be preserved on failure.
+ *
+ * Returns: number of characters written to buf or -errno on failure
+ */
+static ssize_t query_data(char *buf, size_t buf_len,
+                         char *query, size_t query_len)
+{
+       char *out;
+       const char *key;
+       struct aa_profile *profile;
+       struct aa_data *data;
+       u32 bytes, blocks;
+       __le32 outle32;
+
+       if (!query_len)
+               return -EINVAL; /* need a query */
+
+       key = query + strnlen(query, query_len) + 1;
+       if (key + 1 >= query + query_len)
+               return -EINVAL; /* not enough space for a non-empty key */
+       if (key + strnlen(key, query + query_len - key) >= query + query_len)
+               return -EINVAL; /* must end with NUL */
+
+       if (buf_len < sizeof(bytes) + sizeof(blocks))
+               return -EINVAL; /* not enough space */
+
+       profile = aa_current_profile();
+
+       /* We are going to leave space for two numbers. The first is the total
+        * number of bytes we are writing after the first number. This is so
+        * users can read the full output without reallocation.
+        *
+        * The second number is the number of data blocks we're writing. An
+        * application might be confined by multiple policies having data in
+        * the same key.
+        */
+       memset(buf, 0, sizeof(bytes) + sizeof(blocks));
+       out = buf + sizeof(bytes) + sizeof(blocks);
+
+       blocks = 0;
+       if (profile->data) {
+               data = rhashtable_lookup_fast(profile->data, &key,
+                                             profile->data->p);
+
+               if (data) {
+                       if (out + sizeof(outle32) + data->size > buf + buf_len)
+                               return -EINVAL; /* not enough space */
+                       outle32 = __cpu_to_le32(data->size);
+                       memcpy(out, &outle32, sizeof(outle32));
+                       out += sizeof(outle32);
+                       memcpy(out, data->data, data->size);
+                       out += data->size;
+                       blocks++;
+               }
+       }
+
+       outle32 = __cpu_to_le32(out - buf - sizeof(bytes));
+       memcpy(buf, &outle32, sizeof(outle32));
+       outle32 = __cpu_to_le32(blocks);
+       memcpy(buf + sizeof(bytes), &outle32, sizeof(outle32));
+
+       return out - buf;
+}
+
+#define QUERY_CMD_DATA         "data\0"
+#define QUERY_CMD_DATA_LEN     5
+
+/**
+ * aa_write_access - generic permissions and data query
+ * @file: pointer to open apparmorfs/access file
+ * @ubuf: user buffer containing the complete query string (NOT NULL)
+ * @count: size of ubuf
+ * @ppos: position in the file (MUST BE ZERO)
+ *
+ * Allows for one permissions or data query per open(), write(), and read()
+ * sequence. The only queries currently supported are label-based queries for
+ * permissions or data.
+ *
+ * For permissions queries, ubuf must begin with "label\0", followed by the
+ * profile query specific format described in the query_label() function
+ * documentation.
+ *
+ * For data queries, ubuf must have the form "data\0<LABEL>\0<KEY>\0", where
+ * <LABEL> is the name of the security confinement context and <KEY> is the
+ * name of the data to retrieve.
+ *
+ * Returns: number of bytes written or -errno on failure
+ */
+static ssize_t aa_write_access(struct file *file, const char __user *ubuf,
+                              size_t count, loff_t *ppos)
+{
+       char *buf;
+       ssize_t len;
+
+       if (*ppos)
+               return -ESPIPE;
+
+       buf = simple_transaction_get(file, ubuf, count);
+       if (IS_ERR(buf))
+               return PTR_ERR(buf);
+
+       if (count > QUERY_CMD_DATA_LEN &&
+                  !memcmp(buf, QUERY_CMD_DATA, QUERY_CMD_DATA_LEN)) {
+               len = query_data(buf, SIMPLE_TRANSACTION_LIMIT,
+                                buf + QUERY_CMD_DATA_LEN,
+                                count - QUERY_CMD_DATA_LEN);
+       } else
+               len = -EINVAL;
+
+       if (len < 0)
+               return len;
+
+       simple_transaction_set(file, len);
+
+       return count;
+}
+
+static const struct file_operations aa_fs_access = {
+       .write          = aa_write_access,
+       .read           = simple_transaction_read,
+       .release        = simple_transaction_release,
+       .llseek         = generic_file_llseek,
+};
+
 static int aa_fs_seq_show(struct seq_file *seq, void *v)
 {
        struct aa_fs_entry *fs_file = seq->private;
@@ -227,12 +392,12 @@ const struct file_operations aa_fs_seq_file_ops = {
 static int aa_fs_seq_profile_open(struct inode *inode, struct file *file,
                                  int (*show)(struct seq_file *, void *))
 {
-       struct aa_replacedby *r = aa_get_replacedby(inode->i_private);
-       int error = single_open(file, show, r);
+       struct aa_proxy *proxy = aa_get_proxy(inode->i_private);
+       int error = single_open(file, show, proxy);
 
        if (error) {
                file->private_data = NULL;
-               aa_put_replacedby(r);
+               aa_put_proxy(proxy);
        }
 
        return error;
@@ -242,14 +407,14 @@ static int aa_fs_seq_profile_release(struct inode *inode, struct file *file)
 {
        struct seq_file *seq = (struct seq_file *) file->private_data;
        if (seq)
-               aa_put_replacedby(seq->private);
+               aa_put_proxy(seq->private);
        return single_release(inode, file);
 }
 
 static int aa_fs_seq_profname_show(struct seq_file *seq, void *v)
 {
-       struct aa_replacedby *r = seq->private;
-       struct aa_profile *profile = aa_get_profile_rcu(&r->profile);
+       struct aa_proxy *proxy = seq->private;
+       struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile);
        seq_printf(seq, "%s\n", profile->base.name);
        aa_put_profile(profile);
 
@@ -271,8 +436,8 @@ static const struct file_operations aa_fs_profname_fops = {
 
 static int aa_fs_seq_profmode_show(struct seq_file *seq, void *v)
 {
-       struct aa_replacedby *r = seq->private;
-       struct aa_profile *profile = aa_get_profile_rcu(&r->profile);
+       struct aa_proxy *proxy = seq->private;
+       struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile);
        seq_printf(seq, "%s\n", aa_profile_mode_names[profile->mode]);
        aa_put_profile(profile);
 
@@ -294,8 +459,8 @@ static const struct file_operations aa_fs_profmode_fops = {
 
 static int aa_fs_seq_profattach_show(struct seq_file *seq, void *v)
 {
-       struct aa_replacedby *r = seq->private;
-       struct aa_profile *profile = aa_get_profile_rcu(&r->profile);
+       struct aa_proxy *proxy = seq->private;
+       struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile);
        if (profile->attach)
                seq_printf(seq, "%s\n", profile->attach);
        else if (profile->xmatch)
@@ -322,8 +487,8 @@ static const struct file_operations aa_fs_profattach_fops = {
 
 static int aa_fs_seq_hash_show(struct seq_file *seq, void *v)
 {
-       struct aa_replacedby *r = seq->private;
-       struct aa_profile *profile = aa_get_profile_rcu(&r->profile);
+       struct aa_proxy *proxy = seq->private;
+       struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile);
        unsigned int i, size = aa_hash_size();
 
        if (profile->hash) {
@@ -349,6 +514,145 @@ static const struct file_operations aa_fs_seq_hash_fops = {
        .release        = single_release,
 };
 
+
+static int aa_fs_seq_show_ns_level(struct seq_file *seq, void *v)
+{
+       struct aa_ns *ns = aa_current_profile()->ns;
+
+       seq_printf(seq, "%d\n", ns->level);
+
+       return 0;
+}
+
+static int aa_fs_seq_open_ns_level(struct inode *inode, struct file *file)
+{
+       return single_open(file, aa_fs_seq_show_ns_level, inode->i_private);
+}
+
+static const struct file_operations aa_fs_ns_level = {
+       .owner          = THIS_MODULE,
+       .open           = aa_fs_seq_open_ns_level,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int aa_fs_seq_show_ns_name(struct seq_file *seq, void *v)
+{
+       struct aa_ns *ns = aa_current_profile()->ns;
+
+       seq_printf(seq, "%s\n", ns->base.name);
+
+       return 0;
+}
+
+static int aa_fs_seq_open_ns_name(struct inode *inode, struct file *file)
+{
+       return single_open(file, aa_fs_seq_show_ns_name, inode->i_private);
+}
+
+static const struct file_operations aa_fs_ns_name = {
+       .owner          = THIS_MODULE,
+       .open           = aa_fs_seq_open_ns_name,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int rawdata_release(struct inode *inode, struct file *file)
+{
+       /* TODO: switch to loaddata when profile switched to symlink */
+       aa_put_loaddata(file->private_data);
+
+       return 0;
+}
+
+static int aa_fs_seq_raw_abi_show(struct seq_file *seq, void *v)
+{
+       struct aa_proxy *proxy = seq->private;
+       struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile);
+
+       if (profile->rawdata->abi) {
+               seq_printf(seq, "v%d", profile->rawdata->abi);
+               seq_puts(seq, "\n");
+       }
+       aa_put_profile(profile);
+
+       return 0;
+}
+
+static int aa_fs_seq_raw_abi_open(struct inode *inode, struct file *file)
+{
+       return aa_fs_seq_profile_open(inode, file, aa_fs_seq_raw_abi_show);
+}
+
+static const struct file_operations aa_fs_seq_raw_abi_fops = {
+       .owner          = THIS_MODULE,
+       .open           = aa_fs_seq_raw_abi_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = aa_fs_seq_profile_release,
+};
+
+static int aa_fs_seq_raw_hash_show(struct seq_file *seq, void *v)
+{
+       struct aa_proxy *proxy = seq->private;
+       struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile);
+       unsigned int i, size = aa_hash_size();
+
+       if (profile->rawdata->hash) {
+               for (i = 0; i < size; i++)
+                       seq_printf(seq, "%.2x", profile->rawdata->hash[i]);
+               seq_puts(seq, "\n");
+       }
+       aa_put_profile(profile);
+
+       return 0;
+}
+
+static int aa_fs_seq_raw_hash_open(struct inode *inode, struct file *file)
+{
+       return aa_fs_seq_profile_open(inode, file, aa_fs_seq_raw_hash_show);
+}
+
+static const struct file_operations aa_fs_seq_raw_hash_fops = {
+       .owner          = THIS_MODULE,
+       .open           = aa_fs_seq_raw_hash_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = aa_fs_seq_profile_release,
+};
+
+static ssize_t rawdata_read(struct file *file, char __user *buf, size_t size,
+                           loff_t *ppos)
+{
+       struct aa_loaddata *rawdata = file->private_data;
+
+       return simple_read_from_buffer(buf, size, ppos, rawdata->data,
+                                      rawdata->size);
+}
+
+static int rawdata_open(struct inode *inode, struct file *file)
+{
+       struct aa_proxy *proxy = inode->i_private;
+       struct aa_profile *profile;
+
+       if (!policy_view_capable(NULL))
+               return -EACCES;
+       profile = aa_get_profile_rcu(&proxy->profile);
+       file->private_data = aa_get_loaddata(profile->rawdata);
+       aa_put_profile(profile);
+
+       return 0;
+}
+
+static const struct file_operations aa_fs_rawdata_fops = {
+       .open = rawdata_open,
+       .read = rawdata_read,
+       .llseek = generic_file_llseek,
+       .release = rawdata_release,
+};
+
 /** fns to setup dynamic per profile/namespace files **/
 void __aa_fs_profile_rmdir(struct aa_profile *profile)
 {
@@ -362,13 +666,13 @@ void __aa_fs_profile_rmdir(struct aa_profile *profile)
                __aa_fs_profile_rmdir(child);
 
        for (i = AAFS_PROF_SIZEOF - 1; i >= 0; --i) {
-               struct aa_replacedby *r;
+               struct aa_proxy *proxy;
                if (!profile->dents[i])
                        continue;
 
-               r = d_inode(profile->dents[i])->i_private;
+               proxy = d_inode(profile->dents[i])->i_private;
                securityfs_remove(profile->dents[i]);
-               aa_put_replacedby(r);
+               aa_put_proxy(proxy);
                profile->dents[i] = NULL;
        }
 }
@@ -390,12 +694,12 @@ static struct dentry *create_profile_file(struct dentry *dir, const char *name,
                                          struct aa_profile *profile,
                                          const struct file_operations *fops)
 {
-       struct aa_replacedby *r = aa_get_replacedby(profile->replacedby);
+       struct aa_proxy *proxy = aa_get_proxy(profile->proxy);
        struct dentry *dent;
 
-       dent = securityfs_create_file(name, S_IFREG | 0444, dir, r, fops);
+       dent = securityfs_create_file(name, S_IFREG | 0444, dir, proxy, fops);
        if (IS_ERR(dent))
-               aa_put_replacedby(r);
+               aa_put_proxy(proxy);
 
        return dent;
 }
@@ -460,6 +764,29 @@ int __aa_fs_profile_mkdir(struct aa_profile *profile, struct dentry *parent)
                profile->dents[AAFS_PROF_HASH] = dent;
        }
 
+       if (profile->rawdata) {
+               dent = create_profile_file(dir, "raw_sha1", profile,
+                                          &aa_fs_seq_raw_hash_fops);
+               if (IS_ERR(dent))
+                       goto fail;
+               profile->dents[AAFS_PROF_RAW_HASH] = dent;
+
+               dent = create_profile_file(dir, "raw_abi", profile,
+                                          &aa_fs_seq_raw_abi_fops);
+               if (IS_ERR(dent))
+                       goto fail;
+               profile->dents[AAFS_PROF_RAW_ABI] = dent;
+
+               dent = securityfs_create_file("raw_data", S_IFREG | 0444, dir,
+                                             profile->proxy,
+                                             &aa_fs_rawdata_fops);
+               if (IS_ERR(dent))
+                       goto fail;
+               profile->dents[AAFS_PROF_RAW_DATA] = dent;
+               d_inode(dent)->i_size = profile->rawdata->size;
+               aa_get_proxy(profile->proxy);
+       }
+
        list_for_each_entry(child, &profile->base.profiles, base.list) {
                error = __aa_fs_profile_mkdir(child, prof_child_dir(profile));
                if (error)
@@ -477,9 +804,9 @@ fail2:
        return error;
 }
 
-void __aa_fs_namespace_rmdir(struct aa_namespace *ns)
+void __aa_fs_ns_rmdir(struct aa_ns *ns)
 {
-       struct aa_namespace *sub;
+       struct aa_ns *sub;
        struct aa_profile *child;
        int i;
 
@@ -491,51 +818,116 @@ void __aa_fs_namespace_rmdir(struct aa_namespace *ns)
 
        list_for_each_entry(sub, &ns->sub_ns, base.list) {
                mutex_lock(&sub->lock);
-               __aa_fs_namespace_rmdir(sub);
+               __aa_fs_ns_rmdir(sub);
                mutex_unlock(&sub->lock);
        }
 
+       if (ns_subns_dir(ns)) {
+               sub = d_inode(ns_subns_dir(ns))->i_private;
+               aa_put_ns(sub);
+       }
+       if (ns_subload(ns)) {
+               sub = d_inode(ns_subload(ns))->i_private;
+               aa_put_ns(sub);
+       }
+       if (ns_subreplace(ns)) {
+               sub = d_inode(ns_subreplace(ns))->i_private;
+               aa_put_ns(sub);
+       }
+       if (ns_subremove(ns)) {
+               sub = d_inode(ns_subremove(ns))->i_private;
+               aa_put_ns(sub);
+       }
+
        for (i = AAFS_NS_SIZEOF - 1; i >= 0; --i) {
                securityfs_remove(ns->dents[i]);
                ns->dents[i] = NULL;
        }
 }
 
-int __aa_fs_namespace_mkdir(struct aa_namespace *ns, struct dentry *parent,
-                           const char *name)
+/* assumes cleanup in caller */
+static int __aa_fs_ns_mkdir_entries(struct aa_ns *ns, struct dentry *dir)
+{
+       struct dentry *dent;
+
+       AA_BUG(!ns);
+       AA_BUG(!dir);
+
+       dent = securityfs_create_dir("profiles", dir);
+       if (IS_ERR(dent))
+               return PTR_ERR(dent);
+       ns_subprofs_dir(ns) = dent;
+
+       dent = securityfs_create_dir("raw_data", dir);
+       if (IS_ERR(dent))
+               return PTR_ERR(dent);
+       ns_subdata_dir(ns) = dent;
+
+       dent = securityfs_create_file(".load", 0640, dir, ns,
+                                     &aa_fs_profile_load);
+       if (IS_ERR(dent))
+               return PTR_ERR(dent);
+       aa_get_ns(ns);
+       ns_subload(ns) = dent;
+
+       dent = securityfs_create_file(".replace", 0640, dir, ns,
+                                     &aa_fs_profile_replace);
+       if (IS_ERR(dent))
+               return PTR_ERR(dent);
+       aa_get_ns(ns);
+       ns_subreplace(ns) = dent;
+
+       dent = securityfs_create_file(".remove", 0640, dir, ns,
+                                     &aa_fs_profile_remove);
+       if (IS_ERR(dent))
+               return PTR_ERR(dent);
+       aa_get_ns(ns);
+       ns_subremove(ns) = dent;
+
+       dent = securityfs_create_dir("namespaces", dir);
+       if (IS_ERR(dent))
+               return PTR_ERR(dent);
+       aa_get_ns(ns);
+       ns_subns_dir(ns) = dent;
+
+       return 0;
+}
+
+int __aa_fs_ns_mkdir(struct aa_ns *ns, struct dentry *parent, const char *name)
 {
-       struct aa_namespace *sub;
+       struct aa_ns *sub;
        struct aa_profile *child;
        struct dentry *dent, *dir;
        int error;
 
+       AA_BUG(!ns);
+       AA_BUG(!parent);
+       AA_BUG(!mutex_is_locked(&ns->lock));
+
        if (!name)
                name = ns->base.name;
 
+       /* create ns dir if it doesn't already exist */
        dent = securityfs_create_dir(name, parent);
        if (IS_ERR(dent))
                goto fail;
-       ns_dir(ns) = dir = dent;
 
-       dent = securityfs_create_dir("profiles", dir);
-       if (IS_ERR(dent))
-               goto fail;
-       ns_subprofs_dir(ns) = dent;
-
-       dent = securityfs_create_dir("namespaces", dir);
-       if (IS_ERR(dent))
-               goto fail;
-       ns_subns_dir(ns) = dent;
+       ns_dir(ns) = dir = dent;
+       error = __aa_fs_ns_mkdir_entries(ns, dir);
+       if (error)
+               goto fail2;
 
+       /* profiles */
        list_for_each_entry(child, &ns->base.profiles, base.list) {
                error = __aa_fs_profile_mkdir(child, ns_subprofs_dir(ns));
                if (error)
                        goto fail2;
        }
 
+       /* subnamespaces */
        list_for_each_entry(sub, &ns->sub_ns, base.list) {
                mutex_lock(&sub->lock);
-               error = __aa_fs_namespace_mkdir(sub, ns_subns_dir(ns), NULL);
+               error = __aa_fs_ns_mkdir(sub, ns_subns_dir(ns), NULL);
                mutex_unlock(&sub->lock);
                if (error)
                        goto fail2;
@@ -547,7 +939,7 @@ fail:
        error = PTR_ERR(dent);
 
 fail2:
-       __aa_fs_namespace_rmdir(ns);
+       __aa_fs_ns_rmdir(ns);
 
        return error;
 }
@@ -556,7 +948,7 @@ fail2:
 #define list_entry_is_head(pos, head, member) (&pos->member == (head))
 
 /**
- * __next_namespace - find the next namespace to list
+ * __next_ns - find the next namespace to list
  * @root: root namespace to stop search at (NOT NULL)
  * @ns: current ns position (NOT NULL)
  *
@@ -567,10 +959,9 @@ fail2:
  * Requires: ns->parent->lock to be held
  * NOTE: will not unlock root->lock
  */
-static struct aa_namespace *__next_namespace(struct aa_namespace *root,
-                                            struct aa_namespace *ns)
+static struct aa_ns *__next_ns(struct aa_ns *root, struct aa_ns *ns)
 {
-       struct aa_namespace *parent, *next;
+       struct aa_ns *parent, *next;
 
        /* is next namespace a child */
        if (!list_empty(&ns->sub_ns)) {
@@ -603,10 +994,10 @@ static struct aa_namespace *__next_namespace(struct aa_namespace *root,
  * Returns: unrefcounted profile or NULL if no profile
  * Requires: profile->ns.lock to be held
  */
-static struct aa_profile *__first_profile(struct aa_namespace *root,
-                                         struct aa_namespace *ns)
+static struct aa_profile *__first_profile(struct aa_ns *root,
+                                         struct aa_ns *ns)
 {
-       for (; ns; ns = __next_namespace(root, ns)) {
+       for (; ns; ns = __next_ns(root, ns)) {
                if (!list_empty(&ns->base.profiles))
                        return list_first_entry(&ns->base.profiles,
                                                struct aa_profile, base.list);
@@ -626,7 +1017,7 @@ static struct aa_profile *__first_profile(struct aa_namespace *root,
 static struct aa_profile *__next_profile(struct aa_profile *p)
 {
        struct aa_profile *parent;
-       struct aa_namespace *ns = p->ns;
+       struct aa_ns *ns = p->ns;
 
        /* is next profile a child */
        if (!list_empty(&p->base.profiles))
@@ -660,7 +1051,7 @@ static struct aa_profile *__next_profile(struct aa_profile *p)
  *
  * Returns: next profile or NULL if there isn't one
  */
-static struct aa_profile *next_profile(struct aa_namespace *root,
+static struct aa_profile *next_profile(struct aa_ns *root,
                                       struct aa_profile *profile)
 {
        struct aa_profile *next = __next_profile(profile);
@@ -668,7 +1059,7 @@ static struct aa_profile *next_profile(struct aa_namespace *root,
                return next;
 
        /* finished all profiles in namespace move to next namespace */
-       return __first_profile(root, __next_namespace(root, profile->ns));
+       return __first_profile(root, __next_ns(root, profile->ns));
 }
 
 /**
@@ -683,9 +1074,9 @@ static struct aa_profile *next_profile(struct aa_namespace *root,
 static void *p_start(struct seq_file *f, loff_t *pos)
 {
        struct aa_profile *profile = NULL;
-       struct aa_namespace *root = aa_current_profile()->ns;
+       struct aa_ns *root = aa_current_profile()->ns;
        loff_t l = *pos;
-       f->private = aa_get_namespace(root);
+       f->private = aa_get_ns(root);
 
 
        /* find the first profile */
@@ -712,7 +1103,7 @@ static void *p_start(struct seq_file *f, loff_t *pos)
 static void *p_next(struct seq_file *f, void *p, loff_t *pos)
 {
        struct aa_profile *profile = p;
-       struct aa_namespace *ns = f->private;
+       struct aa_ns *ns = f->private;
        (*pos)++;
 
        return next_profile(ns, profile);
@@ -728,14 +1119,14 @@ static void *p_next(struct seq_file *f, void *p, loff_t *pos)
 static void p_stop(struct seq_file *f, void *p)
 {
        struct aa_profile *profile = p;
-       struct aa_namespace *root = f->private, *ns;
+       struct aa_ns *root = f->private, *ns;
 
        if (profile) {
                for (ns = profile->ns; ns && ns != root; ns = ns->parent)
                        mutex_unlock(&ns->lock);
        }
        mutex_unlock(&root->lock);
-       aa_put_namespace(root);
+       aa_put_ns(root);
 }
 
 /**
@@ -748,10 +1139,10 @@ static void p_stop(struct seq_file *f, void *p)
 static int seq_show_profile(struct seq_file *f, void *p)
 {
        struct aa_profile *profile = (struct aa_profile *)p;
-       struct aa_namespace *root = f->private;
+       struct aa_ns *root = f->private;
 
        if (profile->ns != root)
-               seq_printf(f, ":%s://", aa_ns_name(root, profile->ns));
+               seq_printf(f, ":%s://", aa_ns_name(root, profile->ns, true));
        seq_printf(f, "%s (%s)\n", profile->base.hname,
                   aa_profile_mode_names[profile->mode]);
 
@@ -767,6 +1158,9 @@ static const struct seq_operations aa_fs_profiles_op = {
 
 static int profiles_open(struct inode *inode, struct file *file)
 {
+       if (!policy_view_capable(NULL))
+               return -EACCES;
+
        return seq_open(file, &aa_fs_profiles_op);
 }
 
@@ -795,12 +1189,20 @@ static struct aa_fs_entry aa_fs_entry_domain[] = {
        AA_FS_FILE_BOOLEAN("change_hatv",       1),
        AA_FS_FILE_BOOLEAN("change_onexec",     1),
        AA_FS_FILE_BOOLEAN("change_profile",    1),
+       AA_FS_FILE_BOOLEAN("fix_binfmt_elf_mmap",       1),
+       AA_FS_FILE_STRING("version", "1.2"),
+       { }
+};
+
+static struct aa_fs_entry aa_fs_entry_versions[] = {
+       AA_FS_FILE_BOOLEAN("v5",        1),
        { }
 };
 
 static struct aa_fs_entry aa_fs_entry_policy[] = {
-       AA_FS_FILE_BOOLEAN("set_load",          1),
-       {}
+       AA_FS_DIR("versions",                   aa_fs_entry_versions),
+       AA_FS_FILE_BOOLEAN("set_load",          1),
+       { }
 };
 
 static struct aa_fs_entry aa_fs_entry_features[] = {
@@ -814,10 +1216,10 @@ static struct aa_fs_entry aa_fs_entry_features[] = {
 };
 
 static struct aa_fs_entry aa_fs_entry_apparmor[] = {
-       AA_FS_FILE_FOPS(".load", 0640, &aa_fs_profile_load),
-       AA_FS_FILE_FOPS(".replace", 0640, &aa_fs_profile_replace),
-       AA_FS_FILE_FOPS(".remove", 0640, &aa_fs_profile_remove),
-       AA_FS_FILE_FOPS("profiles", 0640, &aa_fs_profiles_fops),
+       AA_FS_FILE_FOPS(".access", 0640, &aa_fs_access),
+       AA_FS_FILE_FOPS(".ns_level", 0666, &aa_fs_ns_level),
+       AA_FS_FILE_FOPS(".ns_name", 0640, &aa_fs_ns_name),
+       AA_FS_FILE_FOPS("profiles", 0440, &aa_fs_profiles_fops),
        AA_FS_DIR("features", aa_fs_entry_features),
        { }
 };
@@ -926,6 +1328,52 @@ void __init aa_destroy_aafs(void)
        aafs_remove_dir(&aa_fs_entry);
 }
 
+
+#define NULL_FILE_NAME ".null"
+struct path aa_null;
+
+static int aa_mk_null_file(struct dentry *parent)
+{
+       struct vfsmount *mount = NULL;
+       struct dentry *dentry;
+       struct inode *inode;
+       int count = 0;
+       int error = simple_pin_fs(parent->d_sb->s_type, &mount, &count);
+
+       if (error)
+               return error;
+
+       inode_lock(d_inode(parent));
+       dentry = lookup_one_len(NULL_FILE_NAME, parent, strlen(NULL_FILE_NAME));
+       if (IS_ERR(dentry)) {
+               error = PTR_ERR(dentry);
+               goto out;
+       }
+       inode = new_inode(parent->d_inode->i_sb);
+       if (!inode) {
+               error = -ENOMEM;
+               goto out1;
+       }
+
+       inode->i_ino = get_next_ino();
+       inode->i_mode = S_IFCHR | S_IRUGO | S_IWUGO;
+       inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+       init_special_inode(inode, S_IFCHR | S_IRUGO | S_IWUGO,
+                          MKDEV(MEM_MAJOR, 3));
+       d_instantiate(dentry, inode);
+       aa_null.dentry = dget(dentry);
+       aa_null.mnt = mntget(mount);
+
+       error = 0;
+
+out1:
+       dput(dentry);
+out:
+       inode_unlock(d_inode(parent));
+       simple_release_fs(&mount, &count);
+       return error;
+}
+
 /**
  * aa_create_aafs - create the apparmor security filesystem
  *
@@ -935,6 +1383,7 @@ void __init aa_destroy_aafs(void)
  */
 static int __init aa_create_aafs(void)
 {
+       struct dentry *dent;
        int error;
 
        if (!apparmor_initialized)
@@ -950,12 +1399,42 @@ static int __init aa_create_aafs(void)
        if (error)
                goto error;
 
-       error = __aa_fs_namespace_mkdir(root_ns, aa_fs_entry.dentry,
-                                       "policy");
+       dent = securityfs_create_file(".load", 0666, aa_fs_entry.dentry,
+                                     NULL, &aa_fs_profile_load);
+       if (IS_ERR(dent)) {
+               error = PTR_ERR(dent);
+               goto error;
+       }
+       ns_subload(root_ns) = dent;
+
+       dent = securityfs_create_file(".replace", 0666, aa_fs_entry.dentry,
+                                     NULL, &aa_fs_profile_replace);
+       if (IS_ERR(dent)) {
+               error = PTR_ERR(dent);
+               goto error;
+       }
+       ns_subreplace(root_ns) = dent;
+
+       dent = securityfs_create_file(".remove", 0666, aa_fs_entry.dentry,
+                                     NULL, &aa_fs_profile_remove);
+       if (IS_ERR(dent)) {
+               error = PTR_ERR(dent);
+               goto error;
+       }
+       ns_subremove(root_ns) = dent;
+
+       mutex_lock(&root_ns->lock);
+       error = __aa_fs_ns_mkdir(root_ns, aa_fs_entry.dentry, "policy");
+       mutex_unlock(&root_ns->lock);
+
+       if (error)
+               goto error;
+
+       error = aa_mk_null_file(aa_fs_entry.dentry);
        if (error)
                goto error;
 
-       /* TODO: add support for apparmorfs_null and apparmorfs_mnt */
+       /* TODO: add default profile to apparmorfs */
 
        /* Report that AppArmor fs is enabled */
        aa_info_message("AppArmor Filesystem Enabled");
index 3a7f1da1425ec34f944b50a70d03963e4db4a1dd..87f40fa8c431c93fb63b61025d263fa9e11b86fd 100644 (file)
 #include "include/apparmor.h"
 #include "include/audit.h"
 #include "include/policy.h"
+#include "include/policy_ns.h"
 
-const char *const op_table[] = {
-       "null",
-
-       "sysctl",
-       "capable",
-
-       "unlink",
-       "mkdir",
-       "rmdir",
-       "mknod",
-       "truncate",
-       "link",
-       "symlink",
-       "rename_src",
-       "rename_dest",
-       "chmod",
-       "chown",
-       "getattr",
-       "open",
-
-       "file_perm",
-       "file_lock",
-       "file_mmap",
-       "file_mprotect",
-
-       "create",
-       "post_create",
-       "bind",
-       "connect",
-       "listen",
-       "accept",
-       "sendmsg",
-       "recvmsg",
-       "getsockname",
-       "getpeername",
-       "getsockopt",
-       "setsockopt",
-       "socket_shutdown",
-
-       "ptrace",
-
-       "exec",
-       "change_hat",
-       "change_profile",
-       "change_onexec",
-
-       "setprocattr",
-       "setrlimit",
-
-       "profile_replace",
-       "profile_load",
-       "profile_remove"
-};
 
 const char *const audit_mode_names[] = {
        "normal",
@@ -114,23 +62,23 @@ static void audit_pre(struct audit_buffer *ab, void *ca)
 
        if (aa_g_audit_header) {
                audit_log_format(ab, "apparmor=");
-               audit_log_string(ab, aa_audit_type[sa->aad->type]);
+               audit_log_string(ab, aa_audit_type[aad(sa)->type]);
        }
 
-       if (sa->aad->op) {
+       if (aad(sa)->op) {
                audit_log_format(ab, " operation=");
-               audit_log_string(ab, op_table[sa->aad->op]);
+               audit_log_string(ab, aad(sa)->op);
        }
 
-       if (sa->aad->info) {
+       if (aad(sa)->info) {
                audit_log_format(ab, " info=");
-               audit_log_string(ab, sa->aad->info);
-               if (sa->aad->error)
-                       audit_log_format(ab, " error=%d", sa->aad->error);
+               audit_log_string(ab, aad(sa)->info);
+               if (aad(sa)->error)
+                       audit_log_format(ab, " error=%d", aad(sa)->error);
        }
 
-       if (sa->aad->profile) {
-               struct aa_profile *profile = sa->aad->profile;
+       if (aad(sa)->profile) {
+               struct aa_profile *profile = aad(sa)->profile;
                if (profile->ns != root_ns) {
                        audit_log_format(ab, " namespace=");
                        audit_log_untrustedstring(ab, profile->ns->base.hname);
@@ -139,9 +87,9 @@ static void audit_pre(struct audit_buffer *ab, void *ca)
                audit_log_untrustedstring(ab, profile->base.hname);
        }
 
-       if (sa->aad->name) {
+       if (aad(sa)->name) {
                audit_log_format(ab, " name=");
-               audit_log_untrustedstring(ab, sa->aad->name);
+               audit_log_untrustedstring(ab, aad(sa)->name);
        }
 }
 
@@ -153,7 +101,7 @@ static void audit_pre(struct audit_buffer *ab, void *ca)
 void aa_audit_msg(int type, struct common_audit_data *sa,
                  void (*cb) (struct audit_buffer *, void *))
 {
-       sa->aad->type = type;
+       aad(sa)->type = type;
        common_lsm_audit(sa, audit_pre, cb);
 }
 
@@ -161,7 +109,6 @@ void aa_audit_msg(int type, struct common_audit_data *sa,
  * aa_audit - Log a profile based audit event to the audit subsystem
  * @type: audit type for the message
  * @profile: profile to check against (NOT NULL)
- * @gfp: allocation flags to use
  * @sa: audit event (NOT NULL)
  * @cb: optional callback fn for type specific fields (MAYBE NULL)
  *
@@ -169,14 +116,13 @@ void aa_audit_msg(int type, struct common_audit_data *sa,
  *
  * Returns: error on failure
  */
-int aa_audit(int type, struct aa_profile *profile, gfp_t gfp,
-            struct common_audit_data *sa,
+int aa_audit(int type, struct aa_profile *profile, struct common_audit_data *sa,
             void (*cb) (struct audit_buffer *, void *))
 {
-       BUG_ON(!profile);
+       AA_BUG(!profile);
 
        if (type == AUDIT_APPARMOR_AUTO) {
-               if (likely(!sa->aad->error)) {
+               if (likely(!aad(sa)->error)) {
                        if (AUDIT_MODE(profile) != AUDIT_ALL)
                                return 0;
                        type = AUDIT_APPARMOR_AUDIT;
@@ -188,23 +134,23 @@ int aa_audit(int type, struct aa_profile *profile, gfp_t gfp,
        if (AUDIT_MODE(profile) == AUDIT_QUIET ||
            (type == AUDIT_APPARMOR_DENIED &&
             AUDIT_MODE(profile) == AUDIT_QUIET))
-               return sa->aad->error;
+               return aad(sa)->error;
 
        if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED)
                type = AUDIT_APPARMOR_KILL;
 
        if (!unconfined(profile))
-               sa->aad->profile = profile;
+               aad(sa)->profile = profile;
 
        aa_audit_msg(type, sa, cb);
 
-       if (sa->aad->type == AUDIT_APPARMOR_KILL)
+       if (aad(sa)->type == AUDIT_APPARMOR_KILL)
                (void)send_sig_info(SIGKILL, NULL,
                        sa->type == LSM_AUDIT_DATA_TASK && sa->u.tsk ?
                                    sa->u.tsk : current);
 
-       if (sa->aad->type == AUDIT_APPARMOR_ALLOWED)
-               return complain_error(sa->aad->error);
+       if (aad(sa)->type == AUDIT_APPARMOR_ALLOWED)
+               return complain_error(aad(sa)->error);
 
-       return sa->aad->error;
+       return aad(sa)->error;
 }
index 1101c6f64bb7cb36602957ef2bcbc1538ee8aa63..ed0a3e6b8022de59e523730454e97fbd0d74ec0b 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/capability.h>
 #include <linux/errno.h>
 #include <linux/gfp.h>
+#include <linux/security.h>
 
 #include "include/apparmor.h"
 #include "include/capability.h"
@@ -55,6 +56,7 @@ static void audit_cb(struct audit_buffer *ab, void *va)
  * audit_caps - audit a capability
  * @profile: profile being tested for confinement (NOT NULL)
  * @cap: capability tested
+ @audit: whether an audit record should be generated
  * @error: error code returned by test
  *
  * Do auditing of capability and handle, audit/complain/kill modes switching
@@ -62,17 +64,16 @@ static void audit_cb(struct audit_buffer *ab, void *va)
  *
  * Returns: 0 or sa->error on success,  error code on failure
  */
-static int audit_caps(struct aa_profile *profile, int cap, int error)
+static int audit_caps(struct aa_profile *profile, int cap, int audit,
+                     int error)
 {
        struct audit_cache *ent;
        int type = AUDIT_APPARMOR_AUTO;
-       struct common_audit_data sa;
-       struct apparmor_audit_data aad = {0,};
-       sa.type = LSM_AUDIT_DATA_CAP;
-       sa.aad = &aad;
+       DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_CAP, OP_CAPABLE);
        sa.u.cap = cap;
-       sa.aad->op = OP_CAPABLE;
-       sa.aad->error = error;
+       aad(&sa)->error = error;
+       if (audit == SECURITY_CAP_NOAUDIT)
+               aad(&sa)->info = "optional: no audit";
 
        if (likely(!error)) {
                /* test if auditing is being forced */
@@ -104,7 +105,7 @@ static int audit_caps(struct aa_profile *profile, int cap, int error)
        }
        put_cpu_var(audit_cache);
 
-       return aa_audit(type, profile, GFP_ATOMIC, &sa, audit_cb);
+       return aa_audit(type, profile, &sa, audit_cb);
 }
 
 /**
@@ -133,11 +134,10 @@ int aa_capable(struct aa_profile *profile, int cap, int audit)
 {
        int error = profile_capable(profile, cap);
 
-       if (!audit) {
-               if (COMPLAIN_MODE(profile))
-                       return complain_error(error);
-               return error;
+       if (audit == SECURITY_CAP_NOAUDIT) {
+               if (!COMPLAIN_MODE(profile))
+                       return error;
        }
 
-       return audit_caps(profile, cap, error);
+       return audit_caps(profile, cap, audit, error);
 }
index 3064c6ced87cae69b8c2eb224e4d2ac5af9d9c79..1fc16b88efbf7543b424effd19231b08bf7ab824 100644 (file)
  * License.
  *
  *
- * AppArmor sets confinement on every task, via the the aa_task_cxt and
- * the aa_task_cxt.profile, both of which are required and are not allowed
- * to be NULL.  The aa_task_cxt is not reference counted and is unique
+ * AppArmor sets confinement on every task, via the the aa_task_ctx and
+ * the aa_task_ctx.profile, both of which are required and are not allowed
+ * to be NULL.  The aa_task_ctx is not reference counted and is unique
  * to each cred (which is reference count).  The profile pointed to by
- * the task_cxt is reference counted.
+ * the task_ctx is reference counted.
  *
  * TODO
  * If a task uses change_hat it currently does not return to the old
 #include "include/policy.h"
 
 /**
- * aa_alloc_task_context - allocate a new task_cxt
+ * aa_alloc_task_context - allocate a new task_ctx
  * @flags: gfp flags for allocation
  *
  * Returns: allocated buffer or NULL on failure
  */
-struct aa_task_cxt *aa_alloc_task_context(gfp_t flags)
+struct aa_task_ctx *aa_alloc_task_context(gfp_t flags)
 {
-       return kzalloc(sizeof(struct aa_task_cxt), flags);
+       return kzalloc(sizeof(struct aa_task_ctx), flags);
 }
 
 /**
- * aa_free_task_context - free a task_cxt
- * @cxt: task_cxt to free (MAYBE NULL)
+ * aa_free_task_context - free a task_ctx
+ * @ctx: task_ctx to free (MAYBE NULL)
  */
-void aa_free_task_context(struct aa_task_cxt *cxt)
+void aa_free_task_context(struct aa_task_ctx *ctx)
 {
-       if (cxt) {
-               aa_put_profile(cxt->profile);
-               aa_put_profile(cxt->previous);
-               aa_put_profile(cxt->onexec);
+       if (ctx) {
+               aa_put_profile(ctx->profile);
+               aa_put_profile(ctx->previous);
+               aa_put_profile(ctx->onexec);
 
-               kzfree(cxt);
+               kzfree(ctx);
        }
 }
 
@@ -60,7 +60,7 @@ void aa_free_task_context(struct aa_task_cxt *cxt)
  * @new: a blank task context      (NOT NULL)
  * @old: the task context to copy  (NOT NULL)
  */
-void aa_dup_task_context(struct aa_task_cxt *new, const struct aa_task_cxt *old)
+void aa_dup_task_context(struct aa_task_ctx *new, const struct aa_task_ctx *old)
 {
        *new = *old;
        aa_get_profile(new->profile);
@@ -93,31 +93,36 @@ struct aa_profile *aa_get_task_profile(struct task_struct *task)
  */
 int aa_replace_current_profile(struct aa_profile *profile)
 {
-       struct aa_task_cxt *cxt = current_cxt();
+       struct aa_task_ctx *ctx = current_ctx();
        struct cred *new;
-       BUG_ON(!profile);
+       AA_BUG(!profile);
 
-       if (cxt->profile == profile)
+       if (ctx->profile == profile)
                return 0;
 
+       if (current_cred() != current_real_cred())
+               return -EBUSY;
+
        new  = prepare_creds();
        if (!new)
                return -ENOMEM;
 
-       cxt = cred_cxt(new);
-       if (unconfined(profile) || (cxt->profile->ns != profile->ns))
+       ctx = cred_ctx(new);
+       if (unconfined(profile) || (ctx->profile->ns != profile->ns))
                /* if switching to unconfined or a different profile namespace
                 * clear out context state
                 */
-               aa_clear_task_cxt_trans(cxt);
+               aa_clear_task_ctx_trans(ctx);
 
-       /* be careful switching cxt->profile, when racing replacement it
-        * is possible that cxt->profile->replacedby->profile is the reference
+       /*
+        * be careful switching ctx->profile, when racing replacement it
+        * is possible that ctx->profile->proxy->profile is the reference
         * keeping @profile valid, so make sure to get its reference before
-        * dropping the reference on cxt->profile */
+        * dropping the reference on ctx->profile
+        */
        aa_get_profile(profile);
-       aa_put_profile(cxt->profile);
-       cxt->profile = profile;
+       aa_put_profile(ctx->profile);
+       ctx->profile = profile;
 
        commit_creds(new);
        return 0;
@@ -131,15 +136,15 @@ int aa_replace_current_profile(struct aa_profile *profile)
  */
 int aa_set_current_onexec(struct aa_profile *profile)
 {
-       struct aa_task_cxt *cxt;
+       struct aa_task_ctx *ctx;
        struct cred *new = prepare_creds();
        if (!new)
                return -ENOMEM;
 
-       cxt = cred_cxt(new);
+       ctx = cred_ctx(new);
        aa_get_profile(profile);
-       aa_put_profile(cxt->onexec);
-       cxt->onexec = profile;
+       aa_put_profile(ctx->onexec);
+       ctx->onexec = profile;
 
        commit_creds(new);
        return 0;
@@ -157,28 +162,28 @@ int aa_set_current_onexec(struct aa_profile *profile)
  */
 int aa_set_current_hat(struct aa_profile *profile, u64 token)
 {
-       struct aa_task_cxt *cxt;
+       struct aa_task_ctx *ctx;
        struct cred *new = prepare_creds();
        if (!new)
                return -ENOMEM;
-       BUG_ON(!profile);
+       AA_BUG(!profile);
 
-       cxt = cred_cxt(new);
-       if (!cxt->previous) {
+       ctx = cred_ctx(new);
+       if (!ctx->previous) {
                /* transfer refcount */
-               cxt->previous = cxt->profile;
-               cxt->token = token;
-       } else if (cxt->token == token) {
-               aa_put_profile(cxt->profile);
+               ctx->previous = ctx->profile;
+               ctx->token = token;
+       } else if (ctx->token == token) {
+               aa_put_profile(ctx->profile);
        } else {
-               /* previous_profile && cxt->token != token */
+               /* previous_profile && ctx->token != token */
                abort_creds(new);
                return -EACCES;
        }
-       cxt->profile = aa_get_newest_profile(profile);
+       ctx->profile = aa_get_newest_profile(profile);
        /* clear exec on switching context */
-       aa_put_profile(cxt->onexec);
-       cxt->onexec = NULL;
+       aa_put_profile(ctx->onexec);
+       ctx->onexec = NULL;
 
        commit_creds(new);
        return 0;
@@ -195,27 +200,27 @@ int aa_set_current_hat(struct aa_profile *profile, u64 token)
  */
 int aa_restore_previous_profile(u64 token)
 {
-       struct aa_task_cxt *cxt;
+       struct aa_task_ctx *ctx;
        struct cred *new = prepare_creds();
        if (!new)
                return -ENOMEM;
 
-       cxt = cred_cxt(new);
-       if (cxt->token != token) {
+       ctx = cred_ctx(new);
+       if (ctx->token != token) {
                abort_creds(new);
                return -EACCES;
        }
        /* ignore restores when there is no saved profile */
-       if (!cxt->previous) {
+       if (!ctx->previous) {
                abort_creds(new);
                return 0;
        }
 
-       aa_put_profile(cxt->profile);
-       cxt->profile = aa_get_newest_profile(cxt->previous);
-       BUG_ON(!cxt->profile);
+       aa_put_profile(ctx->profile);
+       ctx->profile = aa_get_newest_profile(ctx->previous);
+       AA_BUG(!ctx->profile);
        /* clear exec && prev information when restoring to previous context */
-       aa_clear_task_cxt_trans(cxt);
+       aa_clear_task_ctx_trans(ctx);
 
        commit_creds(new);
        return 0;
index b75dab0df1cb2a7f60933ac7150933a6966a7017..de8dc78b61442c4a2c07adcdf2740a685dc08e70 100644 (file)
@@ -29,6 +29,43 @@ unsigned int aa_hash_size(void)
        return apparmor_hash_size;
 }
 
+char *aa_calc_hash(void *data, size_t len)
+{
+       struct {
+               struct shash_desc shash;
+               char ctx[crypto_shash_descsize(apparmor_tfm)];
+       } desc;
+       char *hash = NULL;
+       int error = -ENOMEM;
+
+       if (!apparmor_tfm)
+               return NULL;
+
+       hash = kzalloc(apparmor_hash_size, GFP_KERNEL);
+       if (!hash)
+               goto fail;
+
+       desc.shash.tfm = apparmor_tfm;
+       desc.shash.flags = 0;
+
+       error = crypto_shash_init(&desc.shash);
+       if (error)
+               goto fail;
+       error = crypto_shash_update(&desc.shash, (u8 *) data, len);
+       if (error)
+               goto fail;
+       error = crypto_shash_final(&desc.shash, hash);
+       if (error)
+               goto fail;
+
+       return hash;
+
+fail:
+       kfree(hash);
+
+       return ERR_PTR(error);
+}
+
 int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start,
                         size_t len)
 {
@@ -37,7 +74,7 @@ int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start,
                char ctx[crypto_shash_descsize(apparmor_tfm)];
        } desc;
        int error = -ENOMEM;
-       u32 le32_version = cpu_to_le32(version);
+       __le32 le32_version = cpu_to_le32(version);
 
        if (!aa_g_hash_policy)
                return 0;
index a4d90aa1045afc46499e00da9baf9bbcea34752a..ef4beef06e9d8f84e8b2364f286642452349bf00 100644 (file)
@@ -29,6 +29,7 @@
 #include "include/match.h"
 #include "include/path.h"
 #include "include/policy.h"
+#include "include/policy_ns.h"
 
 /**
  * aa_free_domain_entries - free entries in a domain table
@@ -93,7 +94,7 @@ out:
  * Returns: permission set
  */
 static struct file_perms change_profile_perms(struct aa_profile *profile,
-                                             struct aa_namespace *ns,
+                                             struct aa_ns *ns,
                                              const char *name, u32 request,
                                              unsigned int start)
 {
@@ -170,7 +171,7 @@ static struct aa_profile *__attach_match(const char *name,
  *
  * Returns: profile or NULL if no match found
  */
-static struct aa_profile *find_attach(struct aa_namespace *ns,
+static struct aa_profile *find_attach(struct aa_ns *ns,
                                      struct list_head *list, const char *name)
 {
        struct aa_profile *profile;
@@ -239,7 +240,7 @@ static const char *next_name(int xtype, const char *name)
 static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
 {
        struct aa_profile *new_profile = NULL;
-       struct aa_namespace *ns = profile->ns;
+       struct aa_ns *ns = profile->ns;
        u32 xtype = xindex & AA_X_TYPE_MASK;
        int index = xindex & AA_X_INDEX_MASK;
        const char *name;
@@ -247,7 +248,7 @@ static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
        /* index is guaranteed to be in range, validated at load time */
        for (name = profile->file.trans.table[index]; !new_profile && name;
             name = next_name(xtype, name)) {
-               struct aa_namespace *new_ns;
+               struct aa_ns *new_ns;
                const char *xname = NULL;
 
                new_ns = NULL;
@@ -267,7 +268,7 @@ static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
                                ;
                        }
                        /* released below */
-                       new_ns = aa_find_namespace(ns, ns_name);
+                       new_ns = aa_find_ns(ns, ns_name);
                        if (!new_ns)
                                continue;
                } else if (*name == '@') {
@@ -280,7 +281,7 @@ static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
 
                /* released by caller */
                new_profile = aa_lookup_profile(new_ns ? new_ns : ns, xname);
-               aa_put_namespace(new_ns);
+               aa_put_ns(new_ns);
        }
 
        /* released by caller */
@@ -301,7 +302,7 @@ static struct aa_profile *x_to_profile(struct aa_profile *profile,
                                       const char *name, u32 xindex)
 {
        struct aa_profile *new_profile = NULL;
-       struct aa_namespace *ns = profile->ns;
+       struct aa_ns *ns = profile->ns;
        u32 xtype = xindex & AA_X_TYPE_MASK;
 
        switch (xtype) {
@@ -336,9 +337,9 @@ static struct aa_profile *x_to_profile(struct aa_profile *profile,
  */
 int apparmor_bprm_set_creds(struct linux_binprm *bprm)
 {
-       struct aa_task_cxt *cxt;
+       struct aa_task_ctx *ctx;
        struct aa_profile *profile, *new_profile = NULL;
-       struct aa_namespace *ns;
+       struct aa_ns *ns;
        char *buffer = NULL;
        unsigned int state;
        struct file_perms perms = {};
@@ -352,10 +353,10 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
        if (bprm->cred_prepared)
                return 0;
 
-       cxt = cred_cxt(bprm->cred);
-       BUG_ON(!cxt);
+       ctx = cred_ctx(bprm->cred);
+       AA_BUG(!ctx);
 
-       profile = aa_get_newest_profile(cxt->profile);
+       profile = aa_get_newest_profile(ctx->profile);
        /*
         * get the namespace from the replacement profile as replacement
         * can change the namespace
@@ -379,9 +380,9 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
         */
        if (unconfined(profile)) {
                /* unconfined task */
-               if (cxt->onexec)
+               if (ctx->onexec)
                        /* change_profile on exec already been granted */
-                       new_profile = aa_get_profile(cxt->onexec);
+                       new_profile = aa_get_profile(ctx->onexec);
                else
                        new_profile = find_attach(ns, &ns->base.profiles, name);
                if (!new_profile)
@@ -396,10 +397,10 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
 
        /* find exec permissions for name */
        state = aa_str_perms(profile->file.dfa, state, name, &cond, &perms);
-       if (cxt->onexec) {
+       if (ctx->onexec) {
                struct file_perms cp;
                info = "change_profile onexec";
-               new_profile = aa_get_newest_profile(cxt->onexec);
+               new_profile = aa_get_newest_profile(ctx->onexec);
                if (!(perms.allow & AA_MAY_ONEXEC))
                        goto audit;
 
@@ -408,8 +409,8 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
                 * exec\0change_profile
                 */
                state = aa_dfa_null_transition(profile->file.dfa, state);
-               cp = change_profile_perms(profile, cxt->onexec->ns,
-                                         cxt->onexec->base.name,
+               cp = change_profile_perms(profile, ctx->onexec->ns,
+                                         ctx->onexec->base.name,
                                          AA_MAY_ONEXEC, state);
 
                if (!(cp.allow & AA_MAY_ONEXEC))
@@ -441,7 +442,8 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
                }
        } else if (COMPLAIN_MODE(profile)) {
                /* no exec permission - are we in learning mode */
-               new_profile = aa_new_null_profile(profile, 0);
+               new_profile = aa_new_null_profile(profile, false, name,
+                                                 GFP_ATOMIC);
                if (!new_profile) {
                        error = -ENOMEM;
                        info = "could not create null profile";
@@ -497,17 +499,16 @@ apply:
        bprm->per_clear |= PER_CLEAR_ON_SETID;
 
 x_clear:
-       aa_put_profile(cxt->profile);
-       /* transfer new profile reference will be released when cxt is freed */
-       cxt->profile = new_profile;
+       aa_put_profile(ctx->profile);
+       /* transfer new profile reference will be released when ctx is freed */
+       ctx->profile = new_profile;
        new_profile = NULL;
 
        /* clear out all temporary/transitional state from the context */
-       aa_clear_task_cxt_trans(cxt);
+       aa_clear_task_ctx_trans(ctx);
 
 audit:
-       error = aa_audit_file(profile, &perms, GFP_KERNEL, OP_EXEC, MAY_EXEC,
-                             name,
+       error = aa_audit_file(profile, &perms, OP_EXEC, MAY_EXEC, name,
                              new_profile ? new_profile->base.hname : NULL,
                              cond.uid, info, error);
 
@@ -543,17 +544,17 @@ int apparmor_bprm_secureexec(struct linux_binprm *bprm)
 void apparmor_bprm_committing_creds(struct linux_binprm *bprm)
 {
        struct aa_profile *profile = __aa_current_profile();
-       struct aa_task_cxt *new_cxt = cred_cxt(bprm->cred);
+       struct aa_task_ctx *new_ctx = cred_ctx(bprm->cred);
 
        /* bail out if unconfined or not changing profile */
-       if ((new_cxt->profile == profile) ||
-           (unconfined(new_cxt->profile)))
+       if ((new_ctx->profile == profile) ||
+           (unconfined(new_ctx->profile)))
                return;
 
        current->pdeath_signal = 0;
 
        /* reset soft limits and set hard limits for the new profile */
-       __aa_transition_rlimits(profile, new_cxt->profile);
+       __aa_transition_rlimits(profile, new_ctx->profile);
 }
 
 /**
@@ -602,7 +603,7 @@ static char *new_compound_name(const char *n1, const char *n2)
 int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)
 {
        const struct cred *cred;
-       struct aa_task_cxt *cxt;
+       struct aa_task_ctx *ctx;
        struct aa_profile *profile, *previous_profile, *hat = NULL;
        char *name = NULL;
        int i;
@@ -620,9 +621,9 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)
 
        /* released below */
        cred = get_current_cred();
-       cxt = cred_cxt(cred);
+       ctx = cred_ctx(cred);
        profile = aa_get_newest_profile(aa_cred_profile(cred));
-       previous_profile = aa_get_newest_profile(cxt->previous);
+       previous_profile = aa_get_newest_profile(ctx->previous);
 
        if (unconfined(profile)) {
                info = "unconfined";
@@ -666,7 +667,8 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)
                        aa_put_profile(root);
                        target = name;
                        /* released below */
-                       hat = aa_new_null_profile(profile, 1);
+                       hat = aa_new_null_profile(profile, true, hats[0],
+                                                 GFP_KERNEL);
                        if (!hat) {
                                info = "failed null profile create";
                                error = -ENOMEM;
@@ -711,9 +713,9 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)
 
 audit:
        if (!permtest)
-               error = aa_audit_file(profile, &perms, GFP_KERNEL,
-                                     OP_CHANGE_HAT, AA_MAY_CHANGEHAT, NULL,
-                                     target, GLOBAL_ROOT_UID, info, error);
+               error = aa_audit_file(profile, &perms, OP_CHANGE_HAT,
+                                     AA_MAY_CHANGEHAT, NULL, target,
+                                     GLOBAL_ROOT_UID, info, error);
 
 out:
        aa_put_profile(hat);
@@ -727,8 +729,7 @@ out:
 
 /**
  * aa_change_profile - perform a one-way profile transition
- * @ns_name: name of the profile namespace to change to (MAYBE NULL)
- * @hname: name of profile to change to (MAYBE NULL)
+ * @fqname: name of profile may include namespace (NOT NULL)
  * @onexec: whether this transition is to take place immediately or at exec
  * @permtest: true if this is just a permission test
  *
@@ -740,19 +741,20 @@ out:
  *
  * Returns %0 on success, error otherwise.
  */
-int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
-                     bool permtest)
+int aa_change_profile(const char *fqname, bool onexec,
+                     bool permtest, bool stack)
 {
        const struct cred *cred;
        struct aa_profile *profile, *target = NULL;
-       struct aa_namespace *ns = NULL;
        struct file_perms perms = {};
-       const char *name = NULL, *info = NULL;
-       int op, error = 0;
+       const char *info = NULL, *op;
+       int error = 0;
        u32 request;
 
-       if (!hname && !ns_name)
+       if (!fqname || !*fqname) {
+               AA_DEBUG("no profile name");
                return -EINVAL;
+       }
 
        if (onexec) {
                request = AA_MAY_ONEXEC;
@@ -777,44 +779,15 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
                return -EPERM;
        }
 
-       if (ns_name) {
-               /* released below */
-               ns = aa_find_namespace(profile->ns, ns_name);
-               if (!ns) {
-                       /* we don't create new namespace in complain mode */
-                       name = ns_name;
-                       info = "namespace not found";
-                       error = -ENOENT;
-                       goto audit;
-               }
-       } else
-               /* released below */
-               ns = aa_get_namespace(profile->ns);
-
-       /* if the name was not specified, use the name of the current profile */
-       if (!hname) {
-               if (unconfined(profile))
-                       hname = ns->unconfined->base.hname;
-               else
-                       hname = profile->base.hname;
-       }
-
-       perms = change_profile_perms(profile, ns, hname, request,
-                                    profile->file.start);
-       if (!(perms.allow & request)) {
-               error = -EACCES;
-               goto audit;
-       }
-
-       /* released below */
-       target = aa_lookup_profile(ns, hname);
+       target = aa_fqlookupn_profile(profile, fqname, strlen(fqname));
        if (!target) {
                info = "profile not found";
                error = -ENOENT;
                if (permtest || !COMPLAIN_MODE(profile))
                        goto audit;
                /* released below */
-               target = aa_new_null_profile(profile, 0);
+               target = aa_new_null_profile(profile, false, fqname,
+                                            GFP_KERNEL);
                if (!target) {
                        info = "failed null profile create";
                        error = -ENOMEM;
@@ -822,6 +795,13 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
                }
        }
 
+       perms = change_profile_perms(profile, target->ns, target->base.hname,
+                                    request, profile->file.start);
+       if (!(perms.allow & request)) {
+               error = -EACCES;
+               goto audit;
+       }
+
        /* check if tracing task is allowed to trace target domain */
        error = may_change_ptraced_domain(target);
        if (error) {
@@ -839,10 +819,9 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
 
 audit:
        if (!permtest)
-               error = aa_audit_file(profile, &perms, GFP_KERNEL, op, request,
-                                     name, hname, GLOBAL_ROOT_UID, info, error);
+               error = aa_audit_file(profile, &perms, op, request, NULL,
+                                     fqname, GLOBAL_ROOT_UID, info, error);
 
-       aa_put_namespace(ns);
        aa_put_profile(target);
        put_cred(cred);
 
index 4d2af4b01033fd40623172c988985fece9b4abde..750564c3ab7116e13b46693e6002e87bf6d90e7d 100644 (file)
@@ -67,24 +67,24 @@ static void file_audit_cb(struct audit_buffer *ab, void *va)
        struct common_audit_data *sa = va;
        kuid_t fsuid = current_fsuid();
 
-       if (sa->aad->fs.request & AA_AUDIT_FILE_MASK) {
+       if (aad(sa)->fs.request & AA_AUDIT_FILE_MASK) {
                audit_log_format(ab, " requested_mask=");
-               audit_file_mask(ab, sa->aad->fs.request);
+               audit_file_mask(ab, aad(sa)->fs.request);
        }
-       if (sa->aad->fs.denied & AA_AUDIT_FILE_MASK) {
+       if (aad(sa)->fs.denied & AA_AUDIT_FILE_MASK) {
                audit_log_format(ab, " denied_mask=");
-               audit_file_mask(ab, sa->aad->fs.denied);
+               audit_file_mask(ab, aad(sa)->fs.denied);
        }
-       if (sa->aad->fs.request & AA_AUDIT_FILE_MASK) {
+       if (aad(sa)->fs.request & AA_AUDIT_FILE_MASK) {
                audit_log_format(ab, " fsuid=%d",
                                 from_kuid(&init_user_ns, fsuid));
                audit_log_format(ab, " ouid=%d",
-                                from_kuid(&init_user_ns, sa->aad->fs.ouid));
+                                from_kuid(&init_user_ns, aad(sa)->fs.ouid));
        }
 
-       if (sa->aad->fs.target) {
+       if (aad(sa)->fs.target) {
                audit_log_format(ab, " target=");
-               audit_log_untrustedstring(ab, sa->aad->fs.target);
+               audit_log_untrustedstring(ab, aad(sa)->fs.target);
        }
 }
 
@@ -104,54 +104,53 @@ static void file_audit_cb(struct audit_buffer *ab, void *va)
  * Returns: %0 or error on failure
  */
 int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
-                 gfp_t gfp, int op, u32 request, const char *name,
+                 const char *op, u32 request, const char *name,
                  const char *target, kuid_t ouid, const char *info, int error)
 {
        int type = AUDIT_APPARMOR_AUTO;
-       struct common_audit_data sa;
-       struct apparmor_audit_data aad = {0,};
-       sa.type = LSM_AUDIT_DATA_TASK;
+       DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_TASK, op);
+
+       sa.u.tsk = NULL;
+       aad(&sa)->fs.request = request;
+       aad(&sa)->name = name;
+       aad(&sa)->fs.target = target;
+       aad(&sa)->fs.ouid = ouid;
+       aad(&sa)->info = info;
+       aad(&sa)->error = error;
        sa.u.tsk = NULL;
-       sa.aad = &aad;
-       aad.op = op,
-       aad.fs.request = request;
-       aad.name = name;
-       aad.fs.target = target;
-       aad.fs.ouid = ouid;
-       aad.info = info;
-       aad.error = error;
-
-       if (likely(!sa.aad->error)) {
+
+       if (likely(!aad(&sa)->error)) {
                u32 mask = perms->audit;
 
                if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
                        mask = 0xffff;
 
                /* mask off perms that are not being force audited */
-               sa.aad->fs.request &= mask;
+               aad(&sa)->fs.request &= mask;
 
-               if (likely(!sa.aad->fs.request))
+               if (likely(!aad(&sa)->fs.request))
                        return 0;
                type = AUDIT_APPARMOR_AUDIT;
        } else {
                /* only report permissions that were denied */
-               sa.aad->fs.request = sa.aad->fs.request & ~perms->allow;
+               aad(&sa)->fs.request = aad(&sa)->fs.request & ~perms->allow;
+               AA_BUG(!aad(&sa)->fs.request);
 
-               if (sa.aad->fs.request & perms->kill)
+               if (aad(&sa)->fs.request & perms->kill)
                        type = AUDIT_APPARMOR_KILL;
 
                /* quiet known rejects, assumes quiet and kill do not overlap */
-               if ((sa.aad->fs.request & perms->quiet) &&
+               if ((aad(&sa)->fs.request & perms->quiet) &&
                    AUDIT_MODE(profile) != AUDIT_NOQUIET &&
                    AUDIT_MODE(profile) != AUDIT_ALL)
-                       sa.aad->fs.request &= ~perms->quiet;
+                       aad(&sa)->fs.request &= ~perms->quiet;
 
-               if (!sa.aad->fs.request)
-                       return COMPLAIN_MODE(profile) ? 0 : sa.aad->error;
+               if (!aad(&sa)->fs.request)
+                       return COMPLAIN_MODE(profile) ? 0 : aad(&sa)->error;
        }
 
-       sa.aad->fs.denied = sa.aad->fs.request & ~perms->allow;
-       return aa_audit(type, profile, gfp, &sa, file_audit_cb);
+       aad(&sa)->fs.denied = aad(&sa)->fs.request & ~perms->allow;
+       return aa_audit(type, profile, &sa, file_audit_cb);
 }
 
 /**
@@ -276,8 +275,9 @@ static inline bool is_deleted(struct dentry *dentry)
  *
  * Returns: %0 else error if access denied or other error
  */
-int aa_path_perm(int op, struct aa_profile *profile, const struct path *path,
-                int flags, u32 request, struct path_cond *cond)
+int aa_path_perm(const char *op, struct aa_profile *profile,
+                const struct path *path, int flags, u32 request,
+                struct path_cond *cond)
 {
        char *buffer = NULL;
        struct file_perms perms = {};
@@ -301,8 +301,8 @@ int aa_path_perm(int op, struct aa_profile *profile, const struct path *path,
                if (request & ~perms.allow)
                        error = -EACCES;
        }
-       error = aa_audit_file(profile, &perms, GFP_KERNEL, op, request, name,
-                             NULL, cond->uid, info, error);
+       error = aa_audit_file(profile, &perms, op, request, name, NULL,
+                             cond->uid, info, error);
        kfree(buffer);
 
        return error;
@@ -349,8 +349,8 @@ static inline bool xindex_is_subset(u32 link, u32 target)
 int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry,
                 const struct path *new_dir, struct dentry *new_dentry)
 {
-       struct path link = { new_dir->mnt, new_dentry };
-       struct path target = { new_dir->mnt, old_dentry };
+       struct path link = { .mnt = new_dir->mnt, .dentry = new_dentry };
+       struct path target = { .mnt = new_dir->mnt, .dentry = old_dentry };
        struct path_cond cond = {
                d_backing_inode(old_dentry)->i_uid,
                d_backing_inode(old_dentry)->i_mode
@@ -429,7 +429,7 @@ done_tests:
        error = 0;
 
 audit:
-       error = aa_audit_file(profile, &lperms, GFP_KERNEL, OP_LINK, request,
+       error = aa_audit_file(profile, &lperms, OP_LINK, request,
                              lname, tname, cond.uid, info, error);
        kfree(buffer);
        kfree(buffer2);
@@ -446,7 +446,7 @@ audit:
  *
  * Returns: %0 if access allowed else error
  */
-int aa_file_perm(int op, struct aa_profile *profile, struct file *file,
+int aa_file_perm(const char *op, struct aa_profile *profile, struct file *file,
                 u32 request)
 {
        struct path_cond cond = {
index f067be814626af5055475cec73dabbce2081f326..1750cc0721c17d5f5a3fb0e7912a825dad9ee7b1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * AppArmor security module
  *
- * This file contains AppArmor basic global and lib definitions
+ * This file contains AppArmor basic global
  *
  * Copyright (C) 1998-2008 Novell/SUSE
  * Copyright 2009-2010 Canonical Ltd.
 #ifndef __APPARMOR_H
 #define __APPARMOR_H
 
-#include <linux/slab.h>
-#include <linux/fs.h>
-
-#include "match.h"
+#include <linux/types.h>
 
 /*
  * Class of mediation types in the AppArmor policy db
@@ -43,73 +40,4 @@ extern bool aa_g_logsyscall;
 extern bool aa_g_paranoid_load;
 extern unsigned int aa_g_path_max;
 
-/*
- * DEBUG remains global (no per profile flag) since it is mostly used in sysctl
- * which is not related to profile accesses.
- */
-
-#define AA_DEBUG(fmt, args...)                                         \
-       do {                                                            \
-               if (aa_g_debug && printk_ratelimit())                   \
-                       printk(KERN_DEBUG "AppArmor: " fmt, ##args);    \
-       } while (0)
-
-#define AA_ERROR(fmt, args...)                                         \
-       do {                                                            \
-               if (printk_ratelimit())                                 \
-                       printk(KERN_ERR "AppArmor: " fmt, ##args);      \
-       } while (0)
-
-/* Flag indicating whether initialization completed */
-extern int apparmor_initialized __initdata;
-
-/* fn's in lib */
-char *aa_split_fqname(char *args, char **ns_name);
-void aa_info_message(const char *str);
-void *__aa_kvmalloc(size_t size, gfp_t flags);
-
-static inline void *kvmalloc(size_t size)
-{
-       return __aa_kvmalloc(size, 0);
-}
-
-static inline void *kvzalloc(size_t size)
-{
-       return __aa_kvmalloc(size, __GFP_ZERO);
-}
-
-/**
- * aa_strneq - compare null terminated @str to a non null terminated substring
- * @str: a null terminated string
- * @sub: a substring, not necessarily null terminated
- * @len: length of @sub to compare
- *
- * The @str string must be full consumed for this to be considered a match
- */
-static inline bool aa_strneq(const char *str, const char *sub, int len)
-{
-       return !strncmp(str, sub, len) && !str[len];
-}
-
-/**
- * aa_dfa_null_transition - step to next state after null character
- * @dfa: the dfa to match against
- * @start: the state of the dfa to start matching in
- *
- * aa_dfa_null_transition transitions to the next state after a null
- * character which is not used in standard matching and is only
- * used to separate pairs.
- */
-static inline unsigned int aa_dfa_null_transition(struct aa_dfa *dfa,
-                                                 unsigned int start)
-{
-       /* the null transition only needs the string's null terminator byte */
-       return aa_dfa_next(dfa, start, 0);
-}
-
-static inline bool mediated_filesystem(struct dentry *dentry)
-{
-       return !(dentry->d_sb->s_flags & MS_NOUSER);
-}
-
 #endif /* __APPARMOR_H */
index 414e56878dd0c0462c0f85f0b0296448ad8ba27e..120a798b5bb0b202f3127c73f08cfe0f572f4b9f 100644 (file)
@@ -15,6 +15,8 @@
 #ifndef __AA_APPARMORFS_H
 #define __AA_APPARMORFS_H
 
+extern struct path aa_null;
+
 enum aa_fs_type {
        AA_FS_TYPE_BOOLEAN,
        AA_FS_TYPE_STRING,
@@ -62,12 +64,16 @@ extern const struct file_operations aa_fs_seq_file_ops;
 extern void __init aa_destroy_aafs(void);
 
 struct aa_profile;
-struct aa_namespace;
+struct aa_ns;
 
 enum aafs_ns_type {
        AAFS_NS_DIR,
        AAFS_NS_PROFS,
        AAFS_NS_NS,
+       AAFS_NS_RAW_DATA,
+       AAFS_NS_LOAD,
+       AAFS_NS_REPLACE,
+       AAFS_NS_REMOVE,
        AAFS_NS_COUNT,
        AAFS_NS_MAX_COUNT,
        AAFS_NS_SIZE,
@@ -83,12 +89,19 @@ enum aafs_prof_type {
        AAFS_PROF_MODE,
        AAFS_PROF_ATTACH,
        AAFS_PROF_HASH,
+       AAFS_PROF_RAW_DATA,
+       AAFS_PROF_RAW_HASH,
+       AAFS_PROF_RAW_ABI,
        AAFS_PROF_SIZEOF,
 };
 
 #define ns_dir(X) ((X)->dents[AAFS_NS_DIR])
 #define ns_subns_dir(X) ((X)->dents[AAFS_NS_NS])
 #define ns_subprofs_dir(X) ((X)->dents[AAFS_NS_PROFS])
+#define ns_subdata_dir(X) ((X)->dents[AAFS_NS_RAW_DATA])
+#define ns_subload(X) ((X)->dents[AAFS_NS_LOAD])
+#define ns_subreplace(X) ((X)->dents[AAFS_NS_REPLACE])
+#define ns_subremove(X) ((X)->dents[AAFS_NS_REMOVE])
 
 #define prof_dir(X) ((X)->dents[AAFS_PROF_DIR])
 #define prof_child_dir(X) ((X)->dents[AAFS_PROF_PROFS])
@@ -97,8 +110,8 @@ void __aa_fs_profile_rmdir(struct aa_profile *profile);
 void __aa_fs_profile_migrate_dents(struct aa_profile *old,
                                   struct aa_profile *new);
 int __aa_fs_profile_mkdir(struct aa_profile *profile, struct dentry *parent);
-void __aa_fs_namespace_rmdir(struct aa_namespace *ns);
-int __aa_fs_namespace_mkdir(struct aa_namespace *ns, struct dentry *parent,
-                           const char *name);
+void __aa_fs_ns_rmdir(struct aa_ns *ns);
+int __aa_fs_ns_mkdir(struct aa_ns *ns, struct dentry *parent,
+                    const char *name);
 
 #endif /* __AA_APPARMORFS_H */
index ba3dfd17f23f2671b20512a63c06ba75928ed0fc..fdc4774318ba0d12129c8f169f4d0113d099d0dc 100644 (file)
@@ -46,97 +46,115 @@ enum audit_type {
        AUDIT_APPARMOR_AUTO
 };
 
-extern const char *const op_table[];
-enum aa_ops {
-       OP_NULL,
-
-       OP_SYSCTL,
-       OP_CAPABLE,
-
-       OP_UNLINK,
-       OP_MKDIR,
-       OP_RMDIR,
-       OP_MKNOD,
-       OP_TRUNC,
-       OP_LINK,
-       OP_SYMLINK,
-       OP_RENAME_SRC,
-       OP_RENAME_DEST,
-       OP_CHMOD,
-       OP_CHOWN,
-       OP_GETATTR,
-       OP_OPEN,
-
-       OP_FPERM,
-       OP_FLOCK,
-       OP_FMMAP,
-       OP_FMPROT,
-
-       OP_CREATE,
-       OP_POST_CREATE,
-       OP_BIND,
-       OP_CONNECT,
-       OP_LISTEN,
-       OP_ACCEPT,
-       OP_SENDMSG,
-       OP_RECVMSG,
-       OP_GETSOCKNAME,
-       OP_GETPEERNAME,
-       OP_GETSOCKOPT,
-       OP_SETSOCKOPT,
-       OP_SOCK_SHUTDOWN,
-
-       OP_PTRACE,
-
-       OP_EXEC,
-       OP_CHANGE_HAT,
-       OP_CHANGE_PROFILE,
-       OP_CHANGE_ONEXEC,
-
-       OP_SETPROCATTR,
-       OP_SETRLIMIT,
-
-       OP_PROF_REPL,
-       OP_PROF_LOAD,
-       OP_PROF_RM,
-};
+#define OP_NULL NULL
+
+#define OP_SYSCTL "sysctl"
+#define OP_CAPABLE "capable"
+
+#define OP_UNLINK "unlink"
+#define OP_MKDIR "mkdir"
+#define OP_RMDIR "rmdir"
+#define OP_MKNOD "mknod"
+#define OP_TRUNC "truncate"
+#define OP_LINK "link"
+#define OP_SYMLINK "symlink"
+#define OP_RENAME_SRC "rename_src"
+#define OP_RENAME_DEST "rename_dest"
+#define OP_CHMOD "chmod"
+#define OP_CHOWN "chown"
+#define OP_GETATTR "getattr"
+#define OP_OPEN "open"
+
+#define OP_FPERM "file_perm"
+#define OP_FLOCK "file_lock"
+#define OP_FMMAP "file_mmap"
+#define OP_FMPROT "file_mprotect"
+
+#define OP_CREATE "create"
+#define OP_POST_CREATE "post_create"
+#define OP_BIND "bind"
+#define OP_CONNECT "connect"
+#define OP_LISTEN "listen"
+#define OP_ACCEPT "accept"
+#define OP_SENDMSG "sendmsg"
+#define OP_RECVMSG "recvmsg"
+#define OP_GETSOCKNAME "getsockname"
+#define OP_GETPEERNAME "getpeername"
+#define OP_GETSOCKOPT "getsockopt"
+#define OP_SETSOCKOPT "setsockopt"
+#define OP_SHUTDOWN "socket_shutdown"
+
+#define OP_PTRACE "ptrace"
+
+#define OP_EXEC "exec"
+
+#define OP_CHANGE_HAT "change_hat"
+#define OP_CHANGE_PROFILE "change_profile"
+#define OP_CHANGE_ONEXEC "change_onexec"
+
+#define OP_SETPROCATTR "setprocattr"
+#define OP_SETRLIMIT "setrlimit"
+
+#define OP_PROF_REPL "profile_replace"
+#define OP_PROF_LOAD "profile_load"
+#define OP_PROF_RM "profile_remove"
 
 
 struct apparmor_audit_data {
        int error;
-       int op;
+       const char *op;
        int type;
        void *profile;
        const char *name;
        const char *info;
        union {
-               void *target;
+               /* these entries require a custom callback fn */
+               struct {
+                       struct aa_profile *peer;
+                       struct {
+                               const char *target;
+                               u32 request;
+                               u32 denied;
+                               kuid_t ouid;
+                       } fs;
+               };
                struct {
+                       const char *name;
                        long pos;
-                       void *target;
+                       const char *ns;
                } iface;
                struct {
                        int rlim;
                        unsigned long max;
                } rlim;
-               struct {
-                       const char *target;
-                       u32 request;
-                       u32 denied;
-                       kuid_t ouid;
-               } fs;
        };
 };
 
-/* define a short hand for apparmor_audit_data structure */
-#define aad apparmor_audit_data
+/* macros for dealing with  apparmor_audit_data structure */
+#define aad(SA) ((SA)->apparmor_audit_data)
+#define DEFINE_AUDIT_DATA(NAME, T, X)                                  \
+       /* TODO: cleanup audit init so we don't need _aad = {0,} */     \
+       struct apparmor_audit_data NAME ## _aad = { .op = (X), };       \
+       struct common_audit_data NAME =                                 \
+       {                                                               \
+       .type = (T),                                                    \
+       .u.tsk = NULL,                                                  \
+       };                                                              \
+       NAME.apparmor_audit_data = &(NAME ## _aad)
 
 void aa_audit_msg(int type, struct common_audit_data *sa,
                  void (*cb) (struct audit_buffer *, void *));
-int aa_audit(int type, struct aa_profile *profile, gfp_t gfp,
-            struct common_audit_data *sa,
+int aa_audit(int type, struct aa_profile *profile, struct common_audit_data *sa,
             void (*cb) (struct audit_buffer *, void *));
 
+#define aa_audit_error(ERROR, SA, CB)                          \
+({                                                             \
+       aad((SA))->error = (ERROR);                             \
+       aa_audit_msg(AUDIT_APPARMOR_ERROR, (SA), (CB));         \
+       aad((SA))->error;                                       \
+})
+
+
 static inline int complain_error(int error)
 {
        if (error == -EPERM || error == -EACCES)
index 6bf65798e5d145e985a65f674273db20472ece67..5b18fedab4c898afe9539e09cbd5332a13a762e9 100644 (file)
 #include <linux/sched.h>
 
 #include "policy.h"
+#include "policy_ns.h"
 
-#define cred_cxt(X) (X)->security
-#define current_cxt() cred_cxt(current_cred())
+#define cred_ctx(X) ((X)->security)
+#define current_ctx() cred_ctx(current_cred())
 
-/* struct aa_file_cxt - the AppArmor context the file was opened in
+/* struct aa_file_ctx - the AppArmor context the file was opened in
  * @perms: the permission the file was opened with
  *
- * The file_cxt could currently be directly stored in file->f_security
+ * The file_ctx could currently be directly stored in file->f_security
  * as the profile reference is now stored in the f_cred.  However the
- * cxt struct will expand in the future so we keep the struct.
+ * ctx struct will expand in the future so we keep the struct.
  */
-struct aa_file_cxt {
+struct aa_file_ctx {
        u16 allow;
 };
 
 /**
- * aa_alloc_file_context - allocate file_cxt
+ * aa_alloc_file_context - allocate file_ctx
  * @gfp: gfp flags for allocation
  *
- * Returns: file_cxt or NULL on failure
+ * Returns: file_ctx or NULL on failure
  */
-static inline struct aa_file_cxt *aa_alloc_file_context(gfp_t gfp)
+static inline struct aa_file_ctx *aa_alloc_file_context(gfp_t gfp)
 {
-       return kzalloc(sizeof(struct aa_file_cxt), gfp);
+       return kzalloc(sizeof(struct aa_file_ctx), gfp);
 }
 
 /**
- * aa_free_file_context - free a file_cxt
- * @cxt: file_cxt to free  (MAYBE_NULL)
+ * aa_free_file_context - free a file_ctx
+ * @ctx: file_ctx to free  (MAYBE_NULL)
  */
-static inline void aa_free_file_context(struct aa_file_cxt *cxt)
+static inline void aa_free_file_context(struct aa_file_ctx *ctx)
 {
-       if (cxt)
-               kzfree(cxt);
+       if (ctx)
+               kzfree(ctx);
 }
 
 /**
- * struct aa_task_cxt - primary label for confined tasks
+ * struct aa_task_ctx - primary label for confined tasks
  * @profile: the current profile   (NOT NULL)
  * @exec: profile to transition to on next exec  (MAYBE NULL)
  * @previous: profile the task may return to     (MAYBE NULL)
@@ -68,17 +69,17 @@ static inline void aa_free_file_context(struct aa_file_cxt *cxt)
  *
  * TODO: make so a task can be confined by a stack of contexts
  */
-struct aa_task_cxt {
+struct aa_task_ctx {
        struct aa_profile *profile;
        struct aa_profile *onexec;
        struct aa_profile *previous;
        u64 token;
 };
 
-struct aa_task_cxt *aa_alloc_task_context(gfp_t flags);
-void aa_free_task_context(struct aa_task_cxt *cxt);
-void aa_dup_task_context(struct aa_task_cxt *new,
-                        const struct aa_task_cxt *old);
+struct aa_task_ctx *aa_alloc_task_context(gfp_t flags);
+void aa_free_task_context(struct aa_task_ctx *ctx);
+void aa_dup_task_context(struct aa_task_ctx *new,
+                        const struct aa_task_ctx *old);
 int aa_replace_current_profile(struct aa_profile *profile);
 int aa_set_current_onexec(struct aa_profile *profile);
 int aa_set_current_hat(struct aa_profile *profile, u64 token);
@@ -96,9 +97,10 @@ struct aa_profile *aa_get_task_profile(struct task_struct *task);
  */
 static inline struct aa_profile *aa_cred_profile(const struct cred *cred)
 {
-       struct aa_task_cxt *cxt = cred_cxt(cred);
-       BUG_ON(!cxt || !cxt->profile);
-       return cxt->profile;
+       struct aa_task_ctx *ctx = cred_ctx(cred);
+
+       AA_BUG(!ctx || !ctx->profile);
+       return ctx->profile;
 }
 
 /**
@@ -148,31 +150,37 @@ static inline struct aa_profile *__aa_current_profile(void)
  */
 static inline struct aa_profile *aa_current_profile(void)
 {
-       const struct aa_task_cxt *cxt = current_cxt();
+       const struct aa_task_ctx *ctx = current_ctx();
        struct aa_profile *profile;
-       BUG_ON(!cxt || !cxt->profile);
 
-       if (PROFILE_INVALID(cxt->profile)) {
-               profile = aa_get_newest_profile(cxt->profile);
+       AA_BUG(!ctx || !ctx->profile);
+
+       if (profile_is_stale(ctx->profile)) {
+               profile = aa_get_newest_profile(ctx->profile);
                aa_replace_current_profile(profile);
                aa_put_profile(profile);
-               cxt = current_cxt();
+               ctx = current_ctx();
        }
 
-       return cxt->profile;
+       return ctx->profile;
+}
+
+static inline struct aa_ns *aa_get_current_ns(void)
+{
+       return aa_get_ns(__aa_current_profile()->ns);
 }
 
 /**
- * aa_clear_task_cxt_trans - clear transition tracking info from the cxt
- * @cxt: task context to clear (NOT NULL)
+ * aa_clear_task_ctx_trans - clear transition tracking info from the ctx
+ * @ctx: task context to clear (NOT NULL)
  */
-static inline void aa_clear_task_cxt_trans(struct aa_task_cxt *cxt)
+static inline void aa_clear_task_ctx_trans(struct aa_task_ctx *ctx)
 {
-       aa_put_profile(cxt->previous);
-       aa_put_profile(cxt->onexec);
-       cxt->previous = NULL;
-       cxt->onexec = NULL;
-       cxt->token = 0;
+       aa_put_profile(ctx->previous);
+       aa_put_profile(ctx->onexec);
+       ctx->previous = NULL;
+       ctx->onexec = NULL;
+       ctx->token = 0;
 }
 
 #endif /* __AA_CONTEXT_H */
index dc418e5024d922fa8ecd1af8995bbabcd6cc84bb..c1469f8db1747addfdf4805861dacba1685e2baa 100644 (file)
 
 #ifdef CONFIG_SECURITY_APPARMOR_HASH
 unsigned int aa_hash_size(void);
+char *aa_calc_hash(void *data, size_t len);
 int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start,
                         size_t len);
 #else
+static inline char *aa_calc_hash(void *data, size_t len)
+{
+       return NULL;
+}
 static inline int aa_calc_profile_hash(struct aa_profile *profile, u32 version,
                                       void *start, size_t len)
 {
index de04464f0a3fdb0232d4343ef26afffa02613613..30544729878a22903c6b374ce270b0c9a7a5bdd5 100644 (file)
@@ -30,7 +30,7 @@ void apparmor_bprm_committed_creds(struct linux_binprm *bprm);
 
 void aa_free_domain_entries(struct aa_domain *domain);
 int aa_change_hat(const char *hats[], int count, u64 token, bool permtest);
-int aa_change_profile(const char *ns_name, const char *name, bool onexec,
-                     bool permtest);
+int aa_change_profile(const char *fqname, bool onexec, bool permtest,
+                     bool stack);
 
 #endif /* __AA_DOMAIN_H */
index 4803c97d19924c9923a66d5c1a22ccb7ccd3d224..38f821bf49b6df18ee8ffec39b6acba123671dcb 100644 (file)
@@ -145,7 +145,7 @@ static inline u16 dfa_map_xindex(u16 mask)
        dfa_map_xindex((ACCEPT_TABLE(dfa)[state] >> 14) & 0x3fff)
 
 int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
-                 gfp_t gfp, int op, u32 request, const char *name,
+                 const char *op, u32 request, const char *name,
                  const char *target, kuid_t ouid, const char *info, int error);
 
 /**
@@ -171,13 +171,14 @@ unsigned int aa_str_perms(struct aa_dfa *dfa, unsigned int start,
                          const char *name, struct path_cond *cond,
                          struct file_perms *perms);
 
-int aa_path_perm(int op, struct aa_profile *profile, const struct path *path,
-                int flags, u32 request, struct path_cond *cond);
+int aa_path_perm(const char *op, struct aa_profile *profile,
+                const struct path *path, int flags, u32 request,
+                struct path_cond *cond);
 
 int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry,
                 const struct path *new_dir, struct dentry *new_dentry);
 
-int aa_file_perm(int op, struct aa_profile *profile, struct file *file,
+int aa_file_perm(const char *op, struct aa_profile *profile, struct file *file,
                 u32 request);
 
 static inline void aa_free_file_rules(struct aa_file_rules *rules)
diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h
new file mode 100644 (file)
index 0000000..65ff492
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor lib definitions
+ *
+ * 2017 Canonical 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, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_LIB_H
+#define __AA_LIB_H
+
+#include <linux/slab.h>
+#include <linux/fs.h>
+
+#include "match.h"
+
+/* Provide our own test for whether a write lock is held for asserts
+ * this is because on none SMP systems write_can_lock will always
+ * resolve to true, which is what you want for code making decisions
+ * based on it, but wrong for asserts checking that the lock is held
+ */
+#ifdef CONFIG_SMP
+#define write_is_locked(X) !write_can_lock(X)
+#else
+#define write_is_locked(X) (1)
+#endif /* CONFIG_SMP */
+
+/*
+ * DEBUG remains global (no per profile flag) since it is mostly used in sysctl
+ * which is not related to profile accesses.
+ */
+
+#define DEBUG_ON (aa_g_debug)
+#define dbg_printk(__fmt, __args...) pr_debug(__fmt, ##__args)
+#define AA_DEBUG(fmt, args...)                                         \
+       do {                                                            \
+               if (DEBUG_ON)                                           \
+                       pr_debug_ratelimited("AppArmor: " fmt, ##args); \
+       } while (0)
+
+#define AA_WARN(X) WARN((X), "APPARMOR WARN %s: %s\n", __func__, #X)
+
+#define AA_BUG(X, args...) AA_BUG_FMT((X), "" args)
+#ifdef CONFIG_SECURITY_APPARMOR_DEBUG_ASSERTS
+#define AA_BUG_FMT(X, fmt, args...)                                    \
+       WARN((X), "AppArmor WARN %s: (" #X "): " fmt, __func__, ##args)
+#else
+#define AA_BUG_FMT(X, fmt, args...)
+#endif
+
+#define AA_ERROR(fmt, args...)                                         \
+       pr_err_ratelimited("AppArmor: " fmt, ##args)
+
+/* Flag indicating whether initialization completed */
+extern int apparmor_initialized __initdata;
+
+/* fn's in lib */
+char *aa_split_fqname(char *args, char **ns_name);
+const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name,
+                            size_t *ns_len);
+void aa_info_message(const char *str);
+void *__aa_kvmalloc(size_t size, gfp_t flags);
+
+static inline void *kvmalloc(size_t size)
+{
+       return __aa_kvmalloc(size, 0);
+}
+
+static inline void *kvzalloc(size_t size)
+{
+       return __aa_kvmalloc(size, __GFP_ZERO);
+}
+
+/**
+ * aa_strneq - compare null terminated @str to a non null terminated substring
+ * @str: a null terminated string
+ * @sub: a substring, not necessarily null terminated
+ * @len: length of @sub to compare
+ *
+ * The @str string must be full consumed for this to be considered a match
+ */
+static inline bool aa_strneq(const char *str, const char *sub, int len)
+{
+       return !strncmp(str, sub, len) && !str[len];
+}
+
+/**
+ * aa_dfa_null_transition - step to next state after null character
+ * @dfa: the dfa to match against
+ * @start: the state of the dfa to start matching in
+ *
+ * aa_dfa_null_transition transitions to the next state after a null
+ * character which is not used in standard matching and is only
+ * used to separate pairs.
+ */
+static inline unsigned int aa_dfa_null_transition(struct aa_dfa *dfa,
+                                                 unsigned int start)
+{
+       /* the null transition only needs the string's null terminator byte */
+       return aa_dfa_next(dfa, start, 0);
+}
+
+static inline bool path_mediated_fs(struct dentry *dentry)
+{
+       return !(dentry->d_sb->s_flags & MS_NOUSER);
+}
+
+/* struct aa_policy - common part of both namespaces and profiles
+ * @name: name of the object
+ * @hname - The hierarchical name
+ * @list: list policy object is on
+ * @profiles: head of the profiles list contained in the object
+ */
+struct aa_policy {
+       const char *name;
+       const char *hname;
+       struct list_head list;
+       struct list_head profiles;
+};
+
+/**
+ * basename - find the last component of an hname
+ * @name: hname to find the base profile name component of  (NOT NULL)
+ *
+ * Returns: the tail (base profile name) name component of an hname
+ */
+static inline const char *basename(const char *hname)
+{
+       char *split;
+
+       hname = strim((char *)hname);
+       for (split = strstr(hname, "//"); split; split = strstr(hname, "//"))
+               hname = split + 2;
+
+       return hname;
+}
+
+/**
+ * __policy_find - find a policy by @name on a policy list
+ * @head: list to search  (NOT NULL)
+ * @name: name to search for  (NOT NULL)
+ *
+ * Requires: rcu_read_lock be held
+ *
+ * Returns: unrefcounted policy that match @name or NULL if not found
+ */
+static inline struct aa_policy *__policy_find(struct list_head *head,
+                                             const char *name)
+{
+       struct aa_policy *policy;
+
+       list_for_each_entry_rcu(policy, head, list) {
+               if (!strcmp(policy->name, name))
+                       return policy;
+       }
+       return NULL;
+}
+
+/**
+ * __policy_strn_find - find a policy that's name matches @len chars of @str
+ * @head: list to search  (NOT NULL)
+ * @str: string to search for  (NOT NULL)
+ * @len: length of match required
+ *
+ * Requires: rcu_read_lock be held
+ *
+ * Returns: unrefcounted policy that match @str or NULL if not found
+ *
+ * if @len == strlen(@strlen) then this is equiv to __policy_find
+ * other wise it allows searching for policy by a partial match of name
+ */
+static inline struct aa_policy *__policy_strn_find(struct list_head *head,
+                                           const char *str, int len)
+{
+       struct aa_policy *policy;
+
+       list_for_each_entry_rcu(policy, head, list) {
+               if (aa_strneq(policy->name, str, len))
+                       return policy;
+       }
+
+       return NULL;
+}
+
+bool aa_policy_init(struct aa_policy *policy, const char *prefix,
+                   const char *name, gfp_t gfp);
+void aa_policy_destroy(struct aa_policy *policy);
+
+#endif /* AA_LIB_H */
index a1c04fe8679022dd21e9eb468947b314de58452f..add4c672655844a33d9cadc18893f67d605d751f 100644 (file)
@@ -100,13 +100,15 @@ struct aa_dfa {
        struct table_header *tables[YYTD_ID_TSIZE];
 };
 
+extern struct aa_dfa *nulldfa;
+
 #define byte_to_byte(X) (X)
 
-#define UNPACK_ARRAY(TABLE, BLOB, LEN, TYPE, NTOHX) \
+#define UNPACK_ARRAY(TABLE, BLOB, LEN, TTYPE, BTYPE, NTOHX)    \
        do { \
                typeof(LEN) __i; \
-               TYPE *__t = (TYPE *) TABLE; \
-               TYPE *__b = (TYPE *) BLOB; \
+               TTYPE *__t = (TTYPE *) TABLE; \
+               BTYPE *__b = (BTYPE *) BLOB; \
                for (__i = 0; __i < LEN; __i++) { \
                        __t[__i] = NTOHX(__b[__i]); \
                } \
@@ -117,6 +119,9 @@ static inline size_t table_size(size_t len, size_t el_size)
        return ALIGN(sizeof(struct table_header) + len * el_size, 8);
 }
 
+int aa_setup_dfa_engine(void);
+void aa_teardown_dfa_engine(void);
+
 struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags);
 unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,
                              const char *str, int len);
@@ -127,6 +132,21 @@ unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state,
 
 void aa_dfa_free_kref(struct kref *kref);
 
+/**
+ * aa_get_dfa - increment refcount on dfa @p
+ * @dfa: dfa  (MAYBE NULL)
+ *
+ * Returns: pointer to @dfa if @dfa is NULL will return NULL
+ * Requires: @dfa must be held with valid refcount when called
+ */
+static inline struct aa_dfa *aa_get_dfa(struct aa_dfa *dfa)
+{
+       if (dfa)
+               kref_get(&(dfa->count));
+
+       return dfa;
+}
+
 /**
  * aa_put_dfa - put a dfa refcount
  * @dfa: dfa to put refcount   (MAYBE NULL)
index 73560f258784fc3256878f953ad8d194c086106d..0444fdde3918905dded243442a9743a7497c183b 100644 (file)
@@ -29,4 +29,57 @@ enum path_flags {
 int aa_path_name(const struct path *path, int flags, char **buffer,
                 const char **name, const char **info);
 
+#define MAX_PATH_BUFFERS 2
+
+/* Per cpu buffers used during mediation */
+/* preallocated buffers to use during path lookups */
+struct aa_buffers {
+       char *buf[MAX_PATH_BUFFERS];
+};
+
+#include <linux/percpu.h>
+#include <linux/preempt.h>
+
+DECLARE_PER_CPU(struct aa_buffers, aa_buffers);
+
+#define COUNT_ARGS(X...) COUNT_ARGS_HELPER(, ##X, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
+#define COUNT_ARGS_HELPER(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, n, X...) n
+#define CONCAT(X, Y) X ## Y
+#define CONCAT_AFTER(X, Y) CONCAT(X, Y)
+
+#define ASSIGN(FN, X, N) ((X) = FN(N))
+#define EVAL1(FN, X) ASSIGN(FN, X, 0) /*X = FN(0)*/
+#define EVAL2(FN, X, Y...) do { ASSIGN(FN, X, 1);  EVAL1(FN, Y); } while (0)
+#define EVAL(FN, X...) CONCAT_AFTER(EVAL, COUNT_ARGS(X))(FN, X)
+
+#define for_each_cpu_buffer(I) for ((I) = 0; (I) < MAX_PATH_BUFFERS; (I)++)
+
+#ifdef CONFIG_DEBUG_PREEMPT
+#define AA_BUG_PREEMPT_ENABLED(X) AA_BUG(preempt_count() <= 0, X)
+#else
+#define AA_BUG_PREEMPT_ENABLED(X) /* nop */
+#endif
+
+#define __get_buffer(N) ({                                     \
+       struct aa_buffers *__cpu_var; \
+       AA_BUG_PREEMPT_ENABLED("__get_buffer without preempt disabled");  \
+       __cpu_var = this_cpu_ptr(&aa_buffers);                  \
+       __cpu_var->buf[(N)]; })
+
+#define __get_buffers(X...)    EVAL(__get_buffer, X)
+
+#define __put_buffers(X, Y...) ((void)&(X))
+
+#define get_buffers(X...)      \
+do {                           \
+       preempt_disable();      \
+       __get_buffers(X);       \
+} while (0)
+
+#define put_buffers(X, Y...)   \
+do {                           \
+       __put_buffers(X, Y);    \
+       preempt_enable();       \
+} while (0)
+
 #endif /* __AA_PATH_H */
index 46467aaa557b4b0c8d80b11e07d845d867009ba4..67bc96afe54185dff2b0792d5a4cfde8917fdb74 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/capability.h>
 #include <linux/cred.h>
 #include <linux/kref.h>
+#include <linux/rhashtable.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/socket.h>
 #include "capability.h"
 #include "domain.h"
 #include "file.h"
+#include "lib.h"
 #include "resource.h"
 
+
+struct aa_ns;
+
+extern int unprivileged_userns_apparmor_policy;
+
 extern const char *const aa_profile_mode_names[];
 #define APPARMOR_MODE_NAMES_MAX_INDEX 4
 
@@ -42,7 +49,7 @@ extern const char *const aa_profile_mode_names[];
 
 #define PROFILE_IS_HAT(_profile) ((_profile)->flags & PFLAG_HAT)
 
-#define PROFILE_INVALID(_profile) ((_profile)->flags & PFLAG_INVALID)
+#define profile_is_stale(_profile) ((_profile)->flags & PFLAG_STALE)
 
 #define on_list_rcu(X) (!list_empty(X) && (X)->prev != LIST_POISON2)
 
@@ -67,7 +74,7 @@ enum profile_flags {
        PFLAG_USER_DEFINED = 0x20,      /* user based profile - lower privs */
        PFLAG_NO_LIST_REF = 0x40,       /* list doesn't keep profile ref */
        PFLAG_OLD_NULL_TRANS = 0x100,   /* use // as the null transition */
-       PFLAG_INVALID = 0x200,          /* profile replaced/removed */
+       PFLAG_STALE = 0x200,            /* profile replaced/removed */
        PFLAG_NS_COUNT = 0x400,         /* carries NS ref count */
 
        /* These flags must correspond with PATH_flags */
@@ -76,70 +83,6 @@ enum profile_flags {
 
 struct aa_profile;
 
-/* struct aa_policy - common part of both namespaces and profiles
- * @name: name of the object
- * @hname - The hierarchical name
- * @list: list policy object is on
- * @profiles: head of the profiles list contained in the object
- */
-struct aa_policy {
-       char *name;
-       char *hname;
-       struct list_head list;
-       struct list_head profiles;
-};
-
-/* struct aa_ns_acct - accounting of profiles in namespace
- * @max_size: maximum space allowed for all profiles in namespace
- * @max_count: maximum number of profiles that can be in this namespace
- * @size: current size of profiles
- * @count: current count of profiles (includes null profiles)
- */
-struct aa_ns_acct {
-       int max_size;
-       int max_count;
-       int size;
-       int count;
-};
-
-/* struct aa_namespace - namespace for a set of profiles
- * @base: common policy
- * @parent: parent of namespace
- * @lock: lock for modifying the object
- * @acct: accounting for the namespace
- * @unconfined: special unconfined profile for the namespace
- * @sub_ns: list of namespaces under the current namespace.
- * @uniq_null: uniq value used for null learning profiles
- * @uniq_id: a unique id count for the profiles in the namespace
- * @dents: dentries for the namespaces file entries in apparmorfs
- *
- * An aa_namespace defines the set profiles that are searched to determine
- * which profile to attach to a task.  Profiles can not be shared between
- * aa_namespaces and profile names within a namespace are guaranteed to be
- * unique.  When profiles in separate namespaces have the same name they
- * are NOT considered to be equivalent.
- *
- * Namespaces are hierarchical and only namespaces and profiles below the
- * current namespace are visible.
- *
- * Namespace names must be unique and can not contain the characters :/\0
- *
- * FIXME TODO: add vserver support of namespaces (can it all be done in
- *             userspace?)
- */
-struct aa_namespace {
-       struct aa_policy base;
-       struct aa_namespace *parent;
-       struct mutex lock;
-       struct aa_ns_acct acct;
-       struct aa_profile *unconfined;
-       struct list_head sub_ns;
-       atomic_t uniq_null;
-       long uniq_id;
-
-       struct dentry *dents[AAFS_NS_SIZEOF];
-};
-
 /* struct aa_policydb - match engine for a policy
  * dfa: dfa pattern match
  * start: set of start states for the different classes of data
@@ -151,11 +94,24 @@ struct aa_policydb {
 
 };
 
-struct aa_replacedby {
+struct aa_proxy {
        struct kref count;
        struct aa_profile __rcu *profile;
 };
 
+/* struct aa_data - generic data structure
+ * key: name for retrieving this data
+ * size: size of data in bytes
+ * data: binary data
+ * head: reserved for rhashtable
+ */
+struct aa_data {
+       char *key;
+       u32 size;
+       char *data;
+       struct rhash_head head;
+};
+
 
 /* struct aa_profile - basic confinement data
  * @base - base components of the profile (name, refcount, lists, lock ...)
@@ -163,7 +119,7 @@ struct aa_replacedby {
  * @rcu: rcu head used when removing from @list
  * @parent: parent of profile
  * @ns: namespace the profile is in
- * @replacedby: is set to the profile that replaced this profile
+ * @proxy: is set to the profile that replaced this profile
  * @rename: optional profile name that this profile renamed
  * @attach: human readable attachment string
  * @xmatch: optional extended matching for unconfined executables names
@@ -180,13 +136,14 @@ struct aa_replacedby {
  *
  * @dents: dentries for the profiles file entries in apparmorfs
  * @dirname: name of the profile dir in apparmorfs
+ * @data: hashtable for free-form policy aa_data
  *
  * The AppArmor profile contains the basic confinement data.  Each profile
  * has a name, and exists in a namespace.  The @name and @exec_match are
  * used to determine profile attachment against unconfined tasks.  All other
  * attachments are determined by profile X transition rules.
  *
- * The @replacedby struct is write protected by the profile lock.
+ * The @proxy struct is write protected by the profile lock.
  *
  * Profiles have a hierarchy where hats and children profiles keep
  * a reference to their parent.
@@ -201,8 +158,8 @@ struct aa_profile {
        struct rcu_head rcu;
        struct aa_profile __rcu *parent;
 
-       struct aa_namespace *ns;
-       struct aa_replacedby *replacedby;
+       struct aa_ns *ns;
+       struct aa_proxy *proxy;
        const char *rename;
 
        const char *attach;
@@ -219,37 +176,39 @@ struct aa_profile {
        struct aa_caps caps;
        struct aa_rlimit rlimits;
 
+       struct aa_loaddata *rawdata;
        unsigned char *hash;
        char *dirname;
        struct dentry *dents[AAFS_PROF_SIZEOF];
+       struct rhashtable *data;
 };
 
-extern struct aa_namespace *root_ns;
 extern enum profile_mode aa_g_profile_mode;
 
-void aa_add_profile(struct aa_policy *common, struct aa_profile *profile);
-
-bool aa_ns_visible(struct aa_namespace *curr, struct aa_namespace *view);
-const char *aa_ns_name(struct aa_namespace *parent, struct aa_namespace *child);
-int aa_alloc_root_ns(void);
-void aa_free_root_ns(void);
-void aa_free_namespace_kref(struct kref *kref);
+void __aa_update_proxy(struct aa_profile *orig, struct aa_profile *new);
 
-struct aa_namespace *aa_find_namespace(struct aa_namespace *root,
-                                      const char *name);
+void aa_add_profile(struct aa_policy *common, struct aa_profile *profile);
 
 
-void aa_free_replacedby_kref(struct kref *kref);
-struct aa_profile *aa_alloc_profile(const char *name);
-struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat);
+void aa_free_proxy_kref(struct kref *kref);
+struct aa_profile *aa_alloc_profile(const char *name, gfp_t gfp);
+struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat,
+                                      const char *base, gfp_t gfp);
 void aa_free_profile(struct aa_profile *profile);
 void aa_free_profile_kref(struct kref *kref);
 struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name);
-struct aa_profile *aa_lookup_profile(struct aa_namespace *ns, const char *name);
-struct aa_profile *aa_match_profile(struct aa_namespace *ns, const char *name);
-
-ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace);
-ssize_t aa_remove_profiles(char *name, size_t size);
+struct aa_profile *aa_lookupn_profile(struct aa_ns *ns, const char *hname,
+                                     size_t n);
+struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *name);
+struct aa_profile *aa_fqlookupn_profile(struct aa_profile *base,
+                                       const char *fqname, size_t n);
+struct aa_profile *aa_match_profile(struct aa_ns *ns, const char *name);
+
+ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_profile *profile,
+                           bool noreplace, struct aa_loaddata *udata);
+ssize_t aa_remove_profiles(struct aa_ns *view, struct aa_profile *profile,
+                           char *name, size_t size);
+void __aa_profile_list_release(struct list_head *head);
 
 #define PROF_ADD 1
 #define PROF_REPLACE 0
@@ -257,12 +216,6 @@ ssize_t aa_remove_profiles(char *name, size_t size);
 #define unconfined(X) ((X)->mode == APPARMOR_UNCONFINED)
 
 
-static inline struct aa_profile *aa_deref_parent(struct aa_profile *p)
-{
-       return rcu_dereference_protected(p->parent,
-                                        mutex_is_locked(&p->ns->lock));
-}
-
 /**
  * aa_get_profile - increment refcount on profile @p
  * @p: profile  (MAYBE NULL)
@@ -326,8 +279,8 @@ static inline struct aa_profile *aa_get_newest_profile(struct aa_profile *p)
        if (!p)
                return NULL;
 
-       if (PROFILE_INVALID(p))
-               return aa_get_profile_rcu(&p->replacedby->profile);
+       if (profile_is_stale(p))
+               return aa_get_profile_rcu(&p->proxy->profile);
 
        return aa_get_profile(p);
 }
@@ -342,7 +295,7 @@ static inline void aa_put_profile(struct aa_profile *p)
                kref_put(&p->count, aa_free_profile_kref);
 }
 
-static inline struct aa_replacedby *aa_get_replacedby(struct aa_replacedby *p)
+static inline struct aa_proxy *aa_get_proxy(struct aa_proxy *p)
 {
        if (p)
                kref_get(&(p->count));
@@ -350,49 +303,10 @@ static inline struct aa_replacedby *aa_get_replacedby(struct aa_replacedby *p)
        return p;
 }
 
-static inline void aa_put_replacedby(struct aa_replacedby *p)
+static inline void aa_put_proxy(struct aa_proxy *p)
 {
        if (p)
-               kref_put(&p->count, aa_free_replacedby_kref);
-}
-
-/* requires profile list write lock held */
-static inline void __aa_update_replacedby(struct aa_profile *orig,
-                                         struct aa_profile *new)
-{
-       struct aa_profile *tmp;
-       tmp = rcu_dereference_protected(orig->replacedby->profile,
-                                       mutex_is_locked(&orig->ns->lock));
-       rcu_assign_pointer(orig->replacedby->profile, aa_get_profile(new));
-       orig->flags |= PFLAG_INVALID;
-       aa_put_profile(tmp);
-}
-
-/**
- * aa_get_namespace - increment references count on @ns
- * @ns: namespace to increment reference count of (MAYBE NULL)
- *
- * Returns: pointer to @ns, if @ns is NULL returns NULL
- * Requires: @ns must be held with valid refcount when called
- */
-static inline struct aa_namespace *aa_get_namespace(struct aa_namespace *ns)
-{
-       if (ns)
-               aa_get_profile(ns->unconfined);
-
-       return ns;
-}
-
-/**
- * aa_put_namespace - decrement refcount on @ns
- * @ns: namespace to put reference of
- *
- * Decrement reference count of @ns and if no longer in use free it
- */
-static inline void aa_put_namespace(struct aa_namespace *ns)
-{
-       if (ns)
-               aa_put_profile(ns->unconfined);
+               kref_put(&p->count, aa_free_proxy_kref);
 }
 
 static inline int AUDIT_MODE(struct aa_profile *profile)
@@ -403,8 +317,9 @@ static inline int AUDIT_MODE(struct aa_profile *profile)
        return profile->audit;
 }
 
-bool policy_view_capable(void);
-bool policy_admin_capable(void);
-bool aa_may_manage_policy(int op);
+bool policy_view_capable(struct aa_ns *ns);
+bool policy_admin_capable(struct aa_ns *ns);
+int aa_may_manage_policy(struct aa_profile *profile, struct aa_ns *ns,
+                        const char *op);
 
 #endif /* __AA_POLICY_H */
diff --git a/security/apparmor/include/policy_ns.h b/security/apparmor/include/policy_ns.h
new file mode 100644 (file)
index 0000000..89cffdd
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor policy definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2017 Canonical 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, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_NAMESPACE_H
+#define __AA_NAMESPACE_H
+
+#include <linux/kref.h>
+
+#include "apparmor.h"
+#include "apparmorfs.h"
+#include "policy.h"
+
+
+/* struct aa_ns_acct - accounting of profiles in namespace
+ * @max_size: maximum space allowed for all profiles in namespace
+ * @max_count: maximum number of profiles that can be in this namespace
+ * @size: current size of profiles
+ * @count: current count of profiles (includes null profiles)
+ */
+struct aa_ns_acct {
+       int max_size;
+       int max_count;
+       int size;
+       int count;
+};
+
+/* struct aa_ns - namespace for a set of profiles
+ * @base: common policy
+ * @parent: parent of namespace
+ * @lock: lock for modifying the object
+ * @acct: accounting for the namespace
+ * @unconfined: special unconfined profile for the namespace
+ * @sub_ns: list of namespaces under the current namespace.
+ * @uniq_null: uniq value used for null learning profiles
+ * @uniq_id: a unique id count for the profiles in the namespace
+ * @level: level of ns within the tree hierarchy
+ * @dents: dentries for the namespaces file entries in apparmorfs
+ *
+ * An aa_ns defines the set profiles that are searched to determine which
+ * profile to attach to a task.  Profiles can not be shared between aa_ns
+ * and profile names within a namespace are guaranteed to be unique.  When
+ * profiles in separate namespaces have the same name they are NOT considered
+ * to be equivalent.
+ *
+ * Namespaces are hierarchical and only namespaces and profiles below the
+ * current namespace are visible.
+ *
+ * Namespace names must be unique and can not contain the characters :/\0
+ */
+struct aa_ns {
+       struct aa_policy base;
+       struct aa_ns *parent;
+       struct mutex lock;
+       struct aa_ns_acct acct;
+       struct aa_profile *unconfined;
+       struct list_head sub_ns;
+       atomic_t uniq_null;
+       long uniq_id;
+       int level;
+
+       struct dentry *dents[AAFS_NS_SIZEOF];
+};
+
+extern struct aa_ns *root_ns;
+
+extern const char *aa_hidden_ns_name;
+
+bool aa_ns_visible(struct aa_ns *curr, struct aa_ns *view, bool subns);
+const char *aa_ns_name(struct aa_ns *parent, struct aa_ns *child, bool subns);
+void aa_free_ns(struct aa_ns *ns);
+int aa_alloc_root_ns(void);
+void aa_free_root_ns(void);
+void aa_free_ns_kref(struct kref *kref);
+
+struct aa_ns *aa_find_ns(struct aa_ns *root, const char *name);
+struct aa_ns *aa_findn_ns(struct aa_ns *root, const char *name, size_t n);
+struct aa_ns *__aa_find_or_create_ns(struct aa_ns *parent, const char *name,
+                                    struct dentry *dir);
+struct aa_ns *aa_prepare_ns(struct aa_ns *root, const char *name);
+void __aa_remove_ns(struct aa_ns *ns);
+
+static inline struct aa_profile *aa_deref_parent(struct aa_profile *p)
+{
+       return rcu_dereference_protected(p->parent,
+                                        mutex_is_locked(&p->ns->lock));
+}
+
+/**
+ * aa_get_ns - increment references count on @ns
+ * @ns: namespace to increment reference count of (MAYBE NULL)
+ *
+ * Returns: pointer to @ns, if @ns is NULL returns NULL
+ * Requires: @ns must be held with valid refcount when called
+ */
+static inline struct aa_ns *aa_get_ns(struct aa_ns *ns)
+{
+       if (ns)
+               aa_get_profile(ns->unconfined);
+
+       return ns;
+}
+
+/**
+ * aa_put_ns - decrement refcount on @ns
+ * @ns: namespace to put reference of
+ *
+ * Decrement reference count of @ns and if no longer in use free it
+ */
+static inline void aa_put_ns(struct aa_ns *ns)
+{
+       if (ns)
+               aa_put_profile(ns->unconfined);
+}
+
+/**
+ * __aa_findn_ns - find a namespace on a list by @name
+ * @head: list to search for namespace on  (NOT NULL)
+ * @name: name of namespace to look for  (NOT NULL)
+ * @n: length of @name
+ * Returns: unrefcounted namespace
+ *
+ * Requires: rcu_read_lock be held
+ */
+static inline struct aa_ns *__aa_findn_ns(struct list_head *head,
+                                         const char *name, size_t n)
+{
+       return (struct aa_ns *)__policy_strn_find(head, name, n);
+}
+
+static inline struct aa_ns *__aa_find_ns(struct list_head *head,
+                                        const char *name)
+{
+       return __aa_findn_ns(head, name, strlen(name));
+}
+
+#endif /* AA_NAMESPACE_H */
index c214fb88b1bc8ada00577d675de1a149f6f30cf8..4c1319eebc427553769c9fedfaa64863c1c1c7c8 100644 (file)
 #define __POLICY_INTERFACE_H
 
 #include <linux/list.h>
+#include <linux/kref.h>
 
 struct aa_load_ent {
        struct list_head list;
        struct aa_profile *new;
        struct aa_profile *old;
        struct aa_profile *rename;
+       const char *ns_name;
 };
 
 void aa_load_ent_free(struct aa_load_ent *ent);
@@ -34,6 +36,30 @@ struct aa_load_ent *aa_load_ent_alloc(void);
 #define PACKED_MODE_KILL       2
 #define PACKED_MODE_UNCONFINED 3
 
-int aa_unpack(void *udata, size_t size, struct list_head *lh, const char **ns);
+/* struct aa_loaddata - buffer of policy load data set */
+struct aa_loaddata {
+       struct kref count;
+       size_t size;
+       int abi;
+       unsigned char *hash;
+       char data[];
+};
+
+int aa_unpack(struct aa_loaddata *udata, struct list_head *lh, const char **ns);
+
+static inline struct aa_loaddata *
+aa_get_loaddata(struct aa_loaddata *data)
+{
+       if (data)
+               kref_get(&(data->count));
+       return data;
+}
+
+void aa_loaddata_kref(struct kref *kref);
+static inline void aa_put_loaddata(struct aa_loaddata *data)
+{
+       if (data)
+               kref_put(&data->count, aa_loaddata_kref);
+}
 
 #endif /* __POLICY_INTERFACE_H */
diff --git a/security/apparmor/include/secid.h b/security/apparmor/include/secid.h
new file mode 100644 (file)
index 0000000..95ed86a
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor security identifier (secid) definitions
+ *
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_SECID_H
+#define __AA_SECID_H
+
+#include <linux/types.h>
+
+/* secid value that will not be allocated */
+#define AA_SECID_INVALID 0
+#define AA_SECID_ALLOC AA_SECID_INVALID
+
+u32 aa_alloc_secid(void);
+void aa_free_secid(u32 secid);
+
+#endif /* __AA_SECID_H */
diff --git a/security/apparmor/include/sid.h b/security/apparmor/include/sid.h
deleted file mode 100644 (file)
index 513ca0e..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * AppArmor security module
- *
- * This file contains AppArmor security identifier (sid) definitions
- *
- * Copyright 2009-2010 Canonical 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, version 2 of the
- * License.
- */
-
-#ifndef __AA_SID_H
-#define __AA_SID_H
-
-#include <linux/types.h>
-
-/* sid value that will not be allocated */
-#define AA_SID_INVALID 0
-#define AA_SID_ALLOC AA_SID_INVALID
-
-u32 aa_alloc_sid(void);
-void aa_free_sid(u32 sid);
-
-#endif /* __AA_SID_H */
index 777ac1c47253ef4f88aa1bc97c0539a9e0b96e83..edac790923c32aac77cb866a54e8d68e547e976c 100644 (file)
@@ -25,8 +25,8 @@
 static void audit_cb(struct audit_buffer *ab, void *va)
 {
        struct common_audit_data *sa = va;
-       audit_log_format(ab, " target=");
-       audit_log_untrustedstring(ab, sa->aad->target);
+       audit_log_format(ab, " peer=");
+       audit_log_untrustedstring(ab, aad(sa)->peer->base.hname);
 }
 
 /**
@@ -40,16 +40,12 @@ static void audit_cb(struct audit_buffer *ab, void *va)
 static int aa_audit_ptrace(struct aa_profile *profile,
                           struct aa_profile *target, int error)
 {
-       struct common_audit_data sa;
-       struct apparmor_audit_data aad = {0,};
-       sa.type = LSM_AUDIT_DATA_NONE;
-       sa.aad = &aad;
-       aad.op = OP_PTRACE;
-       aad.target = target;
-       aad.error = error;
+       DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_PTRACE);
 
-       return aa_audit(AUDIT_APPARMOR_AUTO, profile, GFP_ATOMIC, &sa,
-                       audit_cb);
+       aad(&sa)->peer = target;
+       aad(&sa)->error = error;
+
+       return aa_audit(AUDIT_APPARMOR_AUTO, profile, &sa, audit_cb);
 }
 
 /**
index c1827e068454cf992c510fd7f6bc9cbbda67a500..66475bda6f72212c330e7c6f8febfc930beb4e74 100644 (file)
@@ -12,6 +12,7 @@
  * License.
  */
 
+#include <linux/ctype.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/string.h>
@@ -19,7 +20,8 @@
 
 #include "include/audit.h"
 #include "include/apparmor.h"
-
+#include "include/lib.h"
+#include "include/policy.h"
 
 /**
  * aa_split_fqname - split a fqname into a profile and namespace name
@@ -59,6 +61,58 @@ char *aa_split_fqname(char *fqname, char **ns_name)
        return name;
 }
 
+/**
+ * skipn_spaces - Removes leading whitespace from @str.
+ * @str: The string to be stripped.
+ *
+ * Returns a pointer to the first non-whitespace character in @str.
+ * if all whitespace will return NULL
+ */
+
+static const char *skipn_spaces(const char *str, size_t n)
+{
+       for (; n && isspace(*str); --n)
+               ++str;
+       if (n)
+               return (char *)str;
+       return NULL;
+}
+
+const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name,
+                            size_t *ns_len)
+{
+       const char *end = fqname + n;
+       const char *name = skipn_spaces(fqname, n);
+
+       if (!name)
+               return NULL;
+       *ns_name = NULL;
+       *ns_len = 0;
+       if (name[0] == ':') {
+               char *split = strnchr(&name[1], end - &name[1], ':');
+               *ns_name = skipn_spaces(&name[1], end - &name[1]);
+               if (!*ns_name)
+                       return NULL;
+               if (split) {
+                       *ns_len = split - *ns_name;
+                       if (*ns_len == 0)
+                               *ns_name = NULL;
+                       split++;
+                       if (end - split > 1 && strncmp(split, "//", 2) == 0)
+                               split += 2;
+                       name = skipn_spaces(split, end - split);
+               } else {
+                       /* a ns name without a following profile is allowed */
+                       name = NULL;
+                       *ns_len = end - *ns_name;
+               }
+       }
+       if (name && *name == 0)
+               name = NULL;
+
+       return name;
+}
+
 /**
  * aa_info_message - log a none profile related status message
  * @str: message to log
@@ -66,11 +120,9 @@ char *aa_split_fqname(char *fqname, char **ns_name)
 void aa_info_message(const char *str)
 {
        if (audit_enabled) {
-               struct common_audit_data sa;
-               struct apparmor_audit_data aad = {0,};
-               sa.type = LSM_AUDIT_DATA_NONE;
-               sa.aad = &aad;
-               aad.info = str;
+               DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, NULL);
+
+               aad(&sa)->info = str;
                aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL);
        }
        printk(KERN_INFO "AppArmor: %s\n", str);
@@ -95,7 +147,8 @@ void *__aa_kvmalloc(size_t size, gfp_t flags)
 
        /* do not attempt kmalloc if we need more than 16 pages at once */
        if (size <= (16*PAGE_SIZE))
-               buffer = kmalloc(size, flags | GFP_NOIO | __GFP_NOWARN);
+               buffer = kmalloc(size, flags | GFP_KERNEL | __GFP_NORETRY |
+                                __GFP_NOWARN);
        if (!buffer) {
                if (flags & __GFP_ZERO)
                        buffer = vzalloc(size);
@@ -104,3 +157,47 @@ void *__aa_kvmalloc(size_t size, gfp_t flags)
        }
        return buffer;
 }
+
+/**
+ * aa_policy_init - initialize a policy structure
+ * @policy: policy to initialize  (NOT NULL)
+ * @prefix: prefix name if any is required.  (MAYBE NULL)
+ * @name: name of the policy, init will make a copy of it  (NOT NULL)
+ *
+ * Note: this fn creates a copy of strings passed in
+ *
+ * Returns: true if policy init successful
+ */
+bool aa_policy_init(struct aa_policy *policy, const char *prefix,
+                   const char *name, gfp_t gfp)
+{
+       /* freed by policy_free */
+       if (prefix) {
+               policy->hname = kmalloc(strlen(prefix) + strlen(name) + 3,
+                                       gfp);
+               if (policy->hname)
+                       sprintf((char *)policy->hname, "%s//%s", prefix, name);
+       } else
+               policy->hname = kstrdup(name, gfp);
+       if (!policy->hname)
+               return 0;
+       /* base.name is a substring of fqname */
+       policy->name = basename(policy->hname);
+       INIT_LIST_HEAD(&policy->list);
+       INIT_LIST_HEAD(&policy->profiles);
+
+       return 1;
+}
+
+/**
+ * aa_policy_destroy - free the elements referenced by @policy
+ * @policy: policy that is to have its elements freed  (NOT NULL)
+ */
+void aa_policy_destroy(struct aa_policy *policy)
+{
+       AA_BUG(on_list_rcu(&policy->profiles));
+       AA_BUG(on_list_rcu(&policy->list));
+
+       /* don't free name as its a subset of hname */
+       kzfree(policy->hname);
+}
index 41b8cb115801724172ce48cbb3ac6b3d96a8d6f6..709eacd23909acfa5438e9173085d91eb1780991 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/sysctl.h>
 #include <linux/audit.h>
 #include <linux/user_namespace.h>
+#include <linux/kmemleak.h>
 #include <net/sock.h>
 
 #include "include/apparmor.h"
 #include "include/ipc.h"
 #include "include/path.h"
 #include "include/policy.h"
+#include "include/policy_ns.h"
 #include "include/procattr.h"
 
 /* Flag indicating whether initialization completed */
 int apparmor_initialized __initdata;
 
+DEFINE_PER_CPU(struct aa_buffers, aa_buffers);
+
+
 /*
  * LSM hook functions
  */
 
 /*
- * free the associated aa_task_cxt and put its profiles
+ * free the associated aa_task_ctx and put its profiles
  */
 static void apparmor_cred_free(struct cred *cred)
 {
-       aa_free_task_context(cred_cxt(cred));
-       cred_cxt(cred) = NULL;
+       aa_free_task_context(cred_ctx(cred));
+       cred_ctx(cred) = NULL;
 }
 
 /*
@@ -58,27 +63,29 @@ static void apparmor_cred_free(struct cred *cred)
 static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp)
 {
        /* freed by apparmor_cred_free */
-       struct aa_task_cxt *cxt = aa_alloc_task_context(gfp);
-       if (!cxt)
+       struct aa_task_ctx *ctx = aa_alloc_task_context(gfp);
+
+       if (!ctx)
                return -ENOMEM;
 
-       cred_cxt(cred) = cxt;
+       cred_ctx(cred) = ctx;
        return 0;
 }
 
 /*
- * prepare new aa_task_cxt for modification by prepare_cred block
+ * prepare new aa_task_ctx for modification by prepare_cred block
  */
 static int apparmor_cred_prepare(struct cred *new, const struct cred *old,
                                 gfp_t gfp)
 {
        /* freed by apparmor_cred_free */
-       struct aa_task_cxt *cxt = aa_alloc_task_context(gfp);
-       if (!cxt)
+       struct aa_task_ctx *ctx = aa_alloc_task_context(gfp);
+
+       if (!ctx)
                return -ENOMEM;
 
-       aa_dup_task_context(cxt, cred_cxt(old));
-       cred_cxt(new) = cxt;
+       aa_dup_task_context(ctx, cred_ctx(old));
+       cred_ctx(new) = ctx;
        return 0;
 }
 
@@ -87,10 +94,10 @@ static int apparmor_cred_prepare(struct cred *new, const struct cred *old,
  */
 static void apparmor_cred_transfer(struct cred *new, const struct cred *old)
 {
-       const struct aa_task_cxt *old_cxt = cred_cxt(old);
-       struct aa_task_cxt *new_cxt = cred_cxt(new);
+       const struct aa_task_ctx *old_ctx = cred_ctx(old);
+       struct aa_task_ctx *new_ctx = cred_ctx(new);
 
-       aa_dup_task_context(new_cxt, old_cxt);
+       aa_dup_task_context(new_ctx, old_ctx);
 }
 
 static int apparmor_ptrace_access_check(struct task_struct *child,
@@ -149,7 +156,7 @@ static int apparmor_capable(const struct cred *cred, struct user_namespace *ns,
  *
  * Returns: %0 else error code if error or permission denied
  */
-static int common_perm(int op, const struct path *path, u32 mask,
+static int common_perm(const char *op, const struct path *path, u32 mask,
                       struct path_cond *cond)
 {
        struct aa_profile *profile;
@@ -163,41 +170,42 @@ static int common_perm(int op, const struct path *path, u32 mask,
 }
 
 /**
- * common_perm_dir_dentry - common permission wrapper when path is dir, dentry
+ * common_perm_cond - common permission wrapper around inode cond
  * @op: operation being checked
- * @dir: directory of the dentry  (NOT NULL)
- * @dentry: dentry to check  (NOT NULL)
+ * @path: location to check (NOT NULL)
  * @mask: requested permissions mask
- * @cond: conditional info for the permission request  (NOT NULL)
  *
  * Returns: %0 else error code if error or permission denied
  */
-static int common_perm_dir_dentry(int op, const struct path *dir,
-                                 struct dentry *dentry, u32 mask,
-                                 struct path_cond *cond)
+static int common_perm_cond(const char *op, const struct path *path, u32 mask)
 {
-       struct path path = { dir->mnt, dentry };
+       struct path_cond cond = { d_backing_inode(path->dentry)->i_uid,
+                                 d_backing_inode(path->dentry)->i_mode
+       };
 
-       return common_perm(op, &path, mask, cond);
+       if (!path_mediated_fs(path->dentry))
+               return 0;
+
+       return common_perm(op, path, mask, &cond);
 }
 
 /**
- * common_perm_path - common permission wrapper when mnt, dentry
+ * common_perm_dir_dentry - common permission wrapper when path is dir, dentry
  * @op: operation being checked
- * @path: location to check (NOT NULL)
+ * @dir: directory of the dentry  (NOT NULL)
+ * @dentry: dentry to check  (NOT NULL)
  * @mask: requested permissions mask
+ * @cond: conditional info for the permission request  (NOT NULL)
  *
  * Returns: %0 else error code if error or permission denied
  */
-static inline int common_perm_path(int op, const struct path *path, u32 mask)
+static int common_perm_dir_dentry(const char *op, const struct path *dir,
+                                 struct dentry *dentry, u32 mask,
+                                 struct path_cond *cond)
 {
-       struct path_cond cond = { d_backing_inode(path->dentry)->i_uid,
-                                 d_backing_inode(path->dentry)->i_mode
-       };
-       if (!mediated_filesystem(path->dentry))
-               return 0;
+       struct path path = { .mnt = dir->mnt, .dentry = dentry };
 
-       return common_perm(op, path, mask, &cond);
+       return common_perm(op, &path, mask, cond);
 }
 
 /**
@@ -209,13 +217,13 @@ static inline int common_perm_path(int op, const struct path *path, u32 mask)
  *
  * Returns: %0 else error code if error or permission denied
  */
-static int common_perm_rm(int op, const struct path *dir,
+static int common_perm_rm(const char *op, const struct path *dir,
                          struct dentry *dentry, u32 mask)
 {
        struct inode *inode = d_backing_inode(dentry);
        struct path_cond cond = { };
 
-       if (!inode || !mediated_filesystem(dentry))
+       if (!inode || !path_mediated_fs(dentry))
                return 0;
 
        cond.uid = inode->i_uid;
@@ -234,12 +242,12 @@ static int common_perm_rm(int op, const struct path *dir,
  *
  * Returns: %0 else error code if error or permission denied
  */
-static int common_perm_create(int op, const struct path *dir,
+static int common_perm_create(const char *op, const struct path *dir,
                              struct dentry *dentry, u32 mask, umode_t mode)
 {
        struct path_cond cond = { current_fsuid(), mode };
 
-       if (!mediated_filesystem(dir->dentry))
+       if (!path_mediated_fs(dir->dentry))
                return 0;
 
        return common_perm_dir_dentry(op, dir, dentry, mask, &cond);
@@ -270,7 +278,7 @@ static int apparmor_path_mknod(const struct path *dir, struct dentry *dentry,
 
 static int apparmor_path_truncate(const struct path *path)
 {
-       return common_perm_path(OP_TRUNC, path, MAY_WRITE | AA_MAY_META_WRITE);
+       return common_perm_cond(OP_TRUNC, path, MAY_WRITE | AA_MAY_META_WRITE);
 }
 
 static int apparmor_path_symlink(const struct path *dir, struct dentry *dentry,
@@ -286,7 +294,7 @@ static int apparmor_path_link(struct dentry *old_dentry, const struct path *new_
        struct aa_profile *profile;
        int error = 0;
 
-       if (!mediated_filesystem(old_dentry))
+       if (!path_mediated_fs(old_dentry))
                return 0;
 
        profile = aa_current_profile();
@@ -301,13 +309,15 @@ static int apparmor_path_rename(const struct path *old_dir, struct dentry *old_d
        struct aa_profile *profile;
        int error = 0;
 
-       if (!mediated_filesystem(old_dentry))
+       if (!path_mediated_fs(old_dentry))
                return 0;
 
        profile = aa_current_profile();
        if (!unconfined(profile)) {
-               struct path old_path = { old_dir->mnt, old_dentry };
-               struct path new_path = { new_dir->mnt, new_dentry };
+               struct path old_path = { .mnt = old_dir->mnt,
+                                        .dentry = old_dentry };
+               struct path new_path = { .mnt = new_dir->mnt,
+                                        .dentry = new_dentry };
                struct path_cond cond = { d_backing_inode(old_dentry)->i_uid,
                                          d_backing_inode(old_dentry)->i_mode
                };
@@ -327,26 +337,26 @@ static int apparmor_path_rename(const struct path *old_dir, struct dentry *old_d
 
 static int apparmor_path_chmod(const struct path *path, umode_t mode)
 {
-       return common_perm_path(OP_CHMOD, path, AA_MAY_CHMOD);
+       return common_perm_cond(OP_CHMOD, path, AA_MAY_CHMOD);
 }
 
 static int apparmor_path_chown(const struct path *path, kuid_t uid, kgid_t gid)
 {
-       return common_perm_path(OP_CHOWN, path, AA_MAY_CHOWN);
+       return common_perm_cond(OP_CHOWN, path, AA_MAY_CHOWN);
 }
 
 static int apparmor_inode_getattr(const struct path *path)
 {
-       return common_perm_path(OP_GETATTR, path, AA_MAY_META_READ);
+       return common_perm_cond(OP_GETATTR, path, AA_MAY_META_READ);
 }
 
 static int apparmor_file_open(struct file *file, const struct cred *cred)
 {
-       struct aa_file_cxt *fcxt = file->f_security;
+       struct aa_file_ctx *fctx = file->f_security;
        struct aa_profile *profile;
        int error = 0;
 
-       if (!mediated_filesystem(file->f_path.dentry))
+       if (!path_mediated_fs(file->f_path.dentry))
                return 0;
 
        /* If in exec, permission is handled by bprm hooks.
@@ -355,7 +365,7 @@ static int apparmor_file_open(struct file *file, const struct cred *cred)
         * actually execute the image.
         */
        if (current->in_execve) {
-               fcxt->allow = MAY_EXEC | MAY_READ | AA_EXEC_MMAP;
+               fctx->allow = MAY_EXEC | MAY_READ | AA_EXEC_MMAP;
                return 0;
        }
 
@@ -367,7 +377,7 @@ static int apparmor_file_open(struct file *file, const struct cred *cred)
                error = aa_path_perm(OP_OPEN, profile, &file->f_path, 0,
                                     aa_map_file_to_perms(file), &cond);
                /* todo cache full allowed permissions set and state */
-               fcxt->allow = aa_map_file_to_perms(file);
+               fctx->allow = aa_map_file_to_perms(file);
        }
 
        return error;
@@ -385,21 +395,21 @@ static int apparmor_file_alloc_security(struct file *file)
 
 static void apparmor_file_free_security(struct file *file)
 {
-       struct aa_file_cxt *cxt = file->f_security;
+       struct aa_file_ctx *ctx = file->f_security;
 
-       aa_free_file_context(cxt);
+       aa_free_file_context(ctx);
 }
 
-static int common_file_perm(int op, struct file *file, u32 mask)
+static int common_file_perm(const char *op, struct file *file, u32 mask)
 {
-       struct aa_file_cxt *fcxt = file->f_security;
+       struct aa_file_ctx *fctx = file->f_security;
        struct aa_profile *profile, *fprofile = aa_cred_profile(file->f_cred);
        int error = 0;
 
-       BUG_ON(!fprofile);
+       AA_BUG(!fprofile);
 
        if (!file->f_path.mnt ||
-           !mediated_filesystem(file->f_path.dentry))
+           !path_mediated_fs(file->f_path.dentry))
                return 0;
 
        profile = __aa_current_profile();
@@ -412,7 +422,7 @@ static int common_file_perm(int op, struct file *file, u32 mask)
         *       delegation from unconfined tasks
         */
        if (!unconfined(profile) && !unconfined(fprofile) &&
-           ((fprofile != profile) || (mask & ~fcxt->allow)))
+           ((fprofile != profile) || (mask & ~fctx->allow)))
                error = aa_file_perm(op, profile, file, mask);
 
        return error;
@@ -433,7 +443,7 @@ static int apparmor_file_lock(struct file *file, unsigned int cmd)
        return common_file_perm(OP_FLOCK, file, mask);
 }
 
-static int common_mmap(int op, struct file *file, unsigned long prot,
+static int common_mmap(const char *op, struct file *file, unsigned long prot,
                       unsigned long flags)
 {
        int mask = 0;
@@ -474,15 +484,15 @@ static int apparmor_getprocattr(struct task_struct *task, char *name,
        int error = -ENOENT;
        /* released below */
        const struct cred *cred = get_task_cred(task);
-       struct aa_task_cxt *cxt = cred_cxt(cred);
+       struct aa_task_ctx *ctx = cred_ctx(cred);
        struct aa_profile *profile = NULL;
 
        if (strcmp(name, "current") == 0)
-               profile = aa_get_newest_profile(cxt->profile);
-       else if (strcmp(name, "prev") == 0  && cxt->previous)
-               profile = aa_get_newest_profile(cxt->previous);
-       else if (strcmp(name, "exec") == 0 && cxt->onexec)
-               profile = aa_get_newest_profile(cxt->onexec);
+               profile = aa_get_newest_profile(ctx->profile);
+       else if (strcmp(name, "prev") == 0  && ctx->previous)
+               profile = aa_get_newest_profile(ctx->previous);
+       else if (strcmp(name, "exec") == 0 && ctx->onexec)
+               profile = aa_get_newest_profile(ctx->onexec);
        else
                error = -EINVAL;
 
@@ -495,20 +505,16 @@ static int apparmor_getprocattr(struct task_struct *task, char *name,
        return error;
 }
 
-static int apparmor_setprocattr(struct task_struct *task, char *name,
-                               void *value, size_t size)
+static int apparmor_setprocattr(const char *name, void *value,
+                               size_t size)
 {
-       struct common_audit_data sa;
-       struct apparmor_audit_data aad = {0,};
        char *command, *largs = NULL, *args = value;
        size_t arg_size;
        int error;
+       DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_SETPROCATTR);
 
        if (size == 0)
                return -EINVAL;
-       /* task can only write its own attributes */
-       if (current != task)
-               return -EACCES;
 
        /* AppArmor requires that the buffer must be null terminated atm */
        if (args[size - 1] != '\0') {
@@ -538,17 +544,17 @@ static int apparmor_setprocattr(struct task_struct *task, char *name,
                        error = aa_setprocattr_changehat(args, arg_size,
                                                         AA_DO_TEST);
                } else if (strcmp(command, "changeprofile") == 0) {
-                       error = aa_setprocattr_changeprofile(args, !AA_ONEXEC,
-                                                            !AA_DO_TEST);
+                       error = aa_change_profile(args, !AA_ONEXEC,
+                                                 !AA_DO_TEST, false);
                } else if (strcmp(command, "permprofile") == 0) {
-                       error = aa_setprocattr_changeprofile(args, !AA_ONEXEC,
-                                                            AA_DO_TEST);
+                       error = aa_change_profile(args, !AA_ONEXEC, AA_DO_TEST,
+                                                 false);
                } else
                        goto fail;
        } else if (strcmp(name, "exec") == 0) {
                if (strcmp(command, "exec") == 0)
-                       error = aa_setprocattr_changeprofile(args, AA_ONEXEC,
-                                                            !AA_DO_TEST);
+                       error = aa_change_profile(args, AA_ONEXEC, !AA_DO_TEST,
+                                                 false);
                else
                        goto fail;
        } else
@@ -562,12 +568,9 @@ out:
        return error;
 
 fail:
-       sa.type = LSM_AUDIT_DATA_NONE;
-       sa.aad = &aad;
-       aad.profile = aa_current_profile();
-       aad.op = OP_SETPROCATTR;
-       aad.info = name;
-       aad.error = error = -EINVAL;
+       aad(&sa)->profile = aa_current_profile();
+       aad(&sa)->info = name;
+       aad(&sa)->error = error = -EINVAL;
        aa_audit_msg(AUDIT_APPARMOR_DENIED, &sa, NULL);
        goto out;
 }
@@ -671,14 +674,14 @@ enum profile_mode aa_g_profile_mode = APPARMOR_ENFORCE;
 module_param_call(mode, param_set_mode, param_get_mode,
                  &aa_g_profile_mode, S_IRUSR | S_IWUSR);
 
-#ifdef CONFIG_SECURITY_APPARMOR_HASH
 /* whether policy verification hashing is enabled */
 bool aa_g_hash_policy = IS_ENABLED(CONFIG_SECURITY_APPARMOR_HASH_DEFAULT);
+#ifdef CONFIG_SECURITY_APPARMOR_HASH
 module_param_named(hash_policy, aa_g_hash_policy, aabool, S_IRUSR | S_IWUSR);
 #endif
 
 /* Debug mode */
-bool aa_g_debug;
+bool aa_g_debug = IS_ENABLED(CONFIG_SECURITY_DEBUG_MESSAGES);
 module_param_named(debug, aa_g_debug, aabool, S_IRUSR | S_IWUSR);
 
 /* Audit mode */
@@ -711,10 +714,11 @@ module_param_named(path_max, aa_g_path_max, aauint, S_IRUSR | S_IWUSR);
 
 /* Determines how paranoid loading of policy is and how much verification
  * on the loaded policy is done.
+ * DEPRECATED: read only as strict checking of load is always done now
+ * that none root users (user namespaces) can load policy.
  */
 bool aa_g_paranoid_load = 1;
-module_param_named(paranoid_load, aa_g_paranoid_load, aabool,
-                  S_IRUSR | S_IWUSR);
+module_param_named(paranoid_load, aa_g_paranoid_load, aabool, S_IRUGO);
 
 /* Boot time disable flag */
 static bool apparmor_enabled = CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE;
@@ -734,49 +738,59 @@ __setup("apparmor=", apparmor_enabled_setup);
 /* set global flag turning off the ability to load policy */
 static int param_set_aalockpolicy(const char *val, const struct kernel_param *kp)
 {
-       if (!policy_admin_capable())
+       if (!policy_admin_capable(NULL))
                return -EPERM;
        return param_set_bool(val, kp);
 }
 
 static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp)
 {
-       if (!policy_view_capable())
+       if (!policy_view_capable(NULL))
                return -EPERM;
+       if (!apparmor_enabled)
+               return -EINVAL;
        return param_get_bool(buffer, kp);
 }
 
 static int param_set_aabool(const char *val, const struct kernel_param *kp)
 {
-       if (!policy_admin_capable())
+       if (!policy_admin_capable(NULL))
                return -EPERM;
+       if (!apparmor_enabled)
+               return -EINVAL;
        return param_set_bool(val, kp);
 }
 
 static int param_get_aabool(char *buffer, const struct kernel_param *kp)
 {
-       if (!policy_view_capable())
+       if (!policy_view_capable(NULL))
                return -EPERM;
+       if (!apparmor_enabled)
+               return -EINVAL;
        return param_get_bool(buffer, kp);
 }
 
 static int param_set_aauint(const char *val, const struct kernel_param *kp)
 {
-       if (!policy_admin_capable())
+       if (!policy_admin_capable(NULL))
                return -EPERM;
+       if (!apparmor_enabled)
+               return -EINVAL;
        return param_set_uint(val, kp);
 }
 
 static int param_get_aauint(char *buffer, const struct kernel_param *kp)
 {
-       if (!policy_view_capable())
+       if (!policy_view_capable(NULL))
                return -EPERM;
+       if (!apparmor_enabled)
+               return -EINVAL;
        return param_get_uint(buffer, kp);
 }
 
 static int param_get_audit(char *buffer, struct kernel_param *kp)
 {
-       if (!policy_view_capable())
+       if (!policy_view_capable(NULL))
                return -EPERM;
 
        if (!apparmor_enabled)
@@ -788,7 +802,7 @@ static int param_get_audit(char *buffer, struct kernel_param *kp)
 static int param_set_audit(const char *val, struct kernel_param *kp)
 {
        int i;
-       if (!policy_admin_capable())
+       if (!policy_admin_capable(NULL))
                return -EPERM;
 
        if (!apparmor_enabled)
@@ -809,7 +823,7 @@ static int param_set_audit(const char *val, struct kernel_param *kp)
 
 static int param_get_mode(char *buffer, struct kernel_param *kp)
 {
-       if (!policy_admin_capable())
+       if (!policy_view_capable(NULL))
                return -EPERM;
 
        if (!apparmor_enabled)
@@ -821,7 +835,7 @@ static int param_get_mode(char *buffer, struct kernel_param *kp)
 static int param_set_mode(const char *val, struct kernel_param *kp)
 {
        int i;
-       if (!policy_admin_capable())
+       if (!policy_admin_capable(NULL))
                return -EPERM;
 
        if (!apparmor_enabled)
@@ -845,25 +859,102 @@ static int param_set_mode(const char *val, struct kernel_param *kp)
  */
 
 /**
- * set_init_cxt - set a task context and profile on the first task.
+ * set_init_ctx - set a task context and profile on the first task.
  *
  * TODO: allow setting an alternate profile than unconfined
  */
-static int __init set_init_cxt(void)
+static int __init set_init_ctx(void)
 {
        struct cred *cred = (struct cred *)current->real_cred;
-       struct aa_task_cxt *cxt;
+       struct aa_task_ctx *ctx;
 
-       cxt = aa_alloc_task_context(GFP_KERNEL);
-       if (!cxt)
+       ctx = aa_alloc_task_context(GFP_KERNEL);
+       if (!ctx)
                return -ENOMEM;
 
-       cxt->profile = aa_get_profile(root_ns->unconfined);
-       cred_cxt(cred) = cxt;
+       ctx->profile = aa_get_profile(root_ns->unconfined);
+       cred_ctx(cred) = ctx;
 
        return 0;
 }
 
+static void destroy_buffers(void)
+{
+       u32 i, j;
+
+       for_each_possible_cpu(i) {
+               for_each_cpu_buffer(j) {
+                       kfree(per_cpu(aa_buffers, i).buf[j]);
+                       per_cpu(aa_buffers, i).buf[j] = NULL;
+               }
+       }
+}
+
+static int __init alloc_buffers(void)
+{
+       u32 i, j;
+
+       for_each_possible_cpu(i) {
+               for_each_cpu_buffer(j) {
+                       char *buffer;
+
+                       if (cpu_to_node(i) > num_online_nodes())
+                               /* fallback to kmalloc for offline nodes */
+                               buffer = kmalloc(aa_g_path_max, GFP_KERNEL);
+                       else
+                               buffer = kmalloc_node(aa_g_path_max, GFP_KERNEL,
+                                                     cpu_to_node(i));
+                       if (!buffer) {
+                               destroy_buffers();
+                               return -ENOMEM;
+                       }
+                       per_cpu(aa_buffers, i).buf[j] = buffer;
+               }
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_SYSCTL
+static int apparmor_dointvec(struct ctl_table *table, int write,
+                            void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       if (!policy_admin_capable(NULL))
+               return -EPERM;
+       if (!apparmor_enabled)
+               return -EINVAL;
+
+       return proc_dointvec(table, write, buffer, lenp, ppos);
+}
+
+static struct ctl_path apparmor_sysctl_path[] = {
+       { .procname = "kernel", },
+       { }
+};
+
+static struct ctl_table apparmor_sysctl_table[] = {
+       {
+               .procname       = "unprivileged_userns_apparmor_policy",
+               .data           = &unprivileged_userns_apparmor_policy,
+               .maxlen         = sizeof(int),
+               .mode           = 0600,
+               .proc_handler   = apparmor_dointvec,
+       },
+       { }
+};
+
+static int __init apparmor_init_sysctl(void)
+{
+       return register_sysctl_paths(apparmor_sysctl_path,
+                                    apparmor_sysctl_table) ? 0 : -ENOMEM;
+}
+#else
+static inline int apparmor_init_sysctl(void)
+{
+       return 0;
+}
+#endif /* CONFIG_SYSCTL */
+
 static int __init apparmor_init(void)
 {
        int error;
@@ -874,19 +965,39 @@ static int __init apparmor_init(void)
                return 0;
        }
 
+       error = aa_setup_dfa_engine();
+       if (error) {
+               AA_ERROR("Unable to setup dfa engine\n");
+               goto alloc_out;
+       }
+
        error = aa_alloc_root_ns();
        if (error) {
                AA_ERROR("Unable to allocate default profile namespace\n");
                goto alloc_out;
        }
 
-       error = set_init_cxt();
+       error = apparmor_init_sysctl();
+       if (error) {
+               AA_ERROR("Unable to register sysctls\n");
+               goto alloc_out;
+
+       }
+
+       error = alloc_buffers();
+       if (error) {
+               AA_ERROR("Unable to allocate work buffers\n");
+               goto buffers_out;
+       }
+
+       error = set_init_ctx();
        if (error) {
                AA_ERROR("Failed to set context on init task\n");
                aa_free_root_ns();
-               goto alloc_out;
+               goto buffers_out;
        }
-       security_add_hooks(apparmor_hooks, ARRAY_SIZE(apparmor_hooks));
+       security_add_hooks(apparmor_hooks, ARRAY_SIZE(apparmor_hooks),
+                               "apparmor");
 
        /* Report that AppArmor successfully initialized */
        apparmor_initialized = 1;
@@ -899,8 +1010,12 @@ static int __init apparmor_init(void)
 
        return error;
 
+buffers_out:
+       destroy_buffers();
+
 alloc_out:
        aa_destroy_aafs();
+       aa_teardown_dfa_engine();
 
        apparmor_enabled = 0;
        return error;
index 3f900fcca8fb583b64e90ca7e52e451a600828b1..eb0efef746f56ff193e4b507c97c22c486ffbce9 100644 (file)
 #include <linux/err.h>
 #include <linux/kref.h>
 
-#include "include/apparmor.h"
+#include "include/lib.h"
 #include "include/match.h"
 
 #define base_idx(X) ((X) & 0xffffff)
 
+static char nulldfa_src[] = {
+       #include "nulldfa.in"
+};
+struct aa_dfa *nulldfa;
+
+int aa_setup_dfa_engine(void)
+{
+       int error;
+
+       nulldfa = aa_dfa_unpack(nulldfa_src, sizeof(nulldfa_src),
+                               TO_ACCEPT1_FLAG(YYTD_DATA32) |
+                               TO_ACCEPT2_FLAG(YYTD_DATA32));
+       if (!IS_ERR(nulldfa))
+               return 0;
+
+       error = PTR_ERR(nulldfa);
+       nulldfa = NULL;
+
+       return error;
+}
+
+void aa_teardown_dfa_engine(void)
+{
+       aa_put_dfa(nulldfa);
+       nulldfa = NULL;
+}
+
 /**
  * unpack_table - unpack a dfa table (one of accept, default, base, next check)
  * @blob: data to unpack (NOT NULL)
@@ -46,11 +73,11 @@ static struct table_header *unpack_table(char *blob, size_t bsize)
        /* loaded td_id's start at 1, subtract 1 now to avoid doing
         * it every time we use td_id as an index
         */
-       th.td_id = be16_to_cpu(*(u16 *) (blob)) - 1;
+       th.td_id = be16_to_cpu(*(__be16 *) (blob)) - 1;
        if (th.td_id > YYTD_ID_MAX)
                goto out;
-       th.td_flags = be16_to_cpu(*(u16 *) (blob + 2));
-       th.td_lolen = be32_to_cpu(*(u32 *) (blob + 8));
+       th.td_flags = be16_to_cpu(*(__be16 *) (blob + 2));
+       th.td_lolen = be32_to_cpu(*(__be32 *) (blob + 8));
        blob += sizeof(struct table_header);
 
        if (!(th.td_flags == YYTD_DATA16 || th.td_flags == YYTD_DATA32 ||
@@ -68,13 +95,13 @@ static struct table_header *unpack_table(char *blob, size_t bsize)
                table->td_lolen = th.td_lolen;
                if (th.td_flags == YYTD_DATA8)
                        UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
-                                    u8, byte_to_byte);
+                                    u8, u8, byte_to_byte);
                else if (th.td_flags == YYTD_DATA16)
                        UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
-                                    u16, be16_to_cpu);
+                                    u16, __be16, be16_to_cpu);
                else if (th.td_flags == YYTD_DATA32)
                        UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
-                                    u32, be32_to_cpu);
+                                    u32, __be32, be32_to_cpu);
                else
                        goto fail;
                /* if table was vmalloced make sure the page tables are synced
@@ -222,14 +249,14 @@ struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags)
        if (size < sizeof(struct table_set_header))
                goto fail;
 
-       if (ntohl(*(u32 *) data) != YYTH_MAGIC)
+       if (ntohl(*(__be32 *) data) != YYTH_MAGIC)
                goto fail;
 
-       hsize = ntohl(*(u32 *) (data + 4));
+       hsize = ntohl(*(__be32 *) (data + 4));
        if (size < hsize)
                goto fail;
 
-       dfa->flags = ntohs(*(u16 *) (data + 12));
+       dfa->flags = ntohs(*(__be16 *) (data + 12));
        data += hsize;
        size -= hsize;
 
diff --git a/security/apparmor/nulldfa.in b/security/apparmor/nulldfa.in
new file mode 100644 (file)
index 0000000..3cb3802
--- /dev/null
@@ -0,0 +1 @@
+0x1B, 0x5E, 0x78, 0x3D, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x04, 0x90, 0x00, 0x00, 0x6E, 0x6F, 0x74, 0x66, 0x6C, 0x65, 0x78, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
index 179e68d7dc5f968e9d21e16cff26327ca0b7997a..f44312a19522b6fd1e83a877c6e3557500d1a127 100644 (file)
@@ -76,6 +76,7 @@
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/string.h>
+#include <linux/user_namespace.h>
 
 #include "include/apparmor.h"
 #include "include/capability.h"
 #include "include/match.h"
 #include "include/path.h"
 #include "include/policy.h"
+#include "include/policy_ns.h"
 #include "include/policy_unpack.h"
 #include "include/resource.h"
 
-
-/* root profile namespace */
-struct aa_namespace *root_ns;
+int unprivileged_userns_apparmor_policy = 1;
 
 const char *const aa_profile_mode_names[] = {
        "enforce",
@@ -99,318 +99,16 @@ const char *const aa_profile_mode_names[] = {
        "unconfined",
 };
 
-/**
- * hname_tail - find the last component of an hname
- * @name: hname to find the base profile name component of  (NOT NULL)
- *
- * Returns: the tail (base profile name) name component of an hname
- */
-static const char *hname_tail(const char *hname)
-{
-       char *split;
-       hname = strim((char *)hname);
-       for (split = strstr(hname, "//"); split; split = strstr(hname, "//"))
-               hname = split + 2;
-
-       return hname;
-}
-
-/**
- * policy_init - initialize a policy structure
- * @policy: policy to initialize  (NOT NULL)
- * @prefix: prefix name if any is required.  (MAYBE NULL)
- * @name: name of the policy, init will make a copy of it  (NOT NULL)
- *
- * Note: this fn creates a copy of strings passed in
- *
- * Returns: true if policy init successful
- */
-static bool policy_init(struct aa_policy *policy, const char *prefix,
-                       const char *name)
-{
-       /* freed by policy_free */
-       if (prefix) {
-               policy->hname = kmalloc(strlen(prefix) + strlen(name) + 3,
-                                       GFP_KERNEL);
-               if (policy->hname)
-                       sprintf(policy->hname, "%s//%s", prefix, name);
-       } else
-               policy->hname = kstrdup(name, GFP_KERNEL);
-       if (!policy->hname)
-               return 0;
-       /* base.name is a substring of fqname */
-       policy->name = (char *)hname_tail(policy->hname);
-       INIT_LIST_HEAD(&policy->list);
-       INIT_LIST_HEAD(&policy->profiles);
-
-       return 1;
-}
-
-/**
- * policy_destroy - free the elements referenced by @policy
- * @policy: policy that is to have its elements freed  (NOT NULL)
- */
-static void policy_destroy(struct aa_policy *policy)
-{
-       /* still contains profiles -- invalid */
-       if (on_list_rcu(&policy->profiles)) {
-               AA_ERROR("%s: internal error, "
-                        "policy '%s' still contains profiles\n",
-                        __func__, policy->name);
-               BUG();
-       }
-       if (on_list_rcu(&policy->list)) {
-               AA_ERROR("%s: internal error, policy '%s' still on list\n",
-                        __func__, policy->name);
-               BUG();
-       }
-
-       /* don't free name as its a subset of hname */
-       kzfree(policy->hname);
-}
-
-/**
- * __policy_find - find a policy by @name on a policy list
- * @head: list to search  (NOT NULL)
- * @name: name to search for  (NOT NULL)
- *
- * Requires: rcu_read_lock be held
- *
- * Returns: unrefcounted policy that match @name or NULL if not found
- */
-static struct aa_policy *__policy_find(struct list_head *head, const char *name)
-{
-       struct aa_policy *policy;
-
-       list_for_each_entry_rcu(policy, head, list) {
-               if (!strcmp(policy->name, name))
-                       return policy;
-       }
-       return NULL;
-}
-
-/**
- * __policy_strn_find - find a policy that's name matches @len chars of @str
- * @head: list to search  (NOT NULL)
- * @str: string to search for  (NOT NULL)
- * @len: length of match required
- *
- * Requires: rcu_read_lock be held
- *
- * Returns: unrefcounted policy that match @str or NULL if not found
- *
- * if @len == strlen(@strlen) then this is equiv to __policy_find
- * other wise it allows searching for policy by a partial match of name
- */
-static struct aa_policy *__policy_strn_find(struct list_head *head,
-                                           const char *str, int len)
-{
-       struct aa_policy *policy;
-
-       list_for_each_entry_rcu(policy, head, list) {
-               if (aa_strneq(policy->name, str, len))
-                       return policy;
-       }
-
-       return NULL;
-}
-
-/*
- * Routines for AppArmor namespaces
- */
-
-static const char *hidden_ns_name = "---";
-/**
- * aa_ns_visible - test if @view is visible from @curr
- * @curr: namespace to treat as the parent (NOT NULL)
- * @view:  namespace to test if visible from @curr (NOT NULL)
- *
- * Returns: true if @view is visible from @curr else false
- */
-bool aa_ns_visible(struct aa_namespace *curr, struct aa_namespace *view)
-{
-       if (curr == view)
-               return true;
-
-       for ( ; view; view = view->parent) {
-               if (view->parent == curr)
-                       return true;
-       }
-       return false;
-}
-
-/**
- * aa_na_name - Find the ns name to display for @view from @curr
- * @curr - current namespace (NOT NULL)
- * @view - namespace attempting to view (NOT NULL)
- *
- * Returns: name of @view visible from @curr
- */
-const char *aa_ns_name(struct aa_namespace *curr, struct aa_namespace *view)
-{
-       /* if view == curr then the namespace name isn't displayed */
-       if (curr == view)
-               return "";
-
-       if (aa_ns_visible(curr, view)) {
-               /* at this point if a ns is visible it is in a view ns
-                * thus the curr ns.hname is a prefix of its name.
-                * Only output the virtualized portion of the name
-                * Add + 2 to skip over // separating curr hname prefix
-                * from the visible tail of the views hname
-                */
-               return view->base.hname + strlen(curr->base.hname) + 2;
-       } else
-               return hidden_ns_name;
-}
-
-/**
- * alloc_namespace - allocate, initialize and return a new namespace
- * @prefix: parent namespace name (MAYBE NULL)
- * @name: a preallocated name  (NOT NULL)
- *
- * Returns: refcounted namespace or NULL on failure.
- */
-static struct aa_namespace *alloc_namespace(const char *prefix,
-                                           const char *name)
-{
-       struct aa_namespace *ns;
-
-       ns = kzalloc(sizeof(*ns), GFP_KERNEL);
-       AA_DEBUG("%s(%p)\n", __func__, ns);
-       if (!ns)
-               return NULL;
-       if (!policy_init(&ns->base, prefix, name))
-               goto fail_ns;
-
-       INIT_LIST_HEAD(&ns->sub_ns);
-       mutex_init(&ns->lock);
-
-       /* released by free_namespace */
-       ns->unconfined = aa_alloc_profile("unconfined");
-       if (!ns->unconfined)
-               goto fail_unconfined;
-
-       ns->unconfined->flags = PFLAG_IX_ON_NAME_ERROR |
-               PFLAG_IMMUTABLE | PFLAG_NS_COUNT;
-       ns->unconfined->mode = APPARMOR_UNCONFINED;
-
-       /* ns and ns->unconfined share ns->unconfined refcount */
-       ns->unconfined->ns = ns;
-
-       atomic_set(&ns->uniq_null, 0);
-
-       return ns;
-
-fail_unconfined:
-       kzfree(ns->base.hname);
-fail_ns:
-       kzfree(ns);
-       return NULL;
-}
-
-/**
- * free_namespace - free a profile namespace
- * @ns: the namespace to free  (MAYBE NULL)
- *
- * Requires: All references to the namespace must have been put, if the
- *           namespace was referenced by a profile confining a task,
- */
-static void free_namespace(struct aa_namespace *ns)
+/* requires profile list write lock held */
+void __aa_update_proxy(struct aa_profile *orig, struct aa_profile *new)
 {
-       if (!ns)
-               return;
-
-       policy_destroy(&ns->base);
-       aa_put_namespace(ns->parent);
-
-       ns->unconfined->ns = NULL;
-       aa_free_profile(ns->unconfined);
-       kzfree(ns);
-}
-
-/**
- * __aa_find_namespace - find a namespace on a list by @name
- * @head: list to search for namespace on  (NOT NULL)
- * @name: name of namespace to look for  (NOT NULL)
- *
- * Returns: unrefcounted namespace
- *
- * Requires: rcu_read_lock be held
- */
-static struct aa_namespace *__aa_find_namespace(struct list_head *head,
-                                               const char *name)
-{
-       return (struct aa_namespace *)__policy_find(head, name);
-}
-
-/**
- * aa_find_namespace  -  look up a profile namespace on the namespace list
- * @root: namespace to search in  (NOT NULL)
- * @name: name of namespace to find  (NOT NULL)
- *
- * Returns: a refcounted namespace on the list, or NULL if no namespace
- *          called @name exists.
- *
- * refcount released by caller
- */
-struct aa_namespace *aa_find_namespace(struct aa_namespace *root,
-                                      const char *name)
-{
-       struct aa_namespace *ns = NULL;
-
-       rcu_read_lock();
-       ns = aa_get_namespace(__aa_find_namespace(&root->sub_ns, name));
-       rcu_read_unlock();
-
-       return ns;
-}
-
-/**
- * aa_prepare_namespace - find an existing or create a new namespace of @name
- * @name: the namespace to find or add  (MAYBE NULL)
- *
- * Returns: refcounted namespace or NULL if failed to create one
- */
-static struct aa_namespace *aa_prepare_namespace(const char *name)
-{
-       struct aa_namespace *ns, *root;
-
-       root = aa_current_profile()->ns;
+       struct aa_profile *tmp;
 
-       mutex_lock(&root->lock);
-
-       /* if name isn't specified the profile is loaded to the current ns */
-       if (!name) {
-               /* released by caller */
-               ns = aa_get_namespace(root);
-               goto out;
-       }
-
-       /* try and find the specified ns and if it doesn't exist create it */
-       /* released by caller */
-       ns = aa_get_namespace(__aa_find_namespace(&root->sub_ns, name));
-       if (!ns) {
-               ns = alloc_namespace(root->base.hname, name);
-               if (!ns)
-                       goto out;
-               if (__aa_fs_namespace_mkdir(ns, ns_subns_dir(root), name)) {
-                       AA_ERROR("Failed to create interface for ns %s\n",
-                                ns->base.name);
-                       free_namespace(ns);
-                       ns = NULL;
-                       goto out;
-               }
-               ns->parent = aa_get_namespace(root);
-               list_add_rcu(&ns->base.list, &root->sub_ns);
-               /* add list ref */
-               aa_get_namespace(ns);
-       }
-out:
-       mutex_unlock(&root->lock);
-
-       /* return ref */
-       return ns;
+       tmp = rcu_dereference_protected(orig->proxy->profile,
+                                       mutex_is_locked(&orig->ns->lock));
+       rcu_assign_pointer(orig->proxy->profile, aa_get_profile(new));
+       orig->flags |= PFLAG_STALE;
+       aa_put_profile(tmp);
 }
 
 /**
@@ -448,8 +146,6 @@ static void __list_remove_profile(struct aa_profile *profile)
        aa_put_profile(profile);
 }
 
-static void __profile_list_release(struct list_head *head);
-
 /**
  * __remove_profile - remove old profile, and children
  * @profile: profile to be replaced  (NOT NULL)
@@ -459,122 +155,56 @@ static void __profile_list_release(struct list_head *head);
 static void __remove_profile(struct aa_profile *profile)
 {
        /* release any children lists first */
-       __profile_list_release(&profile->base.profiles);
+       __aa_profile_list_release(&profile->base.profiles);
        /* released by free_profile */
-       __aa_update_replacedby(profile, profile->ns->unconfined);
+       __aa_update_proxy(profile, profile->ns->unconfined);
        __aa_fs_profile_rmdir(profile);
        __list_remove_profile(profile);
 }
 
 /**
- * __profile_list_release - remove all profiles on the list and put refs
+ * __aa_profile_list_release - remove all profiles on the list and put refs
  * @head: list of profiles  (NOT NULL)
  *
  * Requires: namespace lock be held
  */
-static void __profile_list_release(struct list_head *head)
+void __aa_profile_list_release(struct list_head *head)
 {
        struct aa_profile *profile, *tmp;
        list_for_each_entry_safe(profile, tmp, head, base.list)
                __remove_profile(profile);
 }
 
-static void __ns_list_release(struct list_head *head);
 
-/**
- * destroy_namespace - remove everything contained by @ns
- * @ns: namespace to have it contents removed  (NOT NULL)
- */
-static void destroy_namespace(struct aa_namespace *ns)
+static void free_proxy(struct aa_proxy *p)
 {
-       if (!ns)
-               return;
-
-       mutex_lock(&ns->lock);
-       /* release all profiles in this namespace */
-       __profile_list_release(&ns->base.profiles);
-
-       /* release all sub namespaces */
-       __ns_list_release(&ns->sub_ns);
-
-       if (ns->parent)
-               __aa_update_replacedby(ns->unconfined, ns->parent->unconfined);
-       __aa_fs_namespace_rmdir(ns);
-       mutex_unlock(&ns->lock);
+       if (p) {
+               /* r->profile will not be updated any more as r is dead */
+               aa_put_profile(rcu_dereference_protected(p->profile, true));
+               kzfree(p);
+       }
 }
 
-/**
- * __remove_namespace - remove a namespace and all its children
- * @ns: namespace to be removed  (NOT NULL)
- *
- * Requires: ns->parent->lock be held and ns removed from parent.
- */
-static void __remove_namespace(struct aa_namespace *ns)
-{
-       /* remove ns from namespace list */
-       list_del_rcu(&ns->base.list);
-       destroy_namespace(ns);
-       aa_put_namespace(ns);
-}
 
-/**
- * __ns_list_release - remove all profile namespaces on the list put refs
- * @head: list of profile namespaces  (NOT NULL)
- *
- * Requires: namespace lock be held
- */
-static void __ns_list_release(struct list_head *head)
+void aa_free_proxy_kref(struct kref *kref)
 {
-       struct aa_namespace *ns, *tmp;
-       list_for_each_entry_safe(ns, tmp, head, base.list)
-               __remove_namespace(ns);
+       struct aa_proxy *p = container_of(kref, struct aa_proxy, count);
 
+       free_proxy(p);
 }
 
 /**
- * aa_alloc_root_ns - allocate the root profile namespace
- *
- * Returns: %0 on success else error
- *
+ * aa_free_data - free a data blob
+ * @ptr: data to free
+ * @arg: unused
  */
-int __init aa_alloc_root_ns(void)
+static void aa_free_data(void *ptr, void *arg)
 {
-       /* released by aa_free_root_ns - used as list ref*/
-       root_ns = alloc_namespace(NULL, "root");
-       if (!root_ns)
-               return -ENOMEM;
-
-       return 0;
-}
-
- /**
-  * aa_free_root_ns - free the root profile namespace
-  */
-void __init aa_free_root_ns(void)
- {
-        struct aa_namespace *ns = root_ns;
-        root_ns = NULL;
-
-        destroy_namespace(ns);
-        aa_put_namespace(ns);
-}
-
-
-static void free_replacedby(struct aa_replacedby *r)
-{
-       if (r) {
-               /* r->profile will not be updated any more as r is dead */
-               aa_put_profile(rcu_dereference_protected(r->profile, true));
-               kzfree(r);
-       }
-}
+       struct aa_data *data = ptr;
 
-
-void aa_free_replacedby_kref(struct kref *kref)
-{
-       struct aa_replacedby *r = container_of(kref, struct aa_replacedby,
-                                              count);
-       free_replacedby(r);
+       kzfree(data->data);
+       kzfree(data->key);
+       kzfree(data);
 }
 
 /**
@@ -589,16 +219,18 @@ void aa_free_replacedby_kref(struct kref *kref)
  */
 void aa_free_profile(struct aa_profile *profile)
 {
+       struct rhashtable *rht;
+
        AA_DEBUG("%s(%p)\n", __func__, profile);
 
        if (!profile)
                return;
 
        /* free children profiles */
-       policy_destroy(&profile->base);
+       aa_policy_destroy(&profile->base);
        aa_put_profile(rcu_access_pointer(profile->parent));
 
-       aa_put_namespace(profile->ns);
+       aa_put_ns(profile->ns);
        kzfree(profile->rename);
 
        aa_free_file_rules(&profile->file);
@@ -608,9 +240,17 @@ void aa_free_profile(struct aa_profile *profile)
        kzfree(profile->dirname);
        aa_put_dfa(profile->xmatch);
        aa_put_dfa(profile->policy.dfa);
-       aa_put_replacedby(profile->replacedby);
+       aa_put_proxy(profile->proxy);
+
+       if (profile->data) {
+               rht = profile->data;
+               profile->data = NULL;
+               rhashtable_free_and_destroy(rht, aa_free_data, NULL);
+               kzfree(rht);
+       }
 
        kzfree(profile->hash);
+       aa_put_loaddata(profile->rawdata);
        kzfree(profile);
 }
 
@@ -622,7 +262,7 @@ static void aa_free_profile_rcu(struct rcu_head *head)
 {
        struct aa_profile *p = container_of(head, struct aa_profile, rcu);
        if (p->flags & PFLAG_NS_COUNT)
-               free_namespace(p->ns);
+               aa_free_ns(p->ns);
        else
                aa_free_profile(p);
 }
@@ -640,24 +280,25 @@ void aa_free_profile_kref(struct kref *kref)
 /**
  * aa_alloc_profile - allocate, initialize and return a new profile
  * @hname: name of the profile  (NOT NULL)
+ * @gfp: allocation type
  *
  * Returns: refcount profile or NULL on failure
  */
-struct aa_profile *aa_alloc_profile(const char *hname)
+struct aa_profile *aa_alloc_profile(const char *hname, gfp_t gfp)
 {
        struct aa_profile *profile;
 
        /* freed by free_profile - usually through aa_put_profile */
-       profile = kzalloc(sizeof(*profile), GFP_KERNEL);
+       profile = kzalloc(sizeof(*profile), gfp);
        if (!profile)
                return NULL;
 
-       profile->replacedby = kzalloc(sizeof(struct aa_replacedby), GFP_KERNEL);
-       if (!profile->replacedby)
+       profile->proxy = kzalloc(sizeof(struct aa_proxy), gfp);
+       if (!profile->proxy)
                goto fail;
-       kref_init(&profile->replacedby->count);
+       kref_init(&profile->proxy->count);
 
-       if (!policy_init(&profile->base, NULL, hname))
+       if (!aa_policy_init(&profile->base, NULL, hname, gfp))
                goto fail;
        kref_init(&profile->count);
 
@@ -665,19 +306,23 @@ struct aa_profile *aa_alloc_profile(const char *hname)
        return profile;
 
 fail:
-       kzfree(profile->replacedby);
+       kzfree(profile->proxy);
        kzfree(profile);
 
        return NULL;
 }
 
 /**
- * aa_new_null_profile - create a new null-X learning profile
+ * aa_new_null_profile - create or find a null-X learning profile
  * @parent: profile that caused this profile to be created (NOT NULL)
  * @hat: true if the null- learning profile is a hat
+ * @base: name to base the null profile off of
+ * @gfp: type of allocation
  *
- * Create a null- complain mode profile used in learning mode.  The name of
- * the profile is unique and follows the format of parent//null-<uniq>.
+ * Find/Create a null- complain mode profile used in learning mode.  The
+ * name of the profile is unique and follows the format of parent//null-XXX.
+ * where XXX is based on the @name or if that fails or is not supplied
+ * a unique number
  *
  * null profiles are added to the profile list but the list does not
  * hold a count on them so that they are automatically released when
@@ -685,40 +330,65 @@ fail:
  *
  * Returns: new refcounted profile else NULL on failure
  */
-struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat)
+struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat,
+                                      const char *base, gfp_t gfp)
 {
-       struct aa_profile *profile = NULL;
+       struct aa_profile *profile;
        char *name;
-       int uniq = atomic_inc_return(&parent->ns->uniq_null);
 
-       /* freed below */
-       name = kmalloc(strlen(parent->base.hname) + 2 + 7 + 8, GFP_KERNEL);
+       AA_BUG(!parent);
+
+       if (base) {
+               name = kmalloc(strlen(parent->base.hname) + 8 + strlen(base),
+                              gfp);
+               if (name) {
+                       sprintf(name, "%s//null-%s", parent->base.hname, base);
+                       goto name;
+               }
+               /* fall through to try shorter uniq */
+       }
+
+       name = kmalloc(strlen(parent->base.hname) + 2 + 7 + 8, gfp);
        if (!name)
-               goto fail;
-       sprintf(name, "%s//null-%x", parent->base.hname, uniq);
+               return NULL;
+       sprintf(name, "%s//null-%x", parent->base.hname,
+               atomic_inc_return(&parent->ns->uniq_null));
 
-       profile = aa_alloc_profile(name);
-       kfree(name);
+name:
+       /* lookup to see if this is a dup creation */
+       profile = aa_find_child(parent, basename(name));
+       if (profile)
+               goto out;
+
+       profile = aa_alloc_profile(name, gfp);
        if (!profile)
                goto fail;
 
        profile->mode = APPARMOR_COMPLAIN;
-       profile->flags = PFLAG_NULL;
+       profile->flags |= PFLAG_NULL;
        if (hat)
                profile->flags |= PFLAG_HAT;
+       profile->path_flags = parent->path_flags;
 
        /* released on free_profile */
        rcu_assign_pointer(profile->parent, aa_get_profile(parent));
-       profile->ns = aa_get_namespace(parent->ns);
+       profile->ns = aa_get_ns(parent->ns);
+       profile->file.dfa = aa_get_dfa(nulldfa);
+       profile->policy.dfa = aa_get_dfa(nulldfa);
 
        mutex_lock(&profile->ns->lock);
        __list_add_profile(&parent->base.profiles, profile);
        mutex_unlock(&profile->ns->lock);
 
        /* refcount released by caller */
+out:
+       kfree(name);
+
        return profile;
 
 fail:
+       kfree(name);
+       aa_free_profile(profile);
        return NULL;
 }
 
@@ -788,7 +458,7 @@ struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name)
  *
  * Returns: unrefcounted policy or NULL if not found
  */
-static struct aa_policy *__lookup_parent(struct aa_namespace *ns,
+static struct aa_policy *__lookup_parent(struct aa_ns *ns,
                                         const char *hname)
 {
        struct aa_policy *policy;
@@ -812,9 +482,10 @@ static struct aa_policy *__lookup_parent(struct aa_namespace *ns,
 }
 
 /**
- * __lookup_profile - lookup the profile matching @hname
+ * __lookupn_profile - lookup the profile matching @hname
  * @base: base list to start looking up profile name from  (NOT NULL)
  * @hname: hierarchical profile name  (NOT NULL)
+ * @n: length of @hname
  *
  * Requires: rcu_read_lock be held
  *
@@ -822,53 +493,95 @@ static struct aa_policy *__lookup_parent(struct aa_namespace *ns,
  *
  * Do a relative name lookup, recursing through profile tree.
  */
-static struct aa_profile *__lookup_profile(struct aa_policy *base,
-                                          const char *hname)
+static struct aa_profile *__lookupn_profile(struct aa_policy *base,
+                                           const char *hname, size_t n)
 {
        struct aa_profile *profile = NULL;
-       char *split;
+       const char *split;
 
-       for (split = strstr(hname, "//"); split;) {
+       for (split = strnstr(hname, "//", n); split;
+            split = strnstr(hname, "//", n)) {
                profile = __strn_find_child(&base->profiles, hname,
                                            split - hname);
                if (!profile)
                        return NULL;
 
                base = &profile->base;
+               n -= split + 2 - hname;
                hname = split + 2;
-               split = strstr(hname, "//");
        }
 
-       profile = __find_child(&base->profiles, hname);
+       if (n)
+               return __strn_find_child(&base->profiles, hname, n);
+       return NULL;
+}
 
-       return profile;
+static struct aa_profile *__lookup_profile(struct aa_policy *base,
+                                          const char *hname)
+{
+       return __lookupn_profile(base, hname, strlen(hname));
 }
 
 /**
  * aa_lookup_profile - find a profile by its full or partial name
  * @ns: the namespace to start from (NOT NULL)
  * @hname: name to do lookup on.  Does not contain namespace prefix (NOT NULL)
+ * @n: size of @hname
  *
  * Returns: refcounted profile or NULL if not found
  */
-struct aa_profile *aa_lookup_profile(struct aa_namespace *ns, const char *hname)
+struct aa_profile *aa_lookupn_profile(struct aa_ns *ns, const char *hname,
+                                     size_t n)
 {
        struct aa_profile *profile;
 
        rcu_read_lock();
        do {
-               profile = __lookup_profile(&ns->base, hname);
+               profile = __lookupn_profile(&ns->base, hname, n);
        } while (profile && !aa_get_profile_not0(profile));
        rcu_read_unlock();
 
        /* the unconfined profile is not in the regular profile list */
-       if (!profile && strcmp(hname, "unconfined") == 0)
+       if (!profile && strncmp(hname, "unconfined", n) == 0)
                profile = aa_get_newest_profile(ns->unconfined);
 
        /* refcount released by caller */
        return profile;
 }
 
+struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *hname)
+{
+       return aa_lookupn_profile(ns, hname, strlen(hname));
+}
+
+struct aa_profile *aa_fqlookupn_profile(struct aa_profile *base,
+                                       const char *fqname, size_t n)
+{
+       struct aa_profile *profile;
+       struct aa_ns *ns;
+       const char *name, *ns_name;
+       size_t ns_len;
+
+       name = aa_splitn_fqname(fqname, n, &ns_name, &ns_len);
+       if (ns_name) {
+               ns = aa_findn_ns(base->ns, ns_name, ns_len);
+               if (!ns)
+                       return NULL;
+       } else
+               ns = aa_get_ns(base->ns);
+
+       if (name)
+               profile = aa_lookupn_profile(ns, name, n - (name - fqname));
+       else if (ns)
+               /* default profile for ns, currently unconfined */
+               profile = aa_get_newest_profile(ns->unconfined);
+       else
+               profile = NULL;
+       aa_put_ns(ns);
+
+       return profile;
+}
+
 /**
  * replacement_allowed - test to see if replacement is allowed
  * @profile: profile to test if it can be replaced  (MAYBE NULL)
@@ -892,74 +605,109 @@ static int replacement_allowed(struct aa_profile *profile, int noreplace,
        return 0;
 }
 
+/* audit callback for net specific fields */
+static void audit_cb(struct audit_buffer *ab, void *va)
+{
+       struct common_audit_data *sa = va;
+
+       if (aad(sa)->iface.ns) {
+               audit_log_format(ab, " ns=");
+               audit_log_untrustedstring(ab, aad(sa)->iface.ns);
+       }
+}
+
 /**
  * aa_audit_policy - Do auditing of policy changes
+ * @profile: profile to check if it can manage policy
  * @op: policy operation being performed
  * @gfp: memory allocation flags
+ * @nsname: name of the ns being manipulated (MAY BE NULL)
  * @name: name of profile being manipulated (NOT NULL)
  * @info: any extra information to be audited (MAYBE NULL)
  * @error: error code
  *
  * Returns: the error to be returned after audit is done
  */
-static int audit_policy(int op, gfp_t gfp, const char *name, const char *info,
-                       int error)
+static int audit_policy(struct aa_profile *profile, const char *op,
+                       const char *nsname, const char *name,
+                       const char *info, int error)
 {
-       struct common_audit_data sa;
-       struct apparmor_audit_data aad = {0,};
-       sa.type = LSM_AUDIT_DATA_NONE;
-       sa.aad = &aad;
-       aad.op = op;
-       aad.name = name;
-       aad.info = info;
-       aad.error = error;
-
-       return aa_audit(AUDIT_APPARMOR_STATUS, __aa_current_profile(), gfp,
-                       &sa, NULL);
+       DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, op);
+
+       aad(&sa)->iface.ns = nsname;
+       aad(&sa)->name = name;
+       aad(&sa)->info = info;
+       aad(&sa)->error = error;
+
+       return aa_audit(AUDIT_APPARMOR_STATUS, profile, &sa, audit_cb);
 }
 
-bool policy_view_capable(void)
+/**
+ * policy_view_capable - check if viewing policy in at @ns is allowed
+ * ns: namespace being viewed by current task (may be NULL)
+ * Returns: true if viewing policy is allowed
+ *
+ * If @ns is NULL then the namespace being viewed is assumed to be the
+ * tasks current namespace.
+ */
+bool policy_view_capable(struct aa_ns *ns)
 {
        struct user_namespace *user_ns = current_user_ns();
+       struct aa_ns *view_ns = aa_get_current_ns();
+       bool root_in_user_ns = uid_eq(current_euid(), make_kuid(user_ns, 0)) ||
+                              in_egroup_p(make_kgid(user_ns, 0));
        bool response = false;
+       if (!ns)
+               ns = view_ns;
 
-       if (ns_capable(user_ns, CAP_MAC_ADMIN))
+       if (root_in_user_ns && aa_ns_visible(view_ns, ns, true) &&
+           (user_ns == &init_user_ns ||
+            (unprivileged_userns_apparmor_policy != 0 &&
+             user_ns->level == view_ns->level)))
                response = true;
+       aa_put_ns(view_ns);
 
        return response;
 }
 
-bool policy_admin_capable(void)
+bool policy_admin_capable(struct aa_ns *ns)
 {
-       return policy_view_capable() && !aa_g_lock_policy;
+       struct user_namespace *user_ns = current_user_ns();
+       bool capable = ns_capable(user_ns, CAP_MAC_ADMIN);
+
+       AA_DEBUG("cap_mac_admin? %d\n", capable);
+       AA_DEBUG("policy locked? %d\n", aa_g_lock_policy);
+
+       return policy_view_capable(ns) && capable && !aa_g_lock_policy;
 }
 
 /**
  * aa_may_manage_policy - can the current task manage policy
+ * @profile: profile to check if it can manage policy
  * @op: the policy manipulation operation being done
  *
- * Returns: true if the task is allowed to manipulate policy
+ * Returns: 0 if the task is allowed to manipulate policy else error
  */
-bool aa_may_manage_policy(int op)
+int aa_may_manage_policy(struct aa_profile *profile, struct aa_ns *ns,
+                        const char *op)
 {
        /* check if loading policy is locked out */
-       if (aa_g_lock_policy) {
-               audit_policy(op, GFP_KERNEL, NULL, "policy_locked", -EACCES);
-               return 0;
-       }
+       if (aa_g_lock_policy)
+               return audit_policy(profile, op, NULL, NULL,
+                            "policy_locked", -EACCES);
 
-       if (!policy_admin_capable()) {
-               audit_policy(op, GFP_KERNEL, NULL, "not policy admin", -EACCES);
-               return 0;
-       }
+       if (!policy_admin_capable(ns))
+               return audit_policy(profile, op, NULL, NULL,
+                                   "not policy admin", -EACCES);
 
-       return 1;
+       /* TODO: add fine grained mediation of policy loads */
+       return 0;
 }
 
 static struct aa_profile *__list_lookup_parent(struct list_head *lh,
                                               struct aa_profile *profile)
 {
-       const char *base = hname_tail(profile->base.hname);
+       const char *base = basename(profile->base.hname);
        long len = base - profile->base.hname;
        struct aa_load_ent *ent;
 
@@ -983,7 +731,7 @@ static struct aa_profile *__list_lookup_parent(struct list_head *lh,
  * __replace_profile - replace @old with @new on a list
  * @old: profile to be replaced  (NOT NULL)
  * @new: profile to replace @old with  (NOT NULL)
- * @share_replacedby: transfer @old->replacedby to @new
+ * @share_proxy: transfer @old->proxy to @new
  *
  * Will duplicate and refcount elements that @new inherits from @old
  * and will inherit @old children.
@@ -993,7 +741,7 @@ static struct aa_profile *__list_lookup_parent(struct list_head *lh,
  * Requires: namespace list lock be held, or list not be shared
  */
 static void __replace_profile(struct aa_profile *old, struct aa_profile *new,
-                             bool share_replacedby)
+                             bool share_proxy)
 {
        struct aa_profile *child, *tmp;
 
@@ -1008,7 +756,7 @@ static void __replace_profile(struct aa_profile *old, struct aa_profile *new,
                        p = __find_child(&new->base.profiles, child->base.name);
                        if (p) {
                                /* @p replaces @child  */
-                               __replace_profile(child, p, share_replacedby);
+                               __replace_profile(child, p, share_proxy);
                                continue;
                        }
 
@@ -1026,13 +774,13 @@ static void __replace_profile(struct aa_profile *old, struct aa_profile *new,
                struct aa_profile *parent = aa_deref_parent(old);
                rcu_assign_pointer(new->parent, aa_get_profile(parent));
        }
-       __aa_update_replacedby(old, new);
-       if (share_replacedby) {
-               aa_put_replacedby(new->replacedby);
-               new->replacedby = aa_get_replacedby(old->replacedby);
-       } else if (!rcu_access_pointer(new->replacedby->profile))
-               /* aafs interface uses replacedby */
-               rcu_assign_pointer(new->replacedby->profile,
+       __aa_update_proxy(old, new);
+       if (share_proxy) {
+               aa_put_proxy(new->proxy);
+               new->proxy = aa_get_proxy(old->proxy);
+       } else if (!rcu_access_pointer(new->proxy->profile))
+               /* aafs interface uses proxy */
+               rcu_assign_pointer(new->proxy->profile,
                                   aa_get_profile(new));
        __aa_fs_profile_migrate_dents(old, new);
 
@@ -1055,7 +803,7 @@ static void __replace_profile(struct aa_profile *old, struct aa_profile *new,
  *
  * Returns: profile to replace (no ref) on success else ptr error
  */
-static int __lookup_replace(struct aa_namespace *ns, const char *hname,
+static int __lookup_replace(struct aa_ns *ns, const char *hname,
                            bool noreplace, struct aa_profile **p,
                            const char **info)
 {
@@ -1073,42 +821,72 @@ static int __lookup_replace(struct aa_namespace *ns, const char *hname,
 
 /**
  * aa_replace_profiles - replace profile(s) on the profile list
- * @udata: serialized data stream  (NOT NULL)
- * @size: size of the serialized data stream
+ * @view: namespace load is viewed from
+ * @label: label that is attempting to load/replace policy
  * @noreplace: true if only doing addition, no replacement allowed
+ * @udata: serialized data stream  (NOT NULL)
  *
  * unpack and replace a profile on the profile list and uses of that profile
- * by any aa_task_cxt.  If the profile does not exist on the profile list
+ * by any aa_task_ctx.  If the profile does not exist on the profile list
  * it is added.
  *
  * Returns: size of data consumed else error code on failure.
  */
-ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
+ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_profile *profile,
+                           bool noreplace, struct aa_loaddata *udata)
 {
        const char *ns_name, *info = NULL;
-       struct aa_namespace *ns = NULL;
+       struct aa_ns *ns = NULL;
        struct aa_load_ent *ent, *tmp;
-       int op = OP_PROF_REPL;
-       ssize_t error;
+       const char *op = OP_PROF_REPL;
+       ssize_t count, error;
        LIST_HEAD(lh);
 
        /* released below */
-       error = aa_unpack(udata, size, &lh, &ns_name);
+       error = aa_unpack(udata, &lh, &ns_name);
        if (error)
                goto out;
 
-       /* released below */
-       ns = aa_prepare_namespace(ns_name);
-       if (!ns) {
-               error = audit_policy(op, GFP_KERNEL, ns_name,
-                                    "failed to prepare namespace", -ENOMEM);
-               goto free;
+       /* ensure that profiles are all for the same ns
+        * TODO: update locking to remove this constaint. All profiles in
+        *       the load set must succeed as a set or the load will
+        *       fail. Sort ent list and take ns locks in hierarchy order
+        */
+       count = 0;
+       list_for_each_entry(ent, &lh, list) {
+               if (ns_name) {
+                       if (ent->ns_name &&
+                           strcmp(ent->ns_name, ns_name) != 0) {
+                               info = "policy load has mixed namespaces";
+                               error = -EACCES;
+                               goto fail;
+                       }
+               } else if (ent->ns_name) {
+                       if (count) {
+                               info = "policy load has mixed namespaces";
+                               error = -EACCES;
+                               goto fail;
+                       }
+                       ns_name = ent->ns_name;
+               } else
+                       count++;
        }
+       if (ns_name) {
+               ns = aa_prepare_ns(view, ns_name);
+               if (IS_ERR(ns)) {
+                       info = "failed to prepare namespace";
+                       error = PTR_ERR(ns);
+                       ns = NULL;
+                       goto fail;
+               }
+       } else
+               ns = aa_get_ns(view);
 
        mutex_lock(&ns->lock);
        /* setup parent and ns info */
        list_for_each_entry(ent, &lh, list) {
                struct aa_policy *policy;
+               ent->new->rawdata = aa_get_loaddata(udata);
                error = __lookup_replace(ns, ent->new->base.hname, noreplace,
                                         &ent->old, &info);
                if (error)
@@ -1123,7 +901,7 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
                }
 
                /* released when @new is freed */
-               ent->new->ns = aa_get_namespace(ns);
+               ent->new->ns = aa_get_ns(ns);
 
                if (ent->old || ent->rename)
                        continue;
@@ -1177,20 +955,21 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
                list_del_init(&ent->list);
                op = (!ent->old && !ent->rename) ? OP_PROF_LOAD : OP_PROF_REPL;
 
-               audit_policy(op, GFP_ATOMIC, ent->new->base.hname, NULL, error);
+               audit_policy(profile, op, NULL, ent->new->base.hname,
+                            NULL, error);
 
                if (ent->old) {
                        __replace_profile(ent->old, ent->new, 1);
                        if (ent->rename) {
-                               /* aafs interface uses replacedby */
-                               struct aa_replacedby *r = ent->new->replacedby;
+                               /* aafs interface uses proxy */
+                               struct aa_proxy *r = ent->new->proxy;
                                rcu_assign_pointer(r->profile,
                                                   aa_get_profile(ent->new));
                                __replace_profile(ent->rename, ent->new, 0);
                        }
                } else if (ent->rename) {
-                       /* aafs interface uses replacedby */
-                       rcu_assign_pointer(ent->new->replacedby->profile,
+                       /* aafs interface uses proxy */
+                       rcu_assign_pointer(ent->new->proxy->profile,
                                           aa_get_profile(ent->new));
                        __replace_profile(ent->rename, ent->new, 0);
                } else if (ent->new->parent) {
@@ -1204,14 +983,14 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
                                rcu_assign_pointer(ent->new->parent, newest);
                                aa_put_profile(parent);
                        }
-                       /* aafs interface uses replacedby */
-                       rcu_assign_pointer(ent->new->replacedby->profile,
+                       /* aafs interface uses proxy */
+                       rcu_assign_pointer(ent->new->proxy->profile,
                                           aa_get_profile(ent->new));
                        __list_add_profile(&newest->base.profiles, ent->new);
                        aa_put_profile(newest);
                } else {
-                       /* aafs interface uses replacedby */
-                       rcu_assign_pointer(ent->new->replacedby->profile,
+                       /* aafs interface uses proxy */
+                       rcu_assign_pointer(ent->new->proxy->profile,
                                           aa_get_profile(ent->new));
                        __list_add_profile(&ns->base.profiles, ent->new);
                }
@@ -1220,18 +999,20 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
        mutex_unlock(&ns->lock);
 
 out:
-       aa_put_namespace(ns);
+       aa_put_ns(ns);
 
        if (error)
                return error;
-       return size;
+       return udata->size;
 
 fail_lock:
        mutex_unlock(&ns->lock);
 
        /* audit cause of failure */
        op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL;
-       audit_policy(op, GFP_KERNEL, ent->new->base.hname, info, error);
+fail:
+       audit_policy(profile, op, ns_name, ent->new->base.hname,
+                    info, error);
        /* audit status that rest of profiles in the atomic set failed too */
        info = "valid profile in failed atomic policy load";
        list_for_each_entry(tmp, &lh, list) {
@@ -1241,9 +1022,9 @@ fail_lock:
                        continue;
                }
                op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL;
-               audit_policy(op, GFP_KERNEL, tmp->new->base.hname, info, error);
+               audit_policy(profile, op, ns_name,
+                            tmp->new->base.hname, info, error);
        }
-free:
        list_for_each_entry_safe(ent, tmp, &lh, list) {
                list_del_init(&ent->list);
                aa_load_ent_free(ent);
@@ -1254,6 +1035,8 @@ free:
 
 /**
  * aa_remove_profiles - remove profile(s) from the system
+ * @view: namespace the remove is being done from
+ * @subj: profile attempting to remove policy
  * @fqname: name of the profile or namespace to remove  (NOT NULL)
  * @size: size of the name
  *
@@ -1264,11 +1047,13 @@ free:
  *
  * Returns: size of data consume else error code if fails
  */
-ssize_t aa_remove_profiles(char *fqname, size_t size)
+ssize_t aa_remove_profiles(struct aa_ns *view, struct aa_profile *subj,
+                          char *fqname, size_t size)
 {
-       struct aa_namespace *root, *ns = NULL;
+       struct aa_ns *root = NULL, *ns = NULL;
        struct aa_profile *profile = NULL;
        const char *name = fqname, *info = NULL;
+       char *ns_name = NULL;
        ssize_t error = 0;
 
        if (*fqname == 0) {
@@ -1277,13 +1062,12 @@ ssize_t aa_remove_profiles(char *fqname, size_t size)
                goto fail;
        }
 
-       root = aa_current_profile()->ns;
+       root = view;
 
        if (fqname[0] == ':') {
-               char *ns_name;
                name = aa_split_fqname(fqname, &ns_name);
                /* released below */
-               ns = aa_find_namespace(root, ns_name);
+               ns = aa_find_ns(root, ns_name);
                if (!ns) {
                        info = "namespace does not exist";
                        error = -ENOENT;
@@ -1291,12 +1075,12 @@ ssize_t aa_remove_profiles(char *fqname, size_t size)
                }
        } else
                /* released below */
-               ns = aa_get_namespace(root);
+               ns = aa_get_ns(root);
 
        if (!name) {
                /* remove namespace - can only happen if fqname[0] == ':' */
                mutex_lock(&ns->parent->lock);
-               __remove_namespace(ns);
+               __aa_remove_ns(ns);
                mutex_unlock(&ns->parent->lock);
        } else {
                /* remove profile */
@@ -1313,16 +1097,18 @@ ssize_t aa_remove_profiles(char *fqname, size_t size)
        }
 
        /* don't fail removal if audit fails */
-       (void) audit_policy(OP_PROF_RM, GFP_KERNEL, name, info, error);
-       aa_put_namespace(ns);
+       (void) audit_policy(subj, OP_PROF_RM, ns_name, name, info,
+                           error);
+       aa_put_ns(ns);
        aa_put_profile(profile);
        return size;
 
 fail_ns_lock:
        mutex_unlock(&ns->lock);
-       aa_put_namespace(ns);
+       aa_put_ns(ns);
 
 fail:
-       (void) audit_policy(OP_PROF_RM, GFP_KERNEL, name, info, error);
+       (void) audit_policy(subj, OP_PROF_RM, ns_name, name, info,
+                           error);
        return error;
 }
diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c
new file mode 100644 (file)
index 0000000..93d1826
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor policy manipulation functions
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2017 Canonical 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, version 2 of the
+ * License.
+ *
+ * AppArmor policy namespaces, allow for different sets of policies
+ * to be loaded for tasks within the namespace.
+ */
+
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include "include/apparmor.h"
+#include "include/context.h"
+#include "include/policy_ns.h"
+#include "include/policy.h"
+
+/* root profile namespace */
+struct aa_ns *root_ns;
+const char *aa_hidden_ns_name = "---";
+
+/**
+ * aa_ns_visible - test if @view is visible from @curr
+ * @curr: namespace to treat as the parent (NOT NULL)
+ * @view: namespace to test if visible from @curr (NOT NULL)
+ * @subns: whether view of a subns is allowed
+ *
+ * Returns: true if @view is visible from @curr else false
+ */
+bool aa_ns_visible(struct aa_ns *curr, struct aa_ns *view, bool subns)
+{
+       if (curr == view)
+               return true;
+
+       if (!subns)
+               return false;
+
+       for ( ; view; view = view->parent) {
+               if (view->parent == curr)
+                       return true;
+       }
+
+       return false;
+}
+
+/**
+ * aa_na_name - Find the ns name to display for @view from @curr
+ * @curr - current namespace (NOT NULL)
+ * @view - namespace attempting to view (NOT NULL)
+ * @subns - are subns visible
+ *
+ * Returns: name of @view visible from @curr
+ */
+const char *aa_ns_name(struct aa_ns *curr, struct aa_ns *view, bool subns)
+{
+       /* if view == curr then the namespace name isn't displayed */
+       if (curr == view)
+               return "";
+
+       if (aa_ns_visible(curr, view, subns)) {
+               /* at this point if a ns is visible it is in a view ns
+                * thus the curr ns.hname is a prefix of its name.
+                * Only output the virtualized portion of the name
+                * Add + 2 to skip over // separating curr hname prefix
+                * from the visible tail of the views hname
+                */
+               return view->base.hname + strlen(curr->base.hname) + 2;
+       }
+
+       return aa_hidden_ns_name;
+}
+
+/**
+ * alloc_ns - allocate, initialize and return a new namespace
+ * @prefix: parent namespace name (MAYBE NULL)
+ * @name: a preallocated name  (NOT NULL)
+ *
+ * Returns: refcounted namespace or NULL on failure.
+ */
+static struct aa_ns *alloc_ns(const char *prefix, const char *name)
+{
+       struct aa_ns *ns;
+
+       ns = kzalloc(sizeof(*ns), GFP_KERNEL);
+       AA_DEBUG("%s(%p)\n", __func__, ns);
+       if (!ns)
+               return NULL;
+       if (!aa_policy_init(&ns->base, prefix, name, GFP_KERNEL))
+               goto fail_ns;
+
+       INIT_LIST_HEAD(&ns->sub_ns);
+       mutex_init(&ns->lock);
+
+       /* released by aa_free_ns() */
+       ns->unconfined = aa_alloc_profile("unconfined", GFP_KERNEL);
+       if (!ns->unconfined)
+               goto fail_unconfined;
+
+       ns->unconfined->flags = PFLAG_IX_ON_NAME_ERROR |
+               PFLAG_IMMUTABLE | PFLAG_NS_COUNT;
+       ns->unconfined->mode = APPARMOR_UNCONFINED;
+
+       /* ns and ns->unconfined share ns->unconfined refcount */
+       ns->unconfined->ns = ns;
+
+       atomic_set(&ns->uniq_null, 0);
+
+       return ns;
+
+fail_unconfined:
+       kzfree(ns->base.hname);
+fail_ns:
+       kzfree(ns);
+       return NULL;
+}
+
+/**
+ * aa_free_ns - free a profile namespace
+ * @ns: the namespace to free  (MAYBE NULL)
+ *
+ * Requires: All references to the namespace must have been put, if the
+ *           namespace was referenced by a profile confining a task,
+ */
+void aa_free_ns(struct aa_ns *ns)
+{
+       if (!ns)
+               return;
+
+       aa_policy_destroy(&ns->base);
+       aa_put_ns(ns->parent);
+
+       ns->unconfined->ns = NULL;
+       aa_free_profile(ns->unconfined);
+       kzfree(ns);
+}
+
+/**
+ * aa_findn_ns  -  look up a profile namespace on the namespace list
+ * @root: namespace to search in  (NOT NULL)
+ * @name: name of namespace to find  (NOT NULL)
+ * @n: length of @name
+ *
+ * Returns: a refcounted namespace on the list, or NULL if no namespace
+ *          called @name exists.
+ *
+ * refcount released by caller
+ */
+struct aa_ns *aa_findn_ns(struct aa_ns *root, const char *name, size_t n)
+{
+       struct aa_ns *ns = NULL;
+
+       rcu_read_lock();
+       ns = aa_get_ns(__aa_findn_ns(&root->sub_ns, name, n));
+       rcu_read_unlock();
+
+       return ns;
+}
+
+/**
+ * aa_find_ns  -  look up a profile namespace on the namespace list
+ * @root: namespace to search in  (NOT NULL)
+ * @name: name of namespace to find  (NOT NULL)
+ *
+ * Returns: a refcounted namespace on the list, or NULL if no namespace
+ *          called @name exists.
+ *
+ * refcount released by caller
+ */
+struct aa_ns *aa_find_ns(struct aa_ns *root, const char *name)
+{
+       return aa_findn_ns(root, name, strlen(name));
+}
+
+static struct aa_ns *__aa_create_ns(struct aa_ns *parent, const char *name,
+                                   struct dentry *dir)
+{
+       struct aa_ns *ns;
+       int error;
+
+       AA_BUG(!parent);
+       AA_BUG(!name);
+       AA_BUG(!mutex_is_locked(&parent->lock));
+
+       ns = alloc_ns(parent->base.hname, name);
+       if (!ns)
+               return NULL;
+       mutex_lock(&ns->lock);
+       error = __aa_fs_ns_mkdir(ns, ns_subns_dir(parent), name);
+       if (error) {
+               AA_ERROR("Failed to create interface for ns %s\n",
+                        ns->base.name);
+               mutex_unlock(&ns->lock);
+               aa_free_ns(ns);
+               return ERR_PTR(error);
+       }
+       ns->parent = aa_get_ns(parent);
+       ns->level = parent->level + 1;
+       list_add_rcu(&ns->base.list, &parent->sub_ns);
+       /* add list ref */
+       aa_get_ns(ns);
+       mutex_unlock(&ns->lock);
+
+       return ns;
+}
+
+/**
+ * aa_create_ns - create an ns, fail if it already exists
+ * @parent: the parent of the namespace being created
+ * @name: the name of the namespace
+ * @dir: if not null the dir to put the ns entries in
+ *
+ * Returns: the a refcounted ns that has been add or an ERR_PTR
+ */
+struct aa_ns *__aa_find_or_create_ns(struct aa_ns *parent, const char *name,
+                                    struct dentry *dir)
+{
+       struct aa_ns *ns;
+
+       AA_BUG(!mutex_is_locked(&parent->lock));
+
+       /* try and find the specified ns */
+       /* released by caller */
+       ns = aa_get_ns(__aa_find_ns(&parent->sub_ns, name));
+       if (!ns)
+               ns = __aa_create_ns(parent, name, dir);
+       else
+               ns = ERR_PTR(-EEXIST);
+
+       /* return ref */
+       return ns;
+}
+
+/**
+ * aa_prepare_ns - find an existing or create a new namespace of @name
+ * @parent: ns to treat as parent
+ * @name: the namespace to find or add  (NOT NULL)
+ *
+ * Returns: refcounted namespace or PTR_ERR if failed to create one
+ */
+struct aa_ns *aa_prepare_ns(struct aa_ns *parent, const char *name)
+{
+       struct aa_ns *ns;
+
+       mutex_lock(&parent->lock);
+       /* try and find the specified ns and if it doesn't exist create it */
+       /* released by caller */
+       ns = aa_get_ns(__aa_find_ns(&parent->sub_ns, name));
+       if (!ns)
+               ns = __aa_create_ns(parent, name, NULL);
+       mutex_unlock(&parent->lock);
+
+       /* return ref */
+       return ns;
+}
+
+static void __ns_list_release(struct list_head *head);
+
+/**
+ * destroy_ns - remove everything contained by @ns
+ * @ns: namespace to have it contents removed  (NOT NULL)
+ */
+static void destroy_ns(struct aa_ns *ns)
+{
+       if (!ns)
+               return;
+
+       mutex_lock(&ns->lock);
+       /* release all profiles in this namespace */
+       __aa_profile_list_release(&ns->base.profiles);
+
+       /* release all sub namespaces */
+       __ns_list_release(&ns->sub_ns);
+
+       if (ns->parent)
+               __aa_update_proxy(ns->unconfined, ns->parent->unconfined);
+       __aa_fs_ns_rmdir(ns);
+       mutex_unlock(&ns->lock);
+}
+
+/**
+ * __aa_remove_ns - remove a namespace and all its children
+ * @ns: namespace to be removed  (NOT NULL)
+ *
+ * Requires: ns->parent->lock be held and ns removed from parent.
+ */
+void __aa_remove_ns(struct aa_ns *ns)
+{
+       /* remove ns from namespace list */
+       list_del_rcu(&ns->base.list);
+       destroy_ns(ns);
+       aa_put_ns(ns);
+}
+
+/**
+ * __ns_list_release - remove all profile namespaces on the list put refs
+ * @head: list of profile namespaces  (NOT NULL)
+ *
+ * Requires: namespace lock be held
+ */
+static void __ns_list_release(struct list_head *head)
+{
+       struct aa_ns *ns, *tmp;
+
+       list_for_each_entry_safe(ns, tmp, head, base.list)
+               __aa_remove_ns(ns);
+
+}
+
+/**
+ * aa_alloc_root_ns - allocate the root profile namespace
+ *
+ * Returns: %0 on success else error
+ *
+ */
+int __init aa_alloc_root_ns(void)
+{
+       /* released by aa_free_root_ns - used as list ref*/
+       root_ns = alloc_ns(NULL, "root");
+       if (!root_ns)
+               return -ENOMEM;
+
+       return 0;
+}
+
+ /**
+  * aa_free_root_ns - free the root profile namespace
+  */
+void __init aa_free_root_ns(void)
+{
+        struct aa_ns *ns = root_ns;
+
+        root_ns = NULL;
+
+        destroy_ns(ns);
+        aa_put_ns(ns);
+}
index 138120698f839e049a5cf2460572559f3529e337..2e37c9c26bbd17e0affa3155384979f99953ffa7 100644 (file)
 #include "include/policy.h"
 #include "include/policy_unpack.h"
 
+#define K_ABI_MASK 0x3ff
+#define FORCE_COMPLAIN_FLAG 0x800
+#define VERSION_LT(X, Y) (((X) & K_ABI_MASK) < ((Y) & K_ABI_MASK))
+#define VERSION_GT(X, Y) (((X) & K_ABI_MASK) > ((Y) & K_ABI_MASK))
+
+#define v5     5       /* base version */
+#define v6     6       /* per entry policydb mediation check */
+#define v7     7       /* full network masking */
+
 /*
  * The AppArmor interface treats data as a type byte followed by the
  * actual data.  The interface has the notion of a a named entry
@@ -70,18 +79,23 @@ struct aa_ext {
 static void audit_cb(struct audit_buffer *ab, void *va)
 {
        struct common_audit_data *sa = va;
-       if (sa->aad->iface.target) {
-               struct aa_profile *name = sa->aad->iface.target;
+
+       if (aad(sa)->iface.ns) {
+               audit_log_format(ab, " ns=");
+               audit_log_untrustedstring(ab, aad(sa)->iface.ns);
+       }
+       if (aad(sa)->iface.name) {
                audit_log_format(ab, " name=");
-               audit_log_untrustedstring(ab, name->base.hname);
+               audit_log_untrustedstring(ab, aad(sa)->iface.name);
        }
-       if (sa->aad->iface.pos)
-               audit_log_format(ab, " offset=%ld", sa->aad->iface.pos);
+       if (aad(sa)->iface.pos)
+               audit_log_format(ab, " offset=%ld", aad(sa)->iface.pos);
 }
 
 /**
  * audit_iface - do audit message for policy unpacking/load/replace/remove
  * @new: profile if it has been allocated (MAYBE NULL)
+ * @ns_name: name of the ns the profile is to be loaded to (MAY BE NULL)
  * @name: name of the profile being manipulated (MAYBE NULL)
  * @info: any extra info about the failure (MAYBE NULL)
  * @e: buffer position info
@@ -89,23 +103,33 @@ static void audit_cb(struct audit_buffer *ab, void *va)
  *
  * Returns: %0 or error
  */
-static int audit_iface(struct aa_profile *new, const char *name,
-                      const char *info, struct aa_ext *e, int error)
+static int audit_iface(struct aa_profile *new, const char *ns_name,
+                      const char *name, const char *info, struct aa_ext *e,
+                      int error)
 {
        struct aa_profile *profile = __aa_current_profile();
-       struct common_audit_data sa;
-       struct apparmor_audit_data aad = {0,};
-       sa.type = LSM_AUDIT_DATA_NONE;
-       sa.aad = &aad;
+       DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, NULL);
        if (e)
-               aad.iface.pos = e->pos - e->start;
-       aad.iface.target = new;
-       aad.name = name;
-       aad.info = info;
-       aad.error = error;
-
-       return aa_audit(AUDIT_APPARMOR_STATUS, profile, GFP_KERNEL, &sa,
-                       audit_cb);
+               aad(&sa)->iface.pos = e->pos - e->start;
+       aad(&sa)->iface.ns = ns_name;
+       if (new)
+               aad(&sa)->iface.name = new->base.hname;
+       else
+               aad(&sa)->iface.name = name;
+       aad(&sa)->info = info;
+       aad(&sa)->error = error;
+
+       return aa_audit(AUDIT_APPARMOR_STATUS, profile, &sa, audit_cb);
+}
+
+void aa_loaddata_kref(struct kref *kref)
+{
+       struct aa_loaddata *d = container_of(kref, struct aa_loaddata, count);
+
+       if (d) {
+               kzfree(d->hash);
+               kvfree(d);
+       }
 }
 
 /* test if read will be in packed data bounds */
@@ -127,8 +151,8 @@ static size_t unpack_u16_chunk(struct aa_ext *e, char **chunk)
 
        if (!inbounds(e, sizeof(u16)))
                return 0;
-       size = le16_to_cpu(get_unaligned((u16 *) e->pos));
-       e->pos += sizeof(u16);
+       size = le16_to_cpu(get_unaligned((__le16 *) e->pos));
+       e->pos += sizeof(__le16);
        if (!inbounds(e, size))
                return 0;
        *chunk = e->pos;
@@ -199,7 +223,7 @@ static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
                if (!inbounds(e, sizeof(u32)))
                        return 0;
                if (data)
-                       *data = le32_to_cpu(get_unaligned((u32 *) e->pos));
+                       *data = le32_to_cpu(get_unaligned((__le32 *) e->pos));
                e->pos += sizeof(u32);
                return 1;
        }
@@ -212,7 +236,7 @@ static bool unpack_u64(struct aa_ext *e, u64 *data, const char *name)
                if (!inbounds(e, sizeof(u64)))
                        return 0;
                if (data)
-                       *data = le64_to_cpu(get_unaligned((u64 *) e->pos));
+                       *data = le64_to_cpu(get_unaligned((__le64 *) e->pos));
                e->pos += sizeof(u64);
                return 1;
        }
@@ -225,7 +249,7 @@ static size_t unpack_array(struct aa_ext *e, const char *name)
                int size;
                if (!inbounds(e, sizeof(u16)))
                        return 0;
-               size = (int)le16_to_cpu(get_unaligned((u16 *) e->pos));
+               size = (int)le16_to_cpu(get_unaligned((__le16 *) e->pos));
                e->pos += sizeof(u16);
                return size;
        }
@@ -238,7 +262,7 @@ static size_t unpack_blob(struct aa_ext *e, char **blob, const char *name)
                u32 size;
                if (!inbounds(e, sizeof(u32)))
                        return 0;
-               size = le32_to_cpu(get_unaligned((u32 *) e->pos));
+               size = le32_to_cpu(get_unaligned((__le32 *) e->pos));
                e->pos += sizeof(u32);
                if (inbounds(e, (size_t) size)) {
                        *blob = e->pos;
@@ -340,12 +364,7 @@ static struct aa_dfa *unpack_dfa(struct aa_ext *e)
                        ((e->pos - e->start) & 7);
                size_t pad = ALIGN(sz, 8) - sz;
                int flags = TO_ACCEPT1_FLAG(YYTD_DATA32) |
-                       TO_ACCEPT2_FLAG(YYTD_DATA32);
-
-
-               if (aa_g_paranoid_load)
-                       flags |= DFA_FLAG_VERIFY_STATES;
-
+                       TO_ACCEPT2_FLAG(YYTD_DATA32) | DFA_FLAG_VERIFY_STATES;
                dfa = aa_dfa_unpack(blob + pad, size - pad, flags);
 
                if (IS_ERR(dfa))
@@ -466,27 +485,67 @@ fail:
        return 0;
 }
 
+static void *kvmemdup(const void *src, size_t len)
+{
+       void *p = kvmalloc(len);
+
+       if (p)
+               memcpy(p, src, len);
+       return p;
+}
+
+static u32 strhash(const void *data, u32 len, u32 seed)
+{
+       const char * const *key = data;
+
+       return jhash(*key, strlen(*key), seed);
+}
+
+static int datacmp(struct rhashtable_compare_arg *arg, const void *obj)
+{
+       const struct aa_data *data = obj;
+       const char * const *key = arg->key;
+
+       return strcmp(data->key, *key);
+}
+
 /**
  * unpack_profile - unpack a serialized profile
  * @e: serialized data extent information (NOT NULL)
  *
  * NOTE: unpack profile sets audit struct if there is a failure
  */
-static struct aa_profile *unpack_profile(struct aa_ext *e)
+static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
 {
        struct aa_profile *profile = NULL;
-       const char *name = NULL;
+       const char *tmpname, *tmpns = NULL, *name = NULL;
+       size_t ns_len;
+       struct rhashtable_params params = { 0 };
+       char *key = NULL;
+       struct aa_data *data;
        int i, error = -EPROTO;
        kernel_cap_t tmpcap;
        u32 tmp;
 
+       *ns_name = NULL;
+
        /* check that we have the right struct being passed */
        if (!unpack_nameX(e, AA_STRUCT, "profile"))
                goto fail;
        if (!unpack_str(e, &name, NULL))
                goto fail;
+       if (*name == '\0')
+               goto fail;
+
+       tmpname = aa_splitn_fqname(name, strlen(name), &tmpns, &ns_len);
+       if (tmpns) {
+               *ns_name = kstrndup(tmpns, ns_len, GFP_KERNEL);
+               if (!*ns_name)
+                       goto fail;
+               name = tmpname;
+       }
 
-       profile = aa_alloc_profile(name);
+       profile = aa_alloc_profile(name, GFP_KERNEL);
        if (!profile)
                return ERR_PTR(-ENOMEM);
 
@@ -519,7 +578,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
                profile->flags |= PFLAG_HAT;
        if (!unpack_u32(e, &tmp, NULL))
                goto fail;
-       if (tmp == PACKED_MODE_COMPLAIN)
+       if (tmp == PACKED_MODE_COMPLAIN || (e->version & FORCE_COMPLAIN_FLAG))
                profile->mode = APPARMOR_COMPLAIN;
        else if (tmp == PACKED_MODE_KILL)
                profile->mode = APPARMOR_KILL;
@@ -599,7 +658,8 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
                }
                if (!unpack_nameX(e, AA_STRUCTEND, NULL))
                        goto fail;
-       }
+       } else
+               profile->policy.dfa = aa_get_dfa(nulldfa);
 
        /* get file rules */
        profile->file.dfa = unpack_dfa(e);
@@ -607,15 +667,59 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
                error = PTR_ERR(profile->file.dfa);
                profile->file.dfa = NULL;
                goto fail;
-       }
-
-       if (!unpack_u32(e, &profile->file.start, "dfa_start"))
-               /* default start state */
-               profile->file.start = DFA_START;
+       } else if (profile->file.dfa) {
+               if (!unpack_u32(e, &profile->file.start, "dfa_start"))
+                       /* default start state */
+                       profile->file.start = DFA_START;
+       } else if (profile->policy.dfa &&
+                  profile->policy.start[AA_CLASS_FILE]) {
+               profile->file.dfa = aa_get_dfa(profile->policy.dfa);
+               profile->file.start = profile->policy.start[AA_CLASS_FILE];
+       } else
+               profile->file.dfa = aa_get_dfa(nulldfa);
 
        if (!unpack_trans_table(e, profile))
                goto fail;
 
+       if (unpack_nameX(e, AA_STRUCT, "data")) {
+               profile->data = kzalloc(sizeof(*profile->data), GFP_KERNEL);
+               if (!profile->data)
+                       goto fail;
+
+               params.nelem_hint = 3;
+               params.key_len = sizeof(void *);
+               params.key_offset = offsetof(struct aa_data, key);
+               params.head_offset = offsetof(struct aa_data, head);
+               params.hashfn = strhash;
+               params.obj_cmpfn = datacmp;
+
+               if (rhashtable_init(profile->data, &params))
+                       goto fail;
+
+               while (unpack_strdup(e, &key, NULL)) {
+                       data = kzalloc(sizeof(*data), GFP_KERNEL);
+                       if (!data) {
+                               kzfree(key);
+                               goto fail;
+                       }
+
+                       data->key = key;
+                       data->size = unpack_blob(e, &data->data, NULL);
+                       data->data = kvmemdup(data->data, data->size);
+                       if (data->size && !data->data) {
+                               kzfree(data->key);
+                               kzfree(data);
+                               goto fail;
+                       }
+
+                       rhashtable_insert_fast(profile->data, &data->head,
+                                              profile->data->p);
+               }
+
+               if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+                       goto fail;
+       }
+
        if (!unpack_nameX(e, AA_STRUCTEND, NULL))
                goto fail;
 
@@ -626,7 +730,8 @@ fail:
                name = NULL;
        else if (!name)
                name = "unknown";
-       audit_iface(profile, name, "failed to unpack profile", e, error);
+       audit_iface(profile, NULL, name, "failed to unpack profile", e,
+                   error);
        aa_free_profile(profile);
 
        return ERR_PTR(error);
@@ -649,24 +754,32 @@ static int verify_header(struct aa_ext *e, int required, const char **ns)
        /* get the interface version */
        if (!unpack_u32(e, &e->version, "version")) {
                if (required) {
-                       audit_iface(NULL, NULL, "invalid profile format", e,
-                                   error);
-                       return error;
-               }
-
-               /* check that the interface version is currently supported */
-               if (e->version != 5) {
-                       audit_iface(NULL, NULL, "unsupported interface version",
+                       audit_iface(NULL, NULL, NULL, "invalid profile format",
                                    e, error);
                        return error;
                }
        }
 
+       /* Check that the interface version is currently supported.
+        * if not specified use previous version
+        * Mask off everything that is not kernel abi version
+        */
+       if (VERSION_LT(e->version, v5) && VERSION_GT(e->version, v7)) {
+               audit_iface(NULL, NULL, NULL, "unsupported interface version",
+                           e, error);
+               return error;
+       }
 
        /* read the namespace if present */
        if (unpack_str(e, &name, "namespace")) {
+               if (*name == '\0') {
+                       audit_iface(NULL, NULL, NULL, "invalid namespace name",
+                                   e, error);
+                       return error;
+               }
                if (*ns && strcmp(*ns, name))
-                       audit_iface(NULL, NULL, "invalid ns change", e, error);
+                       audit_iface(NULL, NULL, NULL, "invalid ns change", e,
+                                   error);
                else if (!*ns)
                        *ns = name;
        }
@@ -705,14 +818,12 @@ static bool verify_dfa_xindex(struct aa_dfa *dfa, int table_size)
  */
 static int verify_profile(struct aa_profile *profile)
 {
-       if (aa_g_paranoid_load) {
-               if (profile->file.dfa &&
-                   !verify_dfa_xindex(profile->file.dfa,
-                                      profile->file.trans.size)) {
-                       audit_iface(profile, NULL, "Invalid named transition",
-                                   NULL, -EPROTO);
-                       return -EPROTO;
-               }
+       if (profile->file.dfa &&
+           !verify_dfa_xindex(profile->file.dfa,
+                              profile->file.trans.size)) {
+               audit_iface(profile, NULL, NULL, "Invalid named transition",
+                           NULL, -EPROTO);
+               return -EPROTO;
        }
 
        return 0;
@@ -724,6 +835,7 @@ void aa_load_ent_free(struct aa_load_ent *ent)
                aa_put_profile(ent->rename);
                aa_put_profile(ent->old);
                aa_put_profile(ent->new);
+               kfree(ent->ns_name);
                kzfree(ent);
        }
 }
@@ -739,7 +851,6 @@ struct aa_load_ent *aa_load_ent_alloc(void)
 /**
  * aa_unpack - unpack packed binary profile(s) data loaded from user space
  * @udata: user data copied to kmem  (NOT NULL)
- * @size: the size of the user data
  * @lh: list to place unpacked profiles in a aa_repl_ws
  * @ns: Returns namespace profile is in if specified else NULL (NOT NULL)
  *
@@ -749,26 +860,28 @@ struct aa_load_ent *aa_load_ent_alloc(void)
  *
  * Returns: profile(s) on @lh else error pointer if fails to unpack
  */
-int aa_unpack(void *udata, size_t size, struct list_head *lh, const char **ns)
+int aa_unpack(struct aa_loaddata *udata, struct list_head *lh,
+             const char **ns)
 {
        struct aa_load_ent *tmp, *ent;
        struct aa_profile *profile = NULL;
        int error;
        struct aa_ext e = {
-               .start = udata,
-               .end = udata + size,
-               .pos = udata,
+               .start = udata->data,
+               .end = udata->data + udata->size,
+               .pos = udata->data,
        };
 
        *ns = NULL;
        while (e.pos < e.end) {
+               char *ns_name = NULL;
                void *start;
                error = verify_header(&e, e.pos == e.start, ns);
                if (error)
                        goto fail;
 
                start = e.pos;
-               profile = unpack_profile(&e);
+               profile = unpack_profile(&e, &ns_name);
                if (IS_ERR(profile)) {
                        error = PTR_ERR(profile);
                        goto fail;
@@ -778,7 +891,8 @@ int aa_unpack(void *udata, size_t size, struct list_head *lh, const char **ns)
                if (error)
                        goto fail_profile;
 
-               error = aa_calc_profile_hash(profile, e.version, start,
+               if (aa_g_hash_policy)
+                       error = aa_calc_profile_hash(profile, e.version, start,
                                                     e.pos - start);
                if (error)
                        goto fail_profile;
@@ -790,9 +904,18 @@ int aa_unpack(void *udata, size_t size, struct list_head *lh, const char **ns)
                }
 
                ent->new = profile;
+               ent->ns_name = ns_name;
                list_add_tail(&ent->list, lh);
        }
-
+       udata->abi = e.version & K_ABI_MASK;
+       if (aa_g_hash_policy) {
+               udata->hash = aa_calc_hash(udata->data, udata->size);
+               if (IS_ERR(udata->hash)) {
+                       error = PTR_ERR(udata->hash);
+                       udata->hash = NULL;
+                       goto fail;
+               }
+       }
        return 0;
 
 fail_profile:
index b125acc9aa26cc327572955fb7aa83dbf2c5d09d..3466a27bca098fc4d75324fc5df4f744d43e8077 100644 (file)
@@ -15,6 +15,7 @@
 #include "include/apparmor.h"
 #include "include/context.h"
 #include "include/policy.h"
+#include "include/policy_ns.h"
 #include "include/domain.h"
 #include "include/procattr.h"
 
@@ -39,14 +40,14 @@ int aa_getprocattr(struct aa_profile *profile, char **string)
        int len = 0, mode_len = 0, ns_len = 0, name_len;
        const char *mode_str = aa_profile_mode_names[profile->mode];
        const char *ns_name = NULL;
-       struct aa_namespace *ns = profile->ns;
-       struct aa_namespace *current_ns = __aa_current_profile()->ns;
+       struct aa_ns *ns = profile->ns;
+       struct aa_ns *current_ns = __aa_current_profile()->ns;
        char *s;
 
-       if (!aa_ns_visible(current_ns, ns))
+       if (!aa_ns_visible(current_ns, ns, true))
                return -EACCES;
 
-       ns_name = aa_ns_name(current_ns, ns);
+       ns_name = aa_ns_name(current_ns, ns, true);
        ns_len = strlen(ns_name);
 
        /* if the visible ns_name is > 0 increase size for : :// seperator */
@@ -87,13 +88,13 @@ int aa_getprocattr(struct aa_profile *profile, char **string)
  *
  * Returns: start position of name after token else NULL on failure
  */
-static char *split_token_from_name(int op, char *args, u64 * token)
+static char *split_token_from_name(const char *op, char *args, u64 *token)
 {
        char *name;
 
        *token = simple_strtoull(args, &name, 16);
        if ((name == args) || *name != '^') {
-               AA_ERROR("%s: Invalid input '%s'", op_table[op], args);
+               AA_ERROR("%s: Invalid input '%s'", op, args);
                return ERR_PTR(-EINVAL);
        }
 
@@ -138,28 +139,13 @@ int aa_setprocattr_changehat(char *args, size_t size, int test)
                for (count = 0; (hat < end) && count < 16; ++count) {
                        char *next = hat + strlen(hat) + 1;
                        hats[count] = hat;
+                       AA_DEBUG("%s: (pid %d) Magic 0x%llx count %d hat '%s'\n"
+                                , __func__, current->pid, token, count, hat);
                        hat = next;
                }
-       }
-
-       AA_DEBUG("%s: Magic 0x%llx Hat '%s'\n",
-                __func__, token, hat ? hat : NULL);
+       } else
+               AA_DEBUG("%s: (pid %d) Magic 0x%llx count %d Hat '%s'\n",
+                        __func__, current->pid, token, count, "<NULL>");
 
        return aa_change_hat(hats, count, token, test);
 }
-
-/**
- * aa_setprocattr_changeprofile - handle procattr interface to changeprofile
- * @fqname: args received from writting to /proc/<pid>/attr/current (NOT NULL)
- * @onexec: true if change_profile should be delayed until exec
- * @test: true if this is a test of change_profile permissions
- *
- * Returns: %0 or error code if change_profile fails
- */
-int aa_setprocattr_changeprofile(char *fqname, bool onexec, int test)
-{
-       char *name, *ns_name;
-
-       name = aa_split_fqname(fqname, &ns_name);
-       return aa_change_profile(ns_name, name, onexec, test);
-}
index 67a6072ead4b9ed8efe98bdc57080c615839c32a..86a941afd9562a64a4116a0aa234b6e0e74e9728 100644 (file)
@@ -35,7 +35,7 @@ static void audit_cb(struct audit_buffer *ab, void *va)
        struct common_audit_data *sa = va;
 
        audit_log_format(ab, " rlimit=%s value=%lu",
-                        rlim_names[sa->aad->rlim.rlim], sa->aad->rlim.max);
+                        rlim_names[aad(sa)->rlim.rlim], aad(sa)->rlim.max);
 }
 
 /**
@@ -50,17 +50,12 @@ static void audit_cb(struct audit_buffer *ab, void *va)
 static int audit_resource(struct aa_profile *profile, unsigned int resource,
                          unsigned long value, int error)
 {
-       struct common_audit_data sa;
-       struct apparmor_audit_data aad = {0,};
-
-       sa.type = LSM_AUDIT_DATA_NONE;
-       sa.aad = &aad;
-       aad.op = OP_SETRLIMIT,
-       aad.rlim.rlim = resource;
-       aad.rlim.max = value;
-       aad.error = error;
-       return aa_audit(AUDIT_APPARMOR_AUTO, profile, GFP_KERNEL, &sa,
-                       audit_cb);
+       DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_SETRLIMIT);
+
+       aad(&sa)->rlim.rlim = resource;
+       aad(&sa)->rlim.max = value;
+       aad(&sa)->error = error;
+       return aa_audit(AUDIT_APPARMOR_AUTO, profile, &sa, audit_cb);
 }
 
 /**
diff --git a/security/apparmor/secid.c b/security/apparmor/secid.c
new file mode 100644 (file)
index 0000000..3a3edba
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor security identifier (secid) manipulation fns
+ *
+ * Copyright 2009-2010 Canonical 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, version 2 of the
+ * License.
+ *
+ *
+ * AppArmor allocates a unique secid for every profile loaded.  If a profile
+ * is replaced it receives the secid of the profile it is replacing.
+ *
+ * The secid value of 0 is invalid.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+
+#include "include/secid.h"
+
+/* global counter from which secids are allocated */
+static u32 global_secid;
+static DEFINE_SPINLOCK(secid_lock);
+
+/* TODO FIXME: add secid to profile mapping, and secid recycling */
+
+/**
+ * aa_alloc_secid - allocate a new secid for a profile
+ */
+u32 aa_alloc_secid(void)
+{
+       u32 secid;
+
+       /*
+        * TODO FIXME: secid recycling - part of profile mapping table
+        */
+       spin_lock(&secid_lock);
+       secid = (++global_secid);
+       spin_unlock(&secid_lock);
+       return secid;
+}
+
+/**
+ * aa_free_secid - free a secid
+ * @secid: secid to free
+ */
+void aa_free_secid(u32 secid)
+{
+       ;                       /* NOP ATM */
+}
diff --git a/security/apparmor/sid.c b/security/apparmor/sid.c
deleted file mode 100644 (file)
index f0b34f7..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * AppArmor security module
- *
- * This file contains AppArmor security identifier (sid) manipulation fns
- *
- * Copyright 2009-2010 Canonical 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, version 2 of the
- * License.
- *
- *
- * AppArmor allocates a unique sid for every profile loaded.  If a profile
- * is replaced it receives the sid of the profile it is replacing.
- *
- * The sid value of 0 is invalid.
- */
-
-#include <linux/spinlock.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-
-#include "include/sid.h"
-
-/* global counter from which sids are allocated */
-static u32 global_sid;
-static DEFINE_SPINLOCK(sid_lock);
-
-/* TODO FIXME: add sid to profile mapping, and sid recycling */
-
-/**
- * aa_alloc_sid - allocate a new sid for a profile
- */
-u32 aa_alloc_sid(void)
-{
-       u32 sid;
-
-       /*
-        * TODO FIXME: sid recycling - part of profile mapping table
-        */
-       spin_lock(&sid_lock);
-       sid = (++global_sid);
-       spin_unlock(&sid_lock);
-       return sid;
-}
-
-/**
- * aa_free_sid - free a sid
- * @sid: sid to free
- */
-void aa_free_sid(u32 sid)
-{
-       ;                       /* NOP ATM */
-}
index 8df676fbd39366274bf7da334ac5f2aca00c36ae..6d4d586b9356240660e75506d3daacb7ebb8a853 100644 (file)
@@ -1093,7 +1093,8 @@ struct security_hook_list capability_hooks[] = {
 
 void __init capability_add_hooks(void)
 {
-       security_add_hooks(capability_hooks, ARRAY_SIZE(capability_hooks));
+       security_add_hooks(capability_hooks, ARRAY_SIZE(capability_hooks),
+                               "capability");
 }
 
 #endif /* CONFIG_SECURITY */
index c83db05c15aba95801c49418d51728d5774bfdf0..2cb14162ff8d5fa2f2ebfdd58061c07f4569f34c 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/init.h>
 #include <linux/namei.h>
 #include <linux/security.h>
+#include <linux/lsm_hooks.h>
 #include <linux/magic.h>
 
 static struct vfsmount *mount;
@@ -204,6 +205,21 @@ void securityfs_remove(struct dentry *dentry)
 }
 EXPORT_SYMBOL_GPL(securityfs_remove);
 
+#ifdef CONFIG_SECURITY
+static struct dentry *lsm_dentry;
+static ssize_t lsm_read(struct file *filp, char __user *buf, size_t count,
+                       loff_t *ppos)
+{
+       return simple_read_from_buffer(buf, count, ppos, lsm_names,
+               strlen(lsm_names));
+}
+
+static const struct file_operations lsm_ops = {
+       .read = lsm_read,
+       .llseek = generic_file_llseek,
+};
+#endif
+
 static int __init securityfs_init(void)
 {
        int retval;
@@ -213,9 +229,15 @@ static int __init securityfs_init(void)
                return retval;
 
        retval = register_filesystem(&fs_type);
-       if (retval)
+       if (retval) {
                sysfs_remove_mount_point(kernel_kobj, "security");
-       return retval;
+               return retval;
+       }
+#ifdef CONFIG_SECURITY
+       lsm_dentry = securityfs_create_file("lsm", 0444, NULL, NULL,
+                                               &lsm_ops);
+#endif
+       return 0;
 }
 
 core_initcall(securityfs_init);
index 5e6180a4da7d2a9d583d4b81bbcfb76a1d9e558a..b563fbd4d122c24450f98dc7c6aaffd6235c451f 100644 (file)
@@ -204,7 +204,7 @@ int ima_store_template(struct ima_template_entry *entry, int violation,
                       struct inode *inode,
                       const unsigned char *filename, int pcr);
 void ima_free_template_entry(struct ima_template_entry *entry);
-const char *ima_d_path(const struct path *path, char **pathbuf);
+const char *ima_d_path(const struct path *path, char **pathbuf, char *filename);
 
 /* IMA policy related functions */
 int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
index 9df26a2b75ba692ee9d164fb14317779a117ca16..c2edba8de35e4932a13e73ec55907f9987037dce 100644 (file)
@@ -157,7 +157,8 @@ err_out:
 /**
  * ima_get_action - appraise & measure decision based on policy.
  * @inode: pointer to inode to measure
- * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE)
+ * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXEC,
+ *        MAY_APPEND)
  * @func: caller identifier
  * @pcr: pointer filled in if matched measure policy sets pcr=
  *
@@ -318,7 +319,17 @@ void ima_audit_measurement(struct integrity_iint_cache *iint,
        iint->flags |= IMA_AUDITED;
 }
 
-const char *ima_d_path(const struct path *path, char **pathbuf)
+/*
+ * ima_d_path - return a pointer to the full pathname
+ *
+ * Attempt to return a pointer to the full pathname for use in the
+ * IMA measurement list, IMA audit records, and auditing logs.
+ *
+ * On failure, return a pointer to a copy of the filename, not dname.
+ * Returning a pointer to dname, could result in using the pointer
+ * after the memory has been freed.
+ */
+const char *ima_d_path(const struct path *path, char **pathbuf, char *namebuf)
 {
        char *pathname = NULL;
 
@@ -331,5 +342,11 @@ const char *ima_d_path(const struct path *path, char **pathbuf)
                        pathname = NULL;
                }
        }
-       return pathname ?: (const char *)path->dentry->d_name.name;
+
+       if (!pathname) {
+               strlcpy(namebuf, path->dentry->d_name.name, NAME_MAX);
+               pathname = namebuf;
+       }
+
+       return pathname;
 }
index 50818c60538b8e0e764de72c842cfb608abb305a..2aebb7984437f10afe6e9aaa964a42be88f9295a 100644 (file)
@@ -83,6 +83,7 @@ static void ima_rdwr_violation_check(struct file *file,
                                     const char **pathname)
 {
        struct inode *inode = file_inode(file);
+       char filename[NAME_MAX];
        fmode_t mode = file->f_mode;
        bool send_tomtou = false, send_writers = false;
 
@@ -102,7 +103,7 @@ static void ima_rdwr_violation_check(struct file *file,
        if (!send_tomtou && !send_writers)
                return;
 
-       *pathname = ima_d_path(&file->f_path, pathbuf);
+       *pathname = ima_d_path(&file->f_path, pathbuf, filename);
 
        if (send_tomtou)
                ima_add_violation(file, *pathname, iint,
@@ -161,6 +162,7 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
        struct integrity_iint_cache *iint = NULL;
        struct ima_template_desc *template_desc;
        char *pathbuf = NULL;
+       char filename[NAME_MAX];
        const char *pathname = NULL;
        int rc = -ENOMEM, action, must_appraise;
        int pcr = CONFIG_IMA_MEASURE_PCR_IDX;
@@ -239,8 +241,8 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
                goto out_digsig;
        }
 
-       if (!pathname)  /* ima_rdwr_violation possibly pre-fetched */
-               pathname = ima_d_path(&file->f_path, &pathbuf);
+       if (!pathbuf)   /* ima_rdwr_violation possibly pre-fetched */
+               pathname = ima_d_path(&file->f_path, &pathbuf, filename);
 
        if (action & IMA_MEASURE)
                ima_store_measurement(iint, file, pathname,
@@ -307,7 +309,7 @@ int ima_bprm_check(struct linux_binprm *bprm)
 /**
  * ima_path_check - based on policy, collect/store measurement.
  * @file: pointer to the file to be measured
- * @mask: contains MAY_READ, MAY_WRITE or MAY_EXECUTE
+ * @mask: contains MAY_READ, MAY_WRITE, MAY_EXEC or MAY_APPEND
  *
  * Measure files based on the ima_must_measure() policy decision.
  *
@@ -317,8 +319,8 @@ int ima_bprm_check(struct linux_binprm *bprm)
 int ima_file_check(struct file *file, int mask, int opened)
 {
        return process_measurement(file, NULL, 0,
-                                  mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
-                                  FILE_CHECK, opened);
+                                  mask & (MAY_READ | MAY_WRITE | MAY_EXEC |
+                                          MAY_APPEND), FILE_CHECK, opened);
 }
 EXPORT_SYMBOL_GPL(ima_file_check);
 
index 17a06105ccb616ea91aaa5635341136dda1fc915..4fb315cddf5b009672c3aeb31877135551125802 100644 (file)
@@ -437,7 +437,7 @@ static struct skcipher_request *init_skcipher_req(const u8 *key,
 static struct key *request_master_key(struct encrypted_key_payload *epayload,
                                      const u8 **master_key, size_t *master_keylen)
 {
-       struct key *mkey = NULL;
+       struct key *mkey = ERR_PTR(-EINVAL);
 
        if (!strncmp(epayload->master_desc, KEY_TRUSTED_PREFIX,
                     KEY_TRUSTED_PREFIX_LEN)) {
@@ -985,7 +985,7 @@ static void encrypted_destroy(struct key *key)
        if (!epayload)
                return;
 
-       memset(epayload->decrypted_data, 0, epayload->decrypted_datalen);
+       memzero_explicit(epayload->decrypted_data, epayload->decrypted_datalen);
        kfree(key->payload.data[0]);
 }
 
index 89a46f10b8a7b27d3adcad7b5df9a63b15fd84ba..1d82eae3a5b834c4beadf9bdf79415ecb9078ffe 100644 (file)
@@ -182,7 +182,7 @@ static struct security_hook_list loadpin_hooks[] = {
 void __init loadpin_add_hooks(void)
 {
        pr_info("ready to pin (currently %sabled)", enabled ? "en" : "dis");
-       security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks));
+       security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks), "loadpin");
 }
 
 /* Should not be mutable after boot, so not listed in sysfs (perm == 0). */
index f825304f04a773763cad9c36ac5bc68f9e7a9aa1..d0e07f269b2d92b54e384d5a50708543bb7cc131 100644 (file)
@@ -32,6 +32,7 @@
 /* Maximum number of letters for an LSM name string */
 #define SECURITY_NAME_MAX      10
 
+char *lsm_names;
 /* Boot-time LSM user choice */
 static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] =
        CONFIG_DEFAULT_SECURITY;
@@ -78,6 +79,22 @@ static int __init choose_lsm(char *str)
 }
 __setup("security=", choose_lsm);
 
+static int lsm_append(char *new, char **result)
+{
+       char *cp;
+
+       if (*result == NULL) {
+               *result = kstrdup(new, GFP_KERNEL);
+       } else {
+               cp = kasprintf(GFP_KERNEL, "%s,%s", *result, new);
+               if (cp == NULL)
+                       return -ENOMEM;
+               kfree(*result);
+               *result = cp;
+       }
+       return 0;
+}
+
 /**
  * security_module_enable - Load given security module on boot ?
  * @module: the name of the module
@@ -97,6 +114,27 @@ int __init security_module_enable(const char *module)
        return !strcmp(module, chosen_lsm);
 }
 
+/**
+ * security_add_hooks - Add a modules hooks to the hook lists.
+ * @hooks: the hooks to add
+ * @count: the number of hooks to add
+ * @lsm: the name of the security module
+ *
+ * Each LSM has to register its hooks with the infrastructure.
+ */
+void __init security_add_hooks(struct security_hook_list *hooks, int count,
+                               char *lsm)
+{
+       int i;
+
+       for (i = 0; i < count; i++) {
+               hooks[i].lsm = lsm;
+               list_add_tail_rcu(&hooks[i].list, hooks[i].head);
+       }
+       if (lsm_append(lsm, &lsm_names) < 0)
+               panic("%s - Cannot get early memory.\n", __func__);
+}
+
 /*
  * Hook list operation macros.
  *
@@ -1025,11 +1063,6 @@ int security_task_kill(struct task_struct *p, struct siginfo *info,
        return call_int_hook(task_kill, 0, p, info, sig, secid);
 }
 
-int security_task_wait(struct task_struct *p)
-{
-       return call_int_hook(task_wait, 0, p);
-}
-
 int security_task_prctl(int option, unsigned long arg2, unsigned long arg3,
                         unsigned long arg4, unsigned long arg5)
 {
@@ -1170,9 +1203,9 @@ int security_getprocattr(struct task_struct *p, char *name, char **value)
        return call_int_hook(getprocattr, -EINVAL, p, name, value);
 }
 
-int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size)
+int security_setprocattr(const char *name, void *value, size_t size)
 {
-       return call_int_hook(setprocattr, -EINVAL, p, name, value, size);
+       return call_int_hook(setprocattr, -EINVAL, name, value, size);
 }
 
 int security_netlink_send(struct sock *sk, struct sk_buff *skb)
@@ -1769,7 +1802,6 @@ struct security_hook_heads security_hook_heads = {
        .task_movememory =
                LIST_HEAD_INIT(security_hook_heads.task_movememory),
        .task_kill =    LIST_HEAD_INIT(security_hook_heads.task_kill),
-       .task_wait =    LIST_HEAD_INIT(security_hook_heads.task_wait),
        .task_prctl =   LIST_HEAD_INIT(security_hook_heads.task_prctl),
        .task_to_inode =
                LIST_HEAD_INIT(security_hook_heads.task_to_inode),
index d98550abe16d40250be4327197c48866953b5645..9bc12bcddc2c977bae6bb54eaf5a28d0d8870090 100644 (file)
@@ -210,16 +210,6 @@ static inline u32 task_sid(const struct task_struct *task)
        return sid;
 }
 
-/*
- * get the subjective security ID of the current task
- */
-static inline u32 current_sid(void)
-{
-       const struct task_security_struct *tsec = current_security();
-
-       return tsec->sid;
-}
-
 /* Allocate and free functions for each kind of security blob. */
 
 static int inode_alloc_security(struct inode *inode)
@@ -490,8 +480,11 @@ static int selinux_is_sblabel_mnt(struct super_block *sb)
                sbsec->behavior == SECURITY_FS_USE_NATIVE ||
                /* Special handling. Genfs but also in-core setxattr handler */
                !strcmp(sb->s_type->name, "sysfs") ||
+               !strcmp(sb->s_type->name, "cgroup") ||
+               !strcmp(sb->s_type->name, "cgroup2") ||
                !strcmp(sb->s_type->name, "pstore") ||
                !strcmp(sb->s_type->name, "debugfs") ||
+               !strcmp(sb->s_type->name, "tracefs") ||
                !strcmp(sb->s_type->name, "rootfs");
 }
 
@@ -833,10 +826,14 @@ static int selinux_set_mnt_opts(struct super_block *sb,
        }
 
        /*
-        * If this is a user namespace mount, no contexts are allowed
-        * on the command line and security labels must be ignored.
+        * If this is a user namespace mount and the filesystem type is not
+        * explicitly whitelisted, then no contexts are allowed on the command
+        * line and security labels must be ignored.
         */
-       if (sb->s_user_ns != &init_user_ns) {
+       if (sb->s_user_ns != &init_user_ns &&
+           strcmp(sb->s_type->name, "tmpfs") &&
+           strcmp(sb->s_type->name, "ramfs") &&
+           strcmp(sb->s_type->name, "devpts")) {
                if (context_sid || fscontext_sid || rootcontext_sid ||
                    defcontext_sid) {
                        rc = -EACCES;
@@ -1268,6 +1265,8 @@ static inline int default_protocol_dgram(int protocol)
 
 static inline u16 socket_type_to_security_class(int family, int type, int protocol)
 {
+       int extsockclass = selinux_policycap_extsockclass;
+
        switch (family) {
        case PF_UNIX:
                switch (type) {
@@ -1282,13 +1281,19 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc
        case PF_INET6:
                switch (type) {
                case SOCK_STREAM:
+               case SOCK_SEQPACKET:
                        if (default_protocol_stream(protocol))
                                return SECCLASS_TCP_SOCKET;
+                       else if (extsockclass && protocol == IPPROTO_SCTP)
+                               return SECCLASS_SCTP_SOCKET;
                        else
                                return SECCLASS_RAWIP_SOCKET;
                case SOCK_DGRAM:
                        if (default_protocol_dgram(protocol))
                                return SECCLASS_UDP_SOCKET;
+                       else if (extsockclass && (protocol == IPPROTO_ICMP ||
+                                                 protocol == IPPROTO_ICMPV6))
+                               return SECCLASS_ICMP_SOCKET;
                        else
                                return SECCLASS_RAWIP_SOCKET;
                case SOCK_DCCP:
@@ -1342,6 +1347,66 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc
                return SECCLASS_APPLETALK_SOCKET;
        }
 
+       if (extsockclass) {
+               switch (family) {
+               case PF_AX25:
+                       return SECCLASS_AX25_SOCKET;
+               case PF_IPX:
+                       return SECCLASS_IPX_SOCKET;
+               case PF_NETROM:
+                       return SECCLASS_NETROM_SOCKET;
+               case PF_ATMPVC:
+                       return SECCLASS_ATMPVC_SOCKET;
+               case PF_X25:
+                       return SECCLASS_X25_SOCKET;
+               case PF_ROSE:
+                       return SECCLASS_ROSE_SOCKET;
+               case PF_DECnet:
+                       return SECCLASS_DECNET_SOCKET;
+               case PF_ATMSVC:
+                       return SECCLASS_ATMSVC_SOCKET;
+               case PF_RDS:
+                       return SECCLASS_RDS_SOCKET;
+               case PF_IRDA:
+                       return SECCLASS_IRDA_SOCKET;
+               case PF_PPPOX:
+                       return SECCLASS_PPPOX_SOCKET;
+               case PF_LLC:
+                       return SECCLASS_LLC_SOCKET;
+               case PF_CAN:
+                       return SECCLASS_CAN_SOCKET;
+               case PF_TIPC:
+                       return SECCLASS_TIPC_SOCKET;
+               case PF_BLUETOOTH:
+                       return SECCLASS_BLUETOOTH_SOCKET;
+               case PF_IUCV:
+                       return SECCLASS_IUCV_SOCKET;
+               case PF_RXRPC:
+                       return SECCLASS_RXRPC_SOCKET;
+               case PF_ISDN:
+                       return SECCLASS_ISDN_SOCKET;
+               case PF_PHONET:
+                       return SECCLASS_PHONET_SOCKET;
+               case PF_IEEE802154:
+                       return SECCLASS_IEEE802154_SOCKET;
+               case PF_CAIF:
+                       return SECCLASS_CAIF_SOCKET;
+               case PF_ALG:
+                       return SECCLASS_ALG_SOCKET;
+               case PF_NFC:
+                       return SECCLASS_NFC_SOCKET;
+               case PF_VSOCK:
+                       return SECCLASS_VSOCK_SOCKET;
+               case PF_KCM:
+                       return SECCLASS_KCM_SOCKET;
+               case PF_QIPCRTR:
+                       return SECCLASS_QIPCRTR_SOCKET;
+#if PF_MAX > 43
+#error New address family defined, please update this function.
+#endif
+               }
+       }
+
        return SECCLASS_SOCKET;
 }
 
@@ -1608,55 +1673,6 @@ static inline u32 signal_to_av(int sig)
        return perm;
 }
 
-/*
- * Check permission between a pair of credentials
- * fork check, ptrace check, etc.
- */
-static int cred_has_perm(const struct cred *actor,
-                        const struct cred *target,
-                        u32 perms)
-{
-       u32 asid = cred_sid(actor), tsid = cred_sid(target);
-
-       return avc_has_perm(asid, tsid, SECCLASS_PROCESS, perms, NULL);
-}
-
-/*
- * Check permission between a pair of tasks, e.g. signal checks,
- * fork check, ptrace check, etc.
- * tsk1 is the actor and tsk2 is the target
- * - this uses the default subjective creds of tsk1
- */
-static int task_has_perm(const struct task_struct *tsk1,
-                        const struct task_struct *tsk2,
-                        u32 perms)
-{
-       const struct task_security_struct *__tsec1, *__tsec2;
-       u32 sid1, sid2;
-
-       rcu_read_lock();
-       __tsec1 = __task_cred(tsk1)->security;  sid1 = __tsec1->sid;
-       __tsec2 = __task_cred(tsk2)->security;  sid2 = __tsec2->sid;
-       rcu_read_unlock();
-       return avc_has_perm(sid1, sid2, SECCLASS_PROCESS, perms, NULL);
-}
-
-/*
- * Check permission between current and another task, e.g. signal checks,
- * fork check, ptrace check, etc.
- * current is the actor and tsk2 is the target
- * - this uses current's subjective creds
- */
-static int current_has_perm(const struct task_struct *tsk,
-                           u32 perms)
-{
-       u32 sid, tsid;
-
-       sid = current_sid();
-       tsid = task_sid(tsk);
-       return avc_has_perm(sid, tsid, SECCLASS_PROCESS, perms, NULL);
-}
-
 #if CAP_LAST_CAP > 63
 #error Fix SELinux to handle capabilities > 63.
 #endif
@@ -1698,16 +1714,6 @@ static int cred_has_capability(const struct cred *cred,
        return rc;
 }
 
-/* Check whether a task is allowed to use a system operation. */
-static int task_has_system(struct task_struct *tsk,
-                          u32 perms)
-{
-       u32 sid = task_sid(tsk);
-
-       return avc_has_perm(sid, SECINITSID_KERNEL,
-                           SECCLASS_SYSTEM, perms, NULL);
-}
-
 /* Check whether a task has a particular permission to an inode.
    The 'adp' parameter is optional and allows other audit
    data to be passed (e.g. the dentry). */
@@ -1879,15 +1885,6 @@ static int may_create(struct inode *dir,
                            FILESYSTEM__ASSOCIATE, &ad);
 }
 
-/* Check whether a task can create a key. */
-static int may_create_key(u32 ksid,
-                         struct task_struct *ctx)
-{
-       u32 sid = task_sid(ctx);
-
-       return avc_has_perm(sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
-}
-
 #define MAY_LINK       0
 #define MAY_UNLINK     1
 #define MAY_RMDIR      2
@@ -2143,24 +2140,26 @@ static int selinux_binder_transfer_file(struct task_struct *from,
 static int selinux_ptrace_access_check(struct task_struct *child,
                                     unsigned int mode)
 {
-       if (mode & PTRACE_MODE_READ) {
-               u32 sid = current_sid();
-               u32 csid = task_sid(child);
+       u32 sid = current_sid();
+       u32 csid = task_sid(child);
+
+       if (mode & PTRACE_MODE_READ)
                return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL);
-       }
 
-       return current_has_perm(child, PROCESS__PTRACE);
+       return avc_has_perm(sid, csid, SECCLASS_PROCESS, PROCESS__PTRACE, NULL);
 }
 
 static int selinux_ptrace_traceme(struct task_struct *parent)
 {
-       return task_has_perm(parent, current, PROCESS__PTRACE);
+       return avc_has_perm(task_sid(parent), current_sid(), SECCLASS_PROCESS,
+                           PROCESS__PTRACE, NULL);
 }
 
 static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
                          kernel_cap_t *inheritable, kernel_cap_t *permitted)
 {
-       return current_has_perm(target, PROCESS__GETCAP);
+       return avc_has_perm(current_sid(), task_sid(target), SECCLASS_PROCESS,
+                           PROCESS__GETCAP, NULL);
 }
 
 static int selinux_capset(struct cred *new, const struct cred *old,
@@ -2168,7 +2167,8 @@ static int selinux_capset(struct cred *new, const struct cred *old,
                          const kernel_cap_t *inheritable,
                          const kernel_cap_t *permitted)
 {
-       return cred_has_perm(old, new, PROCESS__SETCAP);
+       return avc_has_perm(cred_sid(old), cred_sid(new), SECCLASS_PROCESS,
+                           PROCESS__SETCAP, NULL);
 }
 
 /*
@@ -2224,29 +2224,22 @@ static int selinux_quota_on(struct dentry *dentry)
 
 static int selinux_syslog(int type)
 {
-       int rc;
-
        switch (type) {
        case SYSLOG_ACTION_READ_ALL:    /* Read last kernel messages */
        case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */
-               rc = task_has_system(current, SYSTEM__SYSLOG_READ);
-               break;
+               return avc_has_perm(current_sid(), SECINITSID_KERNEL,
+                                   SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, NULL);
        case SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging to console */
        case SYSLOG_ACTION_CONSOLE_ON:  /* Enable logging to console */
        /* Set level of messages printed to console */
        case SYSLOG_ACTION_CONSOLE_LEVEL:
-               rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE);
-               break;
-       case SYSLOG_ACTION_CLOSE:       /* Close log */
-       case SYSLOG_ACTION_OPEN:        /* Open log */
-       case SYSLOG_ACTION_READ:        /* Read from log */
-       case SYSLOG_ACTION_READ_CLEAR:  /* Read/clear last kernel messages */
-       case SYSLOG_ACTION_CLEAR:       /* Clear ring buffer */
-       default:
-               rc = task_has_system(current, SYSTEM__SYSLOG_MOD);
-               break;
+               return avc_has_perm(current_sid(), SECINITSID_KERNEL,
+                                   SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE,
+                                   NULL);
        }
-       return rc;
+       /* All other syslog types */
+       return avc_has_perm(current_sid(), SECINITSID_KERNEL,
+                           SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, NULL);
 }
 
 /*
@@ -2271,13 +2264,13 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
 
 /* binprm security operations */
 
-static u32 ptrace_parent_sid(struct task_struct *task)
+static u32 ptrace_parent_sid(void)
 {
        u32 sid = 0;
        struct task_struct *tracer;
 
        rcu_read_lock();
-       tracer = ptrace_parent(task);
+       tracer = ptrace_parent(current);
        if (tracer)
                sid = task_sid(tracer);
        rcu_read_unlock();
@@ -2406,7 +2399,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
                 * changes its SID has the appropriate permit */
                if (bprm->unsafe &
                    (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
-                       u32 ptsid = ptrace_parent_sid(current);
+                       u32 ptsid = ptrace_parent_sid();
                        if (ptsid != 0) {
                                rc = avc_has_perm(ptsid, new_tsec->sid,
                                                  SECCLASS_PROCESS,
@@ -3503,6 +3496,7 @@ static int default_noexec;
 static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
 {
        const struct cred *cred = current_cred();
+       u32 sid = cred_sid(cred);
        int rc = 0;
 
        if (default_noexec &&
@@ -3513,7 +3507,8 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared
                 * private file mapping that will also be writable.
                 * This has an additional check.
                 */
-               rc = cred_has_perm(cred, cred, PROCESS__EXECMEM);
+               rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
+                                 PROCESS__EXECMEM, NULL);
                if (rc)
                        goto error;
        }
@@ -3564,6 +3559,7 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
                                 unsigned long prot)
 {
        const struct cred *cred = current_cred();
+       u32 sid = cred_sid(cred);
 
        if (selinux_checkreqprot)
                prot = reqprot;
@@ -3573,12 +3569,14 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
                int rc = 0;
                if (vma->vm_start >= vma->vm_mm->start_brk &&
                    vma->vm_end <= vma->vm_mm->brk) {
-                       rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP);
+                       rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
+                                         PROCESS__EXECHEAP, NULL);
                } else if (!vma->vm_file &&
                           ((vma->vm_start <= vma->vm_mm->start_stack &&
                             vma->vm_end >= vma->vm_mm->start_stack) ||
                            vma_is_stack_for_current(vma))) {
-                       rc = current_has_perm(current, PROCESS__EXECSTACK);
+                       rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
+                                         PROCESS__EXECSTACK, NULL);
                } else if (vma->vm_file && vma->anon_vma) {
                        /*
                         * We are making executable a file mapping that has
@@ -3711,7 +3709,9 @@ static int selinux_file_open(struct file *file, const struct cred *cred)
 
 static int selinux_task_create(unsigned long clone_flags)
 {
-       return current_has_perm(current, PROCESS__FORK);
+       u32 sid = current_sid();
+
+       return avc_has_perm(sid, sid, SECCLASS_PROCESS, PROCESS__FORK, NULL);
 }
 
 /*
@@ -3821,15 +3821,12 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
 
 static int selinux_kernel_module_request(char *kmod_name)
 {
-       u32 sid;
        struct common_audit_data ad;
 
-       sid = task_sid(current);
-
        ad.type = LSM_AUDIT_DATA_KMOD;
        ad.u.kmod_name = kmod_name;
 
-       return avc_has_perm(sid, SECINITSID_KERNEL, SECCLASS_SYSTEM,
+       return avc_has_perm(current_sid(), SECINITSID_KERNEL, SECCLASS_SYSTEM,
                            SYSTEM__MODULE_REQUEST, &ad);
 }
 
@@ -3881,17 +3878,20 @@ static int selinux_kernel_read_file(struct file *file,
 
 static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
 {
-       return current_has_perm(p, PROCESS__SETPGID);
+       return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS,
+                           PROCESS__SETPGID, NULL);
 }
 
 static int selinux_task_getpgid(struct task_struct *p)
 {
-       return current_has_perm(p, PROCESS__GETPGID);
+       return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS,
+                           PROCESS__GETPGID, NULL);
 }
 
 static int selinux_task_getsid(struct task_struct *p)
 {
-       return current_has_perm(p, PROCESS__GETSESSION);
+       return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS,
+                           PROCESS__GETSESSION, NULL);
 }
 
 static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
@@ -3901,17 +3901,20 @@ static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
 
 static int selinux_task_setnice(struct task_struct *p, int nice)
 {
-       return current_has_perm(p, PROCESS__SETSCHED);
+       return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS,
+                           PROCESS__SETSCHED, NULL);
 }
 
 static int selinux_task_setioprio(struct task_struct *p, int ioprio)
 {
-       return current_has_perm(p, PROCESS__SETSCHED);
+       return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS,
+                           PROCESS__SETSCHED, NULL);
 }
 
 static int selinux_task_getioprio(struct task_struct *p)
 {
-       return current_has_perm(p, PROCESS__GETSCHED);
+       return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS,
+                           PROCESS__GETSCHED, NULL);
 }
 
 static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
@@ -3924,47 +3927,42 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
           later be used as a safe reset point for the soft limit
           upon context transitions.  See selinux_bprm_committing_creds. */
        if (old_rlim->rlim_max != new_rlim->rlim_max)
-               return current_has_perm(p, PROCESS__SETRLIMIT);
+               return avc_has_perm(current_sid(), task_sid(p),
+                                   SECCLASS_PROCESS, PROCESS__SETRLIMIT, NULL);
 
        return 0;
 }
 
 static int selinux_task_setscheduler(struct task_struct *p)
 {
-       return current_has_perm(p, PROCESS__SETSCHED);
+       return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS,
+                           PROCESS__SETSCHED, NULL);
 }
 
 static int selinux_task_getscheduler(struct task_struct *p)
 {
-       return current_has_perm(p, PROCESS__GETSCHED);
+       return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS,
+                           PROCESS__GETSCHED, NULL);
 }
 
 static int selinux_task_movememory(struct task_struct *p)
 {
-       return current_has_perm(p, PROCESS__SETSCHED);
+       return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS,
+                           PROCESS__SETSCHED, NULL);
 }
 
 static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
                                int sig, u32 secid)
 {
        u32 perm;
-       int rc;
 
        if (!sig)
                perm = PROCESS__SIGNULL; /* null signal; existence test */
        else
                perm = signal_to_av(sig);
-       if (secid)
-               rc = avc_has_perm(secid, task_sid(p),
-                                 SECCLASS_PROCESS, perm, NULL);
-       else
-               rc = current_has_perm(p, perm);
-       return rc;
-}
-
-static int selinux_task_wait(struct task_struct *p)
-{
-       return task_has_perm(p, current, PROCESS__SIGCHLD);
+       if (!secid)
+               secid = current_sid();
+       return avc_has_perm(secid, task_sid(p), SECCLASS_PROCESS, perm, NULL);
 }
 
 static void selinux_task_to_inode(struct task_struct *p,
@@ -4254,12 +4252,11 @@ static int socket_sockcreate_sid(const struct task_security_struct *tsec,
                                       socksid);
 }
 
-static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms)
+static int sock_has_perm(struct sock *sk, u32 perms)
 {
        struct sk_security_struct *sksec = sk->sk_security;
        struct common_audit_data ad;
        struct lsm_network_audit net = {0,};
-       u32 tsid = task_sid(task);
 
        if (sksec->sid == SECINITSID_KERNEL)
                return 0;
@@ -4268,7 +4265,8 @@ static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms)
        ad.u.net = &net;
        ad.u.net->sk = sk;
 
-       return avc_has_perm(tsid, sksec->sid, sksec->sclass, perms, &ad);
+       return avc_has_perm(current_sid(), sksec->sid, sksec->sclass, perms,
+                           &ad);
 }
 
 static int selinux_socket_create(int family, int type,
@@ -4330,7 +4328,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
        u16 family;
        int err;
 
-       err = sock_has_perm(current, sk, SOCKET__BIND);
+       err = sock_has_perm(sk, SOCKET__BIND);
        if (err)
                goto out;
 
@@ -4429,7 +4427,7 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
        struct sk_security_struct *sksec = sk->sk_security;
        int err;
 
-       err = sock_has_perm(current, sk, SOCKET__CONNECT);
+       err = sock_has_perm(sk, SOCKET__CONNECT);
        if (err)
                return err;
 
@@ -4481,7 +4479,7 @@ out:
 
 static int selinux_socket_listen(struct socket *sock, int backlog)
 {
-       return sock_has_perm(current, sock->sk, SOCKET__LISTEN);
+       return sock_has_perm(sock->sk, SOCKET__LISTEN);
 }
 
 static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
@@ -4492,7 +4490,7 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
        u16 sclass;
        u32 sid;
 
-       err = sock_has_perm(current, sock->sk, SOCKET__ACCEPT);
+       err = sock_has_perm(sock->sk, SOCKET__ACCEPT);
        if (err)
                return err;
 
@@ -4513,30 +4511,30 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
 static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
                                  int size)
 {
-       return sock_has_perm(current, sock->sk, SOCKET__WRITE);
+       return sock_has_perm(sock->sk, SOCKET__WRITE);
 }
 
 static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
                                  int size, int flags)
 {
-       return sock_has_perm(current, sock->sk, SOCKET__READ);
+       return sock_has_perm(sock->sk, SOCKET__READ);
 }
 
 static int selinux_socket_getsockname(struct socket *sock)
 {
-       return sock_has_perm(current, sock->sk, SOCKET__GETATTR);
+       return sock_has_perm(sock->sk, SOCKET__GETATTR);
 }
 
 static int selinux_socket_getpeername(struct socket *sock)
 {
-       return sock_has_perm(current, sock->sk, SOCKET__GETATTR);
+       return sock_has_perm(sock->sk, SOCKET__GETATTR);
 }
 
 static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
 {
        int err;
 
-       err = sock_has_perm(current, sock->sk, SOCKET__SETOPT);
+       err = sock_has_perm(sock->sk, SOCKET__SETOPT);
        if (err)
                return err;
 
@@ -4546,12 +4544,12 @@ static int selinux_socket_setsockopt(struct socket *sock, int level, int optname
 static int selinux_socket_getsockopt(struct socket *sock, int level,
                                     int optname)
 {
-       return sock_has_perm(current, sock->sk, SOCKET__GETOPT);
+       return sock_has_perm(sock->sk, SOCKET__GETOPT);
 }
 
 static int selinux_socket_shutdown(struct socket *sock, int how)
 {
-       return sock_has_perm(current, sock->sk, SOCKET__SHUTDOWN);
+       return sock_has_perm(sock->sk, SOCKET__SHUTDOWN);
 }
 
 static int selinux_socket_unix_stream_connect(struct sock *sock,
@@ -5039,7 +5037,7 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
                goto out;
        }
 
-       err = sock_has_perm(current, sk, perm);
+       err = sock_has_perm(sk, perm);
 out:
        return err;
 }
@@ -5370,20 +5368,17 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
        return selinux_nlmsg_perm(sk, skb);
 }
 
-static int ipc_alloc_security(struct task_struct *task,
-                             struct kern_ipc_perm *perm,
+static int ipc_alloc_security(struct kern_ipc_perm *perm,
                              u16 sclass)
 {
        struct ipc_security_struct *isec;
-       u32 sid;
 
        isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
        if (!isec)
                return -ENOMEM;
 
-       sid = task_sid(task);
        isec->sclass = sclass;
-       isec->sid = sid;
+       isec->sid = current_sid();
        perm->security = isec;
 
        return 0;
@@ -5451,7 +5446,7 @@ static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
        u32 sid = current_sid();
        int rc;
 
-       rc = ipc_alloc_security(current, &msq->q_perm, SECCLASS_MSGQ);
+       rc = ipc_alloc_security(&msq->q_perm, SECCLASS_MSGQ);
        if (rc)
                return rc;
 
@@ -5498,7 +5493,8 @@ static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd)
        case IPC_INFO:
        case MSG_INFO:
                /* No specific object, just general system-wide information. */
-               return task_has_system(current, SYSTEM__IPC_INFO);
+               return avc_has_perm(current_sid(), SECINITSID_KERNEL,
+                                   SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
        case IPC_STAT:
        case MSG_STAT:
                perms = MSGQ__GETATTR | MSGQ__ASSOCIATE;
@@ -5592,7 +5588,7 @@ static int selinux_shm_alloc_security(struct shmid_kernel *shp)
        u32 sid = current_sid();
        int rc;
 
-       rc = ipc_alloc_security(current, &shp->shm_perm, SECCLASS_SHM);
+       rc = ipc_alloc_security(&shp->shm_perm, SECCLASS_SHM);
        if (rc)
                return rc;
 
@@ -5640,7 +5636,8 @@ static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd)
        case IPC_INFO:
        case SHM_INFO:
                /* No specific object, just general system-wide information. */
-               return task_has_system(current, SYSTEM__IPC_INFO);
+               return avc_has_perm(current_sid(), SECINITSID_KERNEL,
+                                   SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
        case IPC_STAT:
        case SHM_STAT:
                perms = SHM__GETATTR | SHM__ASSOCIATE;
@@ -5684,7 +5681,7 @@ static int selinux_sem_alloc_security(struct sem_array *sma)
        u32 sid = current_sid();
        int rc;
 
-       rc = ipc_alloc_security(current, &sma->sem_perm, SECCLASS_SEM);
+       rc = ipc_alloc_security(&sma->sem_perm, SECCLASS_SEM);
        if (rc)
                return rc;
 
@@ -5732,7 +5729,8 @@ static int selinux_sem_semctl(struct sem_array *sma, int cmd)
        case IPC_INFO:
        case SEM_INFO:
                /* No specific object, just general system-wide information. */
-               return task_has_system(current, SYSTEM__IPC_INFO);
+               return avc_has_perm(current_sid(), SECINITSID_KERNEL,
+                                   SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
        case GETPID:
        case GETNCNT:
        case GETZCNT:
@@ -5813,15 +5811,16 @@ static int selinux_getprocattr(struct task_struct *p,
        int error;
        unsigned len;
 
+       rcu_read_lock();
+       __tsec = __task_cred(p)->security;
+
        if (current != p) {
-               error = current_has_perm(p, PROCESS__GETATTR);
+               error = avc_has_perm(current_sid(), __tsec->sid,
+                                    SECCLASS_PROCESS, PROCESS__GETATTR, NULL);
                if (error)
-                       return error;
+                       goto bad;
        }
 
-       rcu_read_lock();
-       __tsec = __task_cred(p)->security;
-
        if (!strcmp(name, "current"))
                sid = __tsec->sid;
        else if (!strcmp(name, "prev"))
@@ -5834,8 +5833,10 @@ static int selinux_getprocattr(struct task_struct *p,
                sid = __tsec->keycreate_sid;
        else if (!strcmp(name, "sockcreate"))
                sid = __tsec->sockcreate_sid;
-       else
-               goto invalid;
+       else {
+               error = -EINVAL;
+               goto bad;
+       }
        rcu_read_unlock();
 
        if (!sid)
@@ -5846,41 +5847,37 @@ static int selinux_getprocattr(struct task_struct *p,
                return error;
        return len;
 
-invalid:
+bad:
        rcu_read_unlock();
-       return -EINVAL;
+       return error;
 }
 
-static int selinux_setprocattr(struct task_struct *p,
-                              char *name, void *value, size_t size)
+static int selinux_setprocattr(const char *name, void *value, size_t size)
 {
        struct task_security_struct *tsec;
        struct cred *new;
-       u32 sid = 0, ptsid;
+       u32 mysid = current_sid(), sid = 0, ptsid;
        int error;
        char *str = value;
 
-       if (current != p) {
-               /* SELinux only allows a process to change its own
-                  security attributes. */
-               return -EACCES;
-       }
-
        /*
         * Basic control over ability to set these attributes at all.
-        * current == p, but we'll pass them separately in case the
-        * above restriction is ever removed.
         */
        if (!strcmp(name, "exec"))
-               error = current_has_perm(p, PROCESS__SETEXEC);
+               error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
+                                    PROCESS__SETEXEC, NULL);
        else if (!strcmp(name, "fscreate"))
-               error = current_has_perm(p, PROCESS__SETFSCREATE);
+               error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
+                                    PROCESS__SETFSCREATE, NULL);
        else if (!strcmp(name, "keycreate"))
-               error = current_has_perm(p, PROCESS__SETKEYCREATE);
+               error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
+                                    PROCESS__SETKEYCREATE, NULL);
        else if (!strcmp(name, "sockcreate"))
-               error = current_has_perm(p, PROCESS__SETSOCKCREATE);
+               error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
+                                    PROCESS__SETSOCKCREATE, NULL);
        else if (!strcmp(name, "current"))
-               error = current_has_perm(p, PROCESS__SETCURRENT);
+               error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
+                                    PROCESS__SETCURRENT, NULL);
        else
                error = -EINVAL;
        if (error)
@@ -5934,7 +5931,8 @@ static int selinux_setprocattr(struct task_struct *p,
        } else if (!strcmp(name, "fscreate")) {
                tsec->create_sid = sid;
        } else if (!strcmp(name, "keycreate")) {
-               error = may_create_key(sid, p);
+               error = avc_has_perm(mysid, sid, SECCLASS_KEY, KEY__CREATE,
+                                    NULL);
                if (error)
                        goto abort_change;
                tsec->keycreate_sid = sid;
@@ -5961,7 +5959,7 @@ static int selinux_setprocattr(struct task_struct *p,
 
                /* Check for ptracing, and update the task SID if ok.
                   Otherwise, leave SID unchanged and fail. */
-               ptsid = ptrace_parent_sid(p);
+               ptsid = ptrace_parent_sid();
                if (ptsid != 0) {
                        error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
                                             PROCESS__PTRACE, NULL);
@@ -6209,7 +6207,6 @@ static struct security_hook_list selinux_hooks[] = {
        LSM_HOOK_INIT(task_getscheduler, selinux_task_getscheduler),
        LSM_HOOK_INIT(task_movememory, selinux_task_movememory),
        LSM_HOOK_INIT(task_kill, selinux_task_kill),
-       LSM_HOOK_INIT(task_wait, selinux_task_wait),
        LSM_HOOK_INIT(task_to_inode, selinux_task_to_inode),
 
        LSM_HOOK_INIT(ipc_permission, selinux_ipc_permission),
@@ -6349,7 +6346,7 @@ static __init int selinux_init(void)
                                            0, SLAB_PANIC, NULL);
        avc_init();
 
-       security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks));
+       security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux");
 
        if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET))
                panic("SELinux: Unable to register AVC netcache callback\n");
index 13ae49b0baa091f3ca9202fd51e3a20e46d9b6f4..7898ffa6d3e61a7aa8cf020f2312e8c7207ec139 100644 (file)
@@ -171,5 +171,67 @@ struct security_class_mapping secclass_map[] = {
          { COMMON_CAP_PERMS, NULL } },
        { "cap2_userns",
          { COMMON_CAP2_PERMS, NULL } },
+       { "sctp_socket",
+         { COMMON_SOCK_PERMS,
+           "node_bind", NULL } },
+       { "icmp_socket",
+         { COMMON_SOCK_PERMS,
+           "node_bind", NULL } },
+       { "ax25_socket",
+         { COMMON_SOCK_PERMS, NULL } },
+       { "ipx_socket",
+         { COMMON_SOCK_PERMS, NULL } },
+       { "netrom_socket",
+         { COMMON_SOCK_PERMS, NULL } },
+       { "atmpvc_socket",
+         { COMMON_SOCK_PERMS, NULL } },
+       { "x25_socket",
+         { COMMON_SOCK_PERMS, NULL } },
+       { "rose_socket",
+         { COMMON_SOCK_PERMS, NULL } },
+       { "decnet_socket",
+         { COMMON_SOCK_PERMS, NULL } },
+       { "atmsvc_socket",
+         { COMMON_SOCK_PERMS, NULL } },
+       { "rds_socket",
+         { COMMON_SOCK_PERMS, NULL } },
+       { "irda_socket",
+         { COMMON_SOCK_PERMS, NULL } },
+       { "pppox_socket",
+         { COMMON_SOCK_PERMS, NULL } },
+       { "llc_socket",
+         { COMMON_SOCK_PERMS, NULL } },
+       { "can_socket",
+         { COMMON_SOCK_PERMS, NULL } },
+       { "tipc_socket",
+         { COMMON_SOCK_PERMS, NULL } },
+       { "bluetooth_socket",
+         { COMMON_SOCK_PERMS, NULL } },
+       { "iucv_socket",
+         { COMMON_SOCK_PERMS, NULL } },
+       { "rxrpc_socket",
+         { COMMON_SOCK_PERMS, NULL } },
+       { "isdn_socket",
+         { COMMON_SOCK_PERMS, NULL } },
+       { "phonet_socket",
+         { COMMON_SOCK_PERMS, NULL } },
+       { "ieee802154_socket",
+         { COMMON_SOCK_PERMS, NULL } },
+       { "caif_socket",
+         { COMMON_SOCK_PERMS, NULL } },
+       { "alg_socket",
+         { COMMON_SOCK_PERMS, NULL } },
+       { "nfc_socket",
+         { COMMON_SOCK_PERMS, NULL } },
+       { "vsock_socket",
+         { COMMON_SOCK_PERMS, NULL } },
+       { "kcm_socket",
+         { COMMON_SOCK_PERMS, NULL } },
+       { "qipcrtr_socket",
+         { COMMON_SOCK_PERMS, NULL } },
        { NULL }
   };
+
+#if PF_MAX > 43
+#error New address family defined, please update secclass_map.
+#endif
index e8dab0f02c7272c94208e1212b90722207df798d..c03cdcd12a3b6d48b2ab12a25e4e7672c6456b84 100644 (file)
@@ -37,6 +37,16 @@ struct task_security_struct {
        u32 sockcreate_sid;     /* fscreate SID */
 };
 
+/*
+ * get the subjective security ID of the current task
+ */
+static inline u32 current_sid(void)
+{
+       const struct task_security_struct *tsec = current_security();
+
+       return tsec->sid;
+}
+
 enum label_initialized {
        LABEL_INVALID,          /* invalid or not initialized */
        LABEL_INITIALIZED,      /* initialized */
index 308a286c6cbebfddafb27f08722dffd11ffce9d3..beaa14b8b6cf570993c1b9ee210232fb03a6a1e4 100644 (file)
@@ -69,7 +69,7 @@ extern int selinux_enabled;
 enum {
        POLICYDB_CAPABILITY_NETPEER,
        POLICYDB_CAPABILITY_OPENPERM,
-       POLICYDB_CAPABILITY_REDHAT1,
+       POLICYDB_CAPABILITY_EXTSOCKCLASS,
        POLICYDB_CAPABILITY_ALWAYSNETWORK,
        __POLICYDB_CAPABILITY_MAX
 };
@@ -77,6 +77,7 @@ enum {
 
 extern int selinux_policycap_netpeer;
 extern int selinux_policycap_openperm;
+extern int selinux_policycap_extsockclass;
 extern int selinux_policycap_alwaysnetwork;
 
 /*
index cf9293e01fc185556acfffd368132764a22bb63b..c354807381c11949604a458b5286989385395a7b 100644 (file)
@@ -45,7 +45,7 @@
 static char *policycap_names[] = {
        "network_peer_controls",
        "open_perms",
-       "redhat1",
+       "extended_socket_class",
        "always_check_network"
 };
 
@@ -77,25 +77,6 @@ static char policy_opened;
 /* global data for policy capabilities */
 static struct dentry *policycap_dir;
 
-/* Check whether a task is allowed to use a security operation. */
-static int task_has_security(struct task_struct *tsk,
-                            u32 perms)
-{
-       const struct task_security_struct *tsec;
-       u32 sid = 0;
-
-       rcu_read_lock();
-       tsec = __task_cred(tsk)->security;
-       if (tsec)
-               sid = tsec->sid;
-       rcu_read_unlock();
-       if (!tsec)
-               return -EACCES;
-
-       return avc_has_perm(sid, SECINITSID_SECURITY,
-                           SECCLASS_SECURITY, perms, NULL);
-}
-
 enum sel_inos {
        SEL_ROOT_INO = 2,
        SEL_LOAD,       /* load policy */
@@ -166,7 +147,9 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
        new_value = !!new_value;
 
        if (new_value != selinux_enforcing) {
-               length = task_has_security(current, SECURITY__SETENFORCE);
+               length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+                                     SECCLASS_SECURITY, SECURITY__SETENFORCE,
+                                     NULL);
                if (length)
                        goto out;
                audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
@@ -368,7 +351,8 @@ static int sel_open_policy(struct inode *inode, struct file *filp)
 
        mutex_lock(&sel_mutex);
 
-       rc = task_has_security(current, SECURITY__READ_POLICY);
+       rc = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+                         SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL);
        if (rc)
                goto err;
 
@@ -429,7 +413,8 @@ static ssize_t sel_read_policy(struct file *filp, char __user *buf,
 
        mutex_lock(&sel_mutex);
 
-       ret = task_has_security(current, SECURITY__READ_POLICY);
+       ret = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+                         SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL);
        if (ret)
                goto out;
 
@@ -499,7 +484,8 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
 
        mutex_lock(&sel_mutex);
 
-       length = task_has_security(current, SECURITY__LOAD_POLICY);
+       length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+                             SECCLASS_SECURITY, SECURITY__LOAD_POLICY, NULL);
        if (length)
                goto out;
 
@@ -522,20 +508,28 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
                goto out;
 
        length = security_load_policy(data, count);
-       if (length)
+       if (length) {
+               pr_warn_ratelimited("SELinux: failed to load policy\n");
                goto out;
+       }
 
        length = sel_make_bools();
-       if (length)
+       if (length) {
+               pr_err("SELinux: failed to load policy booleans\n");
                goto out1;
+       }
 
        length = sel_make_classes();
-       if (length)
+       if (length) {
+               pr_err("SELinux: failed to load policy classes\n");
                goto out1;
+       }
 
        length = sel_make_policycap();
-       if (length)
+       if (length) {
+               pr_err("SELinux: failed to load policy capabilities\n");
                goto out1;
+       }
 
        length = count;
 
@@ -561,7 +555,8 @@ static ssize_t sel_write_context(struct file *file, char *buf, size_t size)
        u32 sid, len;
        ssize_t length;
 
-       length = task_has_security(current, SECURITY__CHECK_CONTEXT);
+       length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+                             SECCLASS_SECURITY, SECURITY__CHECK_CONTEXT, NULL);
        if (length)
                goto out;
 
@@ -604,7 +599,9 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
        ssize_t length;
        unsigned int new_value;
 
-       length = task_has_security(current, SECURITY__SETCHECKREQPROT);
+       length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+                             SECCLASS_SECURITY, SECURITY__SETCHECKREQPROT,
+                             NULL);
        if (length)
                return length;
 
@@ -645,7 +642,8 @@ static ssize_t sel_write_validatetrans(struct file *file,
        u16 tclass;
        int rc;
 
-       rc = task_has_security(current, SECURITY__VALIDATE_TRANS);
+       rc = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+                         SECCLASS_SECURITY, SECURITY__VALIDATE_TRANS, NULL);
        if (rc)
                goto out;
 
@@ -772,7 +770,8 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
        struct av_decision avd;
        ssize_t length;
 
-       length = task_has_security(current, SECURITY__COMPUTE_AV);
+       length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+                             SECCLASS_SECURITY, SECURITY__COMPUTE_AV, NULL);
        if (length)
                goto out;
 
@@ -822,7 +821,9 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
        u32 len;
        int nargs;
 
-       length = task_has_security(current, SECURITY__COMPUTE_CREATE);
+       length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+                             SECCLASS_SECURITY, SECURITY__COMPUTE_CREATE,
+                             NULL);
        if (length)
                goto out;
 
@@ -919,7 +920,9 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
        char *newcon = NULL;
        u32 len;
 
-       length = task_has_security(current, SECURITY__COMPUTE_RELABEL);
+       length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+                             SECCLASS_SECURITY, SECURITY__COMPUTE_RELABEL,
+                             NULL);
        if (length)
                goto out;
 
@@ -975,7 +978,9 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
        int i, rc;
        u32 len, nsids;
 
-       length = task_has_security(current, SECURITY__COMPUTE_USER);
+       length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+                             SECCLASS_SECURITY, SECURITY__COMPUTE_USER,
+                             NULL);
        if (length)
                goto out;
 
@@ -1035,7 +1040,9 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
        char *newcon = NULL;
        u32 len;
 
-       length = task_has_security(current, SECURITY__COMPUTE_MEMBER);
+       length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+                             SECCLASS_SECURITY, SECURITY__COMPUTE_MEMBER,
+                             NULL);
        if (length)
                goto out;
 
@@ -1142,7 +1149,9 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
 
        mutex_lock(&sel_mutex);
 
-       length = task_has_security(current, SECURITY__SETBOOL);
+       length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+                             SECCLASS_SECURITY, SECURITY__SETBOOL,
+                             NULL);
        if (length)
                goto out;
 
@@ -1198,7 +1207,9 @@ static ssize_t sel_commit_bools_write(struct file *filep,
 
        mutex_lock(&sel_mutex);
 
-       length = task_has_security(current, SECURITY__SETBOOL);
+       length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+                             SECCLASS_SECURITY, SECURITY__SETBOOL,
+                             NULL);
        if (length)
                goto out;
 
@@ -1299,8 +1310,11 @@ static int sel_make_bools(void)
 
                isec = (struct inode_security_struct *)inode->i_security;
                ret = security_genfs_sid("selinuxfs", page, SECCLASS_FILE, &sid);
-               if (ret)
-                       goto out;
+               if (ret) {
+                       pr_warn_ratelimited("SELinux: no sid found, defaulting to security isid for %s\n",
+                                          page);
+                       sid = SECINITSID_SECURITY;
+               }
 
                isec->sid = sid;
                isec->initialized = LABEL_INITIALIZED;
@@ -1351,7 +1365,9 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file,
        ssize_t ret;
        unsigned int new_value;
 
-       ret = task_has_security(current, SECURITY__SETSECPARAM);
+       ret = avc_has_perm(current_sid(), SECINITSID_SECURITY,
+                          SECCLASS_SECURITY, SECURITY__SETSECPARAM,
+                          NULL);
        if (ret)
                return ret;
 
index 082b20c78363c8e604f7d3b490ca898b4e8c4730..a70fcee9824ba301cf0b367fd1a701a62a8c87b8 100644 (file)
@@ -72,6 +72,7 @@
 
 int selinux_policycap_netpeer;
 int selinux_policycap_openperm;
+int selinux_policycap_extsockclass;
 int selinux_policycap_alwaysnetwork;
 
 static DEFINE_RWLOCK(policy_rwlock);
@@ -1988,6 +1989,8 @@ static void security_load_policycaps(void)
                                                  POLICYDB_CAPABILITY_NETPEER);
        selinux_policycap_openperm = ebitmap_get_bit(&policydb.policycaps,
                                                  POLICYDB_CAPABILITY_OPENPERM);
+       selinux_policycap_extsockclass = ebitmap_get_bit(&policydb.policycaps,
+                                         POLICYDB_CAPABILITY_EXTSOCKCLASS);
        selinux_policycap_alwaysnetwork = ebitmap_get_bit(&policydb.policycaps,
                                                  POLICYDB_CAPABILITY_ALWAYSNETWORK);
 }
index 77abe2efacae47f121c348c74801a0c0831fc793..612b810fbbc6359838c2a54429a49e88106d9549 100644 (file)
@@ -114,6 +114,7 @@ struct inode_smack {
        struct smack_known      *smk_mmap;      /* label of the mmap domain */
        struct mutex            smk_lock;       /* initialization lock */
        int                     smk_flags;      /* smack inode flags */
+       struct rcu_head         smk_rcu;        /* for freeing inode_smack */
 };
 
 struct task_smack {
@@ -173,6 +174,8 @@ struct smk_port_label {
        unsigned short          smk_port;       /* the port number */
        struct smack_known      *smk_in;        /* inbound label */
        struct smack_known      *smk_out;       /* outgoing label */
+       short                   smk_sock_type;  /* Socket type */
+       short                   smk_can_reuse;
 };
 #endif /* SMACK_IPV6_PORT_LABELING */
 
index 94dc9d406ce33060513231c1f93727a51a106e14..60b4217b9b685db86521239a272773f9a0aa985a 100644 (file)
@@ -52,6 +52,7 @@
 #define SMK_SENDING    2
 
 #ifdef SMACK_IPV6_PORT_LABELING
+DEFINE_MUTEX(smack_ipv6_lock);
 static LIST_HEAD(smk_ipv6_port_list);
 #endif
 static struct kmem_cache *smack_inode_cache;
@@ -347,8 +348,6 @@ static int smk_copy_rules(struct list_head *nhead, struct list_head *ohead,
        struct smack_rule *orp;
        int rc = 0;
 
-       INIT_LIST_HEAD(nhead);
-
        list_for_each_entry_rcu(orp, ohead, list) {
                nrp = kzalloc(sizeof(struct smack_rule), gfp);
                if (nrp == NULL) {
@@ -375,8 +374,6 @@ static int smk_copy_relabel(struct list_head *nhead, struct list_head *ohead,
        struct smack_known_list_elem *nklep;
        struct smack_known_list_elem *oklep;
 
-       INIT_LIST_HEAD(nhead);
-
        list_for_each_entry(oklep, ohead, list) {
                nklep = kzalloc(sizeof(struct smack_known_list_elem), gfp);
                if (nklep == NULL) {
@@ -1009,15 +1006,39 @@ static int smack_inode_alloc_security(struct inode *inode)
 }
 
 /**
- * smack_inode_free_security - free an inode blob
+ * smack_inode_free_rcu - Free inode_smack blob from cache
+ * @head: the rcu_head for getting inode_smack pointer
+ *
+ *  Call back function called from call_rcu() to free
+ *  the i_security blob pointer in inode
+ */
+static void smack_inode_free_rcu(struct rcu_head *head)
+{
+       struct inode_smack *issp;
+
+       issp = container_of(head, struct inode_smack, smk_rcu);
+       kmem_cache_free(smack_inode_cache, issp);
+}
+
+/**
+ * smack_inode_free_security - free an inode blob using call_rcu()
  * @inode: the inode with a blob
  *
- * Clears the blob pointer in inode
+ * Clears the blob pointer in inode using RCU
  */
 static void smack_inode_free_security(struct inode *inode)
 {
-       kmem_cache_free(smack_inode_cache, inode->i_security);
-       inode->i_security = NULL;
+       struct inode_smack *issp = inode->i_security;
+
+       /*
+        * The inode may still be referenced in a path walk and
+        * a call to smack_inode_permission() can be made
+        * after smack_inode_free_security() is called.
+        * To avoid race condition free the i_security via RCU
+        * and leave the current inode->i_security pointer intact.
+        * The inode will be freed after the RCU grace period too.
+        */
+       call_rcu(&issp->smk_rcu, smack_inode_free_rcu);
 }
 
 /**
@@ -1626,6 +1647,9 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd,
        struct smk_audit_info ad;
        struct inode *inode = file_inode(file);
 
+       if (unlikely(IS_PRIVATE(inode)))
+               return 0;
+
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
        smk_ad_setfield_u_fs_path(&ad, file->f_path);
 
@@ -1655,6 +1679,9 @@ static int smack_file_lock(struct file *file, unsigned int cmd)
        int rc;
        struct inode *inode = file_inode(file);
 
+       if (unlikely(IS_PRIVATE(inode)))
+               return 0;
+
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
        smk_ad_setfield_u_fs_path(&ad, file->f_path);
        rc = smk_curacc(smk_of_inode(inode), MAY_LOCK, &ad);
@@ -1681,6 +1708,9 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd,
        int rc = 0;
        struct inode *inode = file_inode(file);
 
+       if (unlikely(IS_PRIVATE(inode)))
+               return 0;
+
        switch (cmd) {
        case F_GETLK:
                break;
@@ -1734,6 +1764,9 @@ static int smack_mmap_file(struct file *file,
        if (file == NULL)
                return 0;
 
+       if (unlikely(IS_PRIVATE(file_inode(file))))
+               return 0;
+
        isp = file_inode(file)->i_security;
        if (isp->smk_mmap == NULL)
                return 0;
@@ -1934,12 +1967,9 @@ static int smack_file_open(struct file *file, const struct cred *cred)
        struct smk_audit_info ad;
        int rc;
 
-       if (smack_privileged(CAP_MAC_OVERRIDE))
-               return 0;
-
        smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
        smk_ad_setfield_u_fs_path(&ad, file->f_path);
-       rc = smk_access(tsp->smk_task, smk_of_inode(inode), MAY_READ, &ad);
+       rc = smk_tskacc(tsp, smk_of_inode(inode), MAY_READ, &ad);
        rc = smk_bu_credfile(cred, file, MAY_READ, rc);
 
        return rc;
@@ -2271,25 +2301,6 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
        return rc;
 }
 
-/**
- * smack_task_wait - Smack access check for waiting
- * @p: task to wait for
- *
- * Returns 0
- */
-static int smack_task_wait(struct task_struct *p)
-{
-       /*
-        * Allow the operation to succeed.
-        * Zombies are bad.
-        * In userless environments (e.g. phones) programs
-        * get marked with SMACK64EXEC and even if the parent
-        * and child shouldn't be talking the parent still
-        * may expect to know when the child exits.
-        */
-       return 0;
-}
-
 /**
  * smack_task_to_inode - copy task smack into the inode blob
  * @p: task to copy from
@@ -2353,6 +2364,20 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
  */
 static void smack_sk_free_security(struct sock *sk)
 {
+#ifdef SMACK_IPV6_PORT_LABELING
+       struct smk_port_label *spp;
+
+       if (sk->sk_family == PF_INET6) {
+               rcu_read_lock();
+               list_for_each_entry_rcu(spp, &smk_ipv6_port_list, list) {
+                       if (spp->smk_sock != sk)
+                               continue;
+                       spp->smk_can_reuse = 1;
+                       break;
+               }
+               rcu_read_unlock();
+       }
+#endif
        kfree(sk->sk_security);
 }
 
@@ -2603,17 +2628,20 @@ static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address)
                 * on the bound socket. Take the changes to the port
                 * as well.
                 */
-               list_for_each_entry(spp, &smk_ipv6_port_list, list) {
+               rcu_read_lock();
+               list_for_each_entry_rcu(spp, &smk_ipv6_port_list, list) {
                        if (sk != spp->smk_sock)
                                continue;
                        spp->smk_in = ssp->smk_in;
                        spp->smk_out = ssp->smk_out;
+                       rcu_read_unlock();
                        return;
                }
                /*
                 * A NULL address is only used for updating existing
                 * bound entries. If there isn't one, it's OK.
                 */
+               rcu_read_unlock();
                return;
        }
 
@@ -2629,16 +2657,23 @@ static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address)
         * Look for an existing port list entry.
         * This is an indication that a port is getting reused.
         */
-       list_for_each_entry(spp, &smk_ipv6_port_list, list) {
-               if (spp->smk_port != port)
+       rcu_read_lock();
+       list_for_each_entry_rcu(spp, &smk_ipv6_port_list, list) {
+               if (spp->smk_port != port || spp->smk_sock_type != sock->type)
                        continue;
+               if (spp->smk_can_reuse != 1) {
+                       rcu_read_unlock();
+                       return;
+               }
                spp->smk_port = port;
                spp->smk_sock = sk;
                spp->smk_in = ssp->smk_in;
                spp->smk_out = ssp->smk_out;
+               spp->smk_can_reuse = 0;
+               rcu_read_unlock();
                return;
        }
-
+       rcu_read_unlock();
        /*
         * A new port entry is required.
         */
@@ -2650,8 +2685,12 @@ static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address)
        spp->smk_sock = sk;
        spp->smk_in = ssp->smk_in;
        spp->smk_out = ssp->smk_out;
+       spp->smk_sock_type = sock->type;
+       spp->smk_can_reuse = 0;
 
-       list_add(&spp->list, &smk_ipv6_port_list);
+       mutex_lock(&smack_ipv6_lock);
+       list_add_rcu(&spp->list, &smk_ipv6_port_list);
+       mutex_unlock(&smack_ipv6_lock);
        return;
 }
 
@@ -2702,14 +2741,16 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address,
                return 0;
 
        port = ntohs(address->sin6_port);
-       list_for_each_entry(spp, &smk_ipv6_port_list, list) {
-               if (spp->smk_port != port)
+       rcu_read_lock();
+       list_for_each_entry_rcu(spp, &smk_ipv6_port_list, list) {
+               if (spp->smk_port != port || spp->smk_sock_type != sk->sk_type)
                        continue;
                object = spp->smk_in;
                if (act == SMK_CONNECTING)
                        ssp->smk_packet = spp->smk_out;
                break;
        }
+       rcu_read_unlock();
 
        return smk_ipv6_check(skp, object, address, act);
 }
@@ -3438,6 +3479,13 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
                case PIPEFS_MAGIC:
                        isp->smk_inode = smk_of_current();
                        break;
+               case SOCKFS_MAGIC:
+                       /*
+                        * Socket access is controlled by the socket
+                        * structures associated with the task involved.
+                        */
+                       isp->smk_inode = &smack_known_star;
+                       break;
                default:
                        isp->smk_inode = sbsp->smk_root;
                        break;
@@ -3454,19 +3502,12 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
         */
        switch (sbp->s_magic) {
        case SMACK_MAGIC:
-       case PIPEFS_MAGIC:
-       case SOCKFS_MAGIC:
        case CGROUP_SUPER_MAGIC:
                /*
                 * Casey says that it's a little embarrassing
                 * that the smack file system doesn't do
                 * extended attributes.
                 *
-                * Casey says pipes are easy (?)
-                *
-                * Socket access is controlled by the socket
-                * structures associated with the task involved.
-                *
                 * Cgroupfs is special
                 */
                final = &smack_known_star;
@@ -3620,7 +3661,6 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value)
 
 /**
  * smack_setprocattr - Smack process attribute setting
- * @p: the object task
  * @name: the name of the attribute in /proc/.../attr
  * @value: the value to set
  * @size: the size of the value
@@ -3630,8 +3670,7 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value)
  *
  * Returns the length of the smack label or an error code
  */
-static int smack_setprocattr(struct task_struct *p, char *name,
-                            void *value, size_t size)
+static int smack_setprocattr(const char *name, void *value, size_t size)
 {
        struct task_smack *tsp = current_security();
        struct cred *new;
@@ -3639,13 +3678,6 @@ static int smack_setprocattr(struct task_struct *p, char *name,
        struct smack_known_list_elem *sklep;
        int rc;
 
-       /*
-        * Changing another process' Smack value is too dangerous
-        * and supports no sane use case.
-        */
-       if (p != current)
-               return -EPERM;
-
        if (!smack_privileged(CAP_MAC_ADMIN) && list_empty(&tsp->smk_relabel))
                return -EPERM;
 
@@ -3849,7 +3881,7 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap,
                 * ambient value.
                 */
                rcu_read_lock();
-               list_for_each_entry(skp, &smack_known_list, list) {
+               list_for_each_entry_rcu(skp, &smack_known_list, list) {
                        if (sap->attr.mls.lvl != skp->smk_netlabel.attr.mls.lvl)
                                continue;
                        /*
@@ -4667,7 +4699,6 @@ static struct security_hook_list smack_hooks[] = {
        LSM_HOOK_INIT(task_getscheduler, smack_task_getscheduler),
        LSM_HOOK_INIT(task_movememory, smack_task_movememory),
        LSM_HOOK_INIT(task_kill, smack_task_kill),
-       LSM_HOOK_INIT(task_wait, smack_task_wait),
        LSM_HOOK_INIT(task_to_inode, smack_task_to_inode),
 
        LSM_HOOK_INIT(ipc_permission, smack_ipc_permission),
@@ -4819,7 +4850,7 @@ static __init int smack_init(void)
        /*
         * Register with LSM
         */
-       security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks));
+       security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack");
 
        return 0;
 }
index 13743a01b35b5000c56e2a83bd2f973dbf787127..366b8356f75b45315c43b6067aa569680c20eea4 100644 (file)
@@ -67,6 +67,7 @@ enum smk_inos {
 /*
  * List locks
  */
+static DEFINE_MUTEX(smack_master_list_lock);
 static DEFINE_MUTEX(smack_cipso_lock);
 static DEFINE_MUTEX(smack_ambient_lock);
 static DEFINE_MUTEX(smk_net4addr_lock);
@@ -262,12 +263,16 @@ static int smk_set_access(struct smack_parsed_rule *srp,
                 * it needs to get added for reporting.
                 */
                if (global) {
+                       mutex_unlock(rule_lock);
                        smlp = kzalloc(sizeof(*smlp), GFP_KERNEL);
                        if (smlp != NULL) {
                                smlp->smk_rule = sp;
+                               mutex_lock(&smack_master_list_lock);
                                list_add_rcu(&smlp->list, &smack_rule_list);
+                               mutex_unlock(&smack_master_list_lock);
                        } else
                                rc = -ENOMEM;
+                       return rc;
                }
        }
 
index 75c998700190ce260f54926e2d49236c154229e6..edc52d620f29cf7b027dd962ab0976a75eef3ba4 100644 (file)
@@ -542,7 +542,7 @@ static int __init tomoyo_init(void)
        if (!security_module_enable("tomoyo"))
                return 0;
        /* register ourselves with the security framework */
-       security_add_hooks(tomoyo_hooks, ARRAY_SIZE(tomoyo_hooks));
+       security_add_hooks(tomoyo_hooks, ARRAY_SIZE(tomoyo_hooks), "tomoyo");
        printk(KERN_INFO "TOMOYO Linux initialized\n");
        cred->security = &tomoyo_kernel_domain;
        tomoyo_mm_init();
index 968e5e0a3f81c611a953875ce1e2b8f14ec2e1fe..88271a3bf37f8378fbc6be1d63dd6b4d2de8054c 100644 (file)
@@ -485,6 +485,6 @@ static inline void yama_init_sysctl(void) { }
 void __init yama_add_hooks(void)
 {
        pr_info("Yama: becoming mindful.\n");
-       security_add_hooks(yama_hooks, ARRAY_SIZE(yama_hooks));
+       security_add_hooks(yama_hooks, ARRAY_SIZE(yama_hooks), "yama");
        yama_init_sysctl();
 }
index c03a79ebf9c8dbf3117be2b716711f1111845911..078b666fd78b8ad9b2cddc32d5975e0d8ae533d8 100644 (file)
@@ -3,11 +3,11 @@
 CC = $(CROSS_COMPILE)gcc
 CFLAGS = -Wall -Wextra -g -I../../include/uapi
 
-all: uledmon
+all: uledmon led_hw_brightness_mon
 %: %.c
        $(CC) $(CFLAGS) -o $@ $^
 
 clean:
-       $(RM) uledmon
+       $(RM) uledmon led_hw_brightness_mon
 
 .PHONY: all clean
diff --git a/tools/leds/led_hw_brightness_mon.c b/tools/leds/led_hw_brightness_mon.c
new file mode 100644 (file)
index 0000000..64642cc
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * led_hw_brightness_mon.c
+ *
+ * This program monitors LED brightness level changes having its origin
+ * in hardware/firmware, i.e. outside of kernel control.
+ * A timestamp and brightness value is printed each time the brightness changes.
+ *
+ * Usage: led_hw_brightness_mon <device-name>
+ *
+ * <device-name> is the name of the LED class device to be monitored. Pressing
+ * CTRL+C will exit.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/uleds.h>
+
+int main(int argc, char const *argv[])
+{
+       int fd, ret;
+       char brightness_file_path[LED_MAX_NAME_SIZE + 11];
+       struct pollfd pollfd;
+       struct timespec ts;
+       char buf[11];
+
+       if (argc != 2) {
+               fprintf(stderr, "Requires <device-name> argument\n");
+               return 1;
+       }
+
+       snprintf(brightness_file_path, LED_MAX_NAME_SIZE,
+                "/sys/class/leds/%s/brightness_hw_changed", argv[1]);
+
+       fd = open(brightness_file_path, O_RDONLY);
+       if (fd == -1) {
+               printf("Failed to open %s file\n", brightness_file_path);
+               return 1;
+       }
+
+       /*
+        * read may fail if no hw brightness change has occurred so far,
+        * but it is required to avoid spurious poll notifications in
+        * the opposite case.
+        */
+       read(fd, buf, sizeof(buf));
+
+       pollfd.fd = fd;
+       pollfd.events = POLLPRI;
+
+       while (1) {
+               ret = poll(&pollfd, 1, -1);
+               if (ret == -1) {
+                       printf("Failed to poll %s file (%d)\n",
+                               brightness_file_path, ret);
+                       ret = 1;
+                       break;
+               }
+
+               clock_gettime(CLOCK_MONOTONIC, &ts);
+
+               ret = read(fd, buf, sizeof(buf));
+               if (ret < 0)
+                       break;
+
+               ret = lseek(pollfd.fd, 0, SEEK_SET);
+               if (ret < 0) {
+                       printf("lseek failed (%d)\n", ret);
+                       break;
+               }
+
+               printf("[%ld.%09ld] %d\n", ts.tv_sec, ts.tv_nsec, atoi(buf));
+       }
+
+       close(fd);
+
+       return ret;
+}
index bc82596d7354d6521b4dec7c6f7fc1bb40e86a10..5b38dc2fec4f8ff05ccce11fa78100c503ab5a52 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3919970f5aea661b4fdcf863d912ecb7df832da4..6e78413bb2cbe7c27afb62c3a2af12582fad5541 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 546cf4a503b78f473b4a705548645b3bde6a84b4..82a2ff896a9559e6a860ba034d5fde6786b04dae 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 66c4badf03e5e967fd4225cf88487e09b7a05ad2..ea14eaeb268f3ed1ca91d3962fb06a422c6c08c6 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index cbfbce18783d322978ffa32dea43f4d6d96a7f20..cf9b5a54df9218004c5a703be029e8b634b8842e 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 10648aaf616476aa24577a1820f0a8ff4150b513..c04e8fea2c6021a1bf5d12713024911f9529d7fb 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -316,6 +316,28 @@ acpi_os_physical_table_override(struct acpi_table_header *existing_table,
        return (AE_SUPPORT);
 }
 
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_os_enter_sleep
+ *
+ * PARAMETERS:  sleep_state         - Which sleep state to enter
+ *              rega_value          - Register A value
+ *              regb_value          - Register B value
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: A hook before writing sleep registers to enter the sleep
+ *              state. Return AE_CTRL_TERMINATE to skip further sleep register
+ *              writes.
+ *
+ *****************************************************************************/
+
+acpi_status acpi_os_enter_sleep(u8 sleep_state, u32 rega_value, u32 regb_value)
+{
+
+       return (AE_OK);
+}
+
 /******************************************************************************
  *
  * FUNCTION:    acpi_os_redirect_output
index 00423fc45e7cfbd3e3819c8333d7c61e2d79a479..d6aa40fce2b1436cc1f20774eb0f7897a79e2d8b 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 9031be1afe63ccfd1836c16a1d5e3aa1d6b95272..60df1fbd4a776a7e23da202b3ea6e3d69f93de78 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index dd5b861dc4a88946f3309b314f23240f250cb83b..31b5a7f7401555f369800a289652185a216a5a89 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 7ff46be908f0bb278e1e5ceb544b15fa353b54a2..dd82afa897bde211a41a6a42ce9cb40350f35d3c 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2016, Intel Corp.
+ * Copyright (C) 2000 - 2017, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/tools/power/x86/intel_pstate_tracer/intel_pstate_tracer.py b/tools/power/x86/intel_pstate_tracer/intel_pstate_tracer.py
new file mode 100755 (executable)
index 0000000..fd706ac
--- /dev/null
@@ -0,0 +1,569 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+""" This utility can be used to debug and tune the performance of the
+intel_pstate driver. This utility can be used in two ways:
+- If there is Linux trace file with pstate_sample events enabled, then
+this utility can parse the trace file and generate performance plots.
+- If user has not specified a trace file as input via command line parameters,
+then this utility enables and collects trace data for a user specified interval
+and generates performance plots.
+
+Prerequisites:
+    Python version 2.7.x
+    gnuplot 5.0 or higher
+    gnuplot-py 1.8
+    (Most of the distributions have these required packages. They may be called
+     gnuplot-py, phython-gnuplot. )
+
+    HWP (Hardware P-States are disabled)
+    Kernel config for Linux trace is enabled
+
+    see print_help(): for Usage and Output details
+
+"""
+from __future__ import print_function
+from datetime import datetime
+import subprocess
+import os
+import time
+import re
+import sys
+import getopt
+import Gnuplot
+from numpy import *
+from decimal import *
+
+__author__ = "Srinivas Pandruvada"
+__copyright__ = " Copyright (c) 2017, Intel Corporation. "
+__license__ = "GPL version 2"
+
+
+MAX_CPUS = 256
+
+# Define the csv file columns
+C_COMM = 18
+C_GHZ = 17
+C_ELAPSED = 16
+C_SAMPLE = 15
+C_DURATION = 14
+C_LOAD = 13
+C_BOOST = 12
+C_FREQ = 11
+C_TSC = 10
+C_APERF = 9
+C_MPERF = 8
+C_TO = 7
+C_FROM = 6
+C_SCALED = 5
+C_CORE = 4
+C_USEC = 3
+C_SEC = 2
+C_CPU = 1
+
+global sample_num, last_sec_cpu, last_usec_cpu, start_time, testname
+
+# 11 digits covers uptime to 115 days
+getcontext().prec = 11
+
+sample_num =0
+last_sec_cpu = [0] * MAX_CPUS
+last_usec_cpu = [0] * MAX_CPUS
+
+def print_help():
+    print('intel_pstate_tracer.py:')
+    print('  Usage:')
+    print('    If the trace file is available, then to simply parse and plot, use (sudo not required):')
+    print('      ./intel_pstate_tracer.py [-c cpus] -t <trace_file> -n <test_name>')
+    print('    Or')
+    print('      ./intel_pstate_tracer.py [--cpu cpus] ---trace_file <trace_file> --name <test_name>')
+    print('    To generate trace file, parse and plot, use (sudo required):')
+    print('      sudo ./intel_pstate_tracer.py [-c cpus] -i <interval> -n <test_name>')
+    print('    Or')
+    print('      sudo ./intel_pstate_tracer.py [--cpu cpus] --interval <interval> --name <test_name>')
+    print('    Optional argument:')
+    print('      cpus:  comma separated list of CPUs')
+    print('  Output:')
+    print('    If not already present, creates a "results/test_name" folder in the current working directory with:')
+    print('      cpu.csv - comma seperated values file with trace contents and some additional calculations.')
+    print('      cpu???.csv - comma seperated values file for CPU number ???.')
+    print('      *.png - a variety of PNG format plot files created from the trace contents and the additional calculations.')
+    print('  Notes:')
+    print('    Avoid the use of _ (underscore) in test names, because in gnuplot it is a subscript directive.')
+    print('    Maximum number of CPUs is {0:d}. If there are more the script will abort with an error.'.format(MAX_CPUS))
+    print('    Off-line CPUs cause the script to list some warnings, and create some empty files. Use the CPU mask feature for a clean run.')
+    print('    Empty y range warnings for autoscaled plots can occur and can be ignored.')
+
+def plot_perf_busy_with_sample(cpu_index):
+    """ Plot method to per cpu information """
+
+    file_name = 'cpu{:0>3}.csv'.format(cpu_index)
+    if os.path.exists(file_name):
+        output_png = "cpu%03d_perf_busy_vs_samples.png" % cpu_index
+        g_plot = common_all_gnuplot_settings(output_png)
+        g_plot('set yrange [0:40]')
+        g_plot('set y2range [0:200]')
+        g_plot('set y2tics 0, 10')
+        g_plot('set title "{} : cpu perf busy vs. sample : CPU {:0>3} : {:%F %H:%M}"'.format(testname, cpu_index, datetime.now()))
+#       Override common
+        g_plot('set xlabel "Samples"')
+        g_plot('set ylabel "P-State"')
+        g_plot('set y2label "Scaled Busy/performance/io-busy(%)"')
+        set_4_plot_linestyles(g_plot)
+        g_plot('plot "' + file_name + '" using {:d}:{:d} with linespoints linestyle 1 axis x1y2 title "performance",\\'.format(C_SAMPLE, C_CORE))
+        g_plot('"' + file_name + '" using {:d}:{:d} with linespoints linestyle 2 axis x1y2 title "scaled-busy",\\'.format(C_SAMPLE, C_SCALED))
+        g_plot('"' + file_name + '" using {:d}:{:d} with linespoints linestyle 3 axis x1y2 title "io-boost",\\'.format(C_SAMPLE, C_BOOST))
+        g_plot('"' + file_name + '" using {:d}:{:d} with linespoints linestyle 4 axis x1y1 title "P-State"'.format(C_SAMPLE, C_TO))
+
+def plot_perf_busy(cpu_index):
+    """ Plot some per cpu information """
+
+    file_name = 'cpu{:0>3}.csv'.format(cpu_index)
+    if os.path.exists(file_name):
+        output_png = "cpu%03d_perf_busy.png" % cpu_index
+        g_plot = common_all_gnuplot_settings(output_png)
+        g_plot('set yrange [0:40]')
+        g_plot('set y2range [0:200]')
+        g_plot('set y2tics 0, 10')
+        g_plot('set title "{} : perf busy : CPU {:0>3} : {:%F %H:%M}"'.format(testname, cpu_index, datetime.now()))
+        g_plot('set ylabel "P-State"')
+        g_plot('set y2label "Scaled Busy/performance/io-busy(%)"')
+        set_4_plot_linestyles(g_plot)
+        g_plot('plot "' + file_name + '" using {:d}:{:d} with linespoints linestyle 1 axis x1y2 title "performance",\\'.format(C_ELAPSED, C_CORE))
+        g_plot('"' + file_name + '" using {:d}:{:d} with linespoints linestyle 2 axis x1y2 title "scaled-busy",\\'.format(C_ELAPSED, C_SCALED))
+        g_plot('"' + file_name + '" using {:d}:{:d} with linespoints linestyle 3 axis x1y2 title "io-boost",\\'.format(C_ELAPSED, C_BOOST))
+        g_plot('"' + file_name + '" using {:d}:{:d} with linespoints linestyle 4 axis x1y1 title "P-State"'.format(C_ELAPSED, C_TO))
+
+def plot_durations(cpu_index):
+    """ Plot per cpu durations """
+
+    file_name = 'cpu{:0>3}.csv'.format(cpu_index)
+    if os.path.exists(file_name):
+        output_png = "cpu%03d_durations.png" % cpu_index
+        g_plot = common_all_gnuplot_settings(output_png)
+#       Should autoscale be used here? Should seconds be used here?
+        g_plot('set yrange [0:5000]')
+        g_plot('set ytics 0, 500')
+        g_plot('set title "{} : durations : CPU {:0>3} : {:%F %H:%M}"'.format(testname, cpu_index, datetime.now()))
+        g_plot('set ylabel "Timer Duration (MilliSeconds)"')
+#       override common
+        g_plot('set key off')
+        set_4_plot_linestyles(g_plot)
+        g_plot('plot "' + file_name + '" using {:d}:{:d} with linespoints linestyle 1 axis x1y1'.format(C_ELAPSED, C_DURATION))
+
+def plot_loads(cpu_index):
+    """ Plot per cpu loads """
+
+    file_name = 'cpu{:0>3}.csv'.format(cpu_index)
+    if os.path.exists(file_name):
+        output_png = "cpu%03d_loads.png" % cpu_index
+        g_plot = common_all_gnuplot_settings(output_png)
+        g_plot('set yrange [0:100]')
+        g_plot('set ytics 0, 10')
+        g_plot('set title "{} : loads : CPU {:0>3} : {:%F %H:%M}"'.format(testname, cpu_index, datetime.now()))
+        g_plot('set ylabel "CPU load (percent)"')
+#       override common
+        g_plot('set key off')
+        set_4_plot_linestyles(g_plot)
+        g_plot('plot "' + file_name + '" using {:d}:{:d} with linespoints linestyle 1 axis x1y1'.format(C_ELAPSED, C_LOAD))
+
+def plot_pstate_cpu_with_sample():
+    """ Plot all cpu information """
+
+    if os.path.exists('cpu.csv'):
+        output_png = 'all_cpu_pstates_vs_samples.png'
+        g_plot = common_all_gnuplot_settings(output_png)
+        g_plot('set yrange [0:40]')
+#       override common
+        g_plot('set xlabel "Samples"')
+        g_plot('set ylabel "P-State"')
+        g_plot('set title "{} : cpu pstate vs. sample : {:%F %H:%M}"'.format(testname, datetime.now()))
+        title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).replace('\n', ' ')
+        plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 7 ps 1 title i".format(C_SAMPLE, C_TO)
+        g_plot('title_list = "{}"'.format(title_list))
+        g_plot(plot_str)
+
+def plot_pstate_cpu():
+    """ Plot all cpu information from csv files """
+
+    output_png = 'all_cpu_pstates.png'
+    g_plot = common_all_gnuplot_settings(output_png)
+    g_plot('set yrange [0:40]')
+    g_plot('set ylabel "P-State"')
+    g_plot('set title "{} : cpu pstates : {:%F %H:%M}"'.format(testname, datetime.now()))
+
+#    the following command is really cool, but doesn't work with the CPU masking option because it aborts on the first missing file.
+#    plot_str = 'plot for [i=0:*] file=sprintf("cpu%03d.csv",i) title_s=sprintf("cpu%03d",i) file using 16:7 pt 7 ps 1 title title_s'
+#
+    title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).replace('\n', ' ')
+    plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 7 ps 1 title i".format(C_ELAPSED, C_TO)
+    g_plot('title_list = "{}"'.format(title_list))
+    g_plot(plot_str)
+
+def plot_load_cpu():
+    """ Plot all cpu loads """
+
+    output_png = 'all_cpu_loads.png'
+    g_plot = common_all_gnuplot_settings(output_png)
+    g_plot('set yrange [0:100]')
+    g_plot('set ylabel "CPU load (percent)"')
+    g_plot('set title "{} : cpu loads : {:%F %H:%M}"'.format(testname, datetime.now()))
+
+    title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).replace('\n', ' ')
+    plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 7 ps 1 title i".format(C_ELAPSED, C_LOAD)
+    g_plot('title_list = "{}"'.format(title_list))
+    g_plot(plot_str)
+
+def plot_frequency_cpu():
+    """ Plot all cpu frequencies """
+
+    output_png = 'all_cpu_frequencies.png'
+    g_plot = common_all_gnuplot_settings(output_png)
+    g_plot('set yrange [0:4]')
+    g_plot('set ylabel "CPU Frequency (GHz)"')
+    g_plot('set title "{} : cpu frequencies : {:%F %H:%M}"'.format(testname, datetime.now()))
+
+    title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).replace('\n', ' ')
+    plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 7 ps 1 title i".format(C_ELAPSED, C_FREQ)
+    g_plot('title_list = "{}"'.format(title_list))
+    g_plot(plot_str)
+
+def plot_duration_cpu():
+    """ Plot all cpu durations """
+
+    output_png = 'all_cpu_durations.png'
+    g_plot = common_all_gnuplot_settings(output_png)
+    g_plot('set yrange [0:5000]')
+    g_plot('set ytics 0, 500')
+    g_plot('set ylabel "Timer Duration (MilliSeconds)"')
+    g_plot('set title "{} : cpu durations : {:%F %H:%M}"'.format(testname, datetime.now()))
+
+    title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).replace('\n', ' ')
+    plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 7 ps 1 title i".format(C_ELAPSED, C_DURATION)
+    g_plot('title_list = "{}"'.format(title_list))
+    g_plot(plot_str)
+
+def plot_scaled_cpu():
+    """ Plot all cpu scaled busy """
+
+    output_png = 'all_cpu_scaled.png'
+    g_plot = common_all_gnuplot_settings(output_png)
+#   autoscale this one, no set y range
+    g_plot('set ylabel "Scaled Busy (Unitless)"')
+    g_plot('set title "{} : cpu scaled busy : {:%F %H:%M}"'.format(testname, datetime.now()))
+
+    title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).replace('\n', ' ')
+    plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 7 ps 1 title i".format(C_ELAPSED, C_SCALED)
+    g_plot('title_list = "{}"'.format(title_list))
+    g_plot(plot_str)
+
+def plot_boost_cpu():
+    """ Plot all cpu IO Boosts """
+
+    output_png = 'all_cpu_boost.png'
+    g_plot = common_all_gnuplot_settings(output_png)
+    g_plot('set yrange [0:100]')
+    g_plot('set ylabel "CPU IO Boost (percent)"')
+    g_plot('set title "{} : cpu io boost : {:%F %H:%M}"'.format(testname, datetime.now()))
+
+    title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).replace('\n', ' ')
+    plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 7 ps 1 title i".format(C_ELAPSED, C_BOOST)
+    g_plot('title_list = "{}"'.format(title_list))
+    g_plot(plot_str)
+
+def plot_ghz_cpu():
+    """ Plot all cpu tsc ghz """
+
+    output_png = 'all_cpu_ghz.png'
+    g_plot = common_all_gnuplot_settings(output_png)
+#   autoscale this one, no set y range
+    g_plot('set ylabel "TSC Frequency (GHz)"')
+    g_plot('set title "{} : cpu TSC Frequencies (Sanity check calculation) : {:%F %H:%M}"'.format(testname, datetime.now()))
+
+    title_list = subprocess.check_output('ls cpu???.csv | sed -e \'s/.csv//\'',shell=True).replace('\n', ' ')
+    plot_str = "plot for [i in title_list] i.'.csv' using {:d}:{:d} pt 7 ps 1 title i".format(C_ELAPSED, C_GHZ)
+    g_plot('title_list = "{}"'.format(title_list))
+    g_plot(plot_str)
+
+def common_all_gnuplot_settings(output_png):
+    """ common gnuplot settings for multiple CPUs one one graph. """
+
+    g_plot = common_gnuplot_settings()
+    g_plot('set output "' + output_png + '"')
+    return(g_plot)
+
+def common_gnuplot_settings():
+    """ common gnuplot settings. """
+
+    g_plot = Gnuplot.Gnuplot(persist=1)
+#   The following line is for rigor only. It seems to be assumed for .csv files
+    g_plot('set datafile separator \",\"')
+    g_plot('set ytics nomirror')
+    g_plot('set xtics nomirror')
+    g_plot('set xtics font ", 10"')
+    g_plot('set ytics font ", 10"')
+    g_plot('set tics out scale 1.0')
+    g_plot('set grid')
+    g_plot('set key out horiz')
+    g_plot('set key bot center')
+    g_plot('set key samplen 2 spacing .8 font ", 9"')
+    g_plot('set term png size 1200, 600')
+    g_plot('set title font ", 11"')
+    g_plot('set ylabel font ", 10"')
+    g_plot('set xlabel font ", 10"')
+    g_plot('set xlabel offset 0, 0.5')
+    g_plot('set xlabel "Elapsed Time (Seconds)"')
+    return(g_plot)
+
+def set_4_plot_linestyles(g_plot):
+    """ set the linestyles used for 4 plots in 1 graphs. """
+
+    g_plot('set style line 1 linetype 1 linecolor rgb "green" pointtype -1')
+    g_plot('set style line 2 linetype 1 linecolor rgb "red" pointtype -1')
+    g_plot('set style line 3 linetype 1 linecolor rgb "purple" pointtype -1')
+    g_plot('set style line 4 linetype 1 linecolor rgb "blue" pointtype -1')
+
+def store_csv(cpu_int, time_pre_dec, time_post_dec, core_busy, scaled, _from, _to, mperf, aperf, tsc, freq_ghz, io_boost, common_comm, load, duration_ms, sample_num, elapsed_time, tsc_ghz):
+    """ Store master csv file information """
+
+    global graph_data_present
+
+    if cpu_mask[cpu_int] == 0:
+        return
+
+    try:
+        f_handle = open('cpu.csv', 'a')
+        string_buffer = "CPU_%03u, %05u, %06u, %u, %u, %u, %u, %u, %u, %u, %.4f, %u, %.2f, %.3f, %u, %.3f, %.3f, %s\n" % (cpu_int, int(time_pre_dec), int(time_post_dec), int(core_busy), int(scaled), int(_from), int(_to), int(mperf), int(aperf), int(tsc), freq_ghz, int(io_boost), load, duration_ms, sample_num, elapsed_time, tsc_ghz, common_comm)
+        f_handle.write(string_buffer);
+        f_handle.close()
+    except:
+        print('IO error cpu.csv')
+        return
+
+    graph_data_present = True;
+
+def split_csv():
+    """ seperate the all csv file into per CPU csv files. """
+
+    global current_max_cpu
+
+    if os.path.exists('cpu.csv'):
+        for index in range(0, current_max_cpu + 1):
+            if cpu_mask[int(index)] != 0:
+                os.system('grep -m 1 common_cpu cpu.csv > cpu{:0>3}.csv'.format(index))
+                os.system('grep CPU_{:0>3} cpu.csv >> cpu{:0>3}.csv'.format(index, index))
+
+def cleanup_data_files():
+    """ clean up existing data files """
+
+    if os.path.exists('cpu.csv'):
+        os.remove('cpu.csv')
+    f_handle = open('cpu.csv', 'a')
+    f_handle.write('common_cpu, common_secs, common_usecs, core_busy, scaled_busy, from, to, mperf, aperf, tsc, freq, boost, load, duration_ms, sample_num, elapsed_time, tsc_ghz, common_comm')
+    f_handle.write('\n')
+    f_handle.close()
+
+def clear_trace_file():
+    """ Clear trace file """
+
+    try:
+        f_handle = open('/sys/kernel/debug/tracing/trace', 'w')
+        f_handle.close()
+    except:
+        print('IO error clearing trace file ')
+        quit()
+
+def enable_trace():
+    """ Enable trace """
+
+    try:
+       open('/sys/kernel/debug/tracing/events/power/pstate_sample/enable'
+                 , 'w').write("1")
+    except:
+        print('IO error enabling trace ')
+        quit()
+
+def disable_trace():
+    """ Disable trace """
+
+    try:
+       open('/sys/kernel/debug/tracing/events/power/pstate_sample/enable'
+                 , 'w').write("0")
+    except:
+        print('IO error disabling trace ')
+        quit()
+
+def set_trace_buffer_size():
+    """ Set trace buffer size """
+
+    try:
+       open('/sys/kernel/debug/tracing/buffer_size_kb'
+                 , 'w').write("10240")
+    except:
+        print('IO error setting trace buffer size ')
+        quit()
+
+def read_trace_data(filename):
+    """ Read and parse trace data """
+
+    global current_max_cpu
+    global sample_num, last_sec_cpu, last_usec_cpu, start_time
+
+    try:
+        data = open(filename, 'r').read()
+    except:
+        print('Error opening ', filename)
+        quit()
+
+    for line in data.splitlines():
+        search_obj = \
+            re.search(r'(^(.*?)\[)((\d+)[^\]])(.*?)(\d+)([.])(\d+)(.*?core_busy=)(\d+)(.*?scaled=)(\d+)(.*?from=)(\d+)(.*?to=)(\d+)(.*?mperf=)(\d+)(.*?aperf=)(\d+)(.*?tsc=)(\d+)(.*?freq=)(\d+)'
+                      , line)
+
+        if search_obj:
+            cpu = search_obj.group(3)
+            cpu_int = int(cpu)
+            cpu = str(cpu_int)
+
+            time_pre_dec = search_obj.group(6)
+            time_post_dec = search_obj.group(8)
+            core_busy = search_obj.group(10)
+            scaled = search_obj.group(12)
+            _from = search_obj.group(14)
+            _to = search_obj.group(16)
+            mperf = search_obj.group(18)
+            aperf = search_obj.group(20)
+            tsc = search_obj.group(22)
+            freq = search_obj.group(24)
+            common_comm = search_obj.group(2).replace(' ', '')
+
+            # Not all kernel versions have io_boost field
+            io_boost = '0'
+            search_obj = re.search(r'.*?io_boost=(\d+)', line)
+            if search_obj:
+                io_boost = search_obj.group(1)
+
+            if sample_num == 0 :
+                start_time = Decimal(time_pre_dec) + Decimal(time_post_dec) / Decimal(1000000)
+            sample_num += 1
+
+            if last_sec_cpu[cpu_int] == 0 :
+                last_sec_cpu[cpu_int] = time_pre_dec
+                last_usec_cpu[cpu_int] = time_post_dec
+            else :
+                duration_us = (int(time_pre_dec) - int(last_sec_cpu[cpu_int])) * 1000000 + (int(time_post_dec) - int(last_usec_cpu[cpu_int]))
+                duration_ms = Decimal(duration_us) / Decimal(1000)
+                last_sec_cpu[cpu_int] = time_pre_dec
+                last_usec_cpu[cpu_int] = time_post_dec
+                elapsed_time = Decimal(time_pre_dec) + Decimal(time_post_dec) / Decimal(1000000) - start_time
+                load = Decimal(int(mperf)*100)/ Decimal(tsc)
+                freq_ghz = Decimal(freq)/Decimal(1000000)
+#               Sanity check calculation, typically anomalies indicate missed samples
+#               However, check for 0 (should never occur)
+                tsc_ghz = Decimal(0)
+                if duration_ms != Decimal(0) :
+                    tsc_ghz = Decimal(tsc)/duration_ms/Decimal(1000000)
+                store_csv(cpu_int, time_pre_dec, time_post_dec, core_busy, scaled, _from, _to, mperf, aperf, tsc, freq_ghz, io_boost, common_comm, load, duration_ms, sample_num, elapsed_time, tsc_ghz)
+
+            if cpu_int > current_max_cpu:
+                current_max_cpu = cpu_int
+# End of for each trace line loop
+# Now seperate the main overall csv file into per CPU csv files.
+    split_csv()
+
+interval = ""
+filename = ""
+cpu_list = ""
+testname = ""
+graph_data_present = False;
+
+valid1 = False
+valid2 = False
+
+cpu_mask = zeros((MAX_CPUS,), dtype=int)
+
+try:
+    opts, args = getopt.getopt(sys.argv[1:],"ht:i:c:n:",["help","trace_file=","interval=","cpu=","name="])
+except getopt.GetoptError:
+    print_help()
+    sys.exit(2)
+for opt, arg in opts:
+    if opt == '-h':
+        print()
+        sys.exit()
+    elif opt in ("-t", "--trace_file"):
+        valid1 = True
+        location = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))
+        filename = os.path.join(location, arg)
+    elif opt in ("-i", "--interval"):
+        valid1 = True
+        interval = arg
+    elif opt in ("-c", "--cpu"):
+        cpu_list = arg
+    elif opt in ("-n", "--name"):
+        valid2 = True
+        testname = arg
+
+if not (valid1 and valid2):
+    print_help()
+    sys.exit()
+
+if cpu_list:
+    for p in re.split("[,]", cpu_list):
+        if int(p) < MAX_CPUS :
+            cpu_mask[int(p)] = 1
+else:
+    for i in range (0, MAX_CPUS):
+        cpu_mask[i] = 1
+
+if not os.path.exists('results'):
+    os.mkdir('results')
+
+os.chdir('results')
+if os.path.exists(testname):
+    print('The test name directory already exists. Please provide a unique test name. Test re-run not supported, yet.')
+    sys.exit()
+os.mkdir(testname)
+os.chdir(testname)
+
+# Temporary (or perhaps not)
+cur_version = sys.version_info
+print('python version (should be >= 2.7):')
+print(cur_version)
+
+# Left as "cleanup" for potential future re-run ability.
+cleanup_data_files()
+
+if interval:
+    filename = "/sys/kernel/debug/tracing/trace"
+    clear_trace_file()
+    set_trace_buffer_size()
+    enable_trace()
+    print('Sleeping for ', interval, 'seconds')
+    time.sleep(int(interval))
+    disable_trace()
+
+current_max_cpu = 0
+
+read_trace_data(filename)
+
+if graph_data_present == False:
+    print('No valid data to plot')
+    sys.exit(2)
+
+for cpu_no in range(0, current_max_cpu + 1):
+    plot_perf_busy_with_sample(cpu_no)
+    plot_perf_busy(cpu_no)
+    plot_durations(cpu_no)
+    plot_loads(cpu_no)
+
+plot_pstate_cpu_with_sample()
+plot_pstate_cpu()
+plot_load_cpu()
+plot_frequency_cpu()
+plot_duration_cpu()
+plot_scaled_cpu()
+plot_boost_cpu()
+plot_ghz_cpu()
+
+os.chdir('../../')